184 lines
4.8 KiB
C
184 lines
4.8 KiB
C
/* A reverse-engineered implementation of the EasyCard data format */
|
|
|
|
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
|
* All Rights Reserved
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
/* System includes */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stdint.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include <netinet/in.h>
|
|
|
|
/* libnfc includes */
|
|
#include <nfc/nfc-types.h>
|
|
#include <nfc/mifaretag.h>
|
|
|
|
#include "mifare_classic.h"
|
|
|
|
/* Easycard specific includes */
|
|
#include "easycard.h"
|
|
|
|
#define VERSION "0.01"
|
|
#define COPYRIGHT \
|
|
"EasyTool "VERSION"\n" \
|
|
"(C) 2010 by Harald Welte <laforge@gnumonks.org>\n" \
|
|
"This is FREE SOFTWARE with ABSOLUTELY NO VARRANTY\n\n" \
|
|
"Use of this software is only authorized for RESEARCH PURPOSE!\n\n"
|
|
|
|
struct {
|
|
int fd;
|
|
unsigned long size;
|
|
mifare_tag *mft;
|
|
} global;
|
|
|
|
static void dump_easy_log(const struct easy_log_rec *elr)
|
|
{
|
|
printf("%s | %02x | %10s | Paid %4u NTD | %4u NTD remaining\n",
|
|
easy_asc_timestamp(elr->timestamp),
|
|
elr->trans_id,
|
|
get_value_string(easy_tt_names, elr->trans_type),
|
|
elr->amount, elr->remaining);
|
|
switch (elr->trans_type) {
|
|
case EASY_TT_MRT_ENTER:
|
|
case EASY_TT_MRT_REENTER:
|
|
case EASY_TT_MRT_EXIT:
|
|
printf("\tMRT Station %s\n",
|
|
get_value_string(taipei_mrt_stn_id,
|
|
elr->station_code));
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void dump_acc_bits(const struct acc_bits_parsed *abp)
|
|
{
|
|
uint8_t block;
|
|
|
|
for (block = 0; block < 4; block++) {
|
|
printf("\tBlock %u: %x (%u %u %u)\n", block, abp->block[block],
|
|
abp->block[block] & ABP_C1 ? 1 : 0,
|
|
abp->block[block] & ABP_C2 ? 1 : 0,
|
|
abp->block[block] & ABP_C3 ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
static void dump_mfcl(mifare_tag *mft)
|
|
{
|
|
unsigned int sect;
|
|
|
|
mifare_block_manufacturer *manuf = &mft->amb[0].mbm;
|
|
|
|
printf("UID %x, ATQA %x\n", ntohl(*((uint32_t *) manuf->abtUID)),
|
|
ntohs(*((uint16_t *) manuf->abtATQA)));
|
|
|
|
for (sect = 0; sect < 16; sect++) {
|
|
unsigned int block_base = sect * 4;
|
|
uint8_t *access_bits = mft->amb[block_base+3].mbt.abtAccessBits;
|
|
struct acc_bits_parsed abp;
|
|
|
|
printf("Sector %02u (base: 0x%02x) Access bits: 0x%08x\n", sect,
|
|
sect*4*16, ntohl(*((uint32_t *) access_bits)));
|
|
mfcl_parse_acc_bits(&abp, access_bits);
|
|
dump_acc_bits(&abp);
|
|
}
|
|
}
|
|
|
|
static void dump_easycard(mifare_tag *mft)
|
|
{
|
|
unsigned int sect;
|
|
mifare_block_manufacturer *manuf = &mft->amb[0].mbm;
|
|
struct mfcl_value_block *val =
|
|
(struct mfcl_value_block *) mft->amb[8].mbd.abtData;
|
|
struct easy_block2sec0 *b2s0 =
|
|
(struct easy_block2sec0 *) mft->amb[1*4+0].mbd.abtData;
|
|
struct easy_block15sec2 *b15s2 =
|
|
(struct easy_block15sec2 *) mft->amb[15*4+2].mbd.abtData;
|
|
uint32_t uid = *((uint32_t *) manuf->abtUID);
|
|
|
|
/* dump the header */
|
|
printf("EasyCard UID 0x%08x (%u)\n", ntohl(uid), uid);
|
|
printf("Date of manufacture: %s\n",
|
|
easy_asc_timestamp(b2s0->timestamp));
|
|
printf("Current Balance: %5u NTD\n", val->value);
|
|
printf("Sum of all purchases on day %u (of month): %u NTD\n",
|
|
b15s2->day_of_month, b15s2->sum_of_day);
|
|
printf("\nTransaction Log:\n");
|
|
|
|
/* dump the transaction log */
|
|
for (sect = 3; sect < 6; sect++) {
|
|
unsigned int block_base = sect * 4;
|
|
unsigned int i;
|
|
for (i = 0; i < 3; i++) {
|
|
void *data = mft->amb[block_base+i].mbd.abtData;
|
|
/* first block of sector 3 is not a log record */
|
|
if (sect == 3 && i == 0)
|
|
continue;
|
|
dump_easy_log(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void print_help(void)
|
|
{
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct stat st;
|
|
|
|
printf(COPYRIGHT);
|
|
|
|
if (argc < 2) {
|
|
fprintf(stderr, "ERROR: You must specify the file name of "
|
|
"a mifare dump file (.mfd)\n");
|
|
print_help();
|
|
exit(2);
|
|
}
|
|
|
|
global.fd = open(argv[1], O_RDONLY);
|
|
if (global.fd < 0) {
|
|
perror("Error opening the MFD file");
|
|
exit(1);
|
|
}
|
|
if (fstat(global.fd, &st) < 0) {
|
|
perror("Error stat()ing the MFD file");
|
|
exit(1);
|
|
}
|
|
global.size = st.st_size;
|
|
global.mft = mmap(NULL, global.size, PROT_READ, MAP_SHARED,
|
|
global.fd, 0);
|
|
if (!global.mft) {
|
|
perror("Error mmap()ing the MFD file");
|
|
exit(1);
|
|
}
|
|
|
|
//dump_mfcl(global.mft);
|
|
dump_easycard(global.mft);
|
|
|
|
munmap(global.mft, global.size);
|
|
close(global.fd);
|
|
exit(0);
|
|
}
|