From 0d8bb030d17b03c08d5556ed564330e985b3cb24 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 15:40:13 +0200 Subject: [PATCH 01/26] text --- client/src/cmdhficlass.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index ef92e3998..5a9a4973e 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3034,18 +3034,19 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(ERR, "Key is incorrect length"); return PM3_EINVARG; } - - } else if (key_nr >= 0) { - + PrintAndLogEx(NORMAL, ""); + } + + if (key_nr >= 0) { if (key_nr < ICLASS_KEYS_MAX) { auth = true; memcpy(key, iClass_Key_Table[key_nr], 8); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8)); } else { PrintAndLogEx(ERR, "Key number is invalid"); return PM3_EINVARG; } - } if (data_len != 8) { @@ -3087,6 +3088,10 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(SUCCESS, "No key supplied. Trying no authentication read/writes"); } + if (tearoff_loop > 1) { + PrintAndLogEx(SUCCESS, "Loop " _YELLOW_("%u") " times / attempt", tearoff_loop); + } + if (tearoff_sleep) { PrintAndLogEx(SUCCESS, "Using " _YELLOW_("%u") " ms delay between attempts", tearoff_sleep); } @@ -3148,7 +3153,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { first_read = true; reread = false; } - + PrintAndLogEx(SUCCESS, "Original block data... " _CYAN_("%s"), sprint_hex_inrow(data_read_orig, sizeof(data_read_orig))); + PrintAndLogEx(SUCCESS, "New data to write..... " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data))); + PrintAndLogEx(INFO, "------------------------------------------"); // turn off Device side debug messages uint8_t dbg_curr = DBG_NONE; if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) { @@ -3315,6 +3322,8 @@ out: }; handle_tearoff(¶ms, false); PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Done!"); + PrintAndLogEx(NORMAL, ""); clearCommandBuffer(); return isok; } From 00c5af4256e0d79e333261ee1cfbe802137c2c52 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 21:14:58 +0200 Subject: [PATCH 02/26] text --- client/src/cmdhficlass.c | 56 +++++++++++++++++++++------------------- doc/commands.json | 13 +++++----- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 5a9a4973e..b7b9904b0 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1467,8 +1467,9 @@ static void iclass_decode_credentials(uint8_t *data) { bool has_values = (memcmp(b7, empty, PICOPASS_BLOCK_SIZE) != 0) && (memcmp(b7, zeros, PICOPASS_BLOCK_SIZE) != 0); if (has_values && encryption == None) { - // todo: remove preamble/sentinel PrintAndLogEx(INFO, "------------------------ " _CYAN_("Block 7 decoder") " --------------------------"); + + // todo: remove preamble/sentinel if (has_new_pacs) { iclass_decode_credentials_new_pacs(b7); } else { @@ -1487,9 +1488,6 @@ static void iclass_decode_credentials(uint8_t *data) { PrintAndLogEx(NORMAL, ""); decode_wiegand(top, mid, bot, 0); } - - } else { - PrintAndLogEx(INFO, "No unencrypted legacy credential found"); } } @@ -1950,7 +1948,7 @@ static int CmdHFiClassDump(const char *Cmd) { return PM3_EINVARG; } } - + if (credit_key_len > 0 && credit_key_nr >= 0) { PrintAndLogEx(ERR, "Please specify credit key or index, not both"); return PM3_EINVARG; @@ -2921,7 +2919,7 @@ static void iclass_cmp_print(uint8_t *b1, uint8_t *b2, const char *header1, cons strcat(line1, header1); strcat(line2, header2); - for (uint8_t i = 0; i < PICOPASS_BLOCK_SIZE; i++ ) { + for (uint8_t i = 0; i < PICOPASS_BLOCK_SIZE; i++) { int l1 = strlen(line1); int l2 = strlen(line2); @@ -3011,7 +3009,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { bool verbose = arg_get_lit(ctx, 10); bool shallow_mod = arg_get_lit(ctx, 11); - int tearoff_start = arg_get_int_def(ctx, 12, 5000); + int tearoff_start = arg_get_int_def(ctx, 12, 100); int tearoff_increment = arg_get_int_def(ctx, 13, 10); int tearoff_end = arg_get_int_def(ctx, 14, tearoff_start + tearoff_increment + 500); int tearoff_loop = arg_get_int_def(ctx, 15, 1); @@ -3035,8 +3033,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { return PM3_EINVARG; } PrintAndLogEx(NORMAL, ""); - } - + } + if (key_nr >= 0) { if (key_nr < ICLASS_KEYS_MAX) { auth = true; @@ -3060,17 +3058,22 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } if (tearoff_end <= tearoff_start) { - PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay."); + PrintAndLogEx(ERR, "Tearoff end delay must be larger than the start delay"); return PM3_EINVARG; } - if (tearoff_start < 0 || tearoff_end <= 0) { - PrintAndLogEx(ERR, "Tearoff start/end delays should be bigger than 0."); + if (tearoff_start <= 0) { + PrintAndLogEx(ERR, "Tearoff_start delays must be larger than 0"); + return PM3_EINVARG; + } + + if (tearoff_end <= 0) { + PrintAndLogEx(ERR, "Tearoff_end delays must be larger than 0"); return PM3_EINVARG; } if ((use_replay + rawkey + elite) > 1) { - PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'"); + PrintAndLogEx(ERR, "Can not use a combo of `--elite`, `--raw`, `--nr`"); return PM3_EINVARG; } @@ -3134,7 +3137,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { auth = false; } - //perform initial read here, repeat if failed or 00s + // perform initial read here, repeat if failed or 00s uint8_t data_read_orig[8] = {0}; uint8_t ff_data[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; bool first_read = false; @@ -3229,7 +3232,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } } - if (decrease && tearoff_start > 0) { // if there was an error reading repeat the tearoff with the same delay + // if there was an error reading repeat the tearoff with the same delay + if (decrease && tearoff_start > 0) { tearoff_start -= tearoff_increment; } @@ -3240,24 +3244,26 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { tear_success = false; } - if ((tear_success == false) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) { // tearoff succeeded (partially) + if ((tear_success == false) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) { + + // tearoff succeeded (partially) expected_values = false; if (memcmp(data_read, ff_data, 8) == 0 && memcmp(data_read_orig, ff_data, 8) != 0) { erase_phase = true; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, _BLUE_("Erase phase hit: ALL ONES")); + PrintAndLogEx(SUCCESS, _CYAN_("Erase phase hit... ALL ONES")); iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } else { if (erase_phase) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, _MAGENTA_("Tearing! Write Phase (post erase)")); + PrintAndLogEx(SUCCESS, _MAGENTA_("Tearing! Write phase (post erase)")); iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } else { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, _CYAN_("Tearing! (unknown phase)")); + PrintAndLogEx(SUCCESS, _CYAN_("Tearing! unknown phase")); iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } } @@ -3269,6 +3275,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { isok = PM3_SUCCESS; goto out; } + if (data_read[7] != data_read_orig[7]) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Fuse changed, from %02x to %02x", data_read_orig[7], data_read[7]); @@ -3276,10 +3283,6 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { goto out; } } - - } else { // tearoff did not succeed - // PrintAndLogEx(INFO, "Expected: %s", sprint_hex_inrow(data, sizeof(data))); - // PrintAndLogEx(INFO, "Read: %s", sprint_hex_inrow(data_read, sizeof(data_read))); } if (tear_success) { // tearoff succeeded with expected values @@ -3289,9 +3292,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Read: " _GREEN_("%s") " %s" - , sprint_hex_inrow(data_read, sizeof(data_read)), - (expected_values) ? _GREEN_(" -> Expected values!") : "" - ); + , sprint_hex_inrow(data_read, sizeof(data_read)), + (expected_values) ? _GREEN_(" -> Expected values!") : "" + ); } loop_count++; @@ -5950,5 +5953,6 @@ int info_iclass(bool shallow_mod) { } } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } diff --git a/doc/commands.json b/doc/commands.json index 50f8e4065..3de531df8 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3739,12 +3739,13 @@ "--nr replay of NR/MAC", "-v, --verbose verbose output", "--shallow use shallow (ASK) reader modulation instead of OOK", - "-s tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us.", - "-i tearoff delay increment (in us) - default 10.", - "-e tearoff delay end (in us) must be a higher value than the start delay.", - "--loop number of times to loop per tearoff time." + "-s tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us", + "-i tearoff delay increment (in us) - default 10", + "-e tearoff delay end (in us) must be a higher value than the start delay", + "--loop number of times to loop per tearoff time", + "--sleep Sleep between each tear" ], - "usage": "hf iclass tear [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] -s [-i ] [-e ] [--loop ]" + "usage": "hf iclass tear [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] -s [-i ] [-e ] [--loop ] [--sleep ]" }, "hf iclass unhash": { "command": "hf iclass unhash", @@ -13354,6 +13355,6 @@ "metadata": { "commands_extracted": 767, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-05-23T15:21:08" + "extracted_on": "2025-05-24T19:13:03" } } From b6a39768a18da9163187a231866129a4e36c3029 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 21:30:23 +0200 Subject: [PATCH 03/26] text --- armsrc/appmain.c | 25 ++++++++++++++----------- armsrc/iso14443a.c | 14 +++++++------- client/src/cmdhficlass.c | 3 ++- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 30ac348a6..b159eaf8a 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -254,7 +254,7 @@ static uint32_t MeasureAntennaTuningLfData(void) { void print_stack_usage(void) { for (uint32_t *p = _stack_start; ; ++p) { if (*p != 0xdeadbeef) { - Dbprintf(" Max stack usage......... %d / %d bytes", (uint32_t)_stack_end - (uint32_t)p, (uint32_t)_stack_end - (uint32_t)_stack_start); + Dbprintf(" Max stack usage..... %d / %d bytes", (uint32_t)_stack_end - (uint32_t)p, (uint32_t)_stack_end - (uint32_t)_stack_start); break; } } @@ -365,7 +365,7 @@ static void print_debug_level(void) { sprintf(dbglvlstr, "extended"); break; } - Dbprintf(" Debug log level......... %d ( " _YELLOW_("%s")" )", g_dbglevel, dbglvlstr); + Dbprintf(" Debug log level..... %d ( " _YELLOW_("%s")" )", g_dbglevel, dbglvlstr); } // measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. @@ -421,11 +421,11 @@ static void SendStatus(uint32_t wait) { print_debug_level(); tosend_t *ts = get_tosend(); - Dbprintf(" ToSendMax............... %d", ts->max); - Dbprintf(" ToSend BUFFERSIZE....... %d", TOSEND_BUFFER_SIZE); + Dbprintf(" ToSendMax........... %d", ts->max); + Dbprintf(" ToSend BUFFERSIZE... %d", TOSEND_BUFFER_SIZE); while ((AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINRDY) == 0); // Wait for MAINF value to become available... uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINF; // Get # main clocks within 16 slow clocks - Dbprintf(" Slow clock.............. %d Hz", (16 * MAINCK) / mainf); + Dbprintf(" Slow clock.......... %d Hz", (16 * MAINCK) / mainf); uint32_t delta_time = 0; uint32_t start_time = GetTickCount(); #define SLCK_CHECK_MS 50 @@ -449,10 +449,11 @@ static void SendStatus(uint32_t wait) { } else { num = 0; } + if (num > 0) { - Dbprintf(" Mifare.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, MF_KEYS_FILE); + Dbprintf(" Mifare... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, MF_KEYS_FILE); } else { - Dbprintf(" Mifare.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, MF_KEYS_FILE); + Dbprintf(" Mifare... "_RED_("%u")" keys - "_RED_("%s"), num, MF_KEYS_FILE); } if (exists_in_spiffs(T55XX_KEYS_FILE)) { @@ -460,10 +461,11 @@ static void SendStatus(uint32_t wait) { } else { num = 0; } + if (num > 0) { - Dbprintf(" T55xx................... "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, T55XX_KEYS_FILE); + Dbprintf(" T55xx.... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, T55XX_KEYS_FILE); } else { - Dbprintf(" T55xx................... "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, T55XX_KEYS_FILE); + Dbprintf(" T55xx.... "_RED_("%u")" keys - "_RED_("%s"), num, T55XX_KEYS_FILE); } if (exists_in_spiffs(ICLASS_KEYS_FILE)) { @@ -471,10 +473,11 @@ static void SendStatus(uint32_t wait) { } else { num = 0; } + if (num > 0) { - Dbprintf(" iClass.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, ICLASS_KEYS_FILE); + Dbprintf(" iClass... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, ICLASS_KEYS_FILE); } else { - Dbprintf(" iClass.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, ICLASS_KEYS_FILE); + Dbprintf(" iClass... "_RED_("%u")" keys - "_RED_("%s"), num, ICLASS_KEYS_FILE); } #endif DbpString(""); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 8bca5d2de..f77dcdeb3 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -190,35 +190,35 @@ struct Crypto1State crypto1_state = {0, 0}; void printHf14aConfig(void) { DbpString(_CYAN_("HF 14a config")); - Dbprintf(" [a] Anticol override.............. %s%s%s", + Dbprintf(" [a] Anticol override........... %s%s%s", (hf14aconfig.forceanticol == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forceanticol == 1) ? _RED_("force") " ( always do anticol )" : "", (hf14aconfig.forceanticol == 2) ? _RED_("skip") " ( always skip anticol )" : "" ); - Dbprintf(" [b] BCC override.................. %s%s%s", + Dbprintf(" [b] BCC override............... %s%s%s", (hf14aconfig.forcebcc == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forcebcc == 1) ? _RED_("fix") " ( fix bad BCC )" : "", (hf14aconfig.forcebcc == 2) ? _RED_("ignore") " ( ignore bad BCC, always use card BCC )" : "" ); - Dbprintf(" [2] CL2 override.................. %s%s%s", + Dbprintf(" [2] CL2 override............... %s%s%s", (hf14aconfig.forcecl2 == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forcecl2 == 1) ? _RED_("force") " ( always do CL2 )" : "", (hf14aconfig.forcecl2 == 2) ? _RED_("skip") " ( always skip CL2 )" : "" ); - Dbprintf(" [3] CL3 override.................. %s%s%s", + Dbprintf(" [3] CL3 override............... %s%s%s", (hf14aconfig.forcecl3 == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forcecl3 == 1) ? _RED_("force") " ( always do CL3 )" : "", (hf14aconfig.forcecl3 == 2) ? _RED_("skip") " ( always skip CL3 )" : "" ); - Dbprintf(" [r] RATS override................. %s%s%s", + Dbprintf(" [r] RATS override.............. %s%s%s", (hf14aconfig.forcerats == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forcerats == 1) ? _RED_("force") " ( always do RATS )" : "", (hf14aconfig.forcerats == 2) ? _RED_("skip") " ( always skip RATS )" : "" ); - Dbprintf(" [m] Magsafe polling............... %s", + Dbprintf(" [m] Magsafe polling............ %s", (hf14aconfig.magsafe == 1) ? _GREEN_("enabled") : _YELLOW_("disabled") ); - Dbprintf(" [p] Polling loop annotation....... %s %*D", + Dbprintf(" [p] Polling loop annotation.... %s %*D", (hf14aconfig.polling_loop_annotation.frame_length <= 0) ? _YELLOW_("disabled") : _GREEN_("enabled"), hf14aconfig.polling_loop_annotation.frame_length, hf14aconfig.polling_loop_annotation.frame, diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index b7b9904b0..d91b7b931 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3040,7 +3040,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { auth = true; memcpy(key, iClass_Key_Table[key_nr], 8); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8)); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex_inrow(iClass_Key_Table[key_nr], 8)); } else { PrintAndLogEx(ERR, "Key number is invalid"); return PM3_EINVARG; @@ -3156,6 +3156,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { first_read = true; reread = false; } + PrintAndLogEx(SUCCESS, "Original block data... " _CYAN_("%s"), sprint_hex_inrow(data_read_orig, sizeof(data_read_orig))); PrintAndLogEx(SUCCESS, "New data to write..... " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data))); PrintAndLogEx(INFO, "------------------------------------------"); From 36e7736603f5ea8d2651a448e65fadb606d48908 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 21:34:17 +0200 Subject: [PATCH 04/26] text --- client/src/cmdhficlass.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index d91b7b931..b57b845fd 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -584,14 +584,14 @@ static void fuse_config(const picopass_hdr_t *hdr) { uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]); - PrintAndLogEx(INFO, " Raw... " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8)); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit); - PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses); + PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8)); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit); + PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses); uint8_t fuses = hdr->conf.fuses; From bb0445d8860a5b1643f1c1366f773e52fcd2c5e9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 21:45:14 +0200 Subject: [PATCH 05/26] text --- client/src/cmdhficlass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index b57b845fd..0431d7519 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5855,7 +5855,7 @@ int info_iclass(bool shallow_mod) { } else { if ((r->status & FLAG_ICLASS_CC) == FLAG_ICLASS_CC) { - PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); + PrintAndLogEx(SUCCESS, "E-purse: %s card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); } if (memcmp(hdr->key_d, zeros, sizeof(zeros))) { From 607f1bb26c7df4d0686b5d467f838f2dd1c7ee41 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 22:49:46 +0200 Subject: [PATCH 06/26] style --- client/src/cmdhf14a.c | 4 ++-- client/src/cmdhflto.c | 2 +- client/src/cmdhfmf.c | 22 ++++++++++++++++------ client/src/cmdhfmfu.c | 8 +++++--- client/src/cmdhftexkom.c | 2 +- client/src/cmdhfthinfilm.c | 2 +- client/src/cmdhw.c | 6 +++++- client/src/cmdlf.c | 10 +++++++--- client/src/cmdlft55xx.c | 10 +++++----- client/src/cmdlfviking.c | 2 +- client/src/cmdsmartcard.c | 6 +++--- client/src/cmdusart.c | 6 +++--- client/src/comms.c | 4 ++-- client/src/scripting.c | 2 +- 14 files changed, 53 insertions(+), 33 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 634e3c0ba..6e30b0db9 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -914,7 +914,7 @@ int CmdHF14ASim(const char *Cmd) { bool keypress = kbd_enter_pressed(); while (keypress == false) { - if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) + if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false) continue; if (resp.status != PM3_SUCCESS) @@ -4037,7 +4037,7 @@ int CmdHF14AAIDSim(const char *Cmd) { bool keypress = kbd_enter_pressed(); while (keypress == false) { - if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) { + if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false) { continue; } diff --git a/client/src/cmdhflto.c b/client/src/cmdhflto.c index b56a0d34c..51ede17ca 100644 --- a/client/src/cmdhflto.c +++ b/client/src/cmdhflto.c @@ -131,7 +131,7 @@ static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16 SendCommandMIX(CMD_HF_ISO14443A_READER, arg0, arg1, 0, cmd, len); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); return PM3_ETIMEOUT; } diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 70dc058f8..41d4a1a96 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -1915,9 +1915,13 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue; + if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) { + continue; + } - if (resp.status != PM3_SUCCESS) continue; + if (resp.status != PM3_SUCCESS) { + continue; + } uint8_t *data = resp.data.asBytes; key64 = bytes_to_num(data + 10, 6); @@ -4005,9 +4009,13 @@ static int CmdHF14AMfChk(const char *Cmd) { SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue; + if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) { + continue; + } - if (resp.status != PM3_SUCCESS) continue; + if (resp.status != PM3_SUCCESS) { + continue; + } uint8_t *data = resp.data.asBytes; key64 = bytes_to_num(data + 10, MIFARE_KEY_SIZE); @@ -4070,7 +4078,7 @@ out: // Disable fast mode and send a dummy command to make it effective g_conn.block_after_ACK = false; SendCommandNG(CMD_PING, NULL, 0); - if (!WaitForResponseTimeout(CMD_PING, NULL, 1000)) { + if (WaitForResponseTimeout(CMD_PING, NULL, 1000) == false) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -6176,7 +6184,9 @@ static int CmdHF14AMfice(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, NULL, 0); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) goto out; + if (WaitForResponseTimeout(CMD_ACK, &resp, 3000) == false) { + goto out; + } if (resp.oldarg[0]) goto out; uint32_t items = resp.oldarg[2]; diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index f85362a23..0c3fc2e7e 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -4628,7 +4628,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { // we be getting ACK that we are silently ignoring here.. - if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000) == false) { PrintAndLogEx(WARNING, "Failed"); return PM3_ESOFT; } @@ -4649,11 +4649,13 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { got_post = true; } } - if (! got_post) { + + if (!got_post) { PrintAndLogEx(FAILED, "Failed to read block BEFORE"); error_retries++; continue; // try again } + error_retries = 0; char prestr[20] = {0}; snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre))); @@ -4936,7 +4938,7 @@ static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) { clearCommandBuffer(); PacketResponseNG resp; SendCommandNG(CMD_HF_MFU_COUNTER_TEAROFF, (uint8_t*)&payload, sizeof(payload)); - if (!WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000) == false) { PrintAndLogEx(WARNING, "\ntear off command failed"); continue; } diff --git a/client/src/cmdhftexkom.c b/client/src/cmdhftexkom.c index b033050ba..6993d70cf 100644 --- a/client/src/cmdhftexkom.c +++ b/client/src/cmdhftexkom.c @@ -664,7 +664,7 @@ static int CmdHFTexkomReader(const char *Cmd) { SendCommandNG(CMD_HF_ACQ_RAW_ADC, (uint8_t *)&samplesCount, sizeof(uint32_t)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500)) { + if (WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500) == false) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } diff --git a/client/src/cmdhfthinfilm.c b/client/src/cmdhfthinfilm.c index 4e3bafdb9..fa7921dc6 100644 --- a/client/src/cmdhfthinfilm.c +++ b/client/src/cmdhfthinfilm.c @@ -187,7 +187,7 @@ int CmdHfThinFilmSim(const char *Cmd) { int ret; while (!(ret = kbd_enter_pressed())) { - if (WaitForResponseTimeout(CMD_HF_THINFILM_SIMULATE, &resp, 500) == 0) { + if (WaitForResponseTimeout(CMD_HF_THINFILM_SIMULATE, &resp, 500) == false) { continue; } diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 7dd2cee2f..35dbde0d1 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -928,15 +928,19 @@ static int CmdTune(const char *Cmd) { SendCommandNG(CMD_MEASURE_ANTENNA_TUNING, NULL, 0); PacketResponseNG resp; PrintAndLogEx(INPLACE, "% 3i", timeout_max - timeout); - while (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING, &resp, 500)) { + + while (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING, &resp, 500) == false) { + fflush(stdout); if (timeout >= timeout_max) { PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); return PM3_ETIMEOUT; } + timeout++; PrintAndLogEx(INPLACE, "% 3i", timeout_max - timeout); } + PrintAndLogEx(NORMAL, ""); if (resp.status != PM3_SUCCESS) { diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 5a2278859..0282f6c72 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -435,15 +435,17 @@ int CmdLFCommandRead(const char *Cmd) { i = 10; // 20sec wait loop - while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) { + while (WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) == false && i != 0) { if (verbose) { PrintAndLogEx(NORMAL, "." NOLF); } i--; } + if (verbose) { PrintAndLogEx(NORMAL, ""); } + if (resp.status != PM3_SUCCESS) { PrintAndLogEx(WARNING, "command failed."); return PM3_ESOFT; @@ -595,7 +597,7 @@ int lf_getconfig(sample_config *config) { SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000) == false) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -797,10 +799,12 @@ static int lf_read_internal(bool realtime, bool verbose, uint64_t samples) { payload.samples = (samples > MAX_LF_SAMPLES) ? MAX_LF_SAMPLES : samples; SendCommandNG(CMD_LF_ACQ_RAW_ADC, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; + if (is_trigger_threshold_set) { WaitForResponse(CMD_LF_ACQ_RAW_ADC, &resp); } else { - if (!WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500)) { + + if (WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500) == false) { PrintAndLogEx(WARNING, "(lf_read) command execution time out"); return PM3_ETIMEOUT; } diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 7da9967f2..96184c87f 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -466,7 +466,7 @@ int clone_t55xx_tag(uint32_t *blockdata, uint8_t numblocks) { ng.flags = 0; SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng)); - if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT)) { + if (WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT) == false) { PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); return PM3_ETIMEOUT; } @@ -664,7 +664,7 @@ int t55xxWrite(uint8_t block, bool page1, bool usepwd, bool testMode, uint32_t p PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng)); - if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, 2000) == false) { PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation."); return PM3_ETIMEOUT; } @@ -1992,7 +1992,7 @@ static int CmdT55xxDangerousRaw(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_T55XX_DANGERRAW, (uint8_t *)&ng, sizeof(ng)); - if (!WaitForResponseTimeout(CMD_LF_T55XX_DANGERRAW, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_LF_T55XX_DANGERRAW, &resp, 2000) == false) { PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation."); return PM3_ETIMEOUT; } @@ -2840,7 +2840,7 @@ bool AcquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password, u clearCommandBuffer(); SendCommandNG(CMD_LF_T55XX_READBL, (uint8_t *)&payload, sizeof(payload)); - if (!WaitForResponseTimeout(CMD_LF_T55XX_READBL, NULL, 2500)) { + if (WaitForResponseTimeout(CMD_LF_T55XX_READBL, NULL, 2500) == false) { PrintAndLogEx(WARNING, "command execution time out"); return false; } @@ -3435,7 +3435,7 @@ static int CmdT55xxChkPwds(const char *Cmd) { PacketResponseNG resp; uint8_t timeout = 0; - while (!WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000)) { + while (WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000) == false) { timeout++; PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 180) { diff --git a/client/src/cmdlfviking.c b/client/src/cmdlfviking.c index 83f34862a..6807e828c 100644 --- a/client/src/cmdlfviking.c +++ b/client/src/cmdlfviking.c @@ -172,7 +172,7 @@ static int CmdVikingClone(const char *Cmd) { SendCommandNG(CMD_LF_VIKING_CLONE, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_VIKING_CLONE, &resp, T55XX_WRITE_TIMEOUT)) { + if (WaitForResponseTimeout(CMD_LF_VIKING_CLONE, &resp, T55XX_WRITE_TIMEOUT) == false) { PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); return PM3_ETIMEOUT; } diff --git a/client/src/cmdsmartcard.c b/client/src/cmdsmartcard.c index ed515a04a..46b467f94 100644 --- a/client/src/cmdsmartcard.c +++ b/client/src/cmdsmartcard.c @@ -663,7 +663,7 @@ static int CmdSmartUpgrade(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_SMART_UPLOAD, (uint8_t *)&upload, sizeof(upload)); - if (!WaitForResponseTimeout(CMD_SMART_UPLOAD, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_SMART_UPLOAD, &resp, 2000) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply"); free(firmware); return PM3_ETIMEOUT; @@ -695,7 +695,7 @@ static int CmdSmartUpgrade(const char *Cmd) { free(firmware); SendCommandNG(CMD_SMART_UPGRADE, (uint8_t *)&payload, sizeof(payload)); - if (!WaitForResponseTimeout(CMD_SMART_UPGRADE, &resp, 2500)) { + if (WaitForResponseTimeout(CMD_SMART_UPGRADE, &resp, 2500) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply"); return PM3_ETIMEOUT; } @@ -876,7 +876,7 @@ static int CmdSmartSetClock(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_SMART_SETCLOCK, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500)) { + if (WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500) == false) { PrintAndLogEx(WARNING, "smart card select failed"); return PM3_ETIMEOUT; } diff --git a/client/src/cmdusart.c b/client/src/cmdusart.c index 357d20c32..b3e2bdc5d 100644 --- a/client/src/cmdusart.c +++ b/client/src/cmdusart.c @@ -35,7 +35,7 @@ static int usart_tx(uint8_t *data, size_t len) { clearCommandBuffer(); SendCommandNG(CMD_USART_TX, data, len); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_USART_TX, &resp, 1000)) { + if (WaitForResponseTimeout(CMD_USART_TX, &resp, 1000) == false) { return PM3_ETIMEOUT; } return resp.status; @@ -49,7 +49,7 @@ static int usart_rx(uint8_t *data, size_t *len, uint32_t waittime) { payload.waittime = waittime; SendCommandNG(CMD_USART_RX, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_USART_RX, &resp, waittime + 500)) { + if (WaitForResponseTimeout(CMD_USART_RX, &resp, waittime + 500) == false) { return PM3_ETIMEOUT; } if (resp.status == PM3_SUCCESS) { @@ -99,7 +99,7 @@ static int set_usart_config(uint32_t baudrate, uint8_t parity) { payload.parity = parity; SendCommandNG(CMD_USART_CONFIG, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_USART_CONFIG, &resp, 1000)) { + if (WaitForResponseTimeout(CMD_USART_CONFIG, &resp, 1000) == false) { return PM3_ETIMEOUT; } return resp.status; diff --git a/client/src/comms.c b/client/src/comms.c index e2684100f..2ded55ebc 100644 --- a/client/src/comms.c +++ b/client/src/comms.c @@ -871,7 +871,7 @@ int TestProxmark(pm3_device_t *dev) { #endif PacketResponseNG resp; - if (WaitForResponseTimeoutW(CMD_PING, &resp, timeout, false) == 0) { + if (WaitForResponseTimeoutW(CMD_PING, &resp, timeout, false) == false) { return PM3_ETIMEOUT; } @@ -881,7 +881,7 @@ int TestProxmark(pm3_device_t *dev) { } SendCommandNG(CMD_CAPABILITIES, NULL, 0); - if (WaitForResponseTimeoutW(CMD_CAPABILITIES, &resp, 1000, false) == 0) { + if (WaitForResponseTimeoutW(CMD_CAPABILITIES, &resp, 1000, false) == false) { return PM3_ETIMEOUT; } diff --git a/client/src/scripting.c b/client/src/scripting.c index 251a0d915..1cd1ed1a0 100644 --- a/client/src/scripting.c +++ b/client/src/scripting.c @@ -303,7 +303,7 @@ static int l_GetFromFlashMemSpiffs(lua_State *L) { // get size from spiffs itself ! SendCommandNG(CMD_SPIFFS_STAT, (uint8_t *)destfilename, 32); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_SPIFFS_STAT, &resp, 2000)) + if (WaitForResponseTimeout(CMD_SPIFFS_STAT, &resp, 2000) == false) return returnToLuaWithError(L, "No response from the device"); len = resp.data.asDwords[0]; From 96c58db8e8f1754106259ff2004ced83d55dd225 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 22:50:56 +0200 Subject: [PATCH 07/26] style and making sure within limits not to trigger overflows --- client/src/cmdhficlass.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 0431d7519..3c8f72eb6 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2265,7 +2265,7 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == false) { if (verbose) PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -2491,7 +2491,7 @@ static int CmdHFiClassCreditEpurse(const char *Cmd) { PacketResponseNG resp; int isok; - if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == false) { if (verbose) PrintAndLogEx(WARNING, "command execution time out"); isok = PM3_ETIMEOUT; } else if (resp.status != PM3_SUCCESS) { @@ -2673,7 +2673,7 @@ static int CmdHFiClassRestore(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size); - if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == false) { PrintAndLogEx(WARNING, "command execution time out"); DropField(); free(payload); @@ -3092,7 +3092,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } if (tearoff_loop > 1) { - PrintAndLogEx(SUCCESS, "Loop " _YELLOW_("%u") " times / attempt", tearoff_loop); + PrintAndLogEx(SUCCESS, _YELLOW_("%u") " attempts / tearoff", tearoff_loop); } if (tearoff_sleep) { @@ -3174,7 +3174,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "Press " _GREEN_("") " to abort"); - while (tearoff_start <= tearoff_end && read_ok == false) { + while ((tearoff_start <= tearoff_end) && (read_ok == false)) { if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\naborted via keyboard."); @@ -3185,7 +3185,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { // set tear off trigger clearCommandBuffer(); tearoff_params_t params = { - .delay_us = tearoff_start, + .delay_us = (tearoff_start & 0xFFFF), .on = true, .off = false }; @@ -3197,10 +3197,10 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { goto out; } - // write - // don't check the return value. As a tear-off occurred, the write failed. - //PrintAndLogEx(NORMAL, "\r" NOLF); - PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%d")" / "_YELLOW_("%d")" us", tearoff_start, tearoff_end); + + PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%d")" / "_YELLOW_("%d")" us", (tearoff_start & 0xFFFF), (tearoff_end & 0xFFFF)); + + // write block - don't check the return value. As a tear-off occurred, the write failed. iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); //read the data back @@ -3234,7 +3234,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } // if there was an error reading repeat the tearoff with the same delay - if (decrease && tearoff_start > 0) { + if (decrease && (tearoff_start > tearoff_increment)) { tearoff_start -= tearoff_increment; } From 74f1936132f6274c81619158be0043c5aae8a10b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 25 May 2025 09:55:32 +0200 Subject: [PATCH 08/26] convert to our calloc instead since we prefer to know allocated shared memory is empty. Also removed a malloc(1) which is just a waste of bytes just like @NVX said a year ago at DefCon --- armsrc/appmain.c | 10 +++++----- armsrc/em4x50.c | 2 +- armsrc/i2c.c | 4 ++-- armsrc/i2c_direct.c | 2 +- armsrc/iclass.c | 36 ++++++++++++++++++------------------ armsrc/iso14443a.c | 18 ++++++++---------- armsrc/sam_common.c | 17 +++++++++-------- armsrc/sam_picopass.c | 16 +++++++++------- armsrc/sam_seos.c | 10 ++++++---- armsrc/spiffs.c | 2 +- client/src/cmdhficlass.c | 4 ++-- 11 files changed, 62 insertions(+), 59 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index b159eaf8a..774014d6a 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -2357,7 +2357,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint16_t available; uint16_t pre_available = 0; - uint8_t *dest = BigBuf_malloc(USART_FIFOLEN); + uint8_t *dest = BigBuf_calloc(USART_FIFOLEN); uint32_t wait = payload->waittime; StartTicks(); @@ -2401,7 +2401,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint16_t available; uint16_t pre_available = 0; - uint8_t *dest = BigBuf_malloc(USART_FIFOLEN); + uint8_t *dest = BigBuf_calloc(USART_FIFOLEN); uint32_t wait = payload->waittime; StartTicks(); @@ -2697,7 +2697,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint32_t size = packet->oldarg[1]; - uint8_t *buff = BigBuf_malloc(size); + uint8_t *buff = BigBuf_calloc(size); if (buff == NULL) { if (g_dbglevel >= DBG_DEBUG) Dbprintf("Failed to allocate memory"); // Trigger a finish downloading signal with an PM3_EMALLOC @@ -2902,7 +2902,7 @@ static void PacketReceived(PacketCommandNG *packet) { case CMD_FLASHMEM_DOWNLOAD: { LED_B_ON(); - uint8_t *mem = BigBuf_malloc(PM3_CMD_DATA_SIZE); + uint8_t *mem = BigBuf_calloc(PM3_CMD_DATA_SIZE); uint32_t startidx = packet->oldarg[0]; uint32_t numofbytes = packet->oldarg[1]; // arg0 = startindex @@ -2934,7 +2934,7 @@ static void PacketReceived(PacketCommandNG *packet) { case CMD_FLASHMEM_INFO: { LED_B_ON(); - rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_malloc(sizeof(rdv40_validation_t)); + rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_calloc(sizeof(rdv40_validation_t)); bool isok = Flash_ReadData(FLASH_MEM_SIGNATURE_OFFSET_P(spi_flash_pages64k), info->signature, FLASH_MEM_SIGNATURE_LEN); diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 095ae4240..8de00ccae 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -748,7 +748,7 @@ void em4x50_chk(const char *filename, bool ledcontrol) { uint16_t pwd_count = 0; uint32_t size = size_in_spiffs(filename); pwd_count = size / 4; - uint8_t *pwds = BigBuf_malloc(size); + uint8_t *pwds = BigBuf_calloc(size); rdv40_spiffs_read_as_filetype(filename, pwds, size, RDV40_SPIFFS_SAFETY_SAFE); diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 501ce388e..b1af6e30a 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -857,7 +857,7 @@ void SmartCardRaw(const smart_card_raw_t *p) { LED_D_ON(); uint16_t len = 0; - uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME); // check if alloacted... smartcard_command_t flags = p->flags; @@ -937,7 +937,7 @@ void SmartCardUpgrade(uint64_t arg0) { bool isOK = true; uint16_t length = arg0, pos = 0; const uint8_t *fwdata = BigBuf_get_addr(); - uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE); + uint8_t *verfiydata = BigBuf_calloc(I2C_BLOCK_SIZE); while (length) { diff --git a/armsrc/i2c_direct.c b/armsrc/i2c_direct.c index 909c1ec30..49aaa4c2c 100644 --- a/armsrc/i2c_direct.c +++ b/armsrc/i2c_direct.c @@ -40,7 +40,7 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint LED_D_ON(); uint16_t len = 0; - uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME); resp[0] = prepend; // check if alloacted... smartcard_command_t flags = p->flags; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 6b79b7012..cfb73cde2 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -399,40 +399,40 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { int trace_data_size; // Respond SOF -- takes 1 bytes - uint8_t *resp_sof = BigBuf_malloc(1); + uint8_t resp_sof[1] = {0}; int resp_sof_len; // Anticollision CSN (rotated CSN) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_anticoll = BigBuf_malloc(22); + uint8_t *resp_anticoll = BigBuf_calloc(22); int resp_anticoll_len; // CSN (block 0) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_csn = BigBuf_malloc(22); + uint8_t *resp_csn = BigBuf_calloc(22); int resp_csn_len; // configuration (blk 1) PICOPASS 2ks - uint8_t *resp_conf = BigBuf_malloc(22); + uint8_t *resp_conf = BigBuf_calloc(22); int resp_conf_len; // e-Purse (blk 2) // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) - uint8_t *resp_cc = BigBuf_malloc(18); + uint8_t *resp_cc = BigBuf_calloc(18); int resp_cc_len; // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only - uint8_t *resp_ff = BigBuf_malloc(22); + uint8_t *resp_ff = BigBuf_calloc(22); int resp_ff_len; uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; AddCrc(ff_data, 8); // Application Issuer Area (blk 5) - uint8_t *resp_aia = BigBuf_malloc(22); + uint8_t *resp_aia = BigBuf_calloc(22); int resp_aia_len; // receive command - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); + uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE); // Prepare card messages tosend_t *ts = get_tosend(); @@ -474,11 +474,11 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { //This is used for responding to READ-block commands or other data which is dynamically generated //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_malloc(34); // 32 bytes data + 2byte CRC is max tag answer + uint8_t *data_generic_trace = BigBuf_calloc(34); // 32 bytes data + 2byte CRC is max tag answer //Then storage for the modulated data //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) - uint8_t *data_response = BigBuf_malloc((34 * 2) + 3); + uint8_t *data_response = BigBuf_calloc((34 * 2) + 3); enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; @@ -942,29 +942,29 @@ int do_iclass_simulation_nonsec(void) { int trace_data_size = 0; // Respond SOF -- takes 1 bytes - uint8_t *resp_sof = BigBuf_malloc(2); + uint8_t resp_sof[2] = { 0 }; int resp_sof_len; // Anticollision CSN (rotated CSN) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_anticoll = BigBuf_malloc(28); + uint8_t *resp_anticoll = BigBuf_calloc(28); int resp_anticoll_len; // CSN // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_csn = BigBuf_malloc(28); + uint8_t *resp_csn = BigBuf_calloc(28); int resp_csn_len; // configuration (blk 1) PICOPASS 2ks - uint8_t *resp_conf = BigBuf_malloc(28); + uint8_t *resp_conf = BigBuf_calloc(28); int resp_conf_len; // Application Issuer Area (blk 5) - uint8_t *resp_aia = BigBuf_malloc(28); + uint8_t *resp_aia = BigBuf_calloc(28); int resp_aia_len; // receive command - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); + uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE); // Prepare card messages tosend_t *ts = get_tosend(); @@ -997,11 +997,11 @@ int do_iclass_simulation_nonsec(void) { //This is used for responding to READ-block commands or other data which is dynamically generated //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer + uint8_t *data_generic_trace = BigBuf_calloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer //Then storage for the modulated data //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) - uint8_t *data_response = BigBuf_malloc((32 + 2) * 2 + 2); + uint8_t *data_response = BigBuf_calloc((32 + 2) * 2 + 2); enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index f77dcdeb3..732221592 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -805,12 +805,12 @@ void RAMFUNC SniffIso14443a(uint8_t param) { set_tracing(true); // The command (reader -> tag) that we're receiving. - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE); + uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE); + uint8_t *receivedCmdPar = BigBuf_calloc(MAX_PARITY_SIZE); // The response (tag -> reader) that we're receiving. - uint8_t *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE); + uint8_t *receivedResp = BigBuf_calloc(MAX_FRAME_SIZE); + uint8_t *receivedRespPar = BigBuf_calloc(MAX_PARITY_SIZE); uint8_t previous_data = 0; int maxDataLen = 0, dataLen; @@ -2683,9 +2683,9 @@ void iso14443a_antifuzz(uint32_t flags) { int len = 0; // allocate buffers: - uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE); - uint8_t *resp = BigBuf_malloc(20); + uint8_t *received = BigBuf_calloc(MAX_FRAME_SIZE); + uint8_t *receivedPar = BigBuf_calloc(MAX_PARITY_SIZE); + uint8_t *resp = BigBuf_calloc(20); memset(received, 0x00, MAX_FRAME_SIZE); memset(received, 0x00, MAX_PARITY_SIZE); @@ -4070,9 +4070,7 @@ void DetectNACKbug(void) { // i = number of authentications sent. Not always 256, since we are trying to sync but close to it. FpgaDisableTracing(); - uint8_t *data = BigBuf_malloc(4); - data[0] = isOK; - data[1] = num_nacks; + uint8_t data[4] = {isOK, num_nacks, 0, 0}; num_to_bytes(i, 2, data + 2); reply_ng(CMD_HF_MIFARE_NACK_DETECT, status, data, 4); diff --git a/armsrc/sam_common.c b/armsrc/sam_common.c index ed129134d..d104148ff 100644 --- a/armsrc/sam_common.c +++ b/armsrc/sam_common.c @@ -221,10 +221,11 @@ out: int sam_get_version(void) { int res = PM3_SUCCESS; - if (g_dbglevel >= DBG_DEBUG) + if (g_dbglevel >= DBG_DEBUG) { DbpString("start sam_get_version"); + } - uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; uint8_t payload[] = { @@ -252,8 +253,9 @@ int sam_get_version(void) { // 82 01 // 01 // 90 00 - if (g_dbglevel >= DBG_DEBUG) + if (g_dbglevel >= DBG_DEBUG) { DbpString("end sam_get_version"); + } if (response[5] != 0xbd) { Dbprintf("Invalid SAM response"); @@ -289,8 +291,9 @@ error: out: BigBuf_free(); - if (g_dbglevel >= DBG_DEBUG) + if (g_dbglevel >= DBG_DEBUG) { DbpString("end sam_get_version"); + } return res; } @@ -350,12 +353,10 @@ void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type } void sam_send_ack(void) { - uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; - uint8_t payload[] = { - 0xa0, 0 - }; + uint8_t payload[] = { 0xa0, 0 }; uint16_t payload_len = sizeof(payload); sam_send_payload( diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index 0bf2379d8..d22985e49 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -46,11 +46,12 @@ */ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len, const bool shallow_mod, const bool break_on_nr_mac, const bool prevent_epurse_update) { int res = PM3_SUCCESS; - if (g_dbglevel >= DBG_DEBUG) + if (g_dbglevel >= DBG_DEBUG) { DbpString("start sam_send_request_iso14a"); + } - uint8_t *buf1 = BigBuf_malloc(ISO7816_MAX_FRAME); - uint8_t *buf2 = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *buf1 = BigBuf_calloc(ISO7816_MAX_FRAME); + uint8_t *buf2 = BigBuf_calloc(ISO7816_MAX_FRAME); if (buf1 == NULL || buf2 == NULL) { res = PM3_EMALLOC; goto out; @@ -255,10 +256,10 @@ out: */ static int sam_set_card_detected_picopass(const picopass_hdr_t *card_select) { int res = PM3_SUCCESS; - if (g_dbglevel >= DBG_DEBUG) + if (g_dbglevel >= DBG_DEBUG) { DbpString("start sam_set_card_detected"); - - uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); + } + uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; // a0 12 @@ -314,8 +315,9 @@ error: out: BigBuf_free(); - if (g_dbglevel >= DBG_DEBUG) + if (g_dbglevel >= DBG_DEBUG) { DbpString("end sam_set_card_detected"); + } return res; } diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 40846705a..04bc128a2 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -51,13 +51,14 @@ */ static int sam_set_card_detected_seos(iso14a_card_select_t *card_select) { int res = PM3_SUCCESS; - if (g_dbglevel >= DBG_DEBUG) + if (g_dbglevel >= DBG_DEBUG) { DbpString("start sam_set_card_detected"); + } - uint8_t *request = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *request = BigBuf_calloc(ISO7816_MAX_FRAME); uint16_t request_len = ISO7816_MAX_FRAME; - uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; const uint8_t payload[] = { @@ -107,8 +108,9 @@ error: out: BigBuf_free(); - if (g_dbglevel >= DBG_DEBUG) + if (g_dbglevel >= DBG_DEBUG) { DbpString("end sam_set_card_detected"); + } return res; } diff --git a/armsrc/spiffs.c b/armsrc/spiffs.c index 71d0cbd12..0b2799c5a 100644 --- a/armsrc/spiffs.c +++ b/armsrc/spiffs.c @@ -312,7 +312,7 @@ static int is_valid_filename(const char *filename) { */ static void copy_in_spiffs(const char *src, const char *dst) { uint32_t size = size_in_spiffs(src); - uint8_t *mem = BigBuf_malloc(size); + uint8_t *mem = BigBuf_calloc(size); read_from_spiffs(src, (uint8_t *)mem, size); write_to_spiffs(dst, (uint8_t *)mem, size); } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 3c8f72eb6..4996147d0 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3174,6 +3174,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "Press " _GREEN_("") " to abort"); + // Main loop while ((tearoff_start <= tearoff_end) && (read_ok == false)) { if (kbd_enter_pressed()) { @@ -3197,8 +3198,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { goto out; } - - PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%d")" / "_YELLOW_("%d")" us", (tearoff_start & 0xFFFF), (tearoff_end & 0xFFFF)); + PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us", params.delay_us, (tearoff_end & 0xFFFF)); // write block - don't check the return value. As a tear-off occurred, the write failed. iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); From dcec8d6e7128ee147972bc6e0fa7e337ab0d3d2b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 25 May 2025 10:50:40 +0200 Subject: [PATCH 09/26] text --- client/src/cmdhficlass.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 4996147d0..fb8ef2d90 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3159,7 +3159,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(SUCCESS, "Original block data... " _CYAN_("%s"), sprint_hex_inrow(data_read_orig, sizeof(data_read_orig))); PrintAndLogEx(SUCCESS, "New data to write..... " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data))); - PrintAndLogEx(INFO, "------------------------------------------"); + PrintAndLogEx(SUCCESS, "Target block.......... " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno); // turn off Device side debug messages uint8_t dbg_curr = DBG_NONE; if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) { @@ -3170,10 +3170,11 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { return PM3_EFAILED; } - PrintAndLogEx(INFO, "Starting tear off against block " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno); - PrintAndLogEx(INFO, ""); - PrintAndLogEx(INFO, "Press " _GREEN_("") " to abort"); - + PrintAndLogEx(INFO, "---------------------------------------"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Press " _GREEN_("'") " to exit"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n"); // Main loop while ((tearoff_start <= tearoff_end) && (read_ok == false)) { @@ -3203,7 +3204,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { // write block - don't check the return value. As a tear-off occurred, the write failed. iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); - //read the data back + // read the data back uint8_t data_read[8] = {0}; first_read = false; reread = false; From 4da2a9a496242ec56152a46fd420926bd7f12b15 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 25 May 2025 10:55:11 +0200 Subject: [PATCH 10/26] text --- client/src/cmdlfem4x05.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index 709322e3a..11589d881 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -2013,7 +2013,7 @@ int CmdEM4x05Unlock(const char *Cmd) { PrintAndLogEx(INFO, "----------------------------------------------------------------------------\n"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Press " _GREEN_("'") " to exit"); + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------------\n"); From d402903db59c398b870af264595df5e2609d0f45 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sun, 25 May 2025 17:10:31 +0800 Subject: [PATCH 11/26] Fixed authentication read for iclass tear If the card flips to nonsecure mode during the tearoff of block 1, this read command will be stuck. So we can disable auth completely when trying to read block 1 as that block doesn't require authentication anyway for reading operations. --- client/src/cmdhficlass.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index fb8ef2d90..77934bac6 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3137,6 +3137,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { auth = false; } + bool read_auth = auth; + // perform initial read here, repeat if failed or 00s uint8_t data_read_orig[8] = {0}; uint8_t ff_data[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -3218,7 +3220,10 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { goto out; } - res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read, false); + if (blockno == 1){ + read_auth = false; + } + res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read, false); if (res == PM3_SUCCESS && !reread) { if (memcmp(data_read, zeros, 8) == 0) { reread = true; From 4b92118f1f7bfe9d24256d7a4953d41ebd57c037 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 25 May 2025 11:29:43 +0200 Subject: [PATCH 12/26] clear trace log before starting to run hf iclass tear --- armsrc/BigBuf.c | 2 +- client/src/cmdhficlass.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 26af3af0d..b492b4205 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -121,7 +121,7 @@ void BigBuf_Clear_ext(bool verbose) { memset(BigBuf, 0, s_bigbuf_size); clear_trace(); if (verbose) { - Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size); + if (g_dbglevel >= DBG_ERROR) Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size); } } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 77934bac6..ae1b72ac1 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3172,9 +3172,12 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { return PM3_EFAILED; } + // clear trace log + SendCommandNG(CMD_BUFF_CLEAR, NULL, 0); + PrintAndLogEx(INFO, "---------------------------------------"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Press " _GREEN_("'") " to exit"); + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n"); // Main loop @@ -3223,6 +3226,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { if (blockno == 1){ read_auth = false; } + res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read, false); if (res == PM3_SUCCESS && !reread) { if (memcmp(data_read, zeros, 8) == 0) { From 8d3e301b55bbeb828634cb406bc1636b426bd61f Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sun, 25 May 2025 20:36:35 +0800 Subject: [PATCH 13/26] Updated hf iclass tear to not run if the authentication fuses are blown Updated hf iclass tear to not run if the authentication fuses are blown. Or it will just get stuck at the beginning and not start anyway. At least this informs the users why this is happening. --- client/src/cmdhficlass.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index ae1b72ac1..53afe888d 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3137,6 +3137,11 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { auth = false; } + if (pagemap == 0x0) { + PrintAndLogEx(WARNING, _RED_("No auth possible. Read only if RA is enabled")); + goto out; + } + bool read_auth = auth; // perform initial read here, repeat if failed or 00s From eecdad7ac80c7e25774d9c297cff19f17aa15110 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 25 May 2025 14:40:46 +0200 Subject: [PATCH 14/26] text --- client/src/cmdhficlass.c | 7 +++---- doc/commands.json | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index ae1b72ac1..dddfa98e4 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2399,14 +2399,13 @@ static int CmdHFiClassCreditEpurse(const char *Cmd) { "Credit the epurse on an iCLASS tag. The provided key must be the credit key.\n" "The first two bytes of the epurse are the debit value (big endian) and may be any value except FFFF.\n" "The remaining two bytes of the epurse are the credit value and must be smaller than the previous value.", - "hf iclass creditepurse -d FEFFFFFF -k 001122334455667B\n" - "hf iclass creditepurse -d FEFFFFFF --ki 0"); + "hf iclass creditepurse --ki 0 -d FEFFFEFF"); void *argtable[] = { arg_param_begin, arg_str0("k", "key", "", "Credit key as 8 hex bytes"), arg_int0(NULL, "ki", "", "Key index to select key from memory 'hf iclass managekeys'"), - arg_str1("d", "data", "", "data to write as 8 hex bytes"), + arg_str1("d", "data", "", "data to write as 4 hex bytes"), arg_lit0(NULL, "elite", "elite computations applied to key"), arg_lit0(NULL, "raw", "no computations applied to key"), arg_lit0("v", "verbose", "verbose output"), @@ -3223,7 +3222,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { goto out; } - if (blockno == 1){ + if (blockno == 1) { read_auth = false; } diff --git a/doc/commands.json b/doc/commands.json index 3de531df8..4d678aaeb 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3285,15 +3285,14 @@ "command": "hf iclass creditepurse", "description": "Credit the epurse on an iCLASS tag. The provided key must be the credit key. The first two bytes of the epurse are the debit value (big endian) and may be any value except FFFF. The remaining two bytes of the epurse are the credit value and must be smaller than the previous value.", "notes": [ - "hf iclass creditepurse -d FEFFFFFF -k 001122334455667B", - "hf iclass creditepurse -d FEFFFFFF --ki 0" + "hf iclass creditepurse --ki 0 -d FEFFFEFF" ], "offline": false, "options": [ "-h, --help This help", "-k, --key Credit key as 8 hex bytes", "--ki Key index to select key from memory 'hf iclass managekeys'", - "-d, --data data to write as 8 hex bytes", + "-d, --data data to write as 4 hex bytes", "--elite elite computations applied to key", "--raw no computations applied to key", "-v, --verbose verbose output", @@ -13355,6 +13354,6 @@ "metadata": { "commands_extracted": 767, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-05-24T19:13:03" + "extracted_on": "2025-05-25T12:38:36" } } From 1349b6d28258618cecf7005c41920fee18e67de3 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sun, 25 May 2025 21:50:17 +0800 Subject: [PATCH 15/26] Updated tearoff repeat to not go below original start value and show loop count Updated tearoff repeat to not go below original start value and show loop count --- client/src/cmdhficlass.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 07bb7299f..2b16e13ab 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3009,6 +3009,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { bool shallow_mod = arg_get_lit(ctx, 11); int tearoff_start = arg_get_int_def(ctx, 12, 100); + int tearoff_original_start = tearoff_start; // save original start value for later use int tearoff_increment = arg_get_int_def(ctx, 13, 10); int tearoff_end = arg_get_int_def(ctx, 14, tearoff_start + tearoff_increment + 500); int tearoff_loop = arg_get_int_def(ctx, 15, 1); @@ -3208,7 +3209,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { goto out; } - PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us", params.delay_us, (tearoff_end & 0xFFFF)); + PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%u")" / "_YELLOW_("%d")" loops", params.delay_us, (tearoff_end & 0xFFFF), loop_count+1, tearoff_loop); // write block - don't check the return value. As a tear-off occurred, the write failed. iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); @@ -3248,7 +3249,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } // if there was an error reading repeat the tearoff with the same delay - if (decrease && (tearoff_start > tearoff_increment)) { + if (decrease && (tearoff_start > tearoff_increment) && (tearoff_start >= tearoff_original_start)) { tearoff_start -= tearoff_increment; } From b8e8c41f28dcc110aea6ef69519da74843ff5053 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 25 May 2025 20:29:15 +0200 Subject: [PATCH 16/26] fix the cut of version and git sha-hash --- client/src/cmdhw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 35dbde0d1..e0cb44f89 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -1611,7 +1611,7 @@ void pm3_version_short(void) { if (ptr != NULL) { char *ptr_end = strstr(ptr, "\n"); if (ptr_end != NULL) { - uint8_t len = ptr_end - 19 - ptr; + uint8_t len = ptr_end - 12 - ptr; PrintAndLogEx(NORMAL, " Bootrom... %.*s", len, ptr + 12); } } @@ -1621,7 +1621,7 @@ void pm3_version_short(void) { if (ptr != NULL) { char *ptr_end = strstr(ptr, "\n"); if (ptr_end != NULL) { - uint8_t len = ptr_end - 14 - ptr; + uint8_t len = ptr_end - 12 - ptr; PrintAndLogEx(NORMAL, " OS........ %.*s", len, ptr + 12); } } From 23928b40419be154679d97a4fad7318108b92a68 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Mon, 26 May 2025 16:01:06 +0800 Subject: [PATCH 17/26] Updated hf iclass tear Updated hf iclass tear with the following improvements: 1- Show failed read if ran in verbose mode 2- Improved out logic when tearing block 1 3- Showing fuses comparison table when tearoff affects block 1 fuses --- client/src/cmdhficlass.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 2b16e13ab..41bcaf471 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3251,6 +3251,10 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { // if there was an error reading repeat the tearoff with the same delay if (decrease && (tearoff_start > tearoff_increment) && (tearoff_start >= tearoff_original_start)) { tearoff_start -= tearoff_increment; + if(verbose){ + PrintAndLogEx(INFO, " -> Read failed, retearing with "_CYAN_("%u")" us", tearoff_start); + } + } bool tear_success = true; @@ -3284,18 +3288,42 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } } + bool goto_out = false; if (blockno == 1) { if (data_read[0] != data_read_orig[0]) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Application limit changed, from %u to %u", data_read_orig[0], data_read[0]); + PrintAndLogEx(SUCCESS, "Application limit changed, from "_YELLOW_("%u")" to "_YELLOW_("%u"), data_read_orig[0], data_read[0]); isok = PM3_SUCCESS; - goto out; + goto_out = true; } if (data_read[7] != data_read_orig[7]) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Fuse changed, from %02x to %02x", data_read_orig[7], data_read[7]); + PrintAndLogEx(SUCCESS, "Fuse changed, from "_YELLOW_("%02x")" to "_YELLOW_("%02x"), data_read_orig[7], data_read[7]); + + const char *flag_names[8] = { + "RA", + "Fprod0", + "Fprod1", + "Crypt0 (*1)", + "Crypt1 (*0)", + "Coding0", + "Coding1", + "Fpers (*1)" + }; + PrintAndLogEx(INFO, _YELLOW_("%-10s %-10s %-10s"), "Fuse", "Original", "Changed"); + PrintAndLogEx(INFO, "---------------------------------------"); + for (int i = 7; i >= 0; --i) { + int bit1 = (data_read_orig[7] >> i) & 1; + int bit2 = (data_read[7] >> i) & 1; + PrintAndLogEx(INFO, "%-10s %-10d %-10d", flag_names[i], bit1, bit2); + } + isok = PM3_SUCCESS; + goto_out = true; + } + + if (goto_out) { goto out; } } From b378a369d112035306f3135489d027ad0973c4a0 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Mon, 26 May 2025 23:53:33 +0800 Subject: [PATCH 18/26] Updated hf iclass tear to break endless read loop Updated hf iclass tear to break endless read loop when the card can't be read anymore during the tear operation. Set a 10 attempts limit. --- client/src/cmdhficlass.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 41bcaf471..f1da50f14 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3219,7 +3219,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { first_read = false; reread = false; bool decrease = false; - + int readcount = 0; while (first_read == false) { if (kbd_enter_pressed()) { @@ -3246,6 +3246,12 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } else if (res != PM3_SUCCESS) { decrease = true; } + if (readcount >= 10){ + PrintAndLogEx(WARNING, "\n"_RED_("Read failed too many times, giving up")); + isok = PM3_EFAILED; + goto out; + } + readcount++; } // if there was an error reading repeat the tearoff with the same delay From 176b543069a3c49dcf464941415de98db1a61581 Mon Sep 17 00:00:00 2001 From: Kara Zajac Date: Mon, 26 May 2025 15:46:23 -0400 Subject: [PATCH 19/26] Saflok Parsing Added when a Saflok card is detected, it decrypts and parses the data, outputting it to the screen. Previous security researchers did this work, and I merely adapted it from the Flipper Zero code to the Proxmark3 code. Their info is below: // Decryption and parsing from: https://gitee.com/wangshuoyue/unsaflok // Decryption algorithm and parsing published by Shuoyue Wang // Parsing also inspired by Lennert Wouters and Ian Carroll's DEFCON 32 talk // https://defcon.org/html/defcon-32/dc-32-speakers.html // FZ parser by @Torron, with help from @xtruan, @zacharyweiss, @evilmog and kara (@Arkwin) Signed-off-by: Kara Zajac --- client/src/cmdhfmf.c | 292 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 291 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 41d4a1a96..a05cfbb1f 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -48,6 +48,295 @@ #include "mifare/mifarehost.h" #include "crypto/originality.h" + +// Defines for Saflok parsing +#define SAFLOK_YEAR_OFFSET 1980 +#define SAFLOK_BASIC_ACCESS_BYTE_NUM 17 +#define SAFLOK_KEY_LENGTH 6 +#define SAFLOK_UID_LENGTH 4 // Matches Mifare 4-byte UID +#define SAFLOK_MAGIC_TABLE_SIZE 192 +#define SAFLOK_CHECK_SECTOR 1 + +typedef struct { + uint64_t a; + uint64_t b; +} MfClassicKeyPair; + + +// Structure for Saflok key levels +typedef struct { + uint8_t level_num; + const char* level_name; +} SaflokKeyLevel; + +// Static array for Saflok key levels +static const SaflokKeyLevel saflok_key_levels[] = { + {1, "Guest Key"}, + {2, "Connectors"}, + {3, "Suite"}, + {4, "Limited Use"}, + {5, "Failsafe"}, + {6, "Inhibit"}, + {7, "Pool/Meeting Master"}, + {8, "Housekeeping"}, + {9, "Floor Key"}, + {10, "Section Key"}, + {11, "Rooms Master"}, + {12, "Grand Master"}, + {13, "Emergency"}, + {14, "Electronic Lockout"}, + {15, "Secondary Programming Key (SPK)"}, + {16, "Primary Programming Key (PPK)"}, +}; + +// Lookup table for Saflok decryption +static const uint8_t saflok_c_aDecode[256] = { + 0xEA, 0x0D, 0xD9, 0x74, 0x4E, 0x28, 0xFD, 0xBA, 0x7B, 0x98, 0x87, 0x78, 0xDD, 0x8D, 0xB5, + 0x1A, 0x0E, 0x30, 0xF3, 0x2F, 0x6A, 0x3B, 0xAC, 0x09, 0xB9, 0x20, 0x6E, 0x5B, 0x2B, 0xB6, + 0x21, 0xAA, 0x17, 0x44, 0x5A, 0x54, 0x57, 0xBE, 0x0A, 0x52, 0x67, 0xC9, 0x50, 0x35, 0xF5, + 0x41, 0xA0, 0x94, 0x60, 0xFE, 0x24, 0xA2, 0x36, 0xEF, 0x1E, 0x6B, 0xF7, 0x9C, 0x69, 0xDA, + 0x9B, 0x6F, 0xAD, 0xD8, 0xFB, 0x97, 0x62, 0x5F, 0x1F, 0x38, 0xC2, 0xD7, 0x71, 0x31, 0xF0, + 0x13, 0xEE, 0x0F, 0xA3, 0xA7, 0x1C, 0xD5, 0x11, 0x4C, 0x45, 0x2C, 0x04, 0xDB, 0xA6, 0x2E, + 0xF8, 0x64, 0x9A, 0xB8, 0x53, 0x66, 0xDC, 0x7A, 0x5D, 0x03, 0x07, 0x80, 0x37, 0xFF, 0xFC, + 0x06, 0xBC, 0x26, 0xC0, 0x95, 0x4A, 0xF1, 0x51, 0x2D, 0x22, 0x18, 0x01, 0x79, 0x5E, 0x76, + 0x1D, 0x7F, 0x14, 0xE3, 0x9E, 0x8A, 0xBB, 0x34, 0xBF, 0xF4, 0xAB, 0x48, 0x63, 0x55, 0x3E, + 0x56, 0x8C, 0xD1, 0x12, 0xED, 0xC3, 0x49, 0x8E, 0x92, 0x9D, 0xCA, 0xB1, 0xE5, 0xCE, 0x4D, + 0x3F, 0xFA, 0x73, 0x05, 0xE0, 0x4B, 0x93, 0xB2, 0xCB, 0x08, 0xE1, 0x96, 0x19, 0x3D, 0x83, + 0x39, 0x75, 0xEC, 0xD6, 0x3C, 0xD0, 0x70, 0x81, 0x16, 0x29, 0x15, 0x6C, 0xC7, 0xE7, 0xE2, + 0xF6, 0xB7, 0xE8, 0x25, 0x6D, 0x3A, 0xE6, 0xC8, 0x99, 0x46, 0xB0, 0x85, 0x02, 0x61, 0x1B, + 0x8B, 0xB3, 0x9F, 0x0B, 0x2A, 0xA8, 0x77, 0x10, 0xC1, 0x88, 0xCC, 0xA4, 0xDE, 0x43, 0x58, + 0x23, 0xB4, 0xA1, 0xA5, 0x5C, 0xAE, 0xA9, 0x7E, 0x42, 0x40, 0x90, 0xD2, 0xE9, 0x84, 0xCF, + 0xE4, 0xEB, 0x47, 0x4F, 0x82, 0xD4, 0xC5, 0x8F, 0xCD, 0xD3, 0x86, 0x00, 0x59, 0xDF, 0xF2, + 0x0C, 0x7C, 0xC6, 0xBD, 0xF9, 0x7D, 0xC4, 0x91, 0x27, 0x89, 0x32, 0x72, 0x33, 0x65, 0x68, + 0xAF +}; + +// Function to decrypt Saflok card data +static void DecryptSaflokCardData( + const uint8_t strCard[SAFLOK_BASIC_ACCESS_BYTE_NUM], + // int length, // length is always SAFLOK_BASIC_ACCESS_BYTE_NUM + uint8_t decryptedCard[SAFLOK_BASIC_ACCESS_BYTE_NUM]) { + int i, num, num2, num3, num4, b = 0, b2 = 0; + + for(i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM; i++) { + num = saflok_c_aDecode[strCard[i]] - (i + 1); + if(num < 0) num += 256; + decryptedCard[i] = num; + } + + b = decryptedCard[10]; + b2 = b & 1; + + for(num2 = SAFLOK_BASIC_ACCESS_BYTE_NUM; num2 > 0; num2--) { + b = decryptedCard[num2 - 1]; + for(num3 = 8; num3 > 0; num3--) { + num4 = num2 + num3; + if(num4 > SAFLOK_BASIC_ACCESS_BYTE_NUM) num4 -= SAFLOK_BASIC_ACCESS_BYTE_NUM; + int b3 = decryptedCard[num4 - 1]; + int b4 = (b3 & 0x80) >> 7; + b3 = ((b3 << 1) & 0xFF) | b2; + b2 = (b & 0x80) >> 7; + b = ((b << 1) & 0xFF) | b4; + decryptedCard[num4 - 1] = b3; + } + decryptedCard[num2 - 1] = b; + } +} + +// Function to calculate Saflok checksum +static uint8_t CalculateCheckSum(uint8_t data[SAFLOK_BASIC_ACCESS_BYTE_NUM]) { + int sum = 0; + for(int i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM - 1; i++) { + sum += data[i]; + } + sum = 255 - (sum & 0xFF); + return sum & 0xFF; +} + +// Function to parse and print Saflok data +static void ParseAndPrintSaflokData(const sector_t* sector0_info, const sector_t* sector1_info) { + (void)sector1_info; // Not directly used for payload parsing currently + + if (!sector0_info) { + PrintAndLogEx(WARNING, "Saflok: Sector 0 information not available for parsing."); + return; + } + + uint8_t key_bytes_for_s0[MIFARE_KEY_SIZE]; + uint8_t key_type_for_s0; // CORRECTED: Was MifareKeyType, now uint8_t + bool s0_key_found = false; + + // Prioritize Key A for Sector 0 if available + if (sector0_info->foundKey[MF_KEY_A]) { + num_to_bytes(sector0_info->Key[MF_KEY_A], MIFARE_KEY_SIZE, key_bytes_for_s0); + key_type_for_s0 = MF_KEY_A; // MF_KEY_A is typically #define'd as 0x60 + s0_key_found = true; + PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key A for reading blocks."); + } else if (sector0_info->foundKey[MF_KEY_B]) { // Fallback to Key B for Sector 0 + num_to_bytes(sector0_info->Key[MF_KEY_B], MIFARE_KEY_SIZE, key_bytes_for_s0); + key_type_for_s0 = MF_KEY_B; // MF_KEY_B is typically #define'd as 0x61 + s0_key_found = true; + PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key B for reading blocks."); + } + + if (!s0_key_found) { + PrintAndLogEx(WARNING, "Saflok: No known keys for Sector 0. Cannot read blocks 1 & 2 for parsing."); + return; + } + + uint8_t block1_content[MFBLOCK_SIZE]; + uint8_t block2_content[MFBLOCK_SIZE]; + + // Read absolute block 1 (data block within sector 0) + if (mf_read_block(1, key_type_for_s0, key_bytes_for_s0, block1_content) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 1 using Sector 0 %s key.", (key_type_for_s0 == MF_KEY_A) ? "A" : "B"); + return; + } + PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 1."); + + // Read absolute block 2 (data block within sector 0) + if (mf_read_block(2, key_type_for_s0, key_bytes_for_s0, block2_content) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 2 using Sector 0 %s key.", (key_type_for_s0 == MF_KEY_A) ? "A" : "B"); + return; + } + PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 2."); + + uint8_t basicAccess[SAFLOK_BASIC_ACCESS_BYTE_NUM]; + uint8_t decodedBA[SAFLOK_BASIC_ACCESS_BYTE_NUM]; + + memcpy(basicAccess, block1_content, 16); // 16 bytes from Block 1 + memcpy(basicAccess + 16, block2_content, 1); // 1 byte from Block 2 + + DecryptSaflokCardData(basicAccess, decodedBA); + + + // Byte 0: Key level, LED warning bit, and subgroup functions + uint8_t key_level = (decodedBA[0] & 0xF0) >> 4; + uint8_t led_warning = (decodedBA[0] & 0x08) >> 3; + + // Byte 1: Key ID + uint8_t key_id = decodedBA[1]; + + // Byte 2 & 3: KeyRecord, including OpeningKey flag + uint8_t key_record_high = decodedBA[2] & 0x7F; + uint8_t opening_key = (decodedBA[2] & 0x80) >> 7; + uint16_t key_record = (key_record_high << 8) | decodedBA[3]; + + // Byte 5 & 6: EncryptSequence + Combination + uint16_t sequence_combination_number = ((decodedBA[5] & 0x0F) << 8) | decodedBA[6]; + + // Byte 7: OverrideDeadbolt and Days + uint8_t override_deadbolt = (decodedBA[7] & 0x80) >> 7; + uint8_t restricted_weekday = decodedBA[7] & 0x7F; + + // Weekday names array + static const char* weekdays[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; + + // Buffer to store the resulting string (sufficient size for all weekdays) + char restricted_weekday_string[128] = {0}; + int restricted_count = 0; + + // Check each bit from Monday to Sunday + for(int i = 0; i < 7; i++) { + if(restricted_weekday & (0b01000000 >> i)) { + // If the bit is set, append the corresponding weekday to the buffer + if(restricted_count > 0) { + strcat(restricted_weekday_string, ", "); + } + strcat(restricted_weekday_string, weekdays[i]); + restricted_count++; + } + } + + // Determine if all weekdays are restricted + if(restricted_weekday == 0b01111100) { + strcpy(restricted_weekday_string, "weekdays"); + } + // If there are specific restricted days + else if(restricted_weekday == 0b00000011) { + strcpy(restricted_weekday_string, "weekends"); + } + // If no weekdays are restricted + else if(restricted_weekday == 0) { + strcpy(restricted_weekday_string, "none"); + } + + // Bytes 14-15: Property number and part of creation year + uint8_t creation_year_high_bits = (decodedBA[14] & 0xF0); + uint16_t property_id = ((decodedBA[14] & 0x0F) << 8) | decodedBA[15]; + + // Bytes 11-13: Creation date since SAFLOK_YEAR_OFFSET Jan 1st + uint16_t creation_year = (((decodedBA[11] & 0xF0) >> 4) + SAFLOK_YEAR_OFFSET) | creation_year_high_bits; + uint8_t creation_month = decodedBA[11] & 0x0F; + uint8_t creation_day = (decodedBA[12] >> 3) & 0x1F; + uint8_t creation_hour = ((decodedBA[12] & 0x07) << 2) | ((decodedBA[13] & 0xC0) >> 6); + uint8_t creation_minute = decodedBA[13] & 0x3F; + + // Bytes 8-10: Expiry interval / absolute time components + uint8_t interval_year_val = (decodedBA[8] >> 4); + uint8_t interval_month_val = decodedBA[8] & 0x0F; + uint8_t interval_day_val = (decodedBA[9] >> 3) & 0x1F; + uint8_t expiry_hour = ((decodedBA[9] & 0x07) << 2) | ((decodedBA[10] & 0xC0) >> 6); + uint8_t expiry_minute = decodedBA[10] & 0x3F; + + uint16_t expire_year = creation_year + interval_year_val; + uint8_t expire_month = creation_month + interval_month_val; + uint8_t expire_day = creation_day + interval_day_val; + + // Handle month rollover for expiration + while(expire_month > 12) { + expire_month -= 12; + expire_year++; + } + + // Handle day rollover for expiration + static const uint8_t days_in_month_lookup[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 1-indexed month + if (expire_month > 0 && expire_month <= 12) { + while(true) { + uint8_t max_days = days_in_month_lookup[expire_month]; + if(expire_month == 2 && (expire_year % 4 == 0 && (expire_year % 100 != 0 || expire_year % 400 == 0))) { + max_days = 29; // Leap year + } + if(expire_day <= max_days) { + break; + } + if (max_days == 0) { // Should not happen with valid month + PrintAndLogEx(WARNING, "Saflok: Invalid day/month for expiration rollover calculation."); + break; + } + expire_day -= max_days; + expire_month++; + if(expire_month > 12) { + expire_month = 1; + expire_year++; + } + } + } else if (expire_month != 0) { // Allow 0 if it signifies no expiration or error + PrintAndLogEx(WARNING, "Saflok: Invalid expiration month (%u) before day rollover.", expire_month); + } + + uint8_t checksum = decodedBA[16]; + uint8_t checksum_calculated = CalculateCheckSum(decodedBA); + bool checksum_valid = (checksum_calculated == checksum); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Saflok Details")); + PrintAndLogEx(SUCCESS, "Key Level: %u (%s)", saflok_key_levels[key_level].level_num, saflok_key_levels[key_level].level_name); + PrintAndLogEx(SUCCESS, "LED Warning: %s", led_warning ? "Yes" : "No"); + PrintAndLogEx(SUCCESS, "Key ID: %u (0x%02X)", key_id, key_id); + PrintAndLogEx(SUCCESS, "Key Record: %u (0x%04X)", key_record, key_record); + PrintAndLogEx(SUCCESS, "Opening Key: %s", opening_key ? "Yes" : "No"); + PrintAndLogEx(SUCCESS, "Sequence Number & Combination: %u (0x%02X)", sequence_combination_number, sequence_combination_number); + PrintAndLogEx(SUCCESS, "Override Deadbolt: %s", override_deadbolt ? "Yes" : "No"); + PrintAndLogEx(SUCCESS, "Restricted Weekdays: %s", restricted_weekday_string); + PrintAndLogEx(SUCCESS, "Property ID: %u (0x%04X)", property_id, property_id); + PrintAndLogEx(SUCCESS, "Creation Date: %04u-%02u-%02u %02u:%02u", creation_year, creation_month, creation_day, creation_hour, creation_minute); + PrintAndLogEx(SUCCESS, "Expiration Date: %04u-%02u-%02u %02u:%02u", expire_year, expire_month, expire_day, expiry_hour, expiry_minute); + PrintAndLogEx(SUCCESS, "Checksum Valid: %s", checksum_valid ? "Yes" : "No"); +} + + + static int CmdHelp(const char *Cmd); /* @@ -9889,8 +10178,9 @@ static int CmdHF14AMfInfo(const char *Cmd) { PrintAndLogEx(SUCCESS, "unknown"); } - if (e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) { + if (keycnt > 1 && e_sector != NULL && e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) { PrintAndLogEx(SUCCESS, "dormakaba Saflok detected"); + ParseAndPrintSaflokData(&e_sector[0], &e_sector[1]); } } else { From e35a4e292d617ebe04421d24823fbe3c6df4ae54 Mon Sep 17 00:00:00 2001 From: Kara Zajac Date: Mon, 26 May 2025 23:39:25 -0400 Subject: [PATCH 20/26] Used make style Fixed some code comments and ran make style Signed-off-by: Kara Zajac --- client/src/cmdhfmf.c | 58 ++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index a05cfbb1f..3343ad899 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -66,7 +66,7 @@ typedef struct { // Structure for Saflok key levels typedef struct { uint8_t level_num; - const char* level_name; + const char *level_name; } SaflokKeyLevel; // Static array for Saflok key levels @@ -116,22 +116,28 @@ static void DecryptSaflokCardData( const uint8_t strCard[SAFLOK_BASIC_ACCESS_BYTE_NUM], // int length, // length is always SAFLOK_BASIC_ACCESS_BYTE_NUM uint8_t decryptedCard[SAFLOK_BASIC_ACCESS_BYTE_NUM]) { - int i, num, num2, num3, num4, b = 0, b2 = 0; + int i; + int num; + int num2; + int num3; + int num4; + int b = 0; + int b2 = 0; - for(i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM; i++) { + for (i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM; i++) { num = saflok_c_aDecode[strCard[i]] - (i + 1); - if(num < 0) num += 256; + if (num < 0) num += 256; decryptedCard[i] = num; } b = decryptedCard[10]; b2 = b & 1; - for(num2 = SAFLOK_BASIC_ACCESS_BYTE_NUM; num2 > 0; num2--) { + for (num2 = SAFLOK_BASIC_ACCESS_BYTE_NUM; num2 > 0; num2--) { b = decryptedCard[num2 - 1]; - for(num3 = 8; num3 > 0; num3--) { + for (num3 = 8; num3 > 0; num3--) { num4 = num2 + num3; - if(num4 > SAFLOK_BASIC_ACCESS_BYTE_NUM) num4 -= SAFLOK_BASIC_ACCESS_BYTE_NUM; + if (num4 > SAFLOK_BASIC_ACCESS_BYTE_NUM) num4 -= SAFLOK_BASIC_ACCESS_BYTE_NUM; int b3 = decryptedCard[num4 - 1]; int b4 = (b3 & 0x80) >> 7; b3 = ((b3 << 1) & 0xFF) | b2; @@ -146,7 +152,7 @@ static void DecryptSaflokCardData( // Function to calculate Saflok checksum static uint8_t CalculateCheckSum(uint8_t data[SAFLOK_BASIC_ACCESS_BYTE_NUM]) { int sum = 0; - for(int i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM - 1; i++) { + for (int i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM - 1; i++) { sum += data[i]; } sum = 255 - (sum & 0xFF); @@ -228,19 +234,19 @@ static void ParseAndPrintSaflokData(const sector_t* sector0_info, const sector_t // Byte 7: OverrideDeadbolt and Days uint8_t override_deadbolt = (decodedBA[7] & 0x80) >> 7; uint8_t restricted_weekday = decodedBA[7] & 0x7F; - + // Weekday names array - static const char* weekdays[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; - + static const char *weekdays[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; + // Buffer to store the resulting string (sufficient size for all weekdays) char restricted_weekday_string[128] = {0}; int restricted_count = 0; - + // Check each bit from Monday to Sunday - for(int i = 0; i < 7; i++) { - if(restricted_weekday & (0b01000000 >> i)) { + for (int i = 0; i < 7; i++) { + if (restricted_weekday & (0b01000000 >> i)) { // If the bit is set, append the corresponding weekday to the buffer - if(restricted_count > 0) { + if (restricted_count > 0) { strcat(restricted_weekday_string, ", "); } strcat(restricted_weekday_string, weekdays[i]); @@ -249,18 +255,18 @@ static void ParseAndPrintSaflokData(const sector_t* sector0_info, const sector_t } // Determine if all weekdays are restricted - if(restricted_weekday == 0b01111100) { + if (restricted_weekday == 0b01111100) { strcpy(restricted_weekday_string, "weekdays"); } // If there are specific restricted days - else if(restricted_weekday == 0b00000011) { + else if (restricted_weekday == 0b00000011) { strcpy(restricted_weekday_string, "weekends"); } // If no weekdays are restricted - else if(restricted_weekday == 0) { + else if (restricted_weekday == 0) { strcpy(restricted_weekday_string, "none"); } - + // Bytes 14-15: Property number and part of creation year uint8_t creation_year_high_bits = (decodedBA[14] & 0xF0); uint16_t property_id = ((decodedBA[14] & 0x0F) << 8) | decodedBA[15]; @@ -284,7 +290,7 @@ static void ParseAndPrintSaflokData(const sector_t* sector0_info, const sector_t uint8_t expire_day = creation_day + interval_day_val; // Handle month rollover for expiration - while(expire_month > 12) { + while (expire_month > 12) { expire_month -= 12; expire_year++; } @@ -292,12 +298,12 @@ static void ParseAndPrintSaflokData(const sector_t* sector0_info, const sector_t // Handle day rollover for expiration static const uint8_t days_in_month_lookup[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 1-indexed month if (expire_month > 0 && expire_month <= 12) { - while(true) { + while (true) { uint8_t max_days = days_in_month_lookup[expire_month]; - if(expire_month == 2 && (expire_year % 4 == 0 && (expire_year % 100 != 0 || expire_year % 400 == 0))) { + if (expire_month == 2 && (expire_year % 4 == 0 && (expire_year % 100 != 0 || expire_year % 400 == 0))) { max_days = 29; // Leap year } - if(expire_day <= max_days) { + if (expire_day <= max_days) { break; } if (max_days == 0) { // Should not happen with valid month @@ -306,13 +312,13 @@ static void ParseAndPrintSaflokData(const sector_t* sector0_info, const sector_t } expire_day -= max_days; expire_month++; - if(expire_month > 12) { + if (expire_month > 12) { expire_month = 1; expire_year++; } } } else if (expire_month != 0) { // Allow 0 if it signifies no expiration or error - PrintAndLogEx(WARNING, "Saflok: Invalid expiration month (%u) before day rollover.", expire_month); + PrintAndLogEx(WARNING, "Saflok: Invalid expiration month (%u) before day rollover.", expire_month); } uint8_t checksum = decodedBA[16]; @@ -4800,7 +4806,7 @@ void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector _YELLOW_("H") ":Hardnested / " _YELLOW_("C") ":statiCnested / " _YELLOW_("A") ":keyA " - " )" + " )" ); if (sectorscnt == 18) { PrintAndLogEx(INFO, "( " _MAGENTA_("*") " ) These sectors used for signature. Lays outside of user memory"); From 4e07fc2b3151df704d1730f288743a16fbcbd4fd Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 27 May 2025 09:43:11 +0200 Subject: [PATCH 21/26] if enabled but no delay, then disable tear off just in case. enforce user to set a delay. if not this function will be triggered over and over which might confuse users normal operation --- armsrc/appmain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 774014d6a..5537cff79 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -99,6 +99,7 @@ int tearoff_hook(void) { if (g_tearoff_enabled) { if (g_tearoff_delay_us == 0) { Dbprintf(_RED_("No tear-off delay configured!")); + g_tearoff_enabled = false; return PM3_SUCCESS; // SUCCESS = the hook didn't do anything } SpinDelayUsPrecision(g_tearoff_delay_us); From 585670d55c684bd9ed5c93213d1069ca83386368 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 27 May 2025 09:44:27 +0200 Subject: [PATCH 22/26] hf iclass tear - text output and when e-purse get cleared it stops and informs user --- client/src/cmdhficlass.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index f1da50f14..6ba663897 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3209,9 +3209,14 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { goto out; } - PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%u")" / "_YELLOW_("%d")" loops", params.delay_us, (tearoff_end & 0xFFFF), loop_count+1, tearoff_loop); + if (tearoff_loop > 1) { + PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%u")" loops", params.delay_us, (tearoff_end & 0xFFFF), loop_count + 1); + } else { + PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us", params.delay_us, (tearoff_end & 0xFFFF)); + } // write block - don't check the return value. As a tear-off occurred, the write failed. + // when tear off is enabled, the return code will always be PM3_ETEAROFF iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); // read the data back @@ -3228,7 +3233,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { goto out; } - if (blockno == 1) { + // skip authentication for config and e-purse blocks (1,2) + if (blockno < 3) { read_auth = false; } @@ -3295,6 +3301,16 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } bool goto_out = false; + if (blockno == 2) { + if (memcmp(data_read, ff_data, 8) == 0 && memcmp(data_read_orig, ff_data, 8) != 0) { + PrintAndLogEx(SUCCESS, "E-purse has been teared ( %s )", _GREEN_("ok")); + PrintAndLogEx(HINT, "Hint: try `hf iclass creditepurse -d FEFFFEFF --ki 1`"); + PrintAndLogEx(HINT, "Hint: try `hf iclass wrbl -d 'FFFFFFFF FFFF FEFF' --blk 2 --ki 1 --credit`"); + isok = PM3_SUCCESS; + goto_out = true; + } + } + if (blockno == 1) { if (data_read[0] != data_read_orig[0]) { PrintAndLogEx(NORMAL, ""); @@ -3322,13 +3338,20 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { for (int i = 7; i >= 0; --i) { int bit1 = (data_read_orig[7] >> i) & 1; int bit2 = (data_read[7] >> i) & 1; - PrintAndLogEx(INFO, "%-10s %-10d %-10d", flag_names[i], bit1, bit2); + PrintAndLogEx(INFO, "%-11s %-10d %-10d", flag_names[i], bit1, bit2); } isok = PM3_SUCCESS; goto_out = true; } + // if more OTP bits set.. + if (data_read[1] > data_read_orig[1] || + data_read[2] > data_read_orig[2]) { + PrintAndLogEx(SUCCESS, "More OTP bits got set!!!"); + isok = PM3_SUCCESS; + } + if (goto_out) { goto out; } From 01e57db5f175bba49f8cb987b5e8988b68a76de3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 27 May 2025 10:12:58 +0200 Subject: [PATCH 23/26] text --- client/src/cmdhficlass.c | 11 ++++++----- doc/commands.json | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 6ba663897..1a917c1a8 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2958,7 +2958,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { CLIParserInit(&ctx, "hf iclass tear", "Tear off an iCLASS tag block\n" "e-purse usually 300-500us to trigger the erase phase\n" - "also seen 1800-2100us on some cards\n", + "also seen 1800-2100us on some cards\n" + "Make sure you know the target card credit key. Typical `--ki 1` or `--ki 3`\n", "hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B -s 300 -e 600\n" "hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 -s 300 -e 600\n" "hf iclass tear --blk 2 -d fdffffffffffffff --ki 1 --credit -s 400 -e 500" @@ -3138,8 +3139,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } if (pagemap == 0x0) { - PrintAndLogEx(WARNING, _RED_("No auth possible. Read only if RA is enabled")); - goto out; + PrintAndLogEx(WARNING, _RED_("No auth possible. Read only if RA is enabled")); + goto out; } bool read_auth = auth; @@ -3210,7 +3211,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } if (tearoff_loop > 1) { - PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%u")" loops", params.delay_us, (tearoff_end & 0xFFFF), loop_count + 1); + PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%u")" loops ", params.delay_us, (tearoff_end & 0xFFFF), loop_count + 1); } else { PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us", params.delay_us, (tearoff_end & 0xFFFF)); } @@ -3347,7 +3348,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { // if more OTP bits set.. if (data_read[1] > data_read_orig[1] || - data_read[2] > data_read_orig[2]) { + data_read[2] > data_read_orig[2]) { PrintAndLogEx(SUCCESS, "More OTP bits got set!!!"); isok = PM3_SUCCESS; } diff --git a/doc/commands.json b/doc/commands.json index 4d678aaeb..8f43d716a 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3718,7 +3718,7 @@ }, "hf iclass tear": { "command": "hf iclass tear", - "description": "Tear off an iCLASS tag block e-purse usually 300-500us to trigger the erase phase also seen 1800-2100us on some cards", + "description": "Tear off an iCLASS tag block e-purse usually 300-500us to trigger the erase phase also seen 1800-2100us on some cards Make sure you know the target card credit key. Typical `--ki 1` or `--ki 3`", "notes": [ "hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B -s 300 -e 600", "hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 -s 300 -e 600", @@ -13354,6 +13354,6 @@ "metadata": { "commands_extracted": 767, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-05-25T12:38:36" + "extracted_on": "2025-05-27T08:11:15" } } From ada340de948f7eae577070f5a758d70aecec7dd3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 27 May 2025 14:52:04 +0200 Subject: [PATCH 24/26] fix exit call --- client/src/cmdhficlass.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 1a917c1a8..d9bea6771 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3211,14 +3211,14 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } if (tearoff_loop > 1) { - PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%u")" loops ", params.delay_us, (tearoff_end & 0xFFFF), loop_count + 1); + PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%3u")" loops", params.delay_us, (tearoff_end & 0xFFFF), loop_count + 1); } else { PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us", params.delay_us, (tearoff_end & 0xFFFF)); } // write block - don't check the return value. As a tear-off occurred, the write failed. // when tear off is enabled, the return code will always be PM3_ETEAROFF - iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); + iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, false, auth, shallow_mod); // read the data back uint8_t data_read[8] = {0}; @@ -3352,10 +3352,10 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(SUCCESS, "More OTP bits got set!!!"); isok = PM3_SUCCESS; } + } - if (goto_out) { - goto out; - } + if (goto_out) { + goto out; } } From bbd6f51586922c1ed540c556a3eee8258c35bd9a Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Wed, 28 May 2025 23:59:17 +0800 Subject: [PATCH 25/26] Updated hf iclass info for silicon check Updated hf iclass info to use silicone identification based on CSN rather than hf 14b responsiveness This reverted https://github.com/RfidResearchGroup/proxmark3/commit/4f85def6b07ad9cefe78d9bd11b18f14fad5dcb7 --- client/src/cmdhf14b.c | 11 ++++------- client/src/cmdhf14b.h | 1 - client/src/cmdhficlass.c | 7 +++---- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 69011be6c..f61d7d1fb 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1411,7 +1411,7 @@ static bool HF14B_ask_ct_reader(bool verbose) { return false; } -bool HF14B_picopass_reader(bool verbose, bool info) { +static bool HF14B_picopass_reader(bool verbose) { iso14b_raw_cmd_t packet = { .flags = (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_DISCONNECT), @@ -1437,10 +1437,8 @@ bool HF14B_picopass_reader(bool verbose, bool info) { return false; } memcpy(card, resp.data.asBytes, sizeof(picopass_hdr_t)); - if (info) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn))); - } + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn))); free(card); return true; } @@ -3038,7 +3036,6 @@ int infoHF14B(bool verbose, bool do_aid_search) { // get and print general info about all known 14b chips int readHF14B(bool loop, bool verbose, bool read_plot) { bool found = false; - bool info = true; int res = PM3_SUCCESS; do { found = false; @@ -3054,7 +3051,7 @@ int readHF14B(bool loop, bool verbose, bool read_plot) { goto plot; // Picopass - found |= HF14B_picopass_reader(verbose, info); + found |= HF14B_picopass_reader(verbose); if (found) goto plot; diff --git a/client/src/cmdhf14b.h b/client/src/cmdhf14b.h index 067718507..065dbc29c 100644 --- a/client/src/cmdhf14b.h +++ b/client/src/cmdhf14b.h @@ -31,6 +31,5 @@ int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card); int infoHF14B(bool verbose, bool do_aid_search); int readHF14B(bool loop, bool verbose, bool read_plot); -bool HF14B_picopass_reader(bool verbose, bool info); #endif diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index d9bea6771..b3118cb0a 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -40,7 +40,6 @@ #include "crypto/asn1utils.h" // ASN1 decoder #include "preferences.h" #include "generator.h" -#include "cmdhf14b.h" #include "cmdhw.h" #include "hidsio.h" @@ -5985,10 +5984,10 @@ int info_iclass(bool shallow_mod) { uint8_t cardtype = get_mem_config(hdr); PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]); - if (HF14B_picopass_reader(false, false)) { - PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("Old Silicon (14b support)")); - } else { + if (memcmp(hdr->csn + 4, "\xFE\xFF\x12\xE0", 4) == 0) { PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("NEW Silicon (No 14b support)")); + } else { + PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("Old Silicon (14b support)")); } if (legacy) { From 503c03caa244bda4522f9820d193f0c52672d6d3 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Thu, 29 May 2025 00:00:19 +0800 Subject: [PATCH 26/26] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 631bb3084..b192e419f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] +- Changed `hf iclass info` - now uses CSN values based checks (@antiklesys) - Changed `hf iclass dump` - now uses default AA1 key when called without a key or key index (@iceman1001) - Renamed `hf iclass trbl` to `hf iclass tear` (@iceman1001) - Changed `hw tearoff` - the device side message is now debug log controlled (@iceman1001)