From 04cfe2a43e0928e47b908bf2e712dcd26d412005 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 30 May 2025 12:36:42 +0800 Subject: [PATCH 1/4] Modified iclass recover operations 1- Renamed legreclookup to legbrute to be in line with the command name 2- Updated estimate values with speed increase gains 3- Improved some if statements readability in iclass.c and added start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; to increase speed by ~8% (1.86 loops per second to 2.01 loops per second = ~560 more loops per hour). Tried disabling some arm communications/comments but the speed increase was negligible (~1 sec / 1000 updates). --- CHANGELOG.md | 3 ++- armsrc/iclass.c | 32 ++++++++++++++++++++------------ client/src/cmdhficlass.c | 6 +++--- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00233936b..f934ad183 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` - code optimizations gaining a ~8% speed increase (@antiklesys) - Modified `hf iclass tear` - now has a device side implementation also. @antiklesys (@iceman1001) - 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) @@ -10,7 +11,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hw tearoff` - the device side message is now debug log controlled (@iceman1001) - Changed `pm3.sh` - Serial ports enumeration on Proxspace3.xx / MINGW environments, now using powershell.exe since wmic is deprecated (@iceman1001) - Fixed and updated `hf iclass trbl` to correctly use the credit key when passed and show partial tearoff results (@antiklesys) -- Fixed `hf iclass legbrute` was not correctly parsin the index value +- Fixed `hf iclass legbrute` was not correctly parsing the index value - Fixed `hf mf ekeyprn` - failed to download emulator memory due to wrong size calculation (@iceman1001) - Fixed `hf mf fchk --mem` to actually use flash dict (@doegox) - Fixed `make install` on OSX thanks DaveItsLong (@doegox) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 38627ea70..bcf5df684 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2708,6 +2708,7 @@ void iClass_Recover(iclass_recover_req_t *msg) { bool priv_esc = false; while (!priv_esc) { //The privilege escalation is done with a readcheck and not just a normal read! + 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); // expect a 8-byte response here res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); @@ -2747,27 +2748,29 @@ void iClass_Recover(iclass_recover_req_t *msg) { Dbhexdump(8, genkeyblock, false); } //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); - res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); + //res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); //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 != true) { - 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) { DbpString(_GREEN_("*** CARD EPURSE IS LOUD! OK TO ATTEMPT KEY RETRIEVAL! RUN AGAIN WITH -notest ***")); completed = true; goto out; + } else { + 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 != true) { - DbpString("Write Operation : "_GREEN_("VERIFIED! Card Key Updated!")); - written = true; - } else { + if (res) { DbpString("Write Operation : "_RED_("FAILED! Card Key is the Original. Retrying...")); write_error = true; + } else { + DbpString("Write Operation : "_GREEN_("VERIFIED! Card Key Updated!")); + written = true; } } } @@ -2775,10 +2778,12 @@ void iClass_Recover(iclass_recover_req_t *msg) { if (!write_error) { //Step6 Perform 8 authentication attempts + 1 to verify if we found the weak key for (int i = 0; i < 8 ; ++i) { + 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); - res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); + //res2 = 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, iclass_mac_table[i], 8); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); //mac1 here shouldn't matter if (res == true) { bits_found = i; @@ -2794,9 +2799,10 @@ void iClass_Recover(iclass_recover_req_t *msg) { 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); // TODO: check result - GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); + //GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); DbpString(_YELLOW_("Attempting to restore the original key. ")); if (iclass_writeblock_ext(blockno, genkeyblock, mac2, use_mac, shallow_mod)) { @@ -2806,12 +2812,14 @@ void iClass_Recover(iclass_recover_req_t *msg) { } DbpString(_YELLOW_("Verifying Key Restore...")); //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); + //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) { DbpString("Restore of Original Key "_GREEN_("VERIFIED! Card is usable again.")); diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 86dff7e43..b127cb5bf 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -4578,7 +4578,7 @@ void generate_key_block_inverted(const uint8_t *startingKey, uint64_t index, uin } } -static int CmdHFiClassLegRecLookUp(const char *Cmd) { +static int CmdHFiClassLegBrute(const char *Cmd) { //Standalone Command Start CLIParserContext *ctx; @@ -4805,7 +4805,7 @@ static int CmdHFiClassLegacyRecSim(void) { 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 / 6545); + PrintAndLogEx(SUCCESS, "Estimated Time: ~" _GREEN_("%d")" hours", index / 7250); } index++; @@ -5896,7 +5896,7 @@ static command_t CommandTable[] = { {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "Use loclass to perform bruteforce reader attack"}, {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "Uses authentication trace to check for key in dictionary file"}, {"legrec", CmdHFiClassLegacyRecover, IfPm3Iclass, "Recovers 24 bits of the diversified key of a legacy card provided a valid nr-mac combination"}, - {"legbrute", CmdHFiClassLegRecLookUp, AlwaysAvailable, "Bruteforces 40 bits of a partial diversified key, provided 24 bits of the key and two valid nr-macs"}, + {"legbrute", CmdHFiClassLegBrute, AlwaysAvailable, "Bruteforces 40 bits of a partial diversified key, provided 24 bits of the key and two valid nr-macs"}, {"unhash", CmdHFiClassUnhash, AlwaysAvailable, "Reverses a diversified key to retrieve hash0 pre-images after DES encryption"}, {"-----------", CmdHelp, IfPm3Iclass, "-------------------- " _CYAN_("Simulation") " -------------------"}, {"sim", CmdHFiClassSim, IfPm3Iclass, "Simulate iCLASS tag"}, From c32f655023d63565597d1c14dcfd540ac4e30583 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 30 May 2025 13:00:35 +0800 Subject: [PATCH 2/4] Improved hf iclass tear erase phase readability Improved readability of erase phase during iclass tear (client and arm side). It is redundant to see a list of FF during the erase phase (which can be pretty lengthy), so it will only show it once when all bits are FF and then will resume printing the moment bits start changing again post erase phase. --- armsrc/iclass.c | 10 ++++++---- client/src/cmdhficlass.c | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index bcf5df684..4b6097712 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2311,11 +2311,13 @@ void iClass_TearBlock(iclass_tearblock_req_t *msg) { if (memcmp(data_read, ff_data, PICOPASS_BLOCK_SIZE) == 0 && memcmp(data_read_orig, ff_data, PICOPASS_BLOCK_SIZE) != 0) { - erase_phase = true; - DbpString(""); - DbpString(_CYAN_("Erase phase hit... ALL ONES")); + if(erase_phase == false){ + DbpString(""); + DbpString(_CYAN_("Erase phase hit... ALL ONES")); - iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); + iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); + } + erase_phase = true; } else { diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index b127cb5bf..a60df6ebb 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3340,10 +3340,13 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { if (memcmp(data_read, ff_data, 8) == 0 && memcmp(data_read_orig, ff_data, 8) != 0) { + + if (erase_phase == false){ + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _CYAN_("Erase phase hit... ALL ONES")); + iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); + } erase_phase = true; - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, _CYAN_("Erase phase hit... ALL ONES")); - iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } else { if (erase_phase) { From db9667d0fbbe634c1f54498a567e5432627a6bb5 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 30 May 2025 13:02:11 +0800 Subject: [PATCH 3/4] Update CHANGELOG.md Signed-off-by: Antiklesys --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f934ad183..f2395069c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ 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 tear` - readability improvements for erase phase (@antiklesys) - Changed `hf iclass legrec` - code optimizations gaining a ~8% speed increase (@antiklesys) -- Modified `hf iclass tear` - now has a device side implementation also. @antiklesys (@iceman1001) +- Modified `hf iclass tear` - now has a device side implementation also. (@antiklesys) (@iceman1001) - 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) From 2105dbc37946a553e7f7f5c6acc9aea7b53f81ec Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 30 May 2025 13:05:25 +0800 Subject: [PATCH 4/4] Update iclass.c Clarified what tear success means Signed-off-by: Antiklesys --- armsrc/iclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 4b6097712..652993a0a 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2461,7 +2461,7 @@ void iClass_TearBlock(iclass_tearblock_req_t *msg) { read_ok = true; tear_success = true; DbpString(""); - DbpString("tear success!"); + DbpString("tear success (expected values)!"); } loop_count++;