From 3a9087d2a13002cb805c081a82ad61f9d24b65ef Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 22 Sep 2019 15:27:00 +1000 Subject: [PATCH 1/6] Update cmdlfem4x.c em 4x05_dump did not output data --- client/cmdlfem4x.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index e7b1c2b06..80a10e06e 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -1213,19 +1213,27 @@ static int CmdEM4x05Dump(const char *Cmd) { usePwd = true; int success = PM3_SUCCESS; + int status; uint32_t word = 0; - PrintAndLogEx(NORMAL, "Addr | data | ascii"); - PrintAndLogEx(NORMAL, "-----+--------+------"); + PrintAndLogEx(NORMAL, "Addr | data | info"); + PrintAndLogEx(NORMAL, "-----+----------+-------"); for (; addr < 16; addr++) { if (addr == 2) { if (usePwd) { - PrintAndLogEx(NORMAL, " %02u | %08X", addr, pwd, word); + PrintAndLogEx(NORMAL, " %02u | %08X |", addr, pwd, word); } else { - PrintAndLogEx(NORMAL, " 02 | " _RED_("cannot read")); + PrintAndLogEx(NORMAL, " 02 | | " _RED_("cannot read")); } } else { - success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word); + // success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word); + status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read + success &= status; // Update status to match previous return + + if (status == PM3_SUCCESS) + PrintAndLogEx(NORMAL, " %02d | %08X | %s", addr, word, (addr > 13) ? "Lock" : ""); + else + PrintAndLogEx(NORMAL, " %02d | " _RED_("Fail"), addr); } } From 0ea501372ba881c2cc59528edce8511f182fa0cf Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 22 Sep 2019 19:41:45 +1000 Subject: [PATCH 2/6] Update cmdlfem4x.c Added print Ascii to em 4x05_dump --- client/cmdlfem4x.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 80a10e06e..ec535205e 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -1204,6 +1204,8 @@ static int CmdEM4x05Dump(const char *Cmd) { uint32_t pwd = 0; bool usePwd = false; uint8_t ctmp = tolower(param_getchar(Cmd, 0)); + uint8_t bytes[4] = {0}; + if (ctmp == 'h') return usage_lf_em4x05_dump(); // for now use default input of 1 as invalid (unlikely 1 will be a valid password...) @@ -1215,7 +1217,7 @@ static int CmdEM4x05Dump(const char *Cmd) { int success = PM3_SUCCESS; int status; uint32_t word = 0; - PrintAndLogEx(NORMAL, "Addr | data | info"); + PrintAndLogEx(NORMAL, "Addr | data | ascii"); PrintAndLogEx(NORMAL, "-----+----------+-------"); for (; addr < 16; addr++) { @@ -1230,10 +1232,12 @@ static int CmdEM4x05Dump(const char *Cmd) { status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read success &= status; // Update status to match previous return - if (status == PM3_SUCCESS) - PrintAndLogEx(NORMAL, " %02d | %08X | %s", addr, word, (addr > 13) ? "Lock" : ""); + if (status == PM3_SUCCESS) { + num_to_bytes(word, 4, bytes); + PrintAndLogEx(NORMAL, " %02d | %08X | %s", addr, word, (addr > 13) ? "Lock" : sprint_ascii(bytes, 4)); + } else - PrintAndLogEx(NORMAL, " %02d | " _RED_("Fail"), addr); + PrintAndLogEx(NORMAL, " %02d | | " _RED_("Fail"), addr); } } @@ -1244,6 +1248,7 @@ static int CmdEM4x05Read(const char *Cmd) { uint8_t addr; uint32_t pwd; bool usePwd = false; + uint8_t ctmp = tolower(param_getchar(Cmd, 0)); if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_read(); From 361136f06d5a57ee419d6ace2b17886709cd313a Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Mon, 23 Sep 2019 21:04:33 +1000 Subject: [PATCH 3/6] Update cmdlfem4x.c dump display and save to file --- client/cmdlfem4x.c | 59 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index ec535205e..36c2089d8 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -16,6 +16,7 @@ #include #include +#include "fileutils.h" #include "cmdparser.h" // command_t #include "comms.h" #include "commonutil.h" @@ -1199,48 +1200,78 @@ static int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t return demodEM4x05resp(word); } +#define swapedEndian(num) ((num>>24)&0xff) | ((num<<8)&0xff0000) | ((num>>8)&0xff00) | ((num<<24)&0xff000000) + static int CmdEM4x05Dump(const char *Cmd) { uint8_t addr = 0; uint32_t pwd = 0; bool usePwd = false; - uint8_t ctmp = tolower(param_getchar(Cmd, 0)); +//uint8_t ctmp = tolower(param_getchar(Cmd, 0)); + uint8_t cmdp = 0; uint8_t bytes[4] = {0}; + uint32_t data[16]; + char preferredName[FILE_PATH_SIZE] = {0}; + bool save = false; - if (ctmp == 'h') return usage_lf_em4x05_dump(); - + while (param_getchar(Cmd, cmdp) != 0x00) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': return usage_lf_em4x05_dump(); + break; + case 's': param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE); + save = true; + cmdp+=2; + break; + default : // for backwards-compatibility options should be > 'f' else assume its the hex password` + pwd = param_get32ex(Cmd, cmdp, 1, 16); + usePwd = true; + cmdp++; + }; + } +// if (ctmp == 'h') return usage_lf_em4x05_dump(); +// if (ctmp == 's') { // save dump +// +// } // for now use default input of 1 as invalid (unlikely 1 will be a valid password...) - pwd = param_get32ex(Cmd, 0, 1, 16); +// pwd = param_get32ex(Cmd, 0, 1, 16); - if (pwd != 1) - usePwd = true; + // if (pwd != 1) + // usePwd = true; int success = PM3_SUCCESS; int status; uint32_t word = 0; - PrintAndLogEx(NORMAL, "Addr | data | ascii"); - PrintAndLogEx(NORMAL, "-----+----------+-------"); + PrintAndLogEx(NORMAL, "Addr | data | ascii | info"); + PrintAndLogEx(NORMAL, "-----+----------+-------+------"); for (; addr < 16; addr++) { if (addr == 2) { if (usePwd) { - PrintAndLogEx(NORMAL, " %02u | %08X |", addr, pwd, word); + data[addr] = swapedEndian(pwd); + num_to_bytes(pwd, 4, bytes); + PrintAndLogEx(NORMAL, " %02u | %08X | %s | password", addr, pwd, sprint_ascii(bytes, 4)); } else { - PrintAndLogEx(NORMAL, " 02 | | " _RED_("cannot read")); + data[addr] = 0x00; // Unknown password, but not used to set to zeros + PrintAndLogEx(NORMAL, " 02 | | | " _RED_("cannot read")); } } else { // success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word); status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read success &= status; // Update status to match previous return - + data[addr] = swapedEndian(word); if (status == PM3_SUCCESS) { num_to_bytes(word, 4, bytes); - PrintAndLogEx(NORMAL, " %02d | %08X | %s", addr, word, (addr > 13) ? "Lock" : sprint_ascii(bytes, 4)); + PrintAndLogEx(NORMAL, " %02d | %08X | %s | %s", addr, word, sprint_ascii(bytes, 4), (addr > 13) ? "Lock" : ""); } else - PrintAndLogEx(NORMAL, " %02d | | " _RED_("Fail"), addr); + PrintAndLogEx(NORMAL, " %02d | | | " _RED_("Fail"), addr); } } - + + if ((success == PM3_SUCCESS) && (save)) {// all ok save dump to file + saveFileEML(preferredName, (uint8_t *)data, 16*sizeof(uint32_t), sizeof(uint32_t)); + saveFile (preferredName, ".bin", data, sizeof(data)); + } + return success; } From 87a6316f44e13f954752c6925a3e18ba21267917 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 24 Sep 2019 19:59:54 +1000 Subject: [PATCH 4/6] Update cmdlfem4x.c Dump print and save to .eml and .bin --- client/cmdlfem4x.c | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 36c2089d8..e4a9d4983 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -20,6 +20,7 @@ #include "cmdparser.h" // command_t #include "comms.h" #include "commonutil.h" +#include "common.h" #include "util_posix.h" #include "protocols.h" #include "ui.h" @@ -155,13 +156,15 @@ static int usage_lf_em4x50_write(void) { static int usage_lf_em4x05_dump(void) { PrintAndLogEx(NORMAL, "Dump EM4x05/EM4x69. Tag must be on antenna. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x05_dump [h] "); + PrintAndLogEx(NORMAL, "Usage: lf em 4x05_dump [h] [s ] "); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)"); + PrintAndLogEx(NORMAL, " h - this help"); + PrintAndLogEx(NORMAL, " s - overide filename prefix (optional). Default is based on card serial number"); + PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf em 4x05_dump"); PrintAndLogEx(NORMAL, " lf em 4x05_dump 11223344"); + PrintAndLogEx(NORMAL, " lf em 4x50_dump s card1 11223344"); return PM3_SUCCESS; } static int usage_lf_em4x05_read(void) { @@ -1200,42 +1203,30 @@ static int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t return demodEM4x05resp(word); } -#define swapedEndian(num) ((num>>24)&0xff) | ((num<<8)&0xff0000) | ((num>>8)&0xff00) | ((num<<24)&0xff000000) - static int CmdEM4x05Dump(const char *Cmd) { uint8_t addr = 0; uint32_t pwd = 0; bool usePwd = false; -//uint8_t ctmp = tolower(param_getchar(Cmd, 0)); uint8_t cmdp = 0; uint8_t bytes[4] = {0}; uint32_t data[16]; char preferredName[FILE_PATH_SIZE] = {0}; - bool save = false; while (param_getchar(Cmd, cmdp) != 0x00) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_lf_em4x05_dump(); break; case 's': param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE); - save = true; cmdp+=2; break; default : // for backwards-compatibility options should be > 'f' else assume its the hex password` + // for now use default input of 1 as invalid (unlikely 1 will be a valid password...) pwd = param_get32ex(Cmd, cmdp, 1, 16); - usePwd = true; + if (pwd != 1) + usePwd = true; cmdp++; }; } -// if (ctmp == 'h') return usage_lf_em4x05_dump(); -// if (ctmp == 's') { // save dump -// -// } - // for now use default input of 1 as invalid (unlikely 1 will be a valid password...) -// pwd = param_get32ex(Cmd, 0, 1, 16); - - // if (pwd != 1) - // usePwd = true; int success = PM3_SUCCESS; int status; @@ -1246,7 +1237,7 @@ static int CmdEM4x05Dump(const char *Cmd) { if (addr == 2) { if (usePwd) { - data[addr] = swapedEndian(pwd); + data[addr] = BSWAP_32(pwd); num_to_bytes(pwd, 4, bytes); PrintAndLogEx(NORMAL, " %02u | %08X | %s | password", addr, pwd, sprint_ascii(bytes, 4)); } else { @@ -1256,8 +1247,9 @@ static int CmdEM4x05Dump(const char *Cmd) { } else { // success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word); status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read - success &= status; // Update status to match previous return - data[addr] = swapedEndian(word); + if (status != PM3_SUCCESS) + success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data + data[addr] = BSWAP_32(word); if (status == PM3_SUCCESS) { num_to_bytes(word, 4, bytes); PrintAndLogEx(NORMAL, " %02d | %08X | %s | %s", addr, word, sprint_ascii(bytes, 4), (addr > 13) ? "Lock" : ""); @@ -1266,8 +1258,13 @@ static int CmdEM4x05Dump(const char *Cmd) { PrintAndLogEx(NORMAL, " %02d | | | " _RED_("Fail"), addr); } } - - if ((success == PM3_SUCCESS) && (save)) {// all ok save dump to file + + if (success == PM3_SUCCESS) { // all ok save dump to file + // saveFileEML will add .eml extension to filename + // saveFile (binary) passes in the .bin extension. + if (strcmp (preferredName,"") == 0) // Set default filename, if not set by user + sprintf (preferredName,"lf-4x05-%08X-data",BSWAP_32(data[1])); + saveFileEML(preferredName, (uint8_t *)data, 16*sizeof(uint32_t), sizeof(uint32_t)); saveFile (preferredName, ".bin", data, sizeof(data)); } From 072b9599b95e6a38a803a1f1ca52838b1b5c5d1a Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 24 Sep 2019 20:04:21 +1000 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 783b596c5..32a317320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -355,6 +355,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added T55x7 downlink mode support r 0 Default, 1 Long Leading 0, 2 Leading 0, 3 1 of 4 and 4 (in some commands) try all. (@mwalker33) - Added T55x7 downlink mode auto usage via mode detected (lf t55 detect) (@mwalker33) - Fix T55xx config getting displayed when using password when no password needed on read. (@mwalker33) + - Fix `em 4x05_dump` to print all blocks read (@mwalker33) + - Added save to .eml and .bin for `em 4x05_dump` (@mwalker33) ### Fixed - Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (@pwpiwi) From bf395a6c4fc83b20b4e729d43062e9a77669a895 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 24 Sep 2019 21:42:31 +1000 Subject: [PATCH 6/6] Update cmdlfem4x.c Add lck flags and f for filename --- client/cmdlfem4x.c | 61 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index e4a9d4983..fd1250440 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -156,15 +156,15 @@ static int usage_lf_em4x50_write(void) { static int usage_lf_em4x05_dump(void) { PrintAndLogEx(NORMAL, "Dump EM4x05/EM4x69. Tag must be on antenna. "); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf em 4x05_dump [h] [s ] "); + PrintAndLogEx(NORMAL, "Usage: lf em 4x05_dump [h] [f ] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " s - overide filename prefix (optional). Default is based on card serial number"); + PrintAndLogEx(NORMAL, " f - overide filename prefix (optional). Default is based on UID"); PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf em 4x05_dump"); PrintAndLogEx(NORMAL, " lf em 4x05_dump 11223344"); - PrintAndLogEx(NORMAL, " lf em 4x50_dump s card1 11223344"); + PrintAndLogEx(NORMAL, " lf em 4x50_dump f card1 11223344"); return PM3_SUCCESS; } static int usage_lf_em4x05_read(void) { @@ -1211,14 +1211,20 @@ static int CmdEM4x05Dump(const char *Cmd) { uint8_t bytes[4] = {0}; uint32_t data[16]; char preferredName[FILE_PATH_SIZE] = {0}; - + char optchk[10]; + while (param_getchar(Cmd, cmdp) != 0x00) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_lf_em4x05_dump(); break; - case 's': param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE); - cmdp+=2; - break; + case 'f': // since f could match in password, lets confirm it is 1 character only for an option + param_getstr(Cmd, cmdp,optchk,sizeof(optchk)); + if (strlen (optchk) == 1) {// Have a single character f so filename no password + param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE); + cmdp+=2; + break; + } // if not a single 'f' dont break and flow onto default as should be password + default : // for backwards-compatibility options should be > 'f' else assume its the hex password` // for now use default input of 1 as invalid (unlikely 1 will be a valid password...) pwd = param_get32ex(Cmd, cmdp, 1, 16); @@ -1230,19 +1236,39 @@ static int CmdEM4x05Dump(const char *Cmd) { int success = PM3_SUCCESS; int status; + uint32_t lock_bits = 0x00; // no blocks locked + uint32_t word = 0; - PrintAndLogEx(NORMAL, "Addr | data | ascii | info"); - PrintAndLogEx(NORMAL, "-----+----------+-------+------"); - for (; addr < 16; addr++) { + PrintAndLogEx(NORMAL, "Addr | data | ascii |lck| info"); + PrintAndLogEx(NORMAL, "-----+----------+-------+---+-----"); + + // To flag any blocks locked we need to read blocks 14 and 15 first + // dont swap endin until we get block lock flags. + status = EM4x05ReadWord_ext(14, pwd, usePwd, &word); + if (status != PM3_SUCCESS) + success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data + if (word != 0x00) + lock_bits = word; + data[14] = word; + + status = EM4x05ReadWord_ext(15, pwd, usePwd, &word); + if (status != PM3_SUCCESS) + success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data + if (word != 0x00) // assume block 15 is the current lock block + lock_bits = word; + data[15] = word; + + // Now read blocks 0 - 13 as we have 14 and 15 + for (; addr < 14; addr++) { if (addr == 2) { if (usePwd) { data[addr] = BSWAP_32(pwd); num_to_bytes(pwd, 4, bytes); - PrintAndLogEx(NORMAL, " %02u | %08X | %s | password", addr, pwd, sprint_ascii(bytes, 4)); + PrintAndLogEx(NORMAL, " %02u | %08X | %s | %c | password", addr, pwd, sprint_ascii(bytes, 4),((lock_bits >> addr) & 1) ? 'x' : ' '); } else { data[addr] = 0x00; // Unknown password, but not used to set to zeros - PrintAndLogEx(NORMAL, " 02 | | | " _RED_("cannot read")); + PrintAndLogEx(NORMAL, " 02 | | | | " _RED_("cannot read")); } } else { // success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word); @@ -1252,12 +1278,19 @@ static int CmdEM4x05Dump(const char *Cmd) { data[addr] = BSWAP_32(word); if (status == PM3_SUCCESS) { num_to_bytes(word, 4, bytes); - PrintAndLogEx(NORMAL, " %02d | %08X | %s | %s", addr, word, sprint_ascii(bytes, 4), (addr > 13) ? "Lock" : ""); + PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c |", addr, word, sprint_ascii(bytes, 4),((lock_bits >> addr) & 1) ? 'x' : ' '); } else - PrintAndLogEx(NORMAL, " %02d | | | " _RED_("Fail"), addr); + PrintAndLogEx(NORMAL, " %02d | | | | " _RED_("Fail"), addr); } } + // Print blocks 14 and 15 + // Both lock bits are protected with bit idx 14 (special case) + PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c | Lock", 14, data[14], sprint_ascii(bytes, 4),((lock_bits >> 14) & 1) ? 'x' : ' '); + PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c | Lock", 15, data[15], sprint_ascii(bytes, 4),((lock_bits >> 14) & 1) ? 'x' : ' '); + // Update endian for files + data[14] = BSWAP_32(data[14]); + data[15] = BSWAP_32(data[15]); if (success == PM3_SUCCESS) { // all ok save dump to file // saveFileEML will add .eml extension to filename