From e68be39a415b1fd177494674bb8ce7f356d5d8fe Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 6 Jun 2025 16:06:53 +0800 Subject: [PATCH] Updated hf iclass legrec to be able to use shorter delays Added an option for hf iclass legrec to further increase speeds by using a shorter delay of 1500 vs the default of 3390. This seems to be stable on new silicon especially now that we're keeping the field always on. It may be more risky for the --fast operation. --- armsrc/iclass.c | 16 +++++++++++----- armsrc/iclass.h | 1 + client/src/cmdhficlass.c | 13 +++++++++---- include/iclass_cmd.h | 1 + 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 7cb290038..e85e6b1f2 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1795,7 +1795,7 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac, return true; } -static bool iclass_writeblock_sp(uint8_t blockno, uint8_t *data, uint8_t *mac, bool shallow_mod, uint32_t *start_time, uint32_t *eof_time) { +static bool iclass_writeblock_sp(uint8_t blockno, uint8_t *data, uint8_t *mac, bool shallow_mod, uint32_t *start_time, uint32_t *eof_time, bool short_delay) { // write command: cmd, 1 blockno, 8 data, 4 mac uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; @@ -1804,7 +1804,12 @@ static bool iclass_writeblock_sp(uint8_t blockno, uint8_t *data, uint8_t *mac, b memcpy(write + 10, mac, 4); uint8_t resp[10] = {0}; - bool isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_UPDATE, eof_time, shallow_mod); + bool isOK = false; + if(short_delay){ + isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_UPDATE_FAST, eof_time, shallow_mod); + }else{ + isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_UPDATE, eof_time, shallow_mod); + } if (isOK == false) { return false; } @@ -2642,6 +2647,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { uint8_t fast_previous_key[PICOPASS_BLOCK_SIZE] = {0}; uint8_t fast_current_key[PICOPASS_BLOCK_SIZE] = {0}; uint32_t index = msg->index; + bool short_delay = msg->short_delay; int bits_found = -1; bool recovered = false; bool completed = false; @@ -2841,7 +2847,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { bool write_error = false; while (written == false && write_error == false) { //Step5 Perform Write - if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) { + if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time, short_delay)) { status_message = 4; //wrote new key on the card - unverified } if(!msg->fast){ //if we're going slow we check at every write that the write actually happened @@ -2905,7 +2911,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) { + if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time, short_delay)) { status_message = 6; //restore of original key successful but unverified } //Do a readcheck first to reset the cypher state @@ -2991,7 +2997,7 @@ fast_restore: memcpy(wb + 1, fast_restore_key, 8); doMAC_N(wb, sizeof(wb), div_key2, mac2); start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - if (iclass_writeblock_sp(blockno, fast_restore_key, mac2, shallow_mod, &start_time, &eof_time)) { + if (iclass_writeblock_sp(blockno, fast_restore_key, mac2, shallow_mod, &start_time, &eof_time, short_delay)) { status_message = 6; //restore of original key successful but unverified } //Do a readcheck first to reset the cypher state diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 4e242b254..2d2bf8c42 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -34,6 +34,7 @@ // times in samples @ 212kHz when acting as reader #define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us #define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms +#define ICLASS_READER_TIMEOUT_UPDATE_FAST 1500 // A copy of ICLASS_READER_TIMEOUT_UPDATE with reduced timeout values #define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us // The length of a received command will in most cases be no more than 18 bytes. diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index c4a7af66f..aeaf7f514 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -4524,7 +4524,7 @@ void picopass_elite_nextKey(uint8_t *key) { memcpy(key, key_state, 8); } -static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool fast, bool allnight) { +static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool fast, bool short_delay, bool allnight) { int runs = 1; int cycle = 1; @@ -4557,6 +4557,7 @@ static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, u payload->debug = debug; payload->test = test; payload->fast = fast; + payload->short_delay = short_delay; memcpy(payload->nfa, no_first_auth, PICOPASS_BLOCK_SIZE); memcpy(payload->req.key, key, PICOPASS_BLOCK_SIZE); memcpy(payload->req2.key, aa2_standard_key, PICOPASS_BLOCK_SIZE); @@ -4859,9 +4860,11 @@ static int CmdHFiClassLegacyRecSim(void) { bits_found = index; PrintAndLogEx(SUCCESS, "Original Key: " _GREEN_("%s"), sprint_hex(original_key, sizeof(original_key))); PrintAndLogEx(SUCCESS, "Weak Key: " _GREEN_("%s"), sprint_hex(key, sizeof(key))); - PrintAndLogEx(SUCCESS, "Key Updates Required to Weak Key :" _GREEN_("%d"), index); + PrintAndLogEx(SUCCESS, "Key Updates Required to Weak Key: " _GREEN_("%d"), index); PrintAndLogEx(SUCCESS, "Estimated Time (default mode) : ~" _GREEN_("%d")" hours", index / 17800); + PrintAndLogEx(SUCCESS, "Estimated Time (default + --sl) : ~" _GREEN_("%d")" hours", index / 19450); PrintAndLogEx(SUCCESS, "Estimated Time (--fast mode) : ~" _GREEN_("%d")" hours", index / 26860); + PrintAndLogEx(SUCCESS, "Estimated Time (--fast + --sl) : ~" _GREEN_("%d")" hours", index / 29750); } index++; @@ -4890,6 +4893,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { arg_lit0(NULL, "notest", "Perform real writes on the card!"), arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000."), arg_lit0(NULL, "fast", "Increases the speed (4.6->7.4 key updates/second), higher risk to brick the card."), + arg_lit0(NULL, "sl", "Lower card comms delay times, further speeds increases, may cause more errors."), arg_lit0(NULL, "est", "Estimates the key updates based on the card's CSN assuming standard key."), arg_param_end }; @@ -4906,7 +4910,8 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { bool no_test = arg_get_lit(ctx, 5); bool allnight = arg_get_lit(ctx, 6); bool fast = arg_get_lit(ctx, 7); - bool sim = arg_get_lit(ctx, 8); + bool short_delay = arg_get_lit(ctx, 8); + bool sim = arg_get_lit(ctx, 9); if (sim) { CmdHFiClassLegacyRecSim(); @@ -4948,8 +4953,8 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort"); PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n"); - iclass_recover(macs, index, loop, no_first_auth, debug, test, fast, allnight); + iclass_recover(macs, index, loop, no_first_auth, debug, test, fast, short_delay, allnight); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully, you can now run 'hf iclass legbrute' with the partial key found.")); diff --git a/include/iclass_cmd.h b/include/iclass_cmd.h index 2dc658ed9..dcab87809 100644 --- a/include/iclass_cmd.h +++ b/include/iclass_cmd.h @@ -125,6 +125,7 @@ typedef struct { bool debug; bool test; bool fast; + bool short_delay; } PACKED iclass_recover_req_t; typedef struct iclass_premac {