From 047b94fbaae2b4dde89c1099935dc8e4946cecc5 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 23 May 2025 16:32:48 +0800 Subject: [PATCH 1/2] Updated hf iclass trbl to support looping Implemented a functionality for hf iclass trbl to specify how many times to loop at specific delays. --- client/src/cmdhficlass.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 42d516077..84452b49f 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2940,6 +2940,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { arg_int1(NULL, "s", "", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us."), arg_int0(NULL, "i", "", "tearoff delay increment (in us) - default 10."), arg_int0(NULL, "e", "", "tearoff delay end (in us) must be a higher value than the start delay."), + arg_int0(NULL, "loop", "", "number of times to loop per tearoff time."), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3005,6 +3006,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { int tearoff_start = arg_get_int_def(ctx, 12, 5000); 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); + int loop_count = 0; if (tearoff_end <= tearoff_start) { PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay."); @@ -3147,7 +3150,11 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } PrintAndLogEx(INFO, "Read: "_GREEN_("%s"), sprint_hex(data_read, sizeof(data_read))); } - tearoff_start += tearoff_increment; + loop_count++; + if (loop_count == tearoff_loop){ + tearoff_start += tearoff_increment; + loop_count = 0; + } PrintAndLogEx(INFO, "---------------"); } PrintAndLogEx(NORMAL, ""); From fbbfeaa9770e68b1bcec3d5b8aa54c0be9f36800 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 23 May 2025 17:00:41 +0800 Subject: [PATCH 2/2] Update cmdhficlass.c --- client/src/cmdhficlass.c | 80 ++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 84452b49f..13725b392 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3005,7 +3005,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { int tearoff_start = arg_get_int_def(ctx, 12, 5000); 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_end = arg_get_int_def(ctx, 14, tearoff_start + tearoff_increment + 500); int tearoff_loop = arg_get_int_def(ctx, 15, 1); int loop_count = 0; @@ -3041,10 +3041,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { keyType = 0x18; //credit key } - //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}; + uint8_t ff_data[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; bool first_read = false; bool reread = false; bool erase_phase = false; @@ -3062,11 +3061,26 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { reread = false; } + // turn off Device side debug messages + uint8_t dbg_curr = DBG_NONE; + if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) { + return PM3_EFAILED; + } + + if (setDeviceDebugLevel(DBG_NONE, false) != PM3_SUCCESS) { + return PM3_EFAILED; + } + + PrintAndLogEx(INFO, "Starting tear off against block %u / 0x%02x", blockno, blockno); + PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "Press " _GREEN_("") " to abort"); + while (tearoff_start <= tearoff_end && read_ok == false) { + if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\naborted via keyboard."); - return PM3_EOPABORTED; + isok = PM3_EOPABORTED; + goto out; } // set tear off trigger @@ -3076,15 +3090,17 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { .on = true, .off = false }; + int res = handle_tearoff(¶ms, verbose); if (res != PM3_SUCCESS) { PrintAndLogEx(WARNING, "Failed to configure tear off"); - return PM3_ESOFT; + isok = PM3_ESOFT; + goto out; } // write // don't check the return value. As a tear-off occurred, the write failed. - PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")"/"_YELLOW_("%d")" us", tearoff_start,tearoff_end); + PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")" / "_YELLOW_("%d")" us", tearoff_start, tearoff_end); iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); //read the data back @@ -3092,11 +3108,15 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { first_read = false; reread = false; bool decrease = false; + while (first_read == false) { + if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\naborted via keyboard."); - return PM3_EOPABORTED; + isok = PM3_EOPABORTED; + goto out; } + res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read, false); if (res == PM3_SUCCESS && !reread) { if (memcmp(data_read, zeros, 8) == 0) { @@ -3112,50 +3132,64 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { decrease = true; } } + if (decrease && tearoff_start > 0) { //if there was an error reading repeat the tearoff with the same delay tearoff_start -= tearoff_increment; } + bool tear_success = true; bool expected_values = true; - if(memcmp(data_read, data, 8) != 0) { + + if (memcmp(data_read, data, 8) != 0) { tear_success = false; } + 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) { + + if (memcmp(data_read, ff_data, 8) == 0 && memcmp(data_read_orig, ff_data, 8) != 0) { erase_phase = true; PrintAndLogEx(SUCCESS, _BLUE_("Erase phase hit: ALL ONES")); - PrintAndLogEx(INFO, "Original: %s", sprint_hex(data_read_orig, sizeof(data_read))); - PrintAndLogEx(INFO, "Read: "_BLUE_("%s"), sprint_hex(data_read, sizeof(data_read))); - }else{ + PrintAndLogEx(INFO, "Original: %s", sprint_hex_inrow(data_read_orig, sizeof(data_read))); + PrintAndLogEx(INFO, "Read: "_BLUE_("%s"), sprint_hex_inrow(data_read, sizeof(data_read))); + } else { + if (erase_phase) { PrintAndLogEx(SUCCESS, _MAGENTA_("Tearing! Write Phase (post erase)")); - PrintAndLogEx(INFO, "Original: %s", sprint_hex(data_read_orig, sizeof(data_read))); - PrintAndLogEx(INFO, "Read: "_CYAN_("%s"), sprint_hex(data_read, sizeof(data_read))); - }else{ + PrintAndLogEx(INFO, "Original: %s", sprint_hex_inrow(data_read_orig, sizeof(data_read))); + PrintAndLogEx(INFO, "Read: "_CYAN_("%s"), sprint_hex_inrow(data_read, sizeof(data_read))); + } else { PrintAndLogEx(SUCCESS, _CYAN_("Tearing!(unknown phase)!")); - PrintAndLogEx(INFO, "Original: %s", sprint_hex(data_read_orig, sizeof(data_read))); - PrintAndLogEx(INFO, "Read: "_CYAN_("%s"), sprint_hex(data_read, sizeof(data_read))); + PrintAndLogEx(INFO, "Original: %s", sprint_hex_inrow(data_read_orig, sizeof(data_read))); + PrintAndLogEx(INFO, "Read: "_CYAN_("%s"), sprint_hex_inrow(data_read, sizeof(data_read))); } } - }else { //tearoff did not succeed - PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); - PrintAndLogEx(INFO, "Expected: %s", sprint_hex(data, sizeof(data))); + + } else { //tearoff did not succeed + PrintAndLogEx(INFO, "Read: %s", sprint_hex_inrow(data_read, sizeof(data_read))); + PrintAndLogEx(INFO, "Expected: %s", sprint_hex_inrow(data, sizeof(data))); } + if (tear_success) { //tearoff succeeded with expected values read_ok = true; tear_success = true; - if(expected_values) { + if (expected_values) { PrintAndLogEx(SUCCESS, _GREEN_("Expected values!")); } - PrintAndLogEx(INFO, "Read: "_GREEN_("%s"), sprint_hex(data_read, sizeof(data_read))); + PrintAndLogEx(INFO, "Read: "_GREEN_("%s"), sprint_hex_inrow(data_read, sizeof(data_read))); } loop_count++; if (loop_count == tearoff_loop){ tearoff_start += tearoff_increment; loop_count = 0; } - PrintAndLogEx(INFO, "---------------"); + PrintAndLogEx(INFO, "--------------------------"); + } + +out: + if (setDeviceDebugLevel(verbose ? MAX(dbg_curr, DBG_INFO) : DBG_NONE, false) != PM3_SUCCESS) { + return PM3_EFAILED; } PrintAndLogEx(NORMAL, ""); return isok;