From ba8aa6f0abe7605fcec993df853a88acfee5f255 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 15 Oct 2020 19:29:54 +0200 Subject: [PATCH] lf em stuff --- client/src/cmdhfmfp.c | 28 ++-- client/src/cmdhw.c | 27 +++ client/src/cmdhw.h | 2 + client/src/cmdlfem4x.c | 367 ++++++++++++++++++++++++++++++++++++++++- include/pm3_cmd.h | 6 + 5 files changed, 416 insertions(+), 14 deletions(-) diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index e72799bc4..7d9c077fb 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -233,6 +233,7 @@ static int plus_print_version(uint8_t *version) { PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), version[7 + 7 + 7 + 5], version[7 + 7 + 7 + 5 + 1]); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information")); + PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version, 7)); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0])); PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[1])); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]); @@ -241,6 +242,7 @@ static int plus_print_version(uint8_t *version) { PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6], true)); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); + PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version + 7, 6)); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[7])); PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[8])); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[9]); @@ -265,13 +267,21 @@ static int get_plus_version(uint8_t *version, int *version_len) { static int CmdHFMFPInfo(const char *Cmd) { - if (Cmd && strlen(Cmd) > 0) - PrintAndLogEx(WARNING, "command don't have any parameters.\n"); - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); + // Mifare Plus info + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + + bool supportVersion = false; bool supportSignature = false; @@ -284,17 +294,11 @@ static int CmdHFMFPInfo(const char *Cmd) { } else { // info about 14a part infoHF14A(false, false, false); + + // Historical bytes. + } - // Mifare Plus info - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); - PacketResponseNG resp; - WaitForResponse(CMD_ACK, &resp); - - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - - uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision // Signature originality check uint8_t signature[56] = {0}; diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 68b5fdf40..22da51558 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -22,6 +22,7 @@ #include "cmdhw.h" #include "cmddata.h" #include "commonutil.h" +#include "pm3_cmd.h" static int CmdHelp(const char *Cmd); @@ -516,6 +517,32 @@ static int CmdStatus(const char *Cmd) { return PM3_SUCCESS; } +int handle_tearoff(tearoff_params_t *params, bool verbose) { + + if (params == NULL) + return PM3_EINVARG; + + clearCommandBuffer(); + SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)params, sizeof(tearoff_params_t)); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_SET_TEAROFF, &resp, 500) == false) { + PrintAndLogEx(WARNING, "Tear-off command timeout."); + return PM3_ETIMEOUT; + } + + if (resp.status == PM3_SUCCESS) { + if (params->delay_us > 0 && verbose) + PrintAndLogEx(INFO, "Tear-off hook configured with delay of " _GREEN_("%i us"), params->delay_us); + + if (params->on && verbose) + PrintAndLogEx(INFO, "Tear-off hook " _GREEN_("enabled")); + + if (params->off && verbose) + PrintAndLogEx(INFO, "Tear-off hook " _RED_("disabled")); + } + return resp.status; +} + static int CmdTearoff(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hw tearoff", diff --git a/client/src/cmdhw.h b/client/src/cmdhw.h index bf40b70a8..4b48eb840 100644 --- a/client/src/cmdhw.h +++ b/client/src/cmdhw.h @@ -12,9 +12,11 @@ #define CMDHW_H__ #include "common.h" +#include "pm3_cmd.h" int CmdHW(const char *Cmd); +int handle_tearoff(tearoff_params_t *params, bool verbose); void pm3_version(bool verbose, bool oneliner); #endif diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 00019a569..7ffbc4824 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -32,6 +32,7 @@ #include "lfdemod.h" #include "generator.h" #include "cliparser.h" +#include "cmdhw.h" static uint64_t g_em410xid = 0; @@ -715,7 +716,7 @@ static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t col static bool downloadSamplesEM(void) { // 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples) - uint8_t got[6000]; + uint8_t got[5500]; if (!GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "(downloadSamplesEM) command execution time out"); return false; @@ -1413,10 +1414,11 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) { // 7,8, rfu // 9 - 18 customer code // 19, rfu - + 98765432109876543210 001000000000 // 00100000000001111000 + xxx---- // 1100 // 011 // 00100000000 @@ -1643,6 +1645,366 @@ static int CmdEM4x05Chk(const char *Cmd) { return PM3_SUCCESS; } + +static int unlock_write_protect(bool use_pwd, uint32_t pwd, uint32_t data, bool verbose) { + + struct { + uint32_t password; + uint32_t data; + uint8_t usepwd; + } PACKED payload; + + payload.password = pwd; + payload.data = data; + payload.usepwd = use_pwd; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X_PROTECTWORD, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_LF_EM4X_PROTECTWORD, &resp, 2000) == false) { + PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); + return PM3_ETIMEOUT; + } + + if (!downloadSamplesEM()) + return PM3_ENODATA; + + uint32_t dummy = 0; + int status = demodEM4x05resp(&dummy, true); + if (status == PM3_SUCCESS && verbose) + PrintAndLogEx(SUCCESS, "Success writing to tag"); + else if (status == PM3_EFAILED) + PrintAndLogEx(ERR, "Tag denied PROTECT operation"); + else + PrintAndLogEx(DEBUG, "No answer from tag"); + + return status; +} +static int unlock_reset(bool use_pwd, uint32_t pwd, uint32_t data) { + PrintAndLogEx(FAILED, "resetting the " _RED_("active") " lock block"); + return unlock_write_protect(use_pwd, pwd, data, false); +} + +static int CmdEM4x05Unlock(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x05_unlock", + "execute tear off against EM4205/4305/4469/4569", + "lf em 4x05_unlock\n" + "lf em 4x05_unlock -s 4100 -e 4100 -> lock on and autotune at 4100us\n" + "lf em 4x05_unlock -n 10 -s 3000 -e 4400 -> scan delays 3000us -> 4400us" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_0("n", NULL, NULL, "steps to skip"), + arg_u64_0("s", "start", "", "start scan from delay (us)"), + arg_u64_0("e", "end", "", "end scan at delay (us)"), + arg_u64_0("p", "pwd", "", "password (0x00000000)"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + uint64_t n = arg_get_u64_def(ctx, 1, 10); + uint64_t start = arg_get_u64_def(ctx, 2, 2000); + uint64_t end = arg_get_u64_def(ctx, 3, 6000); + uint64_t inputpwd = arg_get_u64_def(ctx, 4, 0xFFFFFFFFFFFFFFFF); + bool verbose = arg_get_lit(ctx, 5); + CLIParserFree(ctx); + + if (session.pm3_present == false) { + PrintAndLogEx(WARNING, "device offline\n"); + return PM3_ENODATA; + } + + bool use_pwd = false; + uint32_t pwd = 0; + if (inputpwd != 0xFFFFFFFFFFFFFFFF) { + use_pwd = true; + pwd = inputpwd & 0xFFFFFFFF; + } + + uint32_t search_value = 0; + uint32_t write_value = 0; + // + // inital phase + // + // read word 14 + uint32_t init_14 = 0; + int res = EM4x05ReadWord_ext(14, pwd, use_pwd, &init_14); + if (res != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "failed to read word 14\n"); + return PM3_ENODATA; + } + + + // read 15 + uint32_t init_15 = 0; + res = EM4x05ReadWord_ext(15, pwd, use_pwd, &init_15); + if (res != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "failed to read word 15\n"); + return PM3_ENODATA; + } + + +#define UNLOCK_WORD 0x00008000 + if (init_15 == UNLOCK_WORD) { + PrintAndLogEx(SUCCESS, "Tag already fully unlocked, nothing to do"); + return PM3_SUCCESS; + } + +#define ACTIVE_MASK 0x00008000 + if ((init_15 & ACTIVE_MASK) == ACTIVE_MASK) { + search_value = init_15; + } else { + search_value = init_14; + } + + + bool my_auto = false; + if (n == 0) { + my_auto = true; + n = (end - start) / 2; + } else { + if ( start > end ) { + PrintAndLogEx(FAILED, "start delay can\'t be larger than end delay %u vs %u", start, end); + return PM3_EINVARG; + } + } + + // fix at one specific delay + if (start == end) { + n = 0; + } + + PrintAndLogEx(INFO, "--------------- " _CYAN_("EM4x05 tear-off : target PROTECT") " -----------------------\n"); + + PrintAndLogEx(INFO, " Word 14,15 inital [ " _GREEN_("%08"PRIX32) ", " _GREEN_("%08"PRIX32) " ]", init_14, init_15); + + if (use_pwd) { + PrintAndLogEx(INFO, " target password [ " _GREEN_("%08"PRIX32) " ]", pwd); + } + if (my_auto) { + PrintAndLogEx(INFO, " automatic mode [ " _GREEN_("enabled") " ]"); + } + + PrintAndLogEx(INFO, " target stepping [ " _GREEN_("%u") " ]", n); + PrintAndLogEx(INFO, "target delay range [ " _GREEN_("%"PRIu32) " ... " _GREEN_("%"PRIu32) " ]", start, end); + PrintAndLogEx(INFO, " search value [ " _GREEN_("%08"PRIX32) " ]", search_value); + PrintAndLogEx(INFO, " write value [ " _GREEN_("%08"PRIX32) " ]", write_value); + + PrintAndLogEx(INFO, "----------------------------------------------------------------------------\n"); + PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command"); + + int exit_code = PM3_SUCCESS; + uint32_t word14 = 0, word15 = 0; + uint32_t tries = 0; + uint32_t soon = 0; + uint32_t late = 0; + // + // main loop + // + //uint32_t prev_delay = 0; + + uint64_t t1 = msclock(); + while (start <= end) { + + if (my_auto && n < 1) { + PrintAndLogEx(INFO, "Reached n < 1 => " _YELLOW_("disabling automatic mode")); + end = start; + my_auto = false; + n = 0; + } + + if (my_auto == false) { + start += n; + } + + if (tries >= 5 && n == 0 && soon != late) { + + if (soon > late) { + PrintAndLogEx(INFO, "Tried %d times, soon:%i late:%i => " _CYAN_("adjust +1us >> %u us"), tries, soon, late, start); + start++; + end++; + } else { + PrintAndLogEx(INFO, "Tried %d times, soon:%i late:%i => " _CYAN_("adjust -1us >> %u us"), tries, soon, late, start); + start--; + end--; + } + tries = 0; + soon = 0; + late = 0; + } + + + + if (is_cancelled()) { + exit_code = PM3_EOPABORTED; + break; + } + + /* + if ( start != prev_delay) { + PrintAndLogEx(INFO, "Tear-off delay hook configured => " _GREEN_("%u us"), start); + prev_delay = start; + } + */ + + // set tear off trigger + clearCommandBuffer(); + tearoff_params_t params = { + .delay_us = start, + .on = true, + .off = false + }; + res = handle_tearoff(¶ms, verbose); + if ( res != PM3_SUCCESS ) { + PrintAndLogEx(WARNING, "failed to configure tear off"); + return PM3_EOPABORTED; + } + + // write + res = unlock_write_protect(use_pwd, pwd, write_value, verbose); + + // read after trigger + res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14); + if (res == PM3_SUCCESS) { + //PrintAndLogEx(INFO, "14 after [ " _GREEN_("%08"PRIX32) " ]", word14); + } else { + continue; + } + + // read after trigger + res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15); + if (res == PM3_SUCCESS) { + //PrintAndLogEx(INFO, "15 after [ " _GREEN_("%08"PRIX32) " ]", word15); + } else { + continue; + } + + PrintAndLogEx(INFO, "ref:%08X 14:%08X 15:%08X ", search_value, word14, word15); + + if ( word14 == search_value && word15 == 0) { + PrintAndLogEx(INFO, "Status: Nothing happened => " _GREEN_("tearing too soon")); + + if (my_auto) { + start += n; + n /= 2; + PrintAndLogEx(INFO, "Adjusting params: n %i start %i end %i", n, start, end); + } else { + soon++; + } + } else { + + if (word15 == search_value) { + + if (word14 == 0) { + PrintAndLogEx(INFO, "Status: Protect succeeded => " _GREEN_("tearing too late")); + } else { + if ( word14 == search_value) { + PrintAndLogEx(INFO, "Status: 15 ok, 14 not yet erased => " _GREEN_("tearing too late")); + } else { + PrintAndLogEx(INFO, "Status: 15 ok, 14 partially erased => " _GREEN_("tearing too late")); + } + } + unlock_reset(use_pwd, pwd, write_value); + + // read after reset + res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14); + if (res != PM3_SUCCESS) { + continue; + } + + if (word14 == 0) { + unlock_reset(use_pwd, pwd, write_value); + } + + if (word14 != search_value) { + + // read after reset + res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15); + if (res == PM3_SUCCESS) { + PrintAndLogEx(INFO, "Status: new definitive value! => " _RED_("SUCCESS:") " 14: " _CYAN_("%08X") " 15: %08X", word14, word15); + break; + } else { + continue; + } + } + if (my_auto) { + end = start; + start -= n; + n /= 2; + PrintAndLogEx(INFO, "Adjusting params: n %i start %i end %i", n, start, end); + } else { + late++; + } + + } else { + + if (( word15 & ACTIVE_MASK) == ACTIVE_MASK) { + + PrintAndLogEx(INFO, "Status: 15 bitflipped and active => " _RED_("SUCCESS?: ") "14: %08X 15: " _CYAN_("%08X"), word14, word15); + PrintAndLogEx(INFO, "Committing results..."); + + unlock_reset(use_pwd, pwd, write_value); + // read after reset + res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14); + if ( res != PM3_SUCCESS ) { + PrintAndLogEx(WARNING, "failed to read 14"); + return PM3_EOPABORTED; + } + res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15); + if ( res != PM3_SUCCESS ) { + PrintAndLogEx(WARNING, "failed to read 15"); + return PM3_EOPABORTED; + } + + PrintAndLogEx(INFO, "ref:%08x 14:%08X 15:%08X", search_value, word14, word15); + + if ((word14 & ACTIVE_MASK) == ACTIVE_MASK) { + + if (word14 == word15) { + PrintAndLogEx(INFO, "Status: confirmed => " _RED_("SUCCESS: ") "14: " _CYAN_("%08X") " 15: %08X", word14, word15); + break; + } + + if (word14 != search_value) { + PrintAndLogEx(INFO, "Status: new definitive value! => " _RED_("SUCCESS: ") "14: " _CYAN_("%08X") " 15: %08X", word14, word15); + break; + } + + PrintAndLogEx(INFO, "Status: failed to commit bitflip => " _RED_("FAIL: ") "14: %08X 15: %08X", word14, word15); + } else { + PrintAndLogEx(INFO, "Status: 15 bitflipped but inactive => " _YELLOW_("PROMISING: ") "14: %08X 15: " _CYAN_("%08X"), word14, word15); + + } + + if (my_auto) { + n = 0; + end = start; + } else { + tries = 0; + soon = 0; + late = 0; + } + } + } + } + + if (my_auto == false) { + tries++; + } + } + + PrintAndLogEx(INFO, "----------------------------- " _CYAN_("exit") " ----------------------------------\n"); + t1 = msclock() - t1; + PrintAndLogEx(SUCCESS, "\ntime in unlock " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); + PrintAndLogEx(INFO, "try " _YELLOW_("`lf em 4x05_dump`")); + PrintAndLogEx(NORMAL, ""); + return exit_code; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 410x") " -----------------------"}, @@ -1662,6 +2024,7 @@ static command_t CommandTable[] = { {"4x05_info", CmdEM4x05Info, IfPm3Lf, "tag information EM4x05/EM4x69"}, {"4x05_read", CmdEM4x05Read, IfPm3Lf, "read word data from EM4x05/EM4x69"}, {"4x05_write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"}, + {"4x05_unlock", CmdEM4x05Unlock, IfPm3Lf, "execute tear off against EM4x05/EM4x69"}, {"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 4x50") " -----------------------"}, {"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"}, {"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"}, diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index a473eb7f3..6fca06786 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -375,6 +375,12 @@ typedef struct { } PACKED picopass_ns_hdr; +typedef struct { + uint16_t delay_us; + bool on; + bool off; +} PACKED tearoff_params_t; + // For the bootloader #define CMD_DEVICE_INFO 0x0000 //#define CMD_SETUP_WRITE 0x0001