summaryrefslogtreecommitdiff
path: root/easytool
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-08-12 15:30:52 +0800
committerHarald Welte <laforge@gnumonks.org>2010-08-12 15:30:52 +0800
commit089fd4bbd25d3b564a3bac787bd9bbb114abfa5f (patch)
tree6d3f7e95cf69e46ecf1d50e05342c22794d5e0c9 /easytool
parente17d05da36d51faf2396c6ec0b198ff84b7cc14b (diff)
add first version of easycard dumping tool
Diffstat (limited to 'easytool')
-rw-r--r--easytool/easytool.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/easytool/easytool.c b/easytool/easytool.c
new file mode 100644
index 0000000..5a77997
--- /dev/null
+++ b/easytool/easytool.c
@@ -0,0 +1,180 @@
+
+#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 <nfc/nfc-types.h>
+#include <nfc/mifaretag.h>
+
+struct value_string {
+ unsigned int value;
+ const char *str;
+};
+
+static char namebuf[255];
+const char *get_value_string(const struct value_string *vs, uint32_t val)
+{
+ int i;
+
+ for (i = 0;; i++) {
+ if (vs[i].value == 0 && vs[i].str == NULL)
+ break;
+ if (vs[i].value == val)
+ return vs[i].str;
+ }
+
+ snprintf(namebuf, sizeof(namebuf), "unknown 0x%x", val);
+ return namebuf;
+}
+
+
+struct {
+ int fd;
+ unsigned long size;
+ mifare_tag *mft;
+} global;
+
+#define ABP_C1 0x04
+#define ABP_C2 0x02
+#define ABP_C3 0x01
+
+struct acc_bits_parsed {
+ uint8_t block[4];
+};
+
+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 parse_acc_bits(struct acc_bits_parsed *abp, uint8_t *acc_bits)
+{
+ uint8_t c1, c2, c3;
+ uint8_t block;
+
+ memset(abp, 0, sizeof(*abp));
+
+ c1 = acc_bits[1] >> 4;
+ c2 = acc_bits[2] & 0xf;
+ c3 = acc_bits[2] >> 4;
+
+ printf("C1 = %x, C2 = %x, C3 = %x\n", c1, c2, c3);
+
+ for (block = 0; block < 4; block++) {
+ uint8_t testbit = 1 << block;
+ if (c1 & testbit)
+ abp->block[block] |= ABP_C1;
+ if (c2 & testbit)
+ abp->block[block] |= ABP_C2;
+ if (c3 & testbit)
+ abp->block[block] |= ABP_C3;
+ }
+}
+
+#define EASY_TT_MRT_ENTER 0x00
+#define EASY_TT_MRT_EXIT 0x11
+#define EASY_TT_PURCHASE 0x20
+
+struct value_string easy_tt_names[] = {
+ { EASY_TT_MRT_ENTER, "Enter MRT Stn" },
+ { EASY_TT_MRT_EXIT, "Leave MRT Stn" },
+ { EASY_TT_PURCHASE, "Shop Purchase" },
+ { 0, NULL }
+};
+
+/* storage of a transaction log record on the transponder itself */
+struct easy_log_rec {
+ uint8_t unknown[2];
+ uint8_t timestamp[3]; /* seconds since January 1st 1970 / 256 */
+ uint8_t trans_type;
+ uint16_t amount; /* transaction amount / value */
+ uint16_t remaining; /* remaining value on card _after_ trans */
+ uint8_t unknown2[6];
+} __attribute__ ((packed));
+
+static time_t convert_timestamp(const uint8_t *easy_ts)
+{
+ return (easy_ts[2] << 16 | easy_ts[1] << 8 | easy_ts[0]) << 8;
+}
+
+static void dump_easy_log(const struct easy_log_rec *elr)
+{
+ time_t t_time = convert_timestamp(elr->timestamp);
+ struct tm *t_tm = gmtime(&t_time);
+ printf("%u-%u-%u %u:%u | %10s %u NTD -> %u NTD remaining\n",
+ t_tm->tm_year+1900, t_tm->tm_mon+1, t_tm->tm_mday,
+ t_tm->tm_hour, t_tm->tm_min,
+ get_value_string(easy_tt_names, elr->trans_type),
+ elr->amount, elr->remaining);
+}
+
+static 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;
+ int i;
+
+ printf("Sector %02u (base: 0x%02x) Access bits: 0x%08x\n", sect,
+ sect*4*16, ntohl(*((uint32_t *) access_bits)));
+ //parse_acc_bits(&abp, access_bits);
+ //dump_acc_bits(&abp);
+ if (sect == 3 || sect == 4) {
+ for (i = 0; i < 3; i++) {
+ void *data = mft->amb[block_base+i].mbd.abtData;
+ dump_easy_log(data);
+ }
+ }
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ struct stat st;
+
+ global.fd = open(argv[1], O_RDONLY);
+ if (global.fd < 0) {
+ perror("open");
+ exit(1);
+ }
+ if (fstat(global.fd, &st) < 0) {
+ perror("stat");
+ exit(1);
+ }
+ global.size = st.st_size;
+ global.mft = mmap(NULL, global.size, PROT_READ, MAP_SHARED,
+ global.fd, 0);
+ if (!global.mft) {
+ perror("mmap");
+ exit(1);
+ }
+
+ dump_mfcl(global.mft);
+
+ munmap(global.mft, global.size);
+ close(global.fd);
+ exit(0);
+}
personal git repositories of Harald Welte. Your mileage may vary