mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge branch 'RfidResearchGroup:master' into master
This commit is contained in:
commit
66c57e8652
45 changed files with 1156 additions and 384 deletions
|
@ -3107,3 +3107,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
|
||||
|
|
357
client/luascripts/hf_mfu_ultra.lua
Normal file
357
client/luascripts/hf_mfu_ultra.lua
Normal file
|
@ -0,0 +1,357 @@
|
|||
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 -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 -f <dump filename> -k <passwd> -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..[[)
|
||||
|
||||
]]
|
||||
|
||||
|
||||
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
|
||||
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)
|
||||
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
|
||||
|
||||
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(dumpFilename) end
|
||||
if opt == 'w' then res, err = wipe() end
|
||||
if not res then return error(err) end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
main(args)
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1903,15 +1901,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 +1934,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 +1945,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 +1959,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 +1971,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 +1997,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 +2053,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 +2127,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 +2192,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;
|
||||
}
|
||||
|
@ -2272,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;
|
||||
}
|
||||
|
@ -2406,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", "<hex>", "Credit key as 8 hex bytes"),
|
||||
arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
|
||||
arg_str1("d", "data", "<hex>", "data to write as 8 hex bytes"),
|
||||
arg_str1("d", "data", "<hex>", "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"),
|
||||
|
@ -2498,7 +2490,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) {
|
||||
|
@ -2680,7 +2672,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);
|
||||
|
@ -2917,12 +2909,60 @@ 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 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,83 +2977,30 @@ 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", "<dec>", "tearoff delay start in ms"),
|
||||
arg_int1(NULL, "tde", "<dec>", "tearoff delay end in ms"),
|
||||
arg_int1("s", NULL, "<dec>", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us"),
|
||||
arg_int0("i", NULL, "<dec>", "tearoff delay increment (in us) - default 10"),
|
||||
arg_int0("e", NULL, "<dec>", "tearoff delay end (in us) must be a higher value than the start delay"),
|
||||
arg_int0(NULL, "loop", "<dec>", "number of times to loop per tearoff time"),
|
||||
arg_int0(NULL, "sleep", "<ms>", "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;
|
||||
}
|
||||
}
|
||||
|
||||
int tearoff_start = arg_get_int_def(ctx, 12, 100);
|
||||
int tearoff_end = arg_get_int_def(ctx, 13, 200);
|
||||
|
||||
if (tearoff_end <= tearoff_start) {
|
||||
PrintAndLogEx(ERR, "Tearoff end delay must be bigger 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.");
|
||||
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);
|
||||
|
@ -3021,58 +3008,231 @@ 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, 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);
|
||||
int tearoff_sleep = arg_get_int_def(ctx, 16, 0);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ((use_replay + rawkey + elite) > 1) {
|
||||
PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
|
||||
// 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;
|
||||
}
|
||||
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_inrow(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 larger than the start delay");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
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`");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
int loop_count = 0;
|
||||
int isok = 0;
|
||||
tearoff_params_t params;
|
||||
bool read_ok = false;
|
||||
while (tearoff_start < tearoff_end && !read_ok) {
|
||||
//perform read here, repeat if failed or 00s
|
||||
uint8_t keyType = 0x88; // debit key
|
||||
|
||||
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, 0x88, 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;
|
||||
}
|
||||
if (use_credit_key) {
|
||||
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key");
|
||||
keyType = 0x18; // credit key
|
||||
}
|
||||
|
||||
if (auth == false) {
|
||||
PrintAndLogEx(SUCCESS, "No key supplied. Trying no authentication read/writes");
|
||||
}
|
||||
|
||||
if (tearoff_loop > 1) {
|
||||
PrintAndLogEx(SUCCESS, _YELLOW_("%u") " attempts / tearoff", tearoff_loop);
|
||||
}
|
||||
|
||||
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)
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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(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(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) {
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (setDeviceDebugLevel(DBG_NONE, false) != PM3_SUCCESS) {
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
// clear trace log
|
||||
SendCommandNG(CMD_BUFF_CLEAR, NULL, 0);
|
||||
|
||||
PrintAndLogEx(INFO, "---------------------------------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n");
|
||||
// Main loop
|
||||
while ((tearoff_start <= tearoff_end) && (read_ok == false)) {
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(WARNING, "\naborted via keyboard.");
|
||||
isok = PM3_EOPABORTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
params.on = true;
|
||||
params.delay_us = tearoff_start;
|
||||
handle_tearoff(¶ms, false);
|
||||
PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")" ms", 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:
|
||||
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 & 0xFFFF),
|
||||
.on = true,
|
||||
.off = false
|
||||
};
|
||||
|
||||
int res = handle_tearoff(¶ms, verbose);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Failed to configure tear off");
|
||||
isok = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
//read the data back
|
||||
|
||||
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);
|
||||
|
||||
// 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, 0x88, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read, false);
|
||||
|
||||
while (first_read == false) {
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(WARNING, "\naborted via keyboard.");
|
||||
isok = PM3_EOPABORTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -3087,26 +3247,103 @@ 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--;
|
||||
|
||||
// if there was an error reading repeat the tearoff with the same delay
|
||||
if (decrease && (tearoff_start > tearoff_increment) && (tearoff_start >= tearoff_original_start)) {
|
||||
tearoff_start -= tearoff_increment;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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, _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)"));
|
||||
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: ");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tear_success) { //tearoff succeeded
|
||||
|
||||
if (tear_success) { // tearoff succeeded with expected values
|
||||
|
||||
read_ok = true;
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success!"));
|
||||
PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read)));
|
||||
} else { //tearoff did not succeed
|
||||
PrintAndLogEx(FAILED, _RED_("Tear-off Failed!"));
|
||||
tearoff_start++;
|
||||
tear_success = true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (tearoff_sleep) {
|
||||
msleep(tearoff_sleep);
|
||||
}
|
||||
PrintAndLogEx(INFO, "---------------");
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
DropField();
|
||||
|
||||
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, "");
|
||||
PrintAndLogEx(INFO, "Done!");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
clearCommandBuffer();
|
||||
return isok;
|
||||
}
|
||||
|
||||
|
@ -3502,7 +3739,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);
|
||||
}
|
||||
|
@ -4255,7 +4491,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);
|
||||
|
@ -5530,7 +5766,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"},
|
||||
|
@ -5634,7 +5870,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))) {
|
||||
|
@ -5733,5 +5969,6 @@ int info_iclass(bool shallow_mod) {
|
|||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
@ -1607,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);
|
||||
}
|
||||
}
|
||||
|
@ -1617,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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -2013,7 +2013,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(INFO, "----------------------------------------------------------------------------\n");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>'") " to exit");
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------------\n");
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue