From 2ed6c90e28f215cb93ca30691195e4d5f14138ae Mon Sep 17 00:00:00 2001 From: hexp Date: Mon, 5 May 2025 18:40:04 +0200 Subject: [PATCH 01/44] =?UTF-8?q?Add=20Consorcio=20de=20Transportes=20de?= =?UTF-8?q?=20Andaluc=C3=ADa=20and=20EMT=20M=C3=A1laga=20card=20keys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/dictionaries/mfc_default_keys.dic | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index e5af9c766..3dd53121d 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -3108,3 +3108,55 @@ AB921CF0752C 265A5F32DE73 567D734C403C 2426217B3B3B +# +# Card keys from Andalusian public transport system (Consorcio de Transportes) +1848A8D1E4C5 +16EE1FE134E4 +5246B8F4ACFC +515A8209843C +0EF7636AA829 +E59D0F78C413 +5AF68604DD6B +B0BCB22DCBA3 +51B3EF60BF56 +99100225D83B +63C88F562B97 +B30B6A5AD434 +D33E4A4A0041 +9C0A4CC89D61 +5204D83D8CD3 +A662F9DC0D3D +# +# Card keys from EMT Malaga (Spain) bus system +41534E354936 +454D41343253 +4541444C4130 +46305234324E +505444505232 +5239425A3546 +454449434631 +414F4544384C +344E4F4E4937 +45444E413254 +3255534D3033 +4F554D523935 +3141544D3735 +494E47463539 +32414F4E3341 +41534C473637 +534E41395430 +41364C38364F +525241414D39 +41304532334F +4D4545494F35 +4E324C453045 +394143494E32 +5352554E3245 +324553553036 +444D414E3539 +324745413232 +4E4E41455236 +394C52493639 +4D4941413236 +414D504F3243 +434C414E3639 From 0655b6389e78fb6b1d89c6814bff5a7e2162b58c Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Thu, 8 May 2025 23:52:01 +0200 Subject: [PATCH 02/44] cmdhfseos: fix stack buffer overflow in select_DF_verify increased CMAC buffer size, otherwise memset in aes_cmac writes 16-bytes to 8-byte buffer --- client/src/cmdhfseos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index 6956f2f2c..a4dfbc2ac 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -562,7 +562,7 @@ static int select_DF_verify(uint8_t *response, uint8_t response_length, uint8_t } // ----------------- MAC Key Generation ----------------- - uint8_t cmac[8]; + uint8_t cmac[16]; uint8_t MAC_key[24] = {0x00}; memcpy(MAC_key, keys[key_index].privMacKey, 16); create_cmac(MAC_key, input, cmac, sizeof(input), encryption_algorithm); From 2163d781267d666ded70678ce62b9916665d8357 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Fri, 9 May 2025 00:05:43 +0200 Subject: [PATCH 03/44] cmdhfseos: fix invalid memory access in select_DF_verify The real default key index in CmdHfSeosGDF passed to select_DF_verify was different than documented, resulting in out of bound read. --- client/src/cmdhfseos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index a4dfbc2ac..69b789d42 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -1351,7 +1351,7 @@ static int CmdHfSeosGDF(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - int key_index = arg_get_int_def(ctx, 1, -1); + int key_index = arg_get_int_def(ctx, 1, 0); CLIParserFree(ctx); return seos_global_df(key_index); From 9744f8afbbb36b9db8c5fab5f029bb48cb280c42 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Fri, 9 May 2025 15:49:01 +0200 Subject: [PATCH 04/44] Add option to override default USART baud rate in platform settings --- Makefile.platform.sample | 4 ++++ common_arm/Makefile.hal | 4 ++++ include/usart_defs.h | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile.platform.sample b/Makefile.platform.sample index 2e1221cb7..5ff0c4748 100644 --- a/Makefile.platform.sample +++ b/Makefile.platform.sample @@ -27,6 +27,10 @@ PLATFORM=PM3RDV4 # Only available with PLATFORM=PM3GENERIC #LED_ORDER=PM3EASY +# Uncomment a line below to change default USART baud rate +# defaults to 115200 used by HC-05 in Blueshark +#USART_BAUD_RATE=19200 + # Uncomment the lines below in order to make a 256KB image # and comment out the lines above diff --git a/common_arm/Makefile.hal b/common_arm/Makefile.hal index f9bb9065e..e317ea247 100644 --- a/common_arm/Makefile.hal +++ b/common_arm/Makefile.hal @@ -252,6 +252,10 @@ endif # WITH_FPC_USART_* needs WITH_FPC_USART : ifneq (,$(findstring WITH_FPC_USART_,$(PLATFORM_DEFS))) PLATFORM_DEFS += -DWITH_FPC_USART + ifeq ($(USART_BAUD_RATE),) + USART_BAUD_RATE=115200 + endif + PLATFORM_DEFS += -DUSART_BAUD_RATE=$(USART_BAUD_RATE) endif PLATFORM_DEFS_INFO = $(strip $(filter-out STANDALONE%, $(subst -DWITH_,,$(PLATFORM_DEFS)))) diff --git a/include/usart_defs.h b/include/usart_defs.h index 501f66464..84d6ff17c 100644 --- a/include/usart_defs.h +++ b/include/usart_defs.h @@ -16,8 +16,9 @@ #ifndef __USART_DEFS_H #define __USART_DEFS_H -//#define USART_BAUD_RATE 9600 +#ifndef USART_BAUD_RATE #define USART_BAUD_RATE 115200 +#endif // BT HC-06 physical layer runs at 128kbps // so it's possible to gain a little bit by using 230400 // with some risk to overflow its internal buffers: From 82278347304bfa6f7ae017deafd5e49b0a675553 Mon Sep 17 00:00:00 2001 From: Dmitry Malenok <_mak_@bk.ru> Date: Sun, 11 May 2025 13:32:21 +0300 Subject: [PATCH 05/44] Added `hf_mfu_ultra.lua` script enables restoring dump to ULTRA/UL-5 tags and clearing previously written ULTRA tags --- CHANGELOG.md | 1 + client/luascripts/hf_mfu_ultra.lua | 352 +++++++++++++++++++++++++++++ doc/magic_cards_notes.md | 52 +++++ 3 files changed, 405 insertions(+) create mode 100644 client/luascripts/hf_mfu_ultra.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index ca5e26a02..35bf0769e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fixed `hf mf fchk --mem` to actually use flash dict (@doegox) - Fixed `make install` on OSX thanks DaveItsLong (@doegox) - Added new standalone mode `HF_ST25_TEAROFF` to store/restore ST25TB tags with tearoff for counters (@seclabz) +- Added `hf_mfu_ultra.lua` script enables restoring dump to ULTRA/UL-5 tags and clearing previously written ULTRA tags (@mak-42) ## [Blue Ice.4.20142][2025-03-25] - Added `des_talk.py` script for easier MIFARE DESFire handling (@trigat) diff --git a/client/luascripts/hf_mfu_ultra.lua b/client/luascripts/hf_mfu_ultra.lua new file mode 100644 index 000000000..d8dc1ab5f --- /dev/null +++ b/client/luascripts/hf_mfu_ultra.lua @@ -0,0 +1,352 @@ +local ansicolors = require('ansicolors') +local cmds = require('commands') +local getopt = require('getopt') +local lib14a = require('read14a') +local utils = require('utils') + +-- globals +copyright = '' +author = 'Dmitry Malenok' +version = 'v1.0.0' +desc = [[ +The script provides functionality for writing Mifare Ultralight Ultra/UL-5 tags. +]] +example = [[ + -- restpre (write) dump to tag + ]]..ansicolors.yellow..[[script run hf_mfu_ultra -k ffffffff -r hf-mfu-3476FF1514D866-dump.bin]]..ansicolors.reset..[[ + + -- wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[) + ]]..ansicolors.yellow..[[script run hf_mfu_ultra -k 1d237f76 -w ]]..ansicolors.reset..[[ +]] +usage = [[ +script run hf_mfu_ultra -h -k -w -r +]] +arguments = [[ + -h this help + -k pwd to use with the restore and wipe operations + -r restore a binary dump to tag + -w wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[) + +]] + + +local _password = nil +local _defaultPassword = 'FFFFFFFF' +local _dumpstart = 0x38*2 + 1 +--- + +--- Handles errors +local function error(err) + print(ansicolors.red.."ERROR:"..ansicolors.reset, err) + core.clearCommandBuffer() + return nil, err +end +--- + +-- sets the global password variable +local function setPassword(password) + if password == nil or #password == 0 then + _password = nil; + elseif #password ~= 8 then + return false, 'Password must be 4 hex bytes' + else + _password = password + end + return true, 'Sets' +end + + +--- Parses response data +local function parseResponse(rawResponse) + local resp = Command.parse(rawResponse) + local len = tonumber(resp.arg1) * 2 + return string.sub(tostring(resp.data), 0, len); +end +--- + +--- Sends raw data to PM3 and returns raw response if any +local function sendRaw(rawdata, options) + + local flags = lib14a.ISO14A_COMMAND.ISO14A_RAW + + if options.keep_signal then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + end + + if options.connect then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_CONNECT + end + + if options.no_select then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_SELECT + end + + if options.append_crc then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + end + + local arg2 = #rawdata / 2 + if options.bits7 then + arg2 = arg2 | tonumber(bit32.lshift(7, 16)) + end + + local command = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER, + arg1 = flags, + arg2 = arg2, + data = rawdata} + return command:sendMIX(options.ignore_response) +end +--- + +--- Sends raw data to PM3 and returns parsed response +local function sendWithResponse(payload, options) + local opts; + if options then + opts = options + else + opts = {ignore_response = false, keep_signal = true, append_crc = true} + end + local rawResp, err = sendRaw(payload, opts) + if err then return err end + return parseResponse(rawResp) +end +--- + +-- Authenticates if password is provided +local function authenticate(password) + if password then + local resp, err = sendWithResponse('1B'..password) + if err then return err end + -- looking for 2 bytes (4 symbols) of PACK and 2 bytes (4 symbols) of CRC + if not resp or #resp ~=8 then return false, 'It seems that password is wrong' end + return true + end + return true +end +-- + +-- selects tag and authenticates if password is provided +local function connect() + core.clearCommandBuffer() + local info, err = lib14a.read(true, true) + if err then + lib14a.disconnect() + return false, err + end + core.clearCommandBuffer() + + return authenticate(_password) +end +-- + +-- reconnects and selects tag again +local function reconnect() + lib14a.disconnect() + utils.Sleep(1) + local info, err = connect() + if not info then return false, "Unable to select tag: "..err end + return true +end +-- + +-- checks tag version +local function checkTagVersion() + local resp, err = sendWithResponse('60'); + if err or resp == nil then return false, err end + if string.find(resp, '0034210101000E03') ~= 1 then return false, 'Wrong tag version: '..string.sub(resp,1,-5) end + return true +end +-- + +-- sends magic wakeup command +local function magicWakeup() + io.write('Sending magic wakeup command...') + local resp, err = sendRaw('5000', {ignore_response = false, append_crc = true}) + if err or resp == nil then return false, "Unable to send first magic wakeup command: "..err end + resp, err = sendRaw('40', {connect = true, no_select = true, ignore_response = false, keep_signal = true, append_crc = false, bits7 = true}) + if err or resp == nil then return false, "Unable to send first magic wakeup command: "..err end + resp, err = sendRaw('43', {ignore_response = false, keep_signal = true, append_crc = false}) + if err or resp == nil then return false, "Unable to send second magic wakeup command: "..err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + return true +end +-- + +-- Writes dump to tag +local function writeDump(filename) + print(string.rep('--',20)) + local info, err = connect() + if not info then return false, "Unable to select tag: "..err end + info, err = checkTagVersion() + if not info then return info, err end + + -- load dump from file + io.write('Loading dump from file '..filename..'...') + local dump + dump, err = utils.ReadDumpFile(filename) + if not dump then return false, err end + if #dump ~= _dumpstart - 1 + 0xa4*2 then return false, 'Invalid dump file' end + print(ansicolors.green..'done'..ansicolors.reset..'.') + + local resp + for i = 3, 0x23 do + local blockStart = i * 8 + _dumpstart + local block = string.sub(dump, blockStart, blockStart + 7) + local cblock = string.format('%02x',i) + io.write('Writing block 0x'..cblock..'...') + resp, err = sendWithResponse('A2'..cblock..block) + if err ~= nil then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + end + + -- set password + io.write('Setting password and pack ') + info, err = reconnect() + if not info then return false, err end + local passwordStart = 0x27*8 + _dumpstart + local password = string.sub(dump, passwordStart, passwordStart + 7) + local packBlock = string.sub(dump, passwordStart+8, passwordStart + 15) + io.write('(password: '..password..') (pack block: '..packBlock..')...') + resp, err = sendWithResponse('A227'..password) + if err ~= nil then return false, err end + resp, err = sendWithResponse('A228'..packBlock) + if err ~= nil then return false, err end + if not setPassword(password) then return false, 'Unable to set password' end + info, err = reconnect() + if not info then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + + -- set configs and locks + for i = 0x24, 0x26 do + local blockStart = i * 8 + _dumpstart + local block = string.sub(dump, blockStart, blockStart + 7) + local cblock = string.format('%02x',i) + io.write('Writing block 0x'..cblock..'...') + resp, err = sendWithResponse('A2'..cblock..block) + if err ~= nil then return false, err end + info, err = reconnect() + if not info then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + end + + info, err = magicWakeup() + if not info then return false, err end + -- set uid and locks + for i = 0x2, 0x0, -1 do + local blockStart = i * 8 + _dumpstart + local block = string.sub(dump, blockStart, blockStart + 7) + local cblock = string.format('%02x',i) + io.write('Writing block 0x'..cblock..'...') + resp, err = sendWithResponse('A2'..cblock..block, {connect = i == 0x2, ignore_response = false, keep_signal = i ~= 0, append_crc = true}) + if err ~= nil then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + end + + print(ansicolors.green..'The dump has been written to the tag.'..ansicolors.reset) + return true +end +-- + +-- Wipes tag +local function wipe() + print(string.rep('--',20)) + print('Wiping tag') + + local info, err = connect() + if not info then return false, "Unable to select tag: "..err end + info, err = checkTagVersion() + if not info then return info, err end + + + local resp + -- clear lock bytes on page 0x02 + resp, err = sendWithResponse('3000') + if err or resp == nil then return false, err end + local currentLowLockPage = string.sub(resp,17,24) + if(string.sub(currentLowLockPage,5,8) ~= '0000') then + info, err = magicWakeup() + if not info then return false, err end + local newLowLockPage = string.sub(currentLowLockPage,1,4)..'0000' + io.write('Clearing lock bytes on page 0x02...') + resp, err = sendWithResponse('A202'..newLowLockPage, {connect = true, ignore_response = false, keep_signal = true, append_crc = true}) + if err ~= nil then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + end + + -- clear lock bytes on page 0x24 + io.write('Clearing lock bytes on page 0x24...') + info, err = reconnect() + if not info then return false, err end + resp, err = sendWithResponse('A224000000BD') + if err ~= nil then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + + -- clear configs + io.write('Clearing cfg0 and cfg1...') + resp, err = sendWithResponse('A225000000FF') + if err ~= nil then return false, err end + resp, err = sendWithResponse('A22600050000') + if err ~= nil then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + + -- clear password + io.write('Reseting password (and pack) to default ('.._defaultPassword..') and 0000...') + info, err = reconnect() + if not info then return false, err end + resp, err = sendWithResponse('A227'.._defaultPassword) + if err ~= nil then return false, err end + resp, err = sendWithResponse('A22800000000') + if err ~= nil then return false, err end + if not setPassword(_defaultPassword) then return false, 'Unable to set password' end + info, err = reconnect() + if not info then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + + -- clear other blocks + for i = 3, 0x23 do + local cblock = string.format('%02x',i) + io.write('Clearing block 0x'..cblock..'...') + resp, err = sendWithResponse('A2'..cblock..'00000000') + if err ~= nil then return false, err end + print(ansicolors.green..'done'..ansicolors.reset..'.') + end + + print(ansicolors.green..'The tag has been wiped.'..ansicolors.reset) + + lib14a.disconnect() + return true +end +-- + +-- Prints help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ansicolors.cyan..'Usage'..ansicolors.reset) + print(usage) + print(ansicolors.cyan..'Arguments'..ansicolors.reset) + print(arguments) + print(ansicolors.cyan..'Example usage'..ansicolors.reset) + print(example) +end +--- + +-- The main entry point +local function main(args) + if #args == 0 then return help() end + + for opt, value in getopt.getopt(args, 'hk:r:w') do + local res, err + res = true + if opt == "h" then return help() end + if opt == 'k' then res, err = setPassword(value) end + if opt == 'r' then res, err = writeDump(value) end + if opt == 'w' then res, err = wipe() end + if not res then return error(err) end + end + +end + +main(args) diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index 0ef15de1b..b734d7a00 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -2356,6 +2356,36 @@ After communication to iKey LLC (importer of those tags to Russian market), new [+] ATS: 85 00 00 A0 00 00 0A 3C 00 04 03 01 01 00 0E 03 [ C8 1D ] ``` +### Magic commands + +^[Top](#top) + +Use the script `hf_mfu_ultra.lua` to restore (write) dump to tag or clear previously written tag. + +Usage: +1. Restore dump to tag: + ``` + script run hf_mfu_ultra -k -r + ``` +2. Wipe tag: + ``` + script run hf_mfu_ultra -k -w + ``` +3. Show help: + ``` + script run hf_mfu_ultra -h + ``` + +Examples: +1. Restore dump to tag: + ``` + script run hf_mfu_ultra -k ffffffff -r hf-mfu-3476FF1514D866-dump.bin + ``` +2. Wipe tag: + ``` + script run hf_mfu_ultra -k 1d237f76 -w + ``` + ## UL-5 ^[Top](#top) @@ -2389,6 +2419,28 @@ The manufacturer confirmed unpersonalized tags could be identified by first 2 by * `AA 55...` +### Magic commands + +^[Top](#top) + +Use the script `hf_mfu_ultra.lua` to restore (write) dump to tag. + +Usage: +1. Restore dump to tag: + ``` + script run hf_mfu_ultra -k -r + ``` +3. Show help: + ``` + script run hf_mfu_ultra -h + ``` + +Examples: +1. Restore dump to tag: + ``` + script run hf_mfu_ultra -k ffffffff -r hf-mfu-3476FF1514D866-dump.bin + ``` + ## UL, other chips ** TODO ** From 0cbf42e0ecc889c284a56f2e2dcdb6ff0ae1cc6a Mon Sep 17 00:00:00 2001 From: Dmitry Malenok <_mak_@bk.ru> Date: Sun, 11 May 2025 13:41:18 +0300 Subject: [PATCH 06/44] The description of wipe operation was clarified. --- doc/magic_cards_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index b734d7a00..76de2cd32 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -2367,7 +2367,7 @@ Usage: ``` script run hf_mfu_ultra -k -r ``` -2. Wipe tag: +2. Wipe tag (use it to prepare tag for restoring another dump): ``` script run hf_mfu_ultra -k -w ``` From 5b9039d82558a97f24c2fd3a27a6a129def8f700 Mon Sep 17 00:00:00 2001 From: Philipp Schuler Date: Mon, 5 May 2025 01:35:40 +0200 Subject: [PATCH 07/44] Ignore UnicodeEncodeError in lprint --- client/pyscripts/fm11rf08s_full.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/pyscripts/fm11rf08s_full.py b/client/pyscripts/fm11rf08s_full.py index b50f9c56f..8d1765b84 100644 --- a/client/pyscripts/fm11rf08s_full.py +++ b/client/pyscripts/fm11rf08s_full.py @@ -90,13 +90,14 @@ def lprint(s='', end='\n', flush=False, prompt="[" + color("=", fg="yellow") + - logfile (R) """ s = f"{prompt}" + f"\n{prompt}".join(s.split('\n')) - print(s, end=end, flush=flush) + safe_s = s.encode('utf-8', errors='ignore').decode('utf-8') + print(safe_s, end=end, flush=flush) if log is True: global logbuffer if logfile is not None: with open(logfile, 'a', encoding='utf-8') as f: - f.write(s + end) + f.write(safe_s + end) else: # buffering logbuffer += s + end From a9244b8ea4b7129ca9fb30a3348864188903cf05 Mon Sep 17 00:00:00 2001 From: Dmitry Malenok <_mak_@bk.ru> Date: Mon, 12 May 2025 22:33:26 +0300 Subject: [PATCH 08/44] The '-f' option replaces the direct specification of the dump filename in the '-r' command. --- client/luascripts/hf_mfu_ultra.lua | 13 +++++++++---- doc/magic_cards_notes.md | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/client/luascripts/hf_mfu_ultra.lua b/client/luascripts/hf_mfu_ultra.lua index d8dc1ab5f..f96becad8 100644 --- a/client/luascripts/hf_mfu_ultra.lua +++ b/client/luascripts/hf_mfu_ultra.lua @@ -13,16 +13,17 @@ The script provides functionality for writing Mifare Ultralight Ultra/UL-5 tags. ]] example = [[ -- restpre (write) dump to tag - ]]..ansicolors.yellow..[[script run hf_mfu_ultra -k ffffffff -r hf-mfu-3476FF1514D866-dump.bin]]..ansicolors.reset..[[ + ]]..ansicolors.yellow..[[script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r]]..ansicolors.reset..[[ -- wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[) ]]..ansicolors.yellow..[[script run hf_mfu_ultra -k 1d237f76 -w ]]..ansicolors.reset..[[ ]] usage = [[ -script run hf_mfu_ultra -h -k -w -r +script run hf_mfu_ultra -h -f -k -w -r ]] arguments = [[ -h this help + -f filename for the datadump to read (bin) -k pwd to use with the restore and wipe operations -r restore a binary dump to tag -w wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[) @@ -181,6 +182,7 @@ local function writeDump(filename) if not info then return info, err end -- load dump from file + if not filename then return false, 'No dump filename provided' end io.write('Loading dump from file '..filename..'...') local dump dump, err = utils.ReadDumpFile(filename) @@ -337,12 +339,15 @@ end local function main(args) if #args == 0 then return help() end - for opt, value in getopt.getopt(args, 'hk:r:w') do + local dumpFilename = nil + + for opt, value in getopt.getopt(args, 'hf:k:rw') do local res, err res = true if opt == "h" then return help() end + if opt == "f" then dumpFilename = value end if opt == 'k' then res, err = setPassword(value) end - if opt == 'r' then res, err = writeDump(value) end + if opt == 'r' then res, err = writeDump(dumpFilename) end if opt == 'w' then res, err = wipe() end if not res then return error(err) end end diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index 76de2cd32..1b43873e5 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -2365,7 +2365,7 @@ Use the script `hf_mfu_ultra.lua` to restore (write) dump to tag or clear previo Usage: 1. Restore dump to tag: ``` - script run hf_mfu_ultra -k -r + script run hf_mfu_ultra -f -k -r ``` 2. Wipe tag (use it to prepare tag for restoring another dump): ``` @@ -2379,7 +2379,7 @@ Usage: Examples: 1. Restore dump to tag: ``` - script run hf_mfu_ultra -k ffffffff -r hf-mfu-3476FF1514D866-dump.bin + script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r ``` 2. Wipe tag: ``` @@ -2428,7 +2428,7 @@ Use the script `hf_mfu_ultra.lua` to restore (write) dump to tag. Usage: 1. Restore dump to tag: ``` - script run hf_mfu_ultra -k -r + script run hf_mfu_ultra -f -k -r ``` 3. Show help: ``` @@ -2438,7 +2438,7 @@ Usage: Examples: 1. Restore dump to tag: ``` - script run hf_mfu_ultra -k ffffffff -r hf-mfu-3476FF1514D866-dump.bin + script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r ``` ## UL, other chips From 3c35a87dee99aaca79c2e0dd31b7af636bbdbec2 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 16 May 2025 23:19:26 +0800 Subject: [PATCH 09/44] Fix bug with iclass legbrute index value being ignored Fixed issue https://github.com/RfidResearchGroup/proxmark3/issues/2845 --- 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 b21282ce2..3264eea54 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -4255,7 +4255,7 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) { uint8_t startingKey[PICOPASS_BLOCK_SIZE] = {0}; CLIGetHexWithReturn(ctx, 4, startingKey, &startingkey_len); - uint64_t index = arg_get_int_def(ctx, 6, 0); //has to be 64 as we're bruteforcing 40 bits + uint64_t index = arg_get_int_def(ctx, 5, 0); //has to be 64 as we're bruteforcing 40 bits index = index * 1000000; CLIParserFree(ctx); From 23232f8aa318a25364951ab05bf79f3d77df26ab Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 17 May 2025 23:19:10 +0800 Subject: [PATCH 10/44] iclass tearoff attack fixes Fixed spacing, time unit, and fixed a bug preventing from properly using the credit key. --- client/src/cmdhficlass.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 3264eea54..70d17e746 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2922,7 +2922,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { CLIParserInit(&ctx, "hf iclass trbl", "Tear off an iCLASS tag block", "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --tdb 100 --tde 150\n" - "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 --tdb 100 --tde 150"); + "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 --tdb 100 --tde 150"); void *argtable[] = { arg_param_begin, @@ -2937,8 +2937,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0("v", "verbose", "verbose output"), arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"), - arg_int1(NULL, "tdb", "", "tearoff delay start in ms"), - arg_int1(NULL, "tde", "", "tearoff delay end in ms"), + arg_int1(NULL, "tdb", "", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us."), + arg_int1(NULL, "tde", "", "tearoff delay end (in us) must be a higher value than the start delay."), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3030,6 +3030,12 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { int isok = 0; tearoff_params_t params; bool read_ok = false; + + uint8_t keyType = 0x88; //debit key + if (use_credit_key) { + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key"); + keyType = 0x18; //credit key + } while (tearoff_start < tearoff_end && !read_ok) { //perform read here, repeat if failed or 00s @@ -3037,7 +3043,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { bool first_read = false; bool reread = false; while (!first_read) { - int res_orig = iclass_read_block_ex(key, blockno, 0x88, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read_orig, false); + int res_orig = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read_orig, false); if (res_orig == PM3_SUCCESS && !reread) { if (memcmp(data_read_orig, zeros, 8) == 0) { reread = true; @@ -3054,7 +3060,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { params.on = true; params.delay_us = tearoff_start; handle_tearoff(¶ms, false); - PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")" ms", tearoff_start); + PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")" us", tearoff_start); isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); switch (isok) { case PM3_SUCCESS: @@ -3072,7 +3078,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { reread = false; bool decrease = false; while (!first_read) { - int res = iclass_read_block_ex(key, blockno, 0x88, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read, false); + int 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) { reread = true; From 67fb546887d71d667dcb2e727f4058c426697f76 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sun, 18 May 2025 01:54:55 +0800 Subject: [PATCH 11/44] Update iclass trbl function Updated trbl function: 1- Better comparison of read values vs expected values 2- Stop on "partial values tearoff", show tearoff results when the block isn't zero, but is also different from the original block (even tho is not yet with the same values of the expected block) 3- Improvement to verbose mode --- client/src/cmdhficlass.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 70d17e746..3063a5f1d 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3030,12 +3030,13 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { int isok = 0; tearoff_params_t params; bool read_ok = false; - uint8_t keyType = 0x88; //debit key + if (use_credit_key) { PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key"); keyType = 0x18; //credit key } + while (tearoff_start < tearoff_end && !read_ok) { //perform read here, repeat if failed or 00s @@ -3097,17 +3098,28 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { tearoff_start--; } bool tear_success = true; - for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - if (data[i] != data_read[i]) { - tear_success = false; - } + bool expected_values = true; + if(memcmp(data_read, data, 8) != 0) { + tear_success = false; + }else if ((!tear_success) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) { //tearoff succeeded (partially) + tear_success = true; + expected_values = false; + PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success! -> Different values")); + PrintAndLogEx(INFO, "Original: %s", sprint_hex(data_read_orig, sizeof(data_read))); + PrintAndLogEx(INFO, "Expected: %s", sprint_hex(data, sizeof(data))); } if (tear_success) { //tearoff succeeded read_ok = true; - PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success!")); - PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); + if(expected_values) { + PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success! -> Expected values")); + } + PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); } else { //tearoff did not succeed PrintAndLogEx(FAILED, _RED_("Tear-off Failed!")); + if(verbose) { + PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); + PrintAndLogEx(INFO, "Expected: %s", sprint_hex(data, sizeof(data))); + } tearoff_start++; } PrintAndLogEx(INFO, "---------------"); From c156e33ad91f65485720e91fffab17ed64dd79de Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sun, 18 May 2025 01:57:59 +0800 Subject: [PATCH 12/44] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35bf0769e..2ec90e804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ 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] +- 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 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) @@ -45,7 +47,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hf mf cload` - now accepts MFC Ev1 sized dumps (@iceman1001) - Changed `hf mfu info` - now properly identify ULEv1 AES 50pF (@iceman1001) - Changed `hf mf info` - now differentiates between full USCUID and cut down ZUID chips (@nvx) -- Changed `lf hitag chk` - added key counter, client side abort and minor delay (@iceman1001) +- Changed `lf hitag chk` - added key counter, client side abort and minor delay (@iceman1001) - Added `hf seos sam` - Added support for HID SAM SEOS communications (@jkramarz) - Changed (extended) area accessible by spiffs into last page of FLASH (@piotrva) - Changed flash-stored key dictionaries (Mifare, iClass, T55XX) and T55XX configurations to SPIFFS files (@piotrva) From 59e4875e6c4dde34bcf8f4237790333ca5f5c349 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sun, 18 May 2025 20:41:04 +0800 Subject: [PATCH 13/44] Updated trbl to support custom increments Updated iclass tearoff function to support custom delay increments --- client/src/cmdhficlass.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 3063a5f1d..16485b262 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2938,7 +2938,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { arg_lit0("v", "verbose", "verbose output"), arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"), arg_int1(NULL, "tdb", "", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us."), - arg_int1(NULL, "tde", "", "tearoff delay end (in us) must be a higher value than the start delay."), + arg_int0(NULL, "incr", "", "tearoff delay increment (in us) - default 10."), + arg_int0(NULL, "tde", "", "tearoff delay end (in us) must be a higher value than the start delay."), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3001,8 +3002,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } } - int tearoff_start = arg_get_int_def(ctx, 12, 100); - int tearoff_end = arg_get_int_def(ctx, 13, 200); + 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); if (tearoff_end <= tearoff_start) { PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay."); @@ -3037,7 +3039,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { keyType = 0x18; //credit key } - while (tearoff_start < tearoff_end && !read_ok) { + while (tearoff_start <= tearoff_end && !read_ok) { //perform read here, repeat if failed or 00s uint8_t data_read_orig[8] = {0}; @@ -3061,7 +3063,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { params.on = true; params.delay_us = tearoff_start; handle_tearoff(¶ms, false); - PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")" us", tearoff_start); + PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")"/"_YELLOW_("%d")" us", tearoff_start,tearoff_end); isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); switch (isok) { case PM3_SUCCESS: @@ -3095,7 +3097,7 @@ 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 - tearoff_start--; + tearoff_start -= tearoff_increment; } bool tear_success = true; bool expected_values = true; @@ -3120,7 +3122,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); PrintAndLogEx(INFO, "Expected: %s", sprint_hex(data, sizeof(data))); } - tearoff_start++; + tearoff_start += tearoff_increment; } PrintAndLogEx(INFO, "---------------"); } From b90348e66b71be6becaa5fd8b62df5c72450e1ba Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 19 May 2025 22:27:50 +0200 Subject: [PATCH 14/44] mingw and proxspace 3.xx environments would hang on Windows 11 24H2 since WMIC is no longer installed. This should enable the usage of powershell to enumerate serial ports on said environments --- CHANGELOG.md | 1 + pm3 | 33 ++++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ec90e804..1eb4b7276 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 `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 mf ekeyprn` - failed to download emulator memory due to wrong size calculation (@iceman1001) diff --git a/pm3 b/pm3 index 80aad83d8..ae87617b6 100755 --- a/pm3 +++ b/pm3 @@ -136,11 +136,15 @@ function get_pm3_list_Windows { PM3LIST=() # Normal SERIAL PORTS (COM) - for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%' Or PNPDeviceID LIKE '%VID_2D2D&PID_504D%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do - DEV=${DEV/ */} + for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.PNPDeviceID -like '*VID_9AC4&PID_4B8F*' -or \$_.PNPDeviceID -like '*VID_2D2D&PID_504D*'} | Select -expandproperty DeviceID" 2>/dev/null); do + + _comport=$DEV + #prevent soft bricking when using pm3-flash-all on an outdated bootloader if [ $(basename -- "$0") = "pm3-flash-all" ]; then - line=$(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}'); + + line=$($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null); + if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" exit 1 @@ -154,8 +158,8 @@ function get_pm3_list_Windows { #BT direct SERIAL PORTS (COM) if $FINDBTRFCOMM; then - for DEV in $(wmic /locale:ms_409 path Win32_PnPEntity Where "Caption LIKE '%Bluetooth%(COM%'" Get Name 2> /dev/null | awk -b 'match($0,/(COM[0-9]+)/,m){print m[1]}'); do - DEV=${DEV/ */} + + for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_PnPEntity | Where-Object Caption -like 'Standard Serial over Bluetooth link (COM*' | Select Name" 2>/dev/null); do PM3LIST+=("$DEV") if [ ${#PM3LIST[*]} -ge "$N" ]; then return @@ -165,8 +169,8 @@ function get_pm3_list_Windows { #white BT dongle SERIAL PORTS (COM) if $FINDBTDONGLE; then - for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_10C4&PID_EA60%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do - DEV=${DEV/ */} + + for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_10C4&PID_EA60*' | Select -expandproperty DeviceID" 2>/dev/null); do PM3LIST+=("$DEV") if [ ${#PM3LIST[*]} -ge "$N" ]; then return @@ -497,6 +501,21 @@ if [ "$HOSTOS" = "LINUX" ]; then elif [ "$HOSTOS" = "DARWIN" ]; then GETPM3LIST=get_pm3_list_macOS elif [[ "$HOSTOS" =~ MINGW(32|64)_NT* ]]; then + + # First try finding it using the PATH environment variable + PSHEXE=$(command -v powershell.exe 2>/dev/null) + + # If it fails (such as if WSLENV is not set), try using the default installation path + if [ -z "$PSHEXE" ]; then + PSHEXE=/cygdrive/c/WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe + fi + + # Finally test if PowerShell is working + if ! "$PSHEXE" exit >/dev/null 2>&1; then + echo >&2 "[!!] Cannot run powershell.exe in your MINGW environment" + exit 1 + fi + GETPM3LIST=get_pm3_list_Windows else echo >&2 "[!!] Host OS not recognized, abort: $HOSTOS" From 84b565bec4d41ef43a26e953f729edac66edb68c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 19 May 2025 22:31:41 +0200 Subject: [PATCH 15/44] style --- armsrc/Standalone/hf_st25_tearoff.c | 98 ++++++++++++++--------------- armsrc/iso14443a.c | 10 +-- client/luascripts/hf_mfu_ultra.lua | 8 +-- client/src/cmdhf.c | 2 +- client/src/cmdhf14a.c | 4 +- client/src/cmdhf14b.c | 4 +- client/src/cmdhficlass.c | 22 +++---- client/src/cmdhfmfu.c | 4 +- client/src/fileutils.c | 30 +++++---- doc/commands.json | 16 +++-- doc/commands.md | 2 +- 11 files changed, 105 insertions(+), 95 deletions(-) diff --git a/armsrc/Standalone/hf_st25_tearoff.c b/armsrc/Standalone/hf_st25_tearoff.c index 0f315e934..65fc2ba52 100644 --- a/armsrc/Standalone/hf_st25_tearoff.c +++ b/armsrc/Standalone/hf_st25_tearoff.c @@ -252,7 +252,7 @@ static void update_leds_mode(standalone_mode_t mode) { */ static void indicate_success(void) { // Blink Green LED (A) 3 times quickly for success - for(int i=0; i<3; ++i) { + for (int i = 0; i < 3; ++i) { LED_A_ON(); SpinDelay(150); LED_A_OFF(); @@ -265,7 +265,7 @@ static void indicate_success(void) { */ static void indicate_failure(void) { // Blink Red LED (B) 3 times quickly for failure - for(int i=0; i<3; ++i) { + for (int i = 0; i < 3; ++i) { LED_B_ON(); SpinDelay(150); LED_B_OFF(); @@ -291,7 +291,7 @@ static bool load_tags_from_flash(st25tb_data_t collection[MAX_SAVED_TAGS]) { // Verify file size uint32_t size = size_in_spiffs(HF_ST25TB_MULTI_SR_FILE); if (size != sizeof(g_stored_tags)) { - Dbprintf(_RED_("Flash file size mismatch (expected %zu, got %u). Wiping old file."), + Dbprintf(_RED_("Flash file size mismatch (expected %zu, got %u). Wiping old file."), sizeof(g_stored_tags), size); // Remove corrupted file rdv40_spiffs_remove(HF_ST25TB_MULTI_SR_FILE, RDV40_SPIFFS_SAFETY_SAFE); @@ -299,8 +299,8 @@ static bool load_tags_from_flash(st25tb_data_t collection[MAX_SAVED_TAGS]) { } // Read file contents - int res = rdv40_spiffs_read(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection, - size, RDV40_SPIFFS_SAFETY_SAFE); + int res = rdv40_spiffs_read(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection, + size, RDV40_SPIFFS_SAFETY_SAFE); if (res != SPIFFS_OK) { Dbprintf(_RED_("Failed to read tag collection from flash (err %d)"), res); @@ -319,8 +319,8 @@ static bool load_tags_from_flash(st25tb_data_t collection[MAX_SAVED_TAGS]) { * @return true if successful, false otherwise */ static bool save_tags_to_flash(const st25tb_data_t collection[MAX_SAVED_TAGS]) { - int res = rdv40_spiffs_write(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection, - sizeof(g_stored_tags), RDV40_SPIFFS_SAFETY_SAFE); + int res = rdv40_spiffs_write(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection, + sizeof(g_stored_tags), RDV40_SPIFFS_SAFETY_SAFE); return (res == SPIFFS_OK); } @@ -356,7 +356,7 @@ static int find_free_tag_slot(void) { //============================================================================= /** - * @brief Stripped version of "iso14443b_setup" that avoids unnecessary LED + * @brief Stripped version of "iso14443b_setup" that avoids unnecessary LED * operations and uses shorter delays */ static void iso14443b_setup_light(void) { @@ -417,7 +417,7 @@ static bool st25tb_tag_read(st25tb_data_t *tag_data_slot) { Dbprintf("Found ST tag. Reading %d blocks...", ST25TB_BLOCK_COUNT); tag_data_slot->uid = bytes_to_num_le(card_info.uid, sizeof(tag_data_slot->uid)); - + // Read all data blocks for (uint8_t block_address = 0; block_address < ST25TB_BLOCK_COUNT; block_address++) { WDT_HIT(); @@ -507,7 +507,7 @@ static bool st25tb_tag_restore(const st25tb_data_t *stored_data_slot) { } if (g_dbglevel >= DBG_DEBUG) { - Dbprintf("Counter Block %d: Stored=0x%08X, Current=0x%08X", + Dbprintf("Counter Block %d: Stored=0x%08X, Current=0x%08X", block_address, stored_value, current_value); } @@ -528,7 +528,7 @@ static bool st25tb_tag_restore(const st25tb_data_t *stored_data_slot) { break; } } else { - Dbprintf("Counter block %d already has the target value (0x%08X). Skipping write.", + Dbprintf("Counter block %d already has the target value (0x%08X). Skipping write.", block_address, stored_value); } } else { @@ -658,7 +658,7 @@ static void st25tb_tear_off_write_block(uint8_t block_address, uint32_t data, ui block[0] = (data & 0xFF); block[1] = (data >> 8) & 0xFF; block[2] = (data >> 16) & 0xFF; - block[3] = (data >> 24) & 0xFF; + block[3] = (data >> 24) & 0xFF; iso14b_card_select_t card; int res = iso14443b_select_srx_card(&card); @@ -667,7 +667,7 @@ static void st25tb_tear_off_write_block(uint8_t block_address, uint32_t data, ui } res = st25tb_cmd_write_block(block_address, block); - + // Tear off the communication at precise timing SpinDelayUsPrecision(tearoff_delay_us); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -685,9 +685,9 @@ out: * @param read_back_value Pointer to store read-back value * @return 0 for success, -1 for failure */ -static int8_t st25tb_tear_off_retry_write_verify(uint8_t block_address, uint32_t target_value, - uint32_t max_try_count, int sleep_time_ms, - uint32_t *read_back_value) { +static int8_t st25tb_tear_off_retry_write_verify(uint8_t block_address, uint32_t target_value, + uint32_t max_try_count, int sleep_time_ms, + uint32_t *read_back_value) { int i = 0; *read_back_value = ~target_value; // Initialize to ensure the loop runs at least once @@ -711,9 +711,9 @@ static int8_t st25tb_tear_off_retry_write_verify(uint8_t block_address, uint32_t * @param read_value Pointer to store read value * @return 0 if consolidated, -1 otherwise */ -static int8_t st25tb_tear_off_is_consolidated(const uint8_t block_address, uint32_t value, - int repeat_read, int sleep_time_ms, - uint32_t *read_value) { +static int8_t st25tb_tear_off_is_consolidated(const uint8_t block_address, uint32_t value, + int repeat_read, int sleep_time_ms, + uint32_t *read_value) { int result; for (int i = 0; i < repeat_read; i++) { if (sleep_time_ms > 0) SpinDelayUsPrecision(sleep_time_ms * 1000); @@ -733,8 +733,8 @@ static int8_t st25tb_tear_off_is_consolidated(const uint8_t block_address, uint3 * @param read_back_value Pointer to store read-back value * @return 0 for success, -1 for failure */ -static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uint32_t current_value, - uint32_t target_value, uint32_t *read_back_value) { +static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uint32_t current_value, + uint32_t target_value, uint32_t *read_back_value) { int8_t result; uint32_t consolidation_value; @@ -746,8 +746,8 @@ static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uin } // Try writing value - 1 - result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 1, - TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value); + result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 1, + TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value); if (result != 0) { Dbprintf("Consolidation failed at step 1 (write 0x%08X)", consolidation_value - 1); return -1; @@ -755,8 +755,8 @@ static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uin // If value is not FE or target is not FD, try writing value - 2 if (*read_back_value != 0xFFFFFFFE || (*read_back_value == 0xFFFFFFFE && target_value == 0xFFFFFFFD)) { - result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 2, - TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value); + result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 2, + TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value); if (result != 0) { Dbprintf("Consolidation failed at step 2 (write 0x%08X)", consolidation_value - 2); return -1; @@ -765,12 +765,12 @@ static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uin // Final checks for stability of unstable high values (due to internal dual counters) if (result == 0 && target_value > 0xFFFFFFFD && *read_back_value > 0xFFFFFFFD) { - result = st25tb_tear_off_is_consolidated(block_address, *read_back_value, - TEAR_OFF_CONSOLIDATE_READ_COUNT, 0, read_back_value); + result = st25tb_tear_off_is_consolidated(block_address, *read_back_value, + TEAR_OFF_CONSOLIDATE_READ_COUNT, 0, read_back_value); if (result == 0) { - result = st25tb_tear_off_is_consolidated(block_address, *read_back_value, - TEAR_OFF_CONSOLIDATE_WAIT_READ_COUNT, - TEAR_OFF_CONSOLIDATE_WAIT_MS, read_back_value); + result = st25tb_tear_off_is_consolidated(block_address, *read_back_value, + TEAR_OFF_CONSOLIDATE_WAIT_READ_COUNT, + TEAR_OFF_CONSOLIDATE_WAIT_MS, read_back_value); if (result != 0) { Dbprintf("Consolidation failed stability check (long wait)"); return -1; @@ -861,8 +861,8 @@ static void st25tb_tear_off_log(int tear_off_us, char *color, uint32_t value) { * @param safety_value Safety threshold to prevent going below * @return 0 for success, non-zero for failure */ -static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t target_value, - uint32_t tear_off_adjustment_us, uint32_t safety_value) { +static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t target_value, + uint32_t tear_off_adjustment_us, uint32_t safety_value) { int result; bool trigger = true; @@ -906,7 +906,7 @@ static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t targ for (;;) { // Safety check: ensure we don't go below the safety threshold if (tear_off_value < safety_value) { - Dbprintf("Stopped. Safety threshold reached (next value 0x%08X < safety 0x%08X)", + Dbprintf("Stopped. Safety threshold reached (next value 0x%08X < safety 0x%08X)", tear_off_value, safety_value); return -1; } @@ -921,15 +921,15 @@ static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t targ } // Analyze the result and decide next action - if (read_value > current_value) { + if (read_value > current_value) { // Partial write succeeded (successful tear-off) if (read_value >= 0xFFFFFFFE || - (read_value - 2) > target_value || - read_value != last_consolidated_value || - ((read_value & 0xF0000000) > (current_value & 0xF0000000))) { // Major bit flip - - result = st25tb_tear_off_consolidate_block(block_address, read_value, - target_value, ¤t_value); + (read_value - 2) > target_value || + read_value != last_consolidated_value || + ((read_value & 0xF0000000) > (current_value & 0xF0000000))) { // Major bit flip + + result = st25tb_tear_off_consolidate_block(block_address, read_value, + target_value, ¤t_value); if (result == 0 && current_value == target_value) { st25tb_tear_off_log(tear_off_us, GREEN, read_value); Dbprintf("Target value 0x%08X reached successfully!", target_value); @@ -1004,11 +1004,11 @@ static void run_learn_function(void) { } else { // Only increment if we are adding to a new slot, not overwriting if (!g_stored_tags[slot_index].data_valid) { - g_valid_tag_count++; + g_valid_tag_count++; } } } - + // Store tag data in collection memcpy(&g_stored_tags[slot_index], &temp_tag_data, sizeof(st25tb_data_t)); g_stored_tags[slot_index].data_valid = true; @@ -1020,7 +1020,7 @@ static void run_learn_function(void) { } else { DbpString(_RED_("Failed to save collection to flash!")); } - + current_state = STATE_DONE; // Indicate success } } @@ -1052,8 +1052,8 @@ static void run_restore_function(void) { current_state = STATE_ERROR; } } else { - // Tag found but not in collection, remain busy to scan again - current_state = STATE_BUSY; + // Tag found but not in collection, remain busy to scan again + current_state = STATE_BUSY; } } else { // No tag found, remain busy to scan again @@ -1131,10 +1131,10 @@ void RunMod(void) { // --- Update Display (only if mode changed) --- if (mode_display_update) { if (g_current_mode == MODE_LEARN) { - Dbprintf("Mode: " _YELLOW_("Learn") ". (Cnt: %d/%d)", + Dbprintf("Mode: " _YELLOW_("Learn") ". (Cnt: %d/%d)", g_valid_tag_count, MAX_SAVED_TAGS); } else { - Dbprintf("Mode: " _BLUE_("Restore") ". (Cnt: %d/%d)", + Dbprintf("Mode: " _BLUE_("Restore") ". (Cnt: %d/%d)", g_valid_tag_count, MAX_SAVED_TAGS); } mode_display_update = false; @@ -1142,14 +1142,14 @@ void RunMod(void) { update_leds_mode(g_current_mode); // Process according to current state - if(current_state == STATE_BUSY) { + if (current_state == STATE_BUSY) { // Run appropriate function based on mode if (g_current_mode == MODE_LEARN) { run_learn_function(); } else { // MODE_RESTORE run_restore_function(); } - } else if(current_state == STATE_DONE) { + } else if (current_state == STATE_DONE) { indicate_success(); } else { indicate_failure(); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index ab144a71e..8bca5d2de 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -524,6 +524,7 @@ RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) { Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; + // Every 8 data bytes, store 8 parity bits into a parity byte if ((Uart.len & 0x0007) == 0) { // every 8 data bytes Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits @@ -1496,6 +1497,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, // "precompiled" responses. // These exist for speed reasons. There are no time in the anti collision phase to calculate responses. // There are 12 predefined responses with a total of 84 bytes data to transmit. + // // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) // 85 * 8 data bits, 85 * 1 parity bits, 12 start bits, 12 stop bits, 12 correction bits // 85 * 8 + 85 + 12 + 12 + 12 == 801 @@ -2771,19 +2773,19 @@ static void iso14a_set_ATS_times(const uint8_t *ats) { static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const iso14a_polling_parameters_t *polling_parameters) { - #define RETRY_TIMEOUT 10 +#define RETRY_TIMEOUT 10 uint32_t save_iso14a_timeout = iso14a_get_timeout(); iso14a_set_timeout(1236 / 128 + 1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer. // refactored to use local pointer, now no modification of polling_parameters pointer is done - // I don't think the intention was to modify polling_parameters when sending in WUPA_POLLING_PARAMETERS etc. + // I don't think the intention was to modify polling_parameters when sending in WUPA_POLLING_PARAMETERS etc. // Modify polling_params, if null use default values. iso14a_polling_parameters_t p; - memcpy(&p, (uint8_t*)polling_parameters, sizeof(iso14a_polling_parameters_t)); + memcpy(&p, (uint8_t *)polling_parameters, sizeof(iso14a_polling_parameters_t)); if (polling_parameters == NULL) { - memcpy(&p, (uint8_t*)&hf14a_polling_parameters, sizeof(iso14a_polling_parameters_t)); + memcpy(&p, (uint8_t *)&hf14a_polling_parameters, sizeof(iso14a_polling_parameters_t)); } bool first_try = true; diff --git a/client/luascripts/hf_mfu_ultra.lua b/client/luascripts/hf_mfu_ultra.lua index f96becad8..ed6a2b974 100644 --- a/client/luascripts/hf_mfu_ultra.lua +++ b/client/luascripts/hf_mfu_ultra.lua @@ -23,7 +23,7 @@ script run hf_mfu_ultra -h -f -k -w -r ]] arguments = [[ -h this help - -f filename for the datadump to read (bin) + -f filename for the datadump to read (bin) -k pwd to use with the restore and wipe operations -r restore a binary dump to tag -w wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[) @@ -50,7 +50,7 @@ local function setPassword(password) _password = nil; elseif #password ~= 8 then return false, 'Password must be 4 hex bytes' - else + else _password = password end return true, 'Sets' @@ -102,7 +102,7 @@ end --- Sends raw data to PM3 and returns parsed response local function sendWithResponse(payload, options) local opts; - if options then + if options then opts = options else opts = {ignore_response = false, keep_signal = true, append_crc = true} @@ -351,7 +351,7 @@ local function main(args) if opt == 'w' then res, err = wipe() end if not res then return error(err) end end - + end main(args) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index ea0c47993..0cdf49b81 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -600,7 +600,7 @@ static command_t CommandTable[] = { {"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"}, {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, - {"vas", CmdHFVAS, AlwaysAvailable, "{ Apple Value Added Service }"}, + {"vas", CmdHFVAS, AlwaysAvailable, "{ Apple Value Added Service... }"}, #ifdef HAVE_GD {"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"}, #endif diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index d1bf67562..634e3c0ba 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -1403,10 +1403,10 @@ static int CmdHF14AAPDU(const char *Cmd) { CLIParserFree(ctx); return PM3_EINVARG; } - + bool extendedAPDU = arg_get_lit(ctx, 6); int le = arg_get_int_def(ctx, 7, 0); - + uint8_t data[PM3_CMD_DATA_SIZE]; int datalen = 0; diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index cb0482cc3..69011be6c 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -3029,7 +3029,9 @@ int infoHF14B(bool verbose, bool do_aid_search) { // try unknown 14b read commands (to be identified later) // could be read of calypso, CEPAS, moneo, or pico pass. - if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); + if (verbose) { + PrintAndLogEx(FAILED, "no 14443-B tag found"); + } return PM3_EOPABORTED; } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 16485b262..6c1de1cb1 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3004,7 +3004,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); if (tearoff_end <= tearoff_start) { PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay."); @@ -3063,7 +3063,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { params.on = true; params.delay_us = tearoff_start; handle_tearoff(¶ms, false); - 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); isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); switch (isok) { case PM3_SUCCESS: @@ -3101,24 +3101,24 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } 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; - }else if ((!tear_success) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) { //tearoff succeeded (partially) - tear_success = true; - expected_values = false; - PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success! -> Different values")); - PrintAndLogEx(INFO, "Original: %s", sprint_hex(data_read_orig, sizeof(data_read))); - PrintAndLogEx(INFO, "Expected: %s", sprint_hex(data, sizeof(data))); + } else if ((!tear_success) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) { //tearoff succeeded (partially) + tear_success = true; + expected_values = false; + PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success! -> Different values")); + PrintAndLogEx(INFO, "Original: %s", sprint_hex(data_read_orig, sizeof(data_read))); + PrintAndLogEx(INFO, "Expected: %s", sprint_hex(data, sizeof(data))); } if (tear_success) { //tearoff succeeded read_ok = true; - if(expected_values) { + if (expected_values) { PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success! -> Expected values")); } PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); } else { //tearoff did not succeed PrintAndLogEx(FAILED, _RED_("Tear-off Failed!")); - if(verbose) { + if (verbose) { PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); PrintAndLogEx(INFO, "Expected: %s", sprint_hex(data, sizeof(data))); } diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index b081eb067..f85362a23 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -1684,7 +1684,7 @@ typedef struct { } mfu_otp_identify_t; static mfu_otp_identify_t mfu_otp_ident_table[] = { - { "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA, NULL }, + { "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA, "report to iceman!" }, { NULL, 0, 0, NULL, NULL, NULL } }; @@ -1963,7 +1963,7 @@ static int mfu_fingerprint(uint64_t tagtype, bool hasAuthKey, const uint8_t *aut // OTP checks mfu_otp_identify_t *item = mfu_match_otp_fingerprint(uid, data); if (item) { - PrintAndLogEx(SUCCESS, _GREEN_("%s"), item->desc); + PrintAndLogEx(SUCCESS, _BACK_GREEN_(" %s "), item->desc); res = PM3_SUCCESS; if (item->hint) { diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 128826c10..f28b2c165 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -165,6 +165,7 @@ static char *filenamemcopy(const char *preferredName, const char *suffix) { char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t)); if (fileName == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); return NULL; } @@ -993,8 +994,8 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, } *pdata = calloc(fsize, sizeof(uint8_t)); - if (!*pdata) { - PrintAndLogEx(FAILED, "error, cannot allocate memory"); + if (*pdata == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); fclose(f); return PM3_EMALLOC; } @@ -1044,8 +1045,8 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { } *pdata = calloc(fsize, sizeof(uint8_t)); - if (!*pdata) { - PrintAndLogEx(FAILED, "error, cannot allocate memory"); + if (*pdata == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); fclose(f); return PM3_EMALLOC; } @@ -1091,6 +1092,7 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { uint8_t *newdump = realloc(*pdata, counter); if (newdump == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); free(*pdata); return PM3_EMALLOC; } else { @@ -1366,8 +1368,8 @@ int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) { } *pdata = calloc(fsize, sizeof(uint8_t)); - if (!*pdata) { - PrintAndLogEx(FAILED, "error, cannot allocate memory"); + if (*pdata == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); fclose(f); return PM3_EMALLOC; } @@ -1414,6 +1416,7 @@ int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) { uint8_t *newdump = realloc(*pdata, counter); if (newdump == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); free(*pdata); return PM3_EMALLOC; } else { @@ -2358,6 +2361,7 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo // allocate some space for the dictionary *pdata = calloc(block_size, sizeof(uint8_t)); if (*pdata == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); free(path); return PM3_EFILE; } @@ -2377,9 +2381,10 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo if ((*keycnt * (keylen >> 1)) >= mem_size) { mem_size += block_size; - *pdata = realloc(*pdata, mem_size); + *pdata = realloc(*pdata, mem_size); if (*pdata == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); retval = PM3_EFILE; fclose(f); goto out; @@ -2473,7 +2478,7 @@ int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya *keya = calloc(fsize, sizeof(uint8_t)); if (*keya == NULL) { - PrintAndLogEx(FAILED, "error, cannot allocate memory"); + PrintAndLogEx(WARNING, "Failed to allocate memory"); fclose(f); free(path); return PM3_EMALLOC; @@ -2483,7 +2488,7 @@ int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya *keyb = calloc(fsize, sizeof(uint8_t)); if (*keyb == NULL) { - PrintAndLogEx(FAILED, "error, cannot allocate memory"); + PrintAndLogEx(WARNING, "Failed to allocate memory"); fclose(f); free(*keya); free(path); @@ -2663,6 +2668,7 @@ static int convert_plain_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) mfu_dump_t *mfu = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t)); if (mfu == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); return PM3_EMALLOC; } @@ -2700,6 +2706,7 @@ static int convert_old_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) { mfu_dump_t *mfu_dump = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t)); if (mfu_dump == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); return PM3_EMALLOC; } @@ -2846,6 +2853,7 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea // explicit absolute (/) or relative path (./) => try only to match it directly char *filename = calloc(strlen(searchname) + 1, sizeof(char)); if (filename == NULL) { + PrintAndLogEx(WARNING, "Failed to allocate memory"); return PM3_EMALLOC; } @@ -3081,7 +3089,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl case JSON: { *pdump = calloc(maxdumplen, sizeof(uint8_t)); if (*pdump == NULL) { - PrintAndLogEx(WARNING, "fail, cannot allocate memory"); + PrintAndLogEx(WARNING, "Failed to allocate memory"); return PM3_EMALLOC; } @@ -3121,7 +3129,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl *pdump = calloc(maxdumplen, sizeof(uint8_t)); if (*pdump == NULL) { - PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + PrintAndLogEx(WARNING, "Failed to allocate memory"); return PM3_EMALLOC; } res = loadFileNFC_safe(fn, *pdump, maxdumplen, dumplen, dumptype); diff --git a/doc/commands.json b/doc/commands.json index 9fc3e4a6a..4c173f86a 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -1342,7 +1342,6 @@ "-t, --timeout Timeout in milliseconds", "-b Number of bits to send. Useful for send partial byte", "-v, --verbose Verbose output", - "--mag Use Apple magsafe polling", "--topaz Use Topaz protocol to send command", "--crypto1 Use crypto1 session", " Raw bytes to send" @@ -1354,8 +1353,7 @@ "description": "Act as a ISO-14443a reader to identify tag. Look for ISO-14443a tags until Enter or the pm3 button is pressed", "notes": [ "hf 14a reader", - "hf 14a reader -@ -> Continuous mode", - "hf 14a reader --mag -> trigger apple magsafe polling" + "hf 14a reader -@ -> Continuous mode" ], "offline": false, "options": [ @@ -1364,7 +1362,6 @@ "-s, --silent silent (no messages)", "--drop just drop the signal field", "--skip ISO14443-3 select only (skip RATS)", - "--mag Use Apple magsafe polling", "-@ continuous reader mode", "-w, --wait wait for card" ], @@ -3204,7 +3201,7 @@ }, "hf help": { "command": "hf help", - "description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } iclass { ICLASS RFIDs... } ict { ICT MFC/DESfire RFIDs... } jooki { Jooki RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service } waveshare { Waveshare NFC ePaper... } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } iclass { ICLASS RFIDs... } ict { ICT MFC/DESfire RFIDs... } jooki { Jooki RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service... } waveshare { Waveshare NFC ePaper... } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf list --frame -> show frame delay times", "hf list -1 -> use trace buffer" @@ -3741,10 +3738,11 @@ "--nr replay of NR/MAC", "-v, --verbose verbose output", "--shallow use shallow (ASK) reader modulation instead of OOK", - "--tdb tearoff delay start in ms", - "--tde tearoff delay end in ms" + "--tdb tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us.", + "--incr tearoff delay increment (in us) - default 10.", + "--tde tearoff delay end (in us) must be a higher value than the start delay." ], - "usage": "hf iclass trbl [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] --tdb --tde " + "usage": "hf iclass trbl [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] --tdb [--incr ] [--tde ]" }, "hf iclass unhash": { "command": "hf iclass unhash", @@ -13354,6 +13352,6 @@ "metadata": { "commands_extracted": 767, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-04-20T09:18:59" + "extracted_on": "2025-05-19T11:17:19" } } diff --git a/doc/commands.md b/doc/commands.md index 12312b7fc..755930dd8 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -786,7 +786,7 @@ Check column "offline" for their availability. ### hf vas - { Apple Value Added Service } + { Apple Value Added Service... } |command |offline |description |------- |------- |----------- From 74c66d89ff88bdd19444a06d8fefdb325074580b Mon Sep 17 00:00:00 2001 From: n-hutton Date: Tue, 20 May 2025 23:28:20 +0100 Subject: [PATCH 16/44] update readme based on @shuffle2 feedback --- doc/fpga_arm_notes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/fpga_arm_notes.md b/doc/fpga_arm_notes.md index 4cc47b88a..21eba6818 100644 --- a/doc/fpga_arm_notes.md +++ b/doc/fpga_arm_notes.md @@ -73,9 +73,9 @@ There is a docker image with webpack installed which has been built which you ca ``` docker pull nhutton/prox-container:webp_image_complete -docker run -v /proxmark3:/tmp --rm -it nhutton/prox-container:webp_image_complete bash -$ cd /tmp/proxmark/fpga -$ make all +docker run -v /proxmark3:/tmp/proxmark3 --rm -it nhutton/prox-container:1.0 bash +$ cd /tmp/proxmark3/fpga +$ make all -j ``` In order to save space, these fpga images are LZ4 compressed and included in the fullimage.elf file when compiling the ARM SRC. `make armsrc` From f9322dfe6c2433230a40d791bfe9f8d2973ddc3d Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 23 May 2025 15:55:53 +0800 Subject: [PATCH 17/44] Updated trbl Fixed a bug preventing tearoff stages from being detected correctly, increased verbosity of read data and granularity of displayed information --- client/src/cmdhficlass.c | 134 +++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 55 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 6c1de1cb1..42d516077 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2937,9 +2937,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0("v", "verbose", "verbose output"), arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"), - arg_int1(NULL, "tdb", "", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us."), - arg_int0(NULL, "incr", "", "tearoff delay increment (in us) - default 10."), - arg_int0(NULL, "tde", "", "tearoff delay end (in us) must be a higher value than the start delay."), + 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_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3004,7 +3004,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); if (tearoff_end <= tearoff_start) { PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay."); @@ -3030,7 +3030,6 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { return PM3_EINVARG; } int isok = 0; - tearoff_params_t params; bool read_ok = false; uint8_t keyType = 0x88; //debit key @@ -3039,49 +3038,63 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { keyType = 0x18; //credit key } - while (tearoff_start <= tearoff_end && !read_ok) { - //perform read here, repeat if failed or 00s - uint8_t data_read_orig[8] = {0}; - bool first_read = false; - bool reread = false; - while (!first_read) { - int res_orig = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read_orig, false); - if (res_orig == PM3_SUCCESS && !reread) { - if (memcmp(data_read_orig, zeros, 8) == 0) { - reread = true; - } else { - first_read = true; - reread = false; - } - } else if (res_orig == PM3_SUCCESS && reread) { - first_read = true; - reread = false; - } + //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; + bool reread = false; + bool erase_phase = false; + + int res_orig = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read_orig, false); + if (res_orig == PM3_SUCCESS && !reread) { + if (memcmp(data_read_orig, zeros, 8) == 0) { + reread = true; + } else { + first_read = true; + reread = false; + } + } else if (res_orig == PM3_SUCCESS && reread) { + first_read = true; + reread = false; + } + + 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; } - params.on = true; - params.delay_us = tearoff_start; - handle_tearoff(¶ms, false); - PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")"/"_YELLOW_("%d")" us", tearoff_start, tearoff_end); - isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); - switch (isok) { - case PM3_SUCCESS: - PrintAndLogEx(SUCCESS, "Wrote block " _YELLOW_("%d") " / " _YELLOW_("0x%02X") " ( " _GREEN_("ok") " )", blockno, blockno); - break; - case PM3_ETEAROFF: - break; - default: - PrintAndLogEx(FAILED, "Writing failed"); - break; + // set tear off trigger + clearCommandBuffer(); + tearoff_params_t params = { + .delay_us = tearoff_start, + .on = true, + .off = false + }; + int res = handle_tearoff(¶ms, verbose); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Failed to configure tear off"); + return PM3_ESOFT; } + + // 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); + iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); + //read the data back uint8_t data_read[8] = {0}; first_read = false; reread = false; bool decrease = false; - while (!first_read) { - int res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read, false); + while (first_read == false) { + if (kbd_enter_pressed()) { + PrintAndLogEx(WARNING, "\naborted via keyboard."); + return PM3_EOPABORTED; + } + 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) { reread = true; @@ -3101,29 +3114,40 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } 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; - } else if ((!tear_success) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) { //tearoff succeeded (partially) - tear_success = true; + } + if ((tear_success == false) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) { //tearoff succeeded (partially) expected_values = false; - PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success! -> Different values")); - PrintAndLogEx(INFO, "Original: %s", sprint_hex(data_read_orig, sizeof(data_read))); + 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{ + 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(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))); + } + } + }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))); } - if (tear_success) { //tearoff succeeded + if (tear_success) { //tearoff succeeded with expected values read_ok = true; - if (expected_values) { - PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success! -> Expected values")); + tear_success = true; + if(expected_values) { + PrintAndLogEx(SUCCESS, _GREEN_("Expected values!")); } - PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); - } else { //tearoff did not succeed - PrintAndLogEx(FAILED, _RED_("Tear-off Failed!")); - if (verbose) { - PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); - PrintAndLogEx(INFO, "Expected: %s", sprint_hex(data, sizeof(data))); - } - tearoff_start += tearoff_increment; + PrintAndLogEx(INFO, "Read: "_GREEN_("%s"), sprint_hex(data_read, sizeof(data_read))); } + tearoff_start += tearoff_increment; PrintAndLogEx(INFO, "---------------"); } PrintAndLogEx(NORMAL, ""); From 047b94fbaae2b4dde89c1099935dc8e4946cecc5 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 23 May 2025 16:32:48 +0800 Subject: [PATCH 18/44] 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 c716467a7ebf4d59836b661a4fc26bdecbabb0a3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 23 May 2025 10:52:09 +0200 Subject: [PATCH 19/44] fixed output for `hf iclass trbl` to not have tear off debug message and its more compact now --- CHANGELOG.md | 1 + armsrc/appmain.c | 2 +- client/src/cmdhficlass.c | 80 ++++++++++++++++++++++++++++------------ doc/commands.json | 10 ++--- pm3 | 6 +-- 5 files changed, 67 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eb4b7276..8a5985436 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 `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 diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 0929f80c5..30ac348a6 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -104,7 +104,7 @@ int tearoff_hook(void) { SpinDelayUsPrecision(g_tearoff_delay_us); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); g_tearoff_enabled = false; - Dbprintf(_YELLOW_("Tear-off triggered!")); + if (g_dbglevel >= DBG_ERROR) Dbprintf(_YELLOW_("Tear-off triggered!")); return PM3_ETEAROFF; } else { return PM3_SUCCESS; // SUCCESS = the hook didn't do anything diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 42d516077..d1c620a9d 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3004,7 +3004,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); if (tearoff_end <= tearoff_start) { PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay."); @@ -3038,10 +3038,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; @@ -3059,11 +3058,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 @@ -3073,15 +3087,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 @@ -3089,11 +3105,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) { @@ -3109,46 +3129,60 @@ 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))); } tearoff_start += tearoff_increment; - 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; diff --git a/doc/commands.json b/doc/commands.json index 4c173f86a..264bc4140 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3738,11 +3738,11 @@ "--nr replay of NR/MAC", "-v, --verbose verbose output", "--shallow use shallow (ASK) reader modulation instead of OOK", - "--tdb tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us.", - "--incr tearoff delay increment (in us) - default 10.", - "--tde tearoff delay end (in us) must be a higher value than the start delay." + "--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." ], - "usage": "hf iclass trbl [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] --tdb [--incr ] [--tde ]" + "usage": "hf iclass trbl [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] --s [--i ] [--e ]" }, "hf iclass unhash": { "command": "hf iclass unhash", @@ -13352,6 +13352,6 @@ "metadata": { "commands_extracted": 767, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-05-19T11:17:19" + "extracted_on": "2025-05-23T08:30:58" } } diff --git a/pm3 b/pm3 index ae87617b6..5122fe536 100755 --- a/pm3 +++ b/pm3 @@ -142,9 +142,9 @@ function get_pm3_list_Windows { #prevent soft bricking when using pm3-flash-all on an outdated bootloader if [ $(basename -- "$0") = "pm3-flash-all" ]; then - + line=$($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null); - + if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" exit 1 @@ -169,7 +169,7 @@ function get_pm3_list_Windows { #white BT dongle SERIAL PORTS (COM) if $FINDBTDONGLE; then - + for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_10C4&PID_EA60*' | Select -expandproperty DeviceID" 2>/dev/null); do PM3LIST+=("$DEV") if [ ${#PM3LIST[*]} -ge "$N" ]; then From fbbfeaa9770e68b1bcec3d5b8aa54c0be9f36800 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 23 May 2025 17:00:41 +0800 Subject: [PATCH 20/44] 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; From 07bfef1550c3cbdcd2d52ff1fa67d8f49b23af2e Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 23 May 2025 17:11:07 +0800 Subject: [PATCH 21/44] Bugfixes on hf iclass trbl Fixed tearoff trigger staying enabled in case of keyboard interruption --- client/src/cmdhficlass.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 13725b392..d98c1e1c1 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3191,6 +3191,14 @@ out: if (setDeviceDebugLevel(verbose ? MAX(dbg_curr, DBG_INFO) : DBG_NONE, false) != PM3_SUCCESS) { return PM3_EFAILED; } + // disable tearoff in case of keyboard abort, or it'll trigger on next operation + clearCommandBuffer(); + tearoff_params_t params = { + .delay_us = tearoff_start, + .on = false, + .off = true + }; + handle_tearoff(¶ms, false); PrintAndLogEx(NORMAL, ""); return isok; } From 335c1444bda43c8157bacbb3abf0a879e63023b3 Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Fri, 23 May 2025 19:06:25 +0800 Subject: [PATCH 22/44] updated hf iclass trbl to support unsecure page mode Added unsecure page mode support --- client/src/cmdhficlass.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 3c15af394..3e36828db 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3042,6 +3042,44 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { keyType = 0x18; //credit key } + //check if the card is in secure mode or not + iclass_card_select_t payload_rdr = { + .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE) + }; + + if (shallow_mod) { + payload_rdr.flags |= FLAG_ICLASS_READER_SHALLOW_MOD; + } + clearCommandBuffer(); + PacketResponseNG resp; + SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t)); + + if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) { + PrintAndLogEx(WARNING, "command execution time out"); + DropField(); + return PM3_ESOFT; + } + DropField(); + + if (resp.status == PM3_ERFTRANS) { + PrintAndLogEx(FAILED, "no tag found"); + DropField(); + return PM3_ESOFT; + } + + iclass_card_select_resp_t *r = (iclass_card_select_resp_t *)resp.data.asBytes; + if (r->status == FLAG_ICLASS_NULL) { + PrintAndLogEx(FAILED, "failed to read block 0,1,2"); + return PM3_ESOFT; + } + + picopass_hdr_t *hdr = &r->header.hdr; + uint8_t pagemap = get_pagemap(hdr); + if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { + PrintAndLogEx(INFO, "Card in non-secure page mode detected"); + auth = false; + } + //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}; From d4bc190dd48b9327be8aa725f55929fb7cac43bd Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 23 May 2025 17:29:28 +0200 Subject: [PATCH 23/44] renamed the hf iclass trdbl -> hf iclass tear --- CHANGELOG.md | 1 + client/src/cmdhficlass.c | 53 ++++++++++++++++++++++----------- client/src/pm3line_vocabulary.h | 2 +- doc/commands.json | 22 +++++++------- doc/commands.md | 2 +- 5 files changed, 50 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a5985436..2ce4c00f3 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] +- Renamed `hf iclass trbl` -> `hf iclass tear` (@iceman1001) - 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) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 3e36828db..d478b204c 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2919,10 +2919,14 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { static int CmdHFiClass_TearBlock(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "hf iclass trbl", - "Tear off an iCLASS tag block", - "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --tdb 100 --tde 150\n" - "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 --tdb 100 --tde 150"); + 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", + "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" + ); void *argtable[] = { arg_param_begin, @@ -2937,9 +2941,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0("v", "verbose", "verbose output"), arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"), - 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_int1("s", NULL, "", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us."), + arg_int0("i", NULL, "", "tearoff delay increment (in us) - default 10."), + arg_int0("e", NULL, "", "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 }; @@ -3075,10 +3079,10 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { picopass_hdr_t *hdr = &r->header.hdr; uint8_t pagemap = get_pagemap(hdr); - if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - PrintAndLogEx(INFO, "Card in non-secure page mode detected"); - auth = false; - } + if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { + PrintAndLogEx(INFO, "Card in non-secure page mode detected"); + auth = false; + } //perform initial read here, repeat if failed or 00s uint8_t data_read_orig[8] = {0}; @@ -3172,7 +3176,7 @@ 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 (decrease && tearoff_start > 0) { // if there was an error reading repeat the tearoff with the same delay tearoff_start -= tearoff_increment; } @@ -3183,7 +3187,7 @@ 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; @@ -3199,18 +3203,31 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { 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(SUCCESS, _CYAN_("Tearing! (unknown phase)")); 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 + if (blockno == 1) { + if (data_read[0] != data_read_orig[0]) { + PrintAndLogEx(SUCCESS, "Application limit changed, from %u to %u", data_read_orig[0], data_read[0]); + isok = PM3_SUCCESS; + goto out; + } + if (data_read[7] != data_read_orig[7]) { + PrintAndLogEx(SUCCESS, "Fuse changed, from %02x to %02x", data_read_orig[7], data_read[7]); + isok = PM3_SUCCESS; + goto out; + } + } + + } 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 + if (tear_success) { // tearoff succeeded with expected values read_ok = true; tear_success = true; if (expected_values) { @@ -3219,7 +3236,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(INFO, "Read: "_GREEN_("%s"), sprint_hex_inrow(data_read, sizeof(data_read))); } loop_count++; - if (loop_count == tearoff_loop){ + if (loop_count == tearoff_loop) { tearoff_start += tearoff_increment; loop_count = 0; } @@ -5662,7 +5679,7 @@ static command_t CommandTable[] = { {"view", CmdHFiClassView, AlwaysAvailable, "Display content from tag dump file"}, {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "Write Picopass / iCLASS block"}, {"creditepurse", CmdHFiClassCreditEpurse, IfPm3Iclass, "Credit epurse value"}, - {"trbl", CmdHFiClass_TearBlock, IfPm3Iclass, "Performs tearoff attack on iClass block"}, + {"tear", CmdHFiClass_TearBlock, IfPm3Iclass, "Performs tearoff attack on iClass block"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("Recovery") " --------------------"}, // {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "Automatic key recovery tool for iCLASS"}, {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "Check keys"}, diff --git a/client/src/pm3line_vocabulary.h b/client/src/pm3line_vocabulary.h index bfe823459..dfa82819a 100644 --- a/client/src/pm3line_vocabulary.h +++ b/client/src/pm3line_vocabulary.h @@ -281,7 +281,7 @@ const static vocabulary_t vocabulary[] = { { 1, "hf iclass view" }, { 0, "hf iclass wrbl" }, { 0, "hf iclass creditepurse" }, - { 0, "hf iclass trbl" }, + { 0, "hf iclass tear" }, { 0, "hf iclass chk" }, { 1, "hf iclass loclass" }, { 1, "hf iclass lookup" }, diff --git a/doc/commands.json b/doc/commands.json index 264bc4140..50f8e4065 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -3717,12 +3717,13 @@ ], "usage": "hf iclass sniff [-hj]" }, - "hf iclass trbl": { - "command": "hf iclass trbl", - "description": "Tear off an iCLASS tag block", + "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", "notes": [ - "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --tdb 100 --tde 150", - "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 --tdb 100 --tde 150" + "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", + "hf iclass tear --blk 2 -d fdffffffffffffff --ki 1 --credit -s 400 -e 500" ], "offline": false, "options": [ @@ -3738,11 +3739,12 @@ "--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." + "-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." ], - "usage": "hf iclass trbl [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] --s [--i ] [--e ]" + "usage": "hf iclass tear [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] -s [-i ] [-e ] [--loop ]" }, "hf iclass unhash": { "command": "hf iclass unhash", @@ -13352,6 +13354,6 @@ "metadata": { "commands_extracted": 767, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-05-23T08:30:58" + "extracted_on": "2025-05-23T15:21:08" } } diff --git a/doc/commands.md b/doc/commands.md index 755930dd8..bc90193ca 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -404,7 +404,7 @@ Check column "offline" for their availability. |`hf iclass view `|Y |`Display content from tag dump file` |`hf iclass wrbl `|N |`Write Picopass / iCLASS block` |`hf iclass creditepurse `|N |`Credit epurse value` -|`hf iclass trbl `|N |`Performs tearoff attack on iClass block` +|`hf iclass tear `|N |`Performs tearoff attack on iClass block` |`hf iclass chk `|N |`Check keys` |`hf iclass loclass `|Y |`Use loclass to perform bruteforce reader attack` |`hf iclass lookup `|Y |`Uses authentication trace to check for key in dictionary file` From ad50e5973815b2f6a92cebf8e36008d4369dc6cf Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 23 May 2025 23:47:45 +0200 Subject: [PATCH 24/44] `hf iclass tear` - some more granular printing and colors when tearing --- client/src/cmdhficlass.c | 56 ++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index d478b204c..e077add5c 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2917,6 +2917,50 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { return PM3_SUCCESS; } + +static void iclass_cmp_print(uint8_t *b1, uint8_t *b2, const char *header1, const char *header2) { + + char line1[240] = {0}; + char line2[240] = {0}; + + strcat(line1, header1); + strcat(line2, header2); + + for (uint8_t i = 0; i < PICOPASS_BLOCK_SIZE; i++ ) { + + int l1 = strlen(line1); + int l2 = strlen(line2); + + uint8_t hi1 = NIBBLE_HIGH(b1[i]); + uint8_t low1 = NIBBLE_LOW(b1[i]); + + uint8_t hi2 = NIBBLE_HIGH(b2[i]); + uint8_t low2 = NIBBLE_LOW(b2[i]); + + if (hi1 != hi2) { + snprintf(line1 + l1, sizeof(line1) - l1, _RED_("%1X"), hi1); + snprintf(line2 + l2, sizeof(line2) - l2, _GREEN_("%1X"), hi2); + } else { + snprintf(line1 + l1, sizeof(line1) - l1, "%1X", hi1); + snprintf(line2 + l2, sizeof(line2) - l2, "%1X", hi2); + } + + l1 = strlen(line1); + l2 = strlen(line2); + + if (low1 != low2) { + snprintf(line1 + l1, sizeof(line1) - l1, _RED_("%1X"), low1); + snprintf(line2 + l2, sizeof(line2) - l2, _GREEN_("%1X"), low2); + } else { + snprintf(line1 + l1, sizeof(line1) - l1, "%1X", low1); + snprintf(line2 + l2, sizeof(line2) - l2, "%1X", low2); + } + } + + PrintAndLogEx(INFO, "%s", line1); + PrintAndLogEx(INFO, "%s", line2); +} + static int CmdHFiClass_TearBlock(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass tear", @@ -3194,18 +3238,15 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { 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_inrow(data_read_orig, sizeof(data_read))); - PrintAndLogEx(INFO, "Read: "_BLUE_("%s"), sprint_hex_inrow(data_read, sizeof(data_read))); + iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } else { if (erase_phase) { PrintAndLogEx(SUCCESS, _MAGENTA_("Tearing! Write Phase (post erase)")); - 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))); + iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } else { PrintAndLogEx(SUCCESS, _CYAN_("Tearing! (unknown phase)")); - 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))); + iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } } @@ -3223,8 +3264,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } } 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))); + iclass_cmp_print(data, data_read, "Expected: ", "Read: "); } if (tear_success) { // tearoff succeeded with expected values From 45ae30fe88399395ddbd02fe14e2e2ad73cfb12e Mon Sep 17 00:00:00 2001 From: Antiklesys Date: Sat, 24 May 2025 13:48:52 +0800 Subject: [PATCH 25/44] Updated iclass tear colors Removed a huge chunk of colorful visual spam for when the tearoff isn't happening --- client/src/cmdhficlass.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index e077add5c..c13fae829 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3264,7 +3264,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } } else { // tearoff did not succeed - iclass_cmp_print(data, data_read, "Expected: ", "Read: "); + 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 From 841828eb4812a1c34f93c10bcce66f51a5a26190 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 11:43:34 +0200 Subject: [PATCH 26/44] hf iclass tear - output texts --- client/src/cmdhficlass.c | 149 ++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 65 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index c13fae829..5ff7c7f33 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2985,78 +2985,83 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0("v", "verbose", "verbose output"), arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"), - arg_int1("s", NULL, "", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us."), - arg_int0("i", NULL, "", "tearoff delay increment (in us) - default 10."), - arg_int0("e", NULL, "", "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_int1("s", NULL, "", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us"), + arg_int0("i", NULL, "", "tearoff delay increment (in us) - default 10"), + arg_int0("e", NULL, "", "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_int0(NULL, "sleep", "", "Sleep between each tear"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); int key_len = 0; uint8_t key[8] = {0}; - CLIGetHexWithReturn(ctx, 1, key, &key_len); int key_nr = arg_get_int_def(ctx, 2, -1); - - if (key_len > 0 && key_nr >= 0) { - PrintAndLogEx(ERR, "Please specify key or index, not both"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - - bool auth = false; - - if (key_len > 0) { - auth = true; - if (key_len != 8) { - PrintAndLogEx(ERR, "Key is incorrect length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } else if (key_nr >= 0) { - if (key_nr < ICLASS_KEYS_MAX) { - auth = true; - memcpy(key, iClass_Key_Table[key_nr], 8); - PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8)); - } else { - PrintAndLogEx(ERR, "Key number is invalid"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } - int blockno = arg_get_int_def(ctx, 3, 0); int data_len = 0; uint8_t data[8] = {0}; CLIGetHexWithReturn(ctx, 4, data, &data_len); - if (data_len != 8) { - PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 hex symbols)"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - int mac_len = 0; uint8_t mac[4] = {0}; CLIGetHexWithReturn(ctx, 5, mac, &mac_len); - if (mac_len) { - if (mac_len != 4) { - PrintAndLogEx(ERR, "MAC must be 4 hex bytes (8 hex symbols)"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } + bool use_credit_key = arg_get_lit(ctx, 6); + bool elite = arg_get_lit(ctx, 7); + bool rawkey = arg_get_lit(ctx, 8); + bool use_replay = arg_get_lit(ctx, 9); + 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_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; + int tearoff_sleep = arg_get_int_def(ctx, 16, 0); + CLIParserFree(ctx); + + // Sanity checks + if (key_len > 0 && key_nr >= 0) { + PrintAndLogEx(ERR, "Please specify key or index, not both"); + return PM3_EINVARG; + } + + bool auth = false; + + if (key_len > 0) { + + auth = true; + if (key_len != 8) { + PrintAndLogEx(ERR, "Key is incorrect length"); + return PM3_EINVARG; + } + + } else if (key_nr >= 0) { + + if (key_nr < ICLASS_KEYS_MAX) { + auth = true; + memcpy(key, iClass_Key_Table[key_nr], 8); + 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) { + PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 hex symbols), got " _RED_("%u"), data_len); + return PM3_EINVARG; + } + + if (mac_len && mac_len != 4) { + PrintAndLogEx(ERR, "MAC must be 4 hex bytes (8 hex symbols)"); + return PM3_EINVARG; + } if (tearoff_end <= tearoff_start) { PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay."); @@ -3068,19 +3073,12 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { return PM3_EINVARG; } - bool use_credit_key = arg_get_lit(ctx, 6); - bool elite = arg_get_lit(ctx, 7); - bool rawkey = arg_get_lit(ctx, 8); - bool use_replay = arg_get_lit(ctx, 9); - bool verbose = arg_get_lit(ctx, 10); - bool shallow_mod = arg_get_lit(ctx, 11); - - CLIParserFree(ctx); - if ((use_replay + rawkey + elite) > 1) { PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'"); return PM3_EINVARG; } + + int loop_count = 0; int isok = 0; bool read_ok = false; uint8_t keyType = 0x88; //debit key @@ -3089,6 +3087,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key"); keyType = 0x18; //credit key } + if (auth == false) { + PrintAndLogEx(SUCCESS, "No key supplied. Trying no authentication read/writes"); + } //check if the card is in secure mode or not iclass_card_select_t payload_rdr = { @@ -3158,7 +3159,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { return PM3_EFAILED; } - PrintAndLogEx(INFO, "Starting tear off against block %u / 0x%02x", blockno, blockno); + PrintAndLogEx(INFO, "Starting tear off against block " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno); PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "Press " _GREEN_("") " to abort"); @@ -3187,7 +3188,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { // 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(NORMAL, "\r" NOLF); + PrintAndLogEx(INPLACE, "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 @@ -3237,14 +3239,17 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { 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")); iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } else { if (erase_phase) { + PrintAndLogEx(NORMAL, ""); 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)")); iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); } @@ -3252,11 +3257,13 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { 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]); 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]); isok = PM3_SUCCESS; goto out; @@ -3264,27 +3271,38 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { } } 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))); + // 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 + read_ok = true; tear_success = true; - if (expected_values) { - PrintAndLogEx(SUCCESS, _GREEN_("Expected values!")); - } - PrintAndLogEx(INFO, "Read: "_GREEN_("%s"), sprint_hex_inrow(data_read, sizeof(data_read))); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Read: " _GREEN_("%s") " %s" + , sprint_hex_inrow(data_read, sizeof(data_read)), + (expected_values) ? _GREEN_(" -> Expected values!") : "" + ); } + loop_count++; + if (loop_count == tearoff_loop) { tearoff_start += tearoff_increment; loop_count = 0; } - PrintAndLogEx(INFO, "--------------------------"); + + if (tearoff_sleep) { + msleep(tearoff_sleep); + } } out: + + DropField(); + if (setDeviceDebugLevel(verbose ? MAX(dbg_curr, DBG_INFO) : DBG_NONE, false) != PM3_SUCCESS) { return PM3_EFAILED; } @@ -3297,6 +3315,7 @@ out: }; handle_tearoff(¶ms, false); PrintAndLogEx(NORMAL, ""); + clearCommandBuffer(); return isok; } From a2f9012e130576797561e64c4760fedea412afc1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 12:33:11 +0200 Subject: [PATCH 27/44] text --- client/src/cmdhficlass.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 5ff7c7f33..b4ab0c7c7 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3081,16 +3081,21 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { int loop_count = 0; int isok = 0; bool read_ok = false; - uint8_t keyType = 0x88; //debit key + uint8_t keyType = 0x88; // debit key if (use_credit_key) { PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key"); - keyType = 0x18; //credit key + keyType = 0x18; // credit key } + if (auth == false) { PrintAndLogEx(SUCCESS, "No key supplied. Trying no authentication read/writes"); } + if (tearoff_sleep) { + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("%u") " ms delay between attempts", tearoff_sleep); + } + //check if the card is in secure mode or not iclass_card_select_t payload_rdr = { .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE) @@ -3189,7 +3194,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { // 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, tearoff_end); iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); //read the data back From 473b5679e2bce47aa9c3c60828839386cff9b2e5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 14:21:36 +0200 Subject: [PATCH 28/44] hf iclass dump - I got tired so now the command defaults to use AA1 key when called without a key or key index --- CHANGELOG.md | 3 +- client/src/cmdhficlass.c | 60 ++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ce4c00f3..631bb3084 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ 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] -- Renamed `hf iclass trbl` -> `hf iclass tear` (@iceman1001) +- 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) - 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) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index b4ab0c7c7..ef92e3998 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1903,15 +1903,32 @@ static int CmdHFiClassDump(const char *Cmd) { int key_len = 0; uint8_t key[8] = {0}; - bool auth = false; - CLIGetHexWithReturn(ctx, 2, key, &key_len); int deb_key_nr = arg_get_int_def(ctx, 3, -1); + int credit_key_len = 0; + uint8_t credit_key[8] = {0}; + CLIGetHexWithReturn(ctx, 4, credit_key, &credit_key_len); + + int credit_key_nr = arg_get_int_def(ctx, 5, -1); + bool elite = arg_get_lit(ctx, 6); + bool rawkey = arg_get_lit(ctx, 7); + bool use_replay = arg_get_lit(ctx, 8); + bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9); + bool force = arg_get_lit(ctx, 10); + bool shallow_mod = arg_get_lit(ctx, 11); + bool nosave = arg_get_lit(ctx, 12); + + CLIParserFree(ctx); + + bool auth = false; + bool have_credit_key = false; + + // Sanity checks + if (key_len > 0 && deb_key_nr >= 0) { PrintAndLogEx(ERR, "Please specify debit key or index, not both"); - CLIParserFree(ctx); return PM3_EINVARG; } @@ -1919,7 +1936,6 @@ static int CmdHFiClassDump(const char *Cmd) { auth = true; if (key_len != 8) { PrintAndLogEx(ERR, "Debit key is incorrect length"); - CLIParserFree(ctx); return PM3_EINVARG; } } @@ -1931,22 +1947,12 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(SUCCESS, "Using AA1 (debit) key[%d] " _GREEN_("%s"), deb_key_nr, sprint_hex(iClass_Key_Table[deb_key_nr], 8)); } else { PrintAndLogEx(ERR, "Key number is invalid"); - CLIParserFree(ctx); return PM3_EINVARG; } } - - int credit_key_len = 0; - uint8_t credit_key[8] = {0}; - bool have_credit_key = false; - - CLIGetHexWithReturn(ctx, 4, credit_key, &credit_key_len); - - int credit_key_nr = arg_get_int_def(ctx, 5, -1); - + if (credit_key_len > 0 && credit_key_nr >= 0) { PrintAndLogEx(ERR, "Please specify credit key or index, not both"); - CLIParserFree(ctx); return PM3_EINVARG; } @@ -1955,7 +1961,6 @@ static int CmdHFiClassDump(const char *Cmd) { have_credit_key = true; if (credit_key_len != 8) { PrintAndLogEx(ERR, "Credit key is incorrect length"); - CLIParserFree(ctx); return PM3_EINVARG; } } @@ -1968,21 +1973,10 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(SUCCESS, "Using AA2 (credit) key[%d] " _GREEN_("%s"), credit_key_nr, sprint_hex(iClass_Key_Table[credit_key_nr], 8)); } else { PrintAndLogEx(ERR, "Key number is invalid"); - CLIParserFree(ctx); return PM3_EINVARG; } } - bool elite = arg_get_lit(ctx, 6); - bool rawkey = arg_get_lit(ctx, 7); - bool use_replay = arg_get_lit(ctx, 8); - bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9); - bool force = arg_get_lit(ctx, 10); - bool shallow_mod = arg_get_lit(ctx, 11); - bool nosave = arg_get_lit(ctx, 12); - - CLIParserFree(ctx); - if ((use_replay + rawkey + elite) > 1) { PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'"); return PM3_EINVARG; @@ -2005,7 +1999,6 @@ static int CmdHFiClassDump(const char *Cmd) { clearCommandBuffer(); PacketResponseNG resp; SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t)); - if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) { PrintAndLogEx(WARNING, "command execution time out"); DropField(); @@ -2062,9 +2055,11 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(INFO, "No keys needed, ignoring user supplied key"); } } else { + if (auth == false) { - PrintAndLogEx(FAILED, "Run command with keys"); - return PM3_ESOFT; + auth = true; + memcpy(key, iClass_Key_Table[0], 8); + PrintAndLogEx(SUCCESS, "Default to AA1 (debit) " _GREEN_("%s"), sprint_hex(key, sizeof(key))); } if (app_limit2 != 0) { @@ -2134,7 +2129,7 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t tempbuf[0x100 * 8]; // response ok - now get bigbuf content of the dump - if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) { + if (GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false) == false) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -2199,7 +2194,7 @@ static int CmdHFiClassDump(const char *Cmd) { } // get dumped data from bigbuf - if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) { + if (GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false) == false) { PrintAndLogEx(WARNING, "command execution time out"); goto write_dump; } @@ -3716,7 +3711,6 @@ static int CmdHFiClassView(const char *Cmd) { } if (verbose) { - PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename); PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, (uint16_t)(bytes_read >> 3), (uint16_t)(bytes_read >> 3)); PrintAndLogEx(INFO, "Printing blocks from: " _YELLOW_("%02d") " to: " _YELLOW_("%02d"), (startblock == 0) ? 6 : startblock, endblock); } From 0d8bb030d17b03c08d5556ed564330e985b3cb24 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 24 May 2025 15:40:13 +0200 Subject: [PATCH 29/44] 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 30/44] 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 31/44] 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 32/44] 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 33/44] 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 34/44] 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 35/44] 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 36/44] 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 37/44] 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 38/44] 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 39/44] 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 40/44] 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 41/44] 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 42/44] 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 43/44] 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 44/44] 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); } }