diff --git a/CHANGELOG.md b/CHANGELOG.md index aa7753fb3..b730df269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Added `LF_THAREXDE` standalone mode which simulates and reads EM4x50 cards (@tharexde) + - Added `hf jooki` commands (@iceman1001) - Changed `wiegand encode` - format param is now optional, w/o it will try encode all formats (@iceman1001) - Fix cppchecker warnings (@iceman1001) - Added `trace list -t mf` - now can use external dictionary keys file @@ -132,6 +133,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Change, use system Whereami library if available (@doegox) - Change, use system Zlib library if available (@doegox) - Fix release version information (@doegox) + - Fix `lf gallagher read` - now correctly decodes card data + - Add support to `lf gallagher clone` and `lf gallagher sim` for writing specific card region, facility, card & issue numbers (@DarkMatterMatt) ## [ice coffee.4.9237][2020-05-21] - Updated documentation (@doegox, @iceman1001) diff --git a/armsrc/Standalone/hf_aveful.c b/armsrc/Standalone/hf_aveful.c index c9464e3d1..475aadfec 100644 --- a/armsrc/Standalone/hf_aveful.c +++ b/armsrc/Standalone/hf_aveful.c @@ -191,7 +191,7 @@ void RunMod(void) { read_successful = false; break; } - // We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on hf_mfu_dumptoemulator + // We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on data_mfu_bin2eml // When converting a bin, it's almost all 0 other than one 0x0F byte, and functionality seems to be unaffected if that byte is set to 0x00. emlSetMem_xt(dataout, 14 + i, 1, 4); Dbhexdump(4, dataout, 0); diff --git a/armsrc/Standalone/lf_em4100emul.c b/armsrc/Standalone/lf_em4100emul.c index e23986ab7..b77f5e2e1 100644 --- a/armsrc/Standalone/lf_em4100emul.c +++ b/armsrc/Standalone/lf_em4100emul.c @@ -52,8 +52,8 @@ static void fill_buff(uint8_t bit) { static void construct_EM410x_emul(uint64_t id) { int i, j; - int binary[4] = {0,0,0,0}; - int parity[4] = {0,0,0,0}; + int binary[4] = {0, 0, 0, 0}; + int parity[4] = {0, 0, 0, 0}; buflen = 0; for (i = 0; i < 9; i++) diff --git a/armsrc/Standalone/lf_em4100rswb.c b/armsrc/Standalone/lf_em4100rswb.c index 060795bd1..27e288e23 100644 --- a/armsrc/Standalone/lf_em4100rswb.c +++ b/armsrc/Standalone/lf_em4100rswb.c @@ -100,8 +100,8 @@ static void fill_buff(uint8_t bit) { static void construct_EM410x_emul(uint64_t id) { int i, j; - int binary[4] = {0,0,0,0}; - int parity[4] = {0,0,0,0}; + int binary[4] = {0, 0, 0, 0}; + int parity[4] = {0, 0, 0, 0}; buflen = 0; for (i = 0; i < 9; i++) diff --git a/armsrc/Standalone/lf_em4100rwc.c b/armsrc/Standalone/lf_em4100rwc.c index 9240feb47..5df6e1a90 100644 --- a/armsrc/Standalone/lf_em4100rwc.c +++ b/armsrc/Standalone/lf_em4100rwc.c @@ -67,8 +67,8 @@ static void fill_buff(uint8_t bit) { static void construct_EM410x_emul(uint64_t id) { int i, j; - int binary[4] = {0,0,0,0}; - int parity[4] = {0,0,0,0}; + int binary[4] = {0, 0, 0, 0}; + int parity[4] = {0, 0, 0, 0}; buflen = 0; for (i = 0; i < 9; i++) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 33ea032de..6a6058d3b 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -50,7 +50,7 @@ #include "crc16.h" #ifdef WITH_LCD -#include "LCD.h" +#include "LCD_disabled.h" #endif #ifdef WITH_SMARTCARD diff --git a/armsrc/iclass.c b/armsrc/iclass.c index f31f17204..4d5975324 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1489,7 +1489,7 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint memcpy(cmd_check + 1, payload->key, 8); } else { - + uint8_t div_key[8] = {0}; if (payload->use_raw) memcpy(div_key, payload->key, 8); @@ -1885,7 +1885,7 @@ void iClass_WriteBlock(uint8_t *msg) { res = false; switch_off(); if (payload->req.send_reply) - reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t*)&res, sizeof(uint8_t)); + reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t)); return; } else { @@ -1927,7 +1927,7 @@ out: switch_off(); if (payload->req.send_reply) - reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t*)&res, sizeof(uint8_t)); + reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t)); } void iClass_Restore(iclass_restore_req_t *msg) { diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 759e5e646..999c5eded 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -916,18 +916,25 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) { uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; (void)b; - uint16_t check = 0; - + uint8_t flip = 0; + uint16_t checker = 0; for (;;) { - if (check == 4000) { -// if (BUTTON_PRESS() || data_available()) + WDT_HIT(); + if (flip == 2) { + if (data_available()) + return false; + + flip = 0; + } + + if (checker >= 4000) { if (BUTTON_PRESS()) return false; - check = 0; - WDT_HIT(); + flip++; + checker = 0; } - ++check; + ++checker; if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -1335,7 +1342,6 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data, uint8_t LED_A_ON(); // main loop - //for (;;) { bool finished = false; bool button_pushed = BUTTON_PRESS(); while (!button_pushed && !finished) { diff --git a/armsrc/lfops.c b/armsrc/lfops.c index f8652c44a..b4daed774 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1009,7 +1009,7 @@ void CmdFSKsimTAGEx(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t cl WDT_HIT(); - Dbprintf("Simulating with fcHigh: %d, fcLow: %d, clk: %d, STT: %d, n: %d", fchigh, fclow, clk, separator, n); + Dbprintf("FSK simulating with rf/%d, fc high %d, fc low %d, STT %d, n %d", clk, fchigh, fclow, separator, n); if (ledcontrol) LED_A_ON(); SimulateTagLowFrequencyEx(n, 0, ledcontrol, numcycles); @@ -1122,10 +1122,10 @@ void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t c WDT_HIT(); - Dbprintf("Simulating with clk: %d, invert: %d, encoding: %s (%d), separator: %d, n: %d" + Dbprintf("ASK simulating with rf/%d, invert %d, encoding %s (%d), separator %d, n %d" , clk , invert - , (encoding == 2) ? "BI" : (encoding == 1) ? "ASK" : "RAW" + , (encoding == 2) ? "ASK/BI" : (encoding == 1) ? "ASK/MAN" : "RAW/MAN" , encoding , separator , n @@ -1176,7 +1176,7 @@ void CmdPSKsimTAG(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, u WDT_HIT(); - Dbprintf("Simulating with Carrier: %d, clk: %d, invert: %d, n: %d", carrier, clk, invert, n); + Dbprintf("PSK simulating with rf/%d, fc/%d, invert %d, n %d", clk, carrier, invert, n); if (ledcontrol) LED_A_ON(); SimulateTagLowFrequency(n, 0, ledcontrol); @@ -1220,7 +1220,7 @@ void CmdNRZsimTAG(uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size, WDT_HIT(); - Dbprintf("Simulating with clk: %d, invert: %d, separator: %d, n: %d" + Dbprintf("NRZ simulating with rf/%d, invert %d, separator %d, n %d" , clk , invert , separator @@ -1251,20 +1251,13 @@ int lf_hid_watch(int findone, uint32_t *high, uint32_t *low) { BigBuf_Clear_keep_EM(); int res = PM3_SUCCESS; - uint16_t interval = 0; - while (BUTTON_PRESS() == false) { + for (;;) { WDT_HIT(); - // cancel w usb command. - if (interval == 4000) { - if (data_available()) { - res = PM3_EOPABORTED; - break; - } - interval = 0; - } else { - interval++; + if (data_available() || BUTTON_PRESS()) { + res = PM3_EOPABORTED; + break; } DoAcquisition_default(-1, false); @@ -1360,20 +1353,13 @@ int lf_awid_watch(int findone, uint32_t *high, uint32_t *low) { LFSetupFPGAForADC(LF_DIVISOR_125, true); int res = PM3_SUCCESS; - uint16_t interval = 0; - while (BUTTON_PRESS() == false) { + for (;;) { WDT_HIT(); - // cancel w usb command. - if (interval == 4000) { - if (data_available()) { - res = PM3_EOPABORTED; - break; - } - interval = 0; - } else { - interval++; + if (data_available() || BUTTON_PRESS()) { + res = PM3_EOPABORTED; + break; } DoAcquisition_default(-1, false); @@ -1465,19 +1451,12 @@ int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low) { LFSetupFPGAForADC(LF_DIVISOR_125, true); int res = PM3_SUCCESS; - uint16_t interval = 0; - while (BUTTON_PRESS() == false) { + for (;;) { WDT_HIT(); - // cancel w usb command. - if (interval == 4000) { - if (data_available()) { - res = PM3_EOPABORTED; - break; - } - interval = 0; - } else { - interval++; + if (data_available() || BUTTON_PRESS()) { + res = PM3_EOPABORTED; + break; } DoAcquisition_default(-1, false); @@ -1541,20 +1520,13 @@ int lf_io_watch(int findone, uint32_t *high, uint32_t *low) { LFSetupFPGAForADC(LF_DIVISOR_125, true); int res = PM3_SUCCESS; - uint16_t interval = 0; - while (BUTTON_PRESS() == false) { + for (;;) { WDT_HIT(); - // cancel w usb command. - if (interval == 4000) { - if (data_available()) { - res = PM3_EOPABORTED; - break; - } - interval = 0; - } else { - interval++; + if (data_available() || BUTTON_PRESS()) { + res = PM3_EOPABORTED; + break; } DoAcquisition_default(-1, false); diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index ef1d128cc..f45fe8920 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -73,11 +73,11 @@ void printSamples(void) { void setSamplingConfig(sample_config *sc) { // decimation (1-8) how many bits of adc sample value to save - if (sc->decimation > 0 && sc->decimation < 8) + if (sc->decimation > 0 && sc->decimation < 9) config.decimation = sc->decimation; // bits per sample (1-8) - if (sc->bits_per_sample > 0 && sc->bits_per_sample < 8) + if (sc->bits_per_sample > 0 && sc->bits_per_sample < 9) config.bits_per_sample = sc->bits_per_sample; // diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 8fc747a97..e22ab64c7 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -68,7 +68,7 @@ uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { // send X byte basic commands int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) { - + uint8_t dcmd[data_size + 3]; dcmd[0] = cmd; if (data_size > 0) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index ddfd288b2..b7c56f881 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -242,6 +242,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdhffelica.c ${PM3_ROOT}/client/src/cmdhffido.c ${PM3_ROOT}/client/src/cmdhficlass.c + ${PM3_ROOT}/client/src/cmdhfjooki.c ${PM3_ROOT}/client/src/cmdhflegic.c ${PM3_ROOT}/client/src/cmdhflist.c ${PM3_ROOT}/client/src/cmdhflto.c diff --git a/client/Makefile b/client/Makefile index a756a2ede..ab26f970e 100644 --- a/client/Makefile +++ b/client/Makefile @@ -474,6 +474,7 @@ SRCS = aiddesfire.c \ cmdhffido.c \ cmdhficlass.c \ cmdhflegic.c \ + cmdhfjooki.c \ cmdhflist.c \ cmdhflto.c \ cmdhfmf.c \ diff --git a/client/deps/hardnested/hardnested_bf_core.c b/client/deps/hardnested/hardnested_bf_core.c index e856d26e1..0f9eb3da8 100644 --- a/client/deps/hardnested/hardnested_bf_core.c +++ b/client/deps/hardnested/hardnested_bf_core.c @@ -579,7 +579,7 @@ static SIMDExecInstr GetSIMDInstr(void) { instr = SIMD_MMX; else #endif - instr = SIMD_NONE; + instr = SIMD_NONE; return instr; } diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index 9f716608a..21319bc3e 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -1283,4 +1283,13 @@ AABAFFCC7612 17D071403C20 # 534F4C415249 -534f4c303232 \ No newline at end of file +534f4c303232 +# +# Nespresso, smart card +# key-gen algo, these keys are for one card +ff9a84635bd2 +6f30126ee7e4 +6039abb101bb +f1a1239a4487 +# +b882fd4a9f78 diff --git a/client/luascripts/data_mf_bin2eml.lua b/client/luascripts/data_mf_bin2eml.lua index ef48ead16..8312fc292 100644 --- a/client/luascripts/data_mf_bin2eml.lua +++ b/client/luascripts/data_mf_bin2eml.lua @@ -6,7 +6,7 @@ local ansicolors = require('ansicolors') copyright = '' author = 'Martin Holst Swende' -version = 'v1.0.2' +version = 'v1.0.3' desc = [[ This script takes a dumpfile from 'hf mf dump' and converts it to a format that can be used by the emulator @@ -46,7 +46,7 @@ end --- -- This is only meant to be used when errors occur local function oops(err) - print('ERROR:', err) + print('[!!] ERROR:', err) core.clearCommandBuffer() return nil, err end @@ -134,7 +134,7 @@ local function main(args) outfile:write(dumpdata:lower()) io.close(outfile) - print(('Wrote an emulator-dump to the file %s'):format(output)) + print(('[+] Wrote an emulator-dump to the file %s'):format(output)) end diff --git a/client/luascripts/data_mf_bin2html.lua b/client/luascripts/data_mf_bin2html.lua index c33b4782b..f412a35e7 100644 --- a/client/luascripts/data_mf_bin2html.lua +++ b/client/luascripts/data_mf_bin2html.lua @@ -7,7 +7,7 @@ local ansicolors = require('ansicolors') copyright = '' author = 'Martin Holst Swende' -version = 'v1.0.2' +version = 'v1.0.3' desc =[[ This script takes a dumpfile and produces a html based dump, which is a bit more easily analyzed. @@ -45,7 +45,7 @@ end --- -- This is only meant to be used when errors occur local function oops(err) - print('ERROR:', err) + print('[!!] ERROR:', err) core.clearCommandBuffer() return nil, err end @@ -76,7 +76,7 @@ local function main(args) local filename, err = dumplib.convert_bin_to_html(input,output, 16) if err then return oops(err) end - print(('Wrote a HTML dump to the file %s'):format(filename)) + print(('[+] Wrote a HTML dump to the file %s'):format(filename)) end --[[ diff --git a/client/luascripts/data_mf_eml2bin.lua b/client/luascripts/data_mf_eml2bin.lua index d31b58418..4291f13b9 100644 --- a/client/luascripts/data_mf_eml2bin.lua +++ b/client/luascripts/data_mf_eml2bin.lua @@ -5,7 +5,7 @@ local ansicolors = require('ansicolors') copyright = '' author = 'Iceman' -version = 'v1.0.2' +version = 'v1.0.3' desc =[[ This script takes an dumpfile in EML (ASCII) format and converts it to the PM3 dumpbin file to be used with `hf mf restore` ]] @@ -40,7 +40,7 @@ end --- -- This is only meant to be used when errors occur local function oops(err) - print('ERROR:', err) + print('[!!] ERROR:', err) core.clearCommandBuffer() return nil, err end @@ -82,7 +82,7 @@ local function main(args) local filename, err = dumplib.convert_eml_to_bin(input,output) if err then return oops(err) end - ExitMsg(('Wrote a BIN dump to the file %s'):format(filename)) + ExitMsg(('[+] Wrote a BIN dump to the file %s'):format(filename)) end main(args) diff --git a/client/luascripts/data_mf_eml2html.lua b/client/luascripts/data_mf_eml2html.lua index 9b2edbe87..a77e7a6d3 100644 --- a/client/luascripts/data_mf_eml2html.lua +++ b/client/luascripts/data_mf_eml2html.lua @@ -7,7 +7,7 @@ local ansicolors = require('ansicolors') copyright = '' author = 'Martin Holst Swende' -version = 'v1.0.2' +version = 'v1.0.3' desc = [[ This script takes a dumpfile on EML (ASCII) format and produces a html based dump, which is a bit more easily analyzed. @@ -44,7 +44,7 @@ end --- -- This is only meant to be used when errors occur local function oops(err) - print('ERROR:', err) + print('[!!] ERROR:', err) core.clearCommandBuffer() return nil, err end @@ -75,7 +75,7 @@ local function main(args) local filename, err = dumplib.convert_eml_to_html(input,output) if err then return oops(err) end - print(('Wrote a HTML dump to the file %s'):format(filename)) + print(('[+] Wrote a HTML dump to the file %s'):format(filename)) end --[[ diff --git a/client/luascripts/hf_mfu_dumptoemulator.lua b/client/luascripts/data_mfu_bin2eml.lua similarity index 94% rename from client/luascripts/hf_mfu_dumptoemulator.lua rename to client/luascripts/data_mfu_bin2eml.lua index 47f52e135..eeece3b7c 100644 --- a/client/luascripts/hf_mfu_dumptoemulator.lua +++ b/client/luascripts/data_mfu_bin2eml.lua @@ -6,16 +6,16 @@ local ansicolors = require('ansicolors') copyright = '' author = "Martin Holst Swende \n @Marshmellow \n @iceman" -version = 'v1.0.2' +version = 'v1.0.4' desc =[[ This script takes a dumpfile from 'hf mfu dump' and converts it to a format that can be used by the emulator ]] example = [[ - script run hf_mfu_dumptoemulator -i dumpdata-foobar.bin + script run data_mfu_bin2eml -i dumpdata-foobar.bin ]] usage = [[ -script run hf_mfu_dumptoemulator [-i ] [-o ] +script run data_mfu_bin2eml [-i ] [-o ] ]] arguments = [[ -h This help @@ -43,7 +43,7 @@ end --- -- This is only meant to be used when errors occur local function oops(err) - print('ERROR:', err) + print('[!!] ERROR:', err) core.clearCommandBuffer() return nil, err end @@ -133,7 +133,7 @@ local function main(args) outfile:write(dumpdata:lower()) io.close(outfile) - print(('Wrote an emulator-dump to the file %s'):format(output)) + print(('[+] Wrote an emulator-dump to the file %s'):format(output)) end --[[ diff --git a/client/resources/mad.json b/client/resources/mad.json index c63190cda..aae377af8 100644 --- a/client/resources/mad.json +++ b/client/resources/mad.json @@ -4749,14 +4749,14 @@ "application": "Security and Access Control", "company": "PEC (New Zealand) Ltd.", "mad": "0x4811", - "service_provider": "Cardax", + "service_provider": "Cardax / Gallagher", "system_integrator": "" }, { "application": "Security and Access Control", "company": "PEC (New Zealand) Ltd.", "mad": "0x4812", - "service_provider": "Cardax", + "service_provider": "Cardax / Gallagher", "system_integrator": "" }, { diff --git a/client/src/cmdanalyse.c b/client/src/cmdanalyse.c index 5f6860e95..eb83fdc9c 100644 --- a/client/src/cmdanalyse.c +++ b/client/src/cmdanalyse.c @@ -13,6 +13,7 @@ #include #include // tolower #include +#include // PRIx64 macro #include "commonutil.h" // reflect... #include "comms.h" // clearCommandBuffer #include "cmdparser.h" // command_t @@ -550,6 +551,13 @@ static int CmdAnalyseA(const char *Cmd) { PrintAndLogEx(FAILED, "Error parsing bytes"); return PM3_EINVARG; } + + uint64_t key = 0; + res = mfc_algo_touch_one(data, 0, 0, &key); + if (res == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "KEY A | %012" PRIx64, key); + } + CLIParserFree(ctx); return PM3_SUCCESS; diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 90a3b3ebf..2bc6edbfe 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -25,6 +25,7 @@ #include "cmdhfemrtd.h" // eMRTD #include "cmdhflegic.h" // LEGIC #include "cmdhficlass.h" // ICLASS +#include "cmdhfjooki.h" // MFU based Jooki #include "cmdhfmf.h" // CLASSIC #include "cmdhfmfu.h" // ULTRALIGHT/NTAG etc #include "cmdhfmfp.h" // Mifare Plus @@ -397,6 +398,7 @@ static command_t CommandTable[] = { {"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"}, {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"}, {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, + {"jooki", CmdHF_Jooki, AlwaysAvailable, "{ Jooki RFIDs... }"}, {"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"}, {"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"}, {"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"}, diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index e772d406e..a2212005f 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -1422,7 +1422,8 @@ typedef enum { MTDESFIRE = 4, MTPLUS = 8, MTULTRALIGHT = 16, - MTOTHER = 32 + HID_SEOS = 32, + MTOTHER = 64 } nxp_mifare_type_t; // Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1 @@ -1525,11 +1526,17 @@ static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) { type |= MTPLUS; } } else { - printTag("MIFARE Plus EV1 2K/4K in SL3"); - printTag("MIFARE Plus S 2K/4K in SL3"); - printTag("MIFARE Plus X 2K/4K in SL3"); - printTag("MIFARE Plus SE 1K"); - type |= MTPLUS; + + if ((atqa & 0x0001) == 0x0001) { + printTag("HID SEOS (smartmx / javacard)"); + type |= HID_SEOS; + } else { + printTag("MIFARE Plus EV1 2K/4K in SL3"); + printTag("MIFARE Plus S 2K/4K in SL3"); + printTag("MIFARE Plus X 2K/4K in SL3"); + printTag("MIFARE Plus SE 1K"); + type |= MTPLUS; + } } printTag("NTAG 4xx"); @@ -1634,6 +1641,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { bool isMifarePlus = false; bool isMifareUltralight = false; bool isST = false; + bool isEMV = false; int nxptype = MTNONE; if (card.uidlen <= 4) { @@ -2048,6 +2056,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (verbose) PrintAndLogEx(SUCCESS, "----------------------------------------------------"); found = true; + isEMV = true; } } @@ -2097,15 +2106,18 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (isMifareUltralight) PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu info`")); - if (isMifarePlus && isMagic == 0) + if (isMifarePlus && isMagic == 0 && isEMV == false) PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfp info`")); - if (isMifareDESFire && isMagic == 0) + if (isMifareDESFire && isMagic == 0 && isEMV == false) PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`")); if (isST) PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf st info`")); + if (isEMV) + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`emv search -s`")); + PrintAndLogEx(NORMAL, ""); DropField(); return select_status; @@ -2309,7 +2321,7 @@ static command_t CommandTable[] = { {"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"}, {"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"}, {"config", CmdHf14AConfig, IfPm3Iso14443a, "Configure 14a settings (use with caution)"}, - {"apdufind", CmdHf14AFindapdu, IfPm3Iso14443a, "Enuerate APDUs - CLA/INS/P1P2"}, + {"apdufind", CmdHf14AFindapdu, IfPm3Iso14443a, "Enumerate APDUs - CLA/INS/P1P2"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 4de6ddd12..ee73e62b5 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -202,7 +202,7 @@ static bool wait_cmd_14b(bool verbose, bool is_select) { (crc) ? _GREEN_("ok") : _RED_("fail") ); } else if (len == 0) { - PrintAndLogEx(INFO, "no response from tag"); + PrintAndLogEx(INFO, "no response from tag"); } else { PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len)); } diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 604beb68c..229f84dee 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1338,19 +1338,26 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) { // Determine and print the document type if (mrz[0] == 'I' && mrz[1] == 'P') { - td_variant = 1; PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport Card")); } else if (mrz[0] == 'I') { - td_variant = 1; PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("ID Card")); } else if (mrz[0] == 'P') { - td_variant = 3; PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport")); + } else if (mrz[0] == 'A') { + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("German Residency Permit")); } else { - td_variant = 1; PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Unknown")); - PrintAndLogEx(INFO, "Assuming ID-style MRZ."); } + + if (mrzlen == 90) { + td_variant = 1; + } else if (mrzlen == 88) { + td_variant = 3; + } else { + PrintAndLogEx(ERR, "MRZ length (%zu) is wrong.", mrzlen); + return PM3_ESOFT; + } + PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant); // Print the MRZ diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c new file mode 100644 index 000000000..352c61ae7 --- /dev/null +++ b/client/src/cmdhfjooki.c @@ -0,0 +1,518 @@ +//----------------------------------------------------------------------------- +// Ultralight Code (c) 2021 Iceman +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency MIFARE ULTRALIGHT / Jooki commands +//----------------------------------------------------------------------------- +#include "cmdhfjooki.h" +#include +#include // memset +#include "commonutil.h" // ARRAYLEN +#include "ui.h" // PrintAndLog +#include "cmdparser.h" +#include "generator.h" +#include "base64.h" +#include "mifare/ndef.h" // print decode ndef +#include "mifare/mifarehost.h" // mfemlsetmem_xt +#include "cliparser.h" +#include "cmdhfmfu.h" +#include "cmdmain.h" +#include "fileutils.h" // convert_mfu.. + + +static int CmdHelp(const char *Cmd); + +typedef struct { + uint8_t uid[7]; + const char b64[17]; + uint8_t tagtype; +} PACKED jooki_t; + +// sample set for selftest. +jooki_t jooks[] = { + { {0x04, 0xDA, 0xB7, 0x6A, 0xE7, 0x4C, 0x80}, "ruxow8lnn88uyeX+", 0x00}, + { {0x04, 0xf0, 0x22, 0xc2, 0x33, 0x5e, 0x80}, "\0" , 0x00}, + { {0x04, 0x8C, 0xEC, 0xDA, 0xF0, 0x4A, 0x80}, "ONrsVf7jX6IaSNV6", 0x01}, + { {0x04, 0x92, 0xA7, 0x6A, 0xE7, 0x4C, 0x81}, "Hjjpcx/mZwuveTF+", 0x02}, + { {0x04, 0xD0, 0xB0, 0x3A, 0xD3, 0x63, 0x80}, "\0", 0x02}, + { {0x04, 0x96, 0x42, 0xDA, 0xF0, 0x4A, 0x80}, "vEWy0WO9wZNEzEok", 0x03}, + { {0x04, 0x33, 0xb5, 0x62, 0x39, 0x4d, 0x80}, "\0", 0x03}, + { {0x04, 0x17, 0xB7, 0x3A, 0xD3, 0x63, 0x81}, "f0axEma+g2WnLGAm", 0x05}, + { {0x04, 0x84, 0x27, 0x6A, 0xE7, 0x4C, 0x80}, "VZB/OLBwOiM5Mpnp", 0x05}, + { {0x04, 0x28, 0xF4, 0xDA, 0xF0, 0x4A, 0x81}, "7WzlgEzqLgwTnWNy", 0x05}, +}; + +const char *jooks_figures[] = {"Dragon", "Fox", "Ghost", "Knight", "?", "Whale"}; +const uint8_t jooki_secret[] = {0x20, 0x20, 0x20, 0x6D, 0x24, 0x0B, 0xEB, 0x94, 0x2C, 0x80, 0x45, 0x16}; +const uint8_t NFC_SECRET[] = { 0x03, 0x9c, 0x25, 0x6f, 0xb9, 0x2e, 0xe8, 0x08, 0x09, 0x83, 0xd9, 0x33, 0x56}; + +#define JOOKI_UID_LEN 7 +#define JOOKI_IV_LEN 4 +#define JOOKI_B64_LEN (16 + 1) +#define JOOKI_PLAIN_LEN 12 + +static int jooki_encode(uint8_t *iv, uint8_t tagtype, uint8_t *uid, uint8_t *out) { + if (out == NULL) { + PrintAndLogEx(ERR, "(encode jooki) base64ndef param is NULL"); + return PM3_EINVARG; + } + + out[0] = 0x00; + if (iv == NULL || uid == NULL) { + PrintAndLogEx(ERR, "(encode jooki) iv or uid param is NULL"); + return PM3_EINVARG; + } + + uint8_t d[JOOKI_PLAIN_LEN] = {iv[0], iv[1],iv[2], iv[3], tagtype, uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]}; + uint8_t enc[JOOKI_PLAIN_LEN] = {0}; + for (uint8_t i = 0; i < JOOKI_PLAIN_LEN; i++) { + + if (i < 3) + enc[i] = d[i] ^ NFC_SECRET[i]; + else + enc[i] = d[i] ^ NFC_SECRET[i] ^ d[i % 3]; + } + + PrintAndLogEx(DEBUG, "encoded result.... %s", sprint_hex(enc, sizeof(enc))); + + size_t b64len = 0; + uint8_t b64[20]; + memset(b64, 0, 20); + mbedtls_base64_encode(b64, sizeof(b64), &b64len, (const unsigned char*)enc, sizeof(enc)); + memcpy(out, b64, b64len); + return PM3_SUCCESS; +} + +static int jooki_decode(uint8_t *b64, uint8_t *result) { + uint8_t ndef[JOOKI_PLAIN_LEN] = {0}; + size_t outputlen = 0; + mbedtls_base64_decode(ndef, sizeof(ndef), &outputlen, (const unsigned char*)b64, 16); + + PrintAndLogEx(DEBUG, "(decode_jooki) raw encoded... " _GREEN_("%s"), sprint_hex(ndef, sizeof(ndef))); + + for (uint8_t i = 0; i < JOOKI_PLAIN_LEN; i++) { + if (i < 3) + result[i] = ndef[i] ^ NFC_SECRET[i]; + else + result[i] = ndef[i] ^ NFC_SECRET[i] ^ ndef[i % 3] ^ NFC_SECRET[i % 3]; + } + PrintAndLogEx(DEBUG, "(decode_jooki) plain......... %s", sprint_hex(result, sizeof(ndef))); + return PM3_SUCCESS; +} + +static int jooki_create_ndef(uint8_t *b64ndef, uint8_t *ndefrecord) { + // sample of url: https://s.jooki.rocks/s/?s=ONrsVf7jX6IaSNV6 + if (ndefrecord == NULL) { + PrintAndLogEx(ERR, "(jooki_create_ndef) ndefrecord param is NULL"); + return PM3_EINVARG; + } + memcpy(ndefrecord, + "\x01\x03\xa0\x0c\x34\x03\x29\xd1" + "\x01\x25\x55\x04\x73\x2e\x6a\x6f" + "\x6f\x6b\x69\x2e\x72\x6f\x63\x6b" + "\x73\x2f\x73\x2f\x3f\x73\x3d", 31); + memcpy(ndefrecord + 31, b64ndef, 16); + memcpy(ndefrecord + 47, "\x0a\xFE\x00\x00\x00", 5); + return PM3_SUCCESS; +} + +static void jooki_printEx(uint8_t *b64, uint8_t *iv, uint8_t tt, uint8_t *uid, bool verbose) { + PrintAndLogEx(INFO, "Encoded URL.. %s ( %s )", sprint_hex(b64, 12), b64); + PrintAndLogEx(INFO, "Figurine..... %02x - " _GREEN_("%s"), tt, jooks_figures[tt]); + PrintAndLogEx(INFO, "iv........... %s", sprint_hex(iv, JOOKI_IV_LEN)); + PrintAndLogEx(INFO, "uid.......... %s", sprint_hex(uid, JOOKI_UID_LEN)); + + uint8_t ndefmsg[52] = {0}; + jooki_create_ndef(b64, ndefmsg); + PrintAndLogEx(INFO, "NDEF raw..... %s", sprint_hex_inrow(ndefmsg, sizeof(ndefmsg))); + + if (verbose) { + int res = NDEFRecordsDecodeAndPrint(ndefmsg, sizeof(ndefmsg)); + if (res != PM3_SUCCESS) { + NDEFDecodeAndPrint(ndefmsg, sizeof(ndefmsg), verbose); + } + } +} + +static void jooki_print(uint8_t *b64, uint8_t *result, bool verbose) { + if (b64 == NULL || result == NULL) + return; + + uint8_t iv[JOOKI_IV_LEN] = {0}; + uint8_t uid[JOOKI_UID_LEN] = {0}; + memcpy(iv, result, sizeof(iv)); + uint8_t tt = result[4]; + memcpy(uid, result + 5, sizeof(uid)); + + jooki_printEx(b64, iv, tt, uid, verbose); +} + +static int jooki_selftest(void) { + + PrintAndLogEx(INFO, "======== " _CYAN_("selftest") " ==========================================="); + for (int i = 0; i < ARRAYLEN(jooks); i++) { + if (strlen(jooks[i].b64) == 0) + continue; + + uint8_t iv[JOOKI_IV_LEN] = {0}; + uint8_t uid[JOOKI_UID_LEN] = {0}; + uint8_t result[JOOKI_PLAIN_LEN] = {0}; + jooki_decode((uint8_t*)jooks[i].b64, result); + + memcpy(iv, result, 4); + uint8_t tt = result[4]; + memcpy(uid, result + 5, sizeof(uid)); + + bool tt_ok = (tt == jooks[i].tagtype); + bool uid_ok = (memcmp(uid, jooks[i].uid, sizeof(uid)) == 0); + + PrintAndLogEx(INFO, "Encoded URL.. %s ( %s )", sprint_hex((const uint8_t*)jooks[i].b64, 12), jooks[i].b64); + PrintAndLogEx(INFO, "Figurine..... %02x - " _GREEN_("%s") " ( %s )", tt, jooks_figures[tt], tt_ok ? _GREEN_("ok") : _RED_("fail")); + PrintAndLogEx(INFO, "iv........... %s", sprint_hex(iv, sizeof(iv))); + PrintAndLogEx(INFO, "uid.......... %s ( %s )", sprint_hex(uid, sizeof(uid)), uid_ok ? _GREEN_("ok") : _RED_("fail")); + + uint8_t b64[JOOKI_B64_LEN] = {0}; + memset(b64, 0, sizeof(b64)); + jooki_encode(iv, tt, uid, b64); + + uint8_t ndefmsg[52] = {0}; + jooki_create_ndef(b64, ndefmsg); + PrintAndLogEx(INFO, "NDEF raw .... %s", sprint_hex(ndefmsg, sizeof(ndefmsg))); + + int status = NDEFRecordsDecodeAndPrint(ndefmsg, sizeof(ndefmsg)); + if ( status != PM3_SUCCESS) { + status = NDEFDecodeAndPrint(ndefmsg, sizeof(ndefmsg), true); + } + PrintAndLogEx(INFO, "=================================================================="); + } + return PM3_SUCCESS; +} + +static int CmdHF14AJookiEncode(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf jooki encode", + "Encode a Jooki token to base64 NDEF URI format", + "hf jooki encode -t --> selftest\n" + "hf jooki encode -r --dragon --> read uid from tag and use for encoding\n" + "hf jooki encode --uid 04010203040506 --dragon" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("u", "uid", "", "uid bytes"), + arg_lit0("r", NULL, "read uid from tag instead"), + arg_lit0("t", NULL, "selftest"), + arg_lit0("v", "verbose", "verbose output"), + arg_lit0(NULL, "dragon", "tag type"), + arg_lit0(NULL, "fox", "tag type"), + arg_lit0(NULL, "ghost", "tag type"), + arg_lit0(NULL, "knight", "tag type"), + arg_lit0(NULL, "whale", "tag type"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + int ulen = 0; + uint8_t uid[JOOKI_UID_LEN] = {0x00}; + memset(uid, 0x0, sizeof(uid)); + int res = CLIParamHexToBuf(arg_get_str(ctx, 1), uid, sizeof(uid), &ulen); + if (res) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + + bool use_tag = arg_get_lit(ctx, 2); + bool selftest = arg_get_lit(ctx, 3); + bool verbose = arg_get_lit(ctx, 4); + bool tt_dragon = arg_get_lit(ctx, 5); + bool tt_fox = arg_get_lit(ctx, 6); + bool tt_ghost = arg_get_lit(ctx, 7); + bool tt_knight = arg_get_lit(ctx, 8); + bool tt_whale = arg_get_lit(ctx, 9); + CLIParserFree(ctx); + + if (selftest) { + return jooki_selftest(); + } + + if ((tt_dragon + tt_fox + tt_ghost + tt_knight + tt_whale) > 1) { + PrintAndLogEx(ERR, "Select one tag type"); + return PM3_EINVARG; + } + uint8_t tt = 0; + if (tt_fox) + tt = 1; + if (tt_ghost) + tt = 2; + if (tt_knight) + tt = 3; + if (tt_whale) + tt = 5; + + uint8_t iv[JOOKI_IV_LEN] = {0x80, 0x77, 0x51, 1}; + if (use_tag) { + res = ul_read_uid(uid); + if (res != PM3_SUCCESS) { + return res; + } + } else { + if (ulen != JOOKI_UID_LEN) { + PrintAndLogEx(ERR, "Wrong length of UID, expect %u, got %d", JOOKI_UID_LEN, ulen); + return PM3_EINVARG; + } + } + + uint8_t b64[JOOKI_B64_LEN] = {0}; + memset(b64, 0, sizeof(b64)); + jooki_encode(iv, tt, uid, b64); + jooki_printEx(b64, iv, tt, uid, verbose); + return PM3_SUCCESS; +} + +static int CmdHF14AJookiDecode(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf jooki decode", + "Decode a base64-encode Jooki token in NDEF URI format", + "hf jooki decode -d 7WzlgEzqLgwTnWNy" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("d", "data", "", "base64 url parameter"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + int dlen = 16; + uint8_t b64[JOOKI_B64_LEN] = {0x00}; + memset(b64, 0x0, sizeof(b64)); + CLIGetStrWithReturn(ctx, 1, b64, &dlen); + bool verbose = arg_get_lit(ctx, 2); + CLIParserFree(ctx); + + uint8_t result[JOOKI_PLAIN_LEN] = {0}; + int res = jooki_decode(b64, result); + if (res == PM3_SUCCESS) { + jooki_print(b64, result, verbose); + } + return PM3_SUCCESS; +} + +static int CmdHF14AJookiSim(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf jooki sim", + "Simulate a Jooki token. Either `hf mfu eload` before or use `-d` param", + "hf jooki sim --> using eload before\n" + "hf jooki sim -d 7WzlgEzqLgwTnWNy" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("d", "data", "", "base64 url parameter"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + int dlen = 16; + uint8_t b64[JOOKI_B64_LEN] = {0x00}; + memset(b64, 0x0, sizeof(b64)); + CLIGetStrWithReturn(ctx, 1, b64, &dlen); + CLIParserFree(ctx); + + uint8_t result[JOOKI_PLAIN_LEN] = {0}; + int res = jooki_decode(b64, result); + if (res != PM3_SUCCESS) { + return res; + } + + jooki_print(b64, result, false); + + // hf mfu sim... + uint8_t *data = calloc(144, sizeof(uint8_t)); + + // copy UID from base64 url parameter + memcpy(data, result + 5, 3); + // bbc0 + data[3] = 0x88 ^ data[0] ^ data[1] ^ data[2]; + + memcpy(data + (1*4), result + 8, 4); + // bbc1 + data[8] = data[4] ^ data[5] ^ data[6] ^ data[7]; + + // copy NDEF magic firs, skip BBC1 + memcpy(data + (2*4) + 1, "\x48\x00\x00\xE1\x10\x12\x00", 7); + + // copy raw NDEF + jooki_create_ndef(b64, data + (4 * 4)); + + // convert plain or old mfu format to new format + size_t datalen = 144; + res = convert_mfu_dump_format(&data, &datalen, true); + if (res != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Failed convert on load to new Ultralight/NTAG format"); + free(data); + return res; + } + + mfu_dump_t *mfu_dump = (mfu_dump_t *)data; + + + memcpy(mfu_dump->version, "\x00\x04\x04\x02\x01\x00\x0F\x03", 8); + mfu_dump->counter_tearing[2][3] = 0xBD; + mfu_dump->pages = 0x2c; + + printMFUdumpEx(mfu_dump, mfu_dump->pages + 1, 0); + + // upload to emulator memory + PrintAndLogEx(INFO, "Uploading to emulator memory"); + + PrintAndLogEx(INFO, "." NOLF); + // fast push mode + conn.block_after_ACK = true; + uint8_t blockwidth = 4, counter = 0, blockno = 0; + while (datalen) { + if (datalen == blockwidth) { + // Disable fast mode on last packet + conn.block_after_ACK = false; + } + + if (mfEmlSetMem_xt(data + counter, blockno, 1, blockwidth) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Cant set emul block: %3d", blockno); + free(data); + return PM3_ESOFT; + } + PrintAndLogEx(NORMAL, "." NOLF); + fflush(stdout); + blockno++; + counter += blockwidth; + datalen -= blockwidth; + } + PrintAndLogEx(NORMAL, "\n"); + + struct { + uint8_t tagtype; + uint8_t flags; + uint8_t uid[10]; + uint8_t exitAfter; + } PACKED payload; + + // NTAG, 7 byte UID in eloaded data. + payload.tagtype = 7; + payload.flags = FLAG_7B_UID_IN_DATA; + payload.exitAfter = 0; + + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + + PrintAndLogEx(INFO, "Press " _GREEN_("") " or pm3-button to abort simulation"); + for (;;) { + if (kbd_enter_pressed()) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + PrintAndLogEx(DEBUG, "User aborted"); + break; + } + + if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) + continue; + + if (resp.status != PM3_SUCCESS) + break; + } + free(data); + PrintAndLogEx(INFO, "Done"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14a list") "` to view trace log" ); + return PM3_SUCCESS; +} + +static int CmdHF14AJookiWrite(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf jooki write", + "Write a Jooki token to a Ultralight or NTAG tag", + "hf jooki write -d xxxxxxxx -> where x is raw NDEF from encode command" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("d", "data", "", "bytes"), + arg_str0("p", "pwd", "", "password for authentication (EV1/NTAG 4 bytes)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + int dlen = 0; + uint8_t data[52] = {0x00}; + memset(data, 0x0, sizeof(data)); + int res = CLIParamHexToBuf(arg_get_str(ctx, 1), data, sizeof(data), &dlen); + if (res) { + CLIParserFree(ctx); + PrintAndLogEx(FAILED, "Error parsing bytes"); + return PM3_EINVARG; + } + + + int plen = 0; + uint8_t pwd[4] = {0x00}; + CLIGetHexWithReturn(ctx, 2, pwd, &plen); + + CLIParserFree(ctx); + + if (dlen != 52) { + PrintAndLogEx(ERR, "Wrong data length. Expected 52 got %d", dlen); + return PM3_EINVARG; + } + + bool has_pwd = false; + if (plen == 4) { + has_pwd = true; + } + + // 0 - no authentication + // 2 - pwd (4 bytes) + uint8_t keytype = 0, blockno = 4, i = 0; + + while ((i * 4) < dlen) { + + uint8_t cmddata[8] = {0}; + memcpy(cmddata, data + (i * 4), 4); + if (has_pwd) { + memcpy(cmddata + 4, pwd, 4); + keytype = 2; + } + clearCommandBuffer(); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, blockno, keytype, 0, cmddata, sizeof(cmddata)); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + uint8_t isOK = resp.oldarg[0] & 0xff; + PrintAndLogEx(SUCCESS, "Write block %d ( %s )", blockno, isOK ? _GREEN_("ok") : _RED_("fail")); + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + } + + blockno++; + i++; + } + + return PM3_SUCCESS; +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"encode", CmdHF14AJookiEncode, AlwaysAvailable, "Encode Jooki token"}, + {"decode", CmdHF14AJookiDecode, AlwaysAvailable, "Decode Jooki token"}, + {"sim", CmdHF14AJookiSim, IfPm3Iso14443a, "Simulate Jooki token"}, + {"write", CmdHF14AJookiWrite, IfPm3Iso14443a, "Write a Jooki token"}, + + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdHF_Jooki(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/src/cmdhfjooki.h b/client/src/cmdhfjooki.h new file mode 100644 index 000000000..ac3ecc3af --- /dev/null +++ b/client/src/cmdhfjooki.h @@ -0,0 +1,16 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2021 iceman1001 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency ISO14443A / MFU / Jooki commands +//----------------------------------------------------------------------------- + +#ifndef CMDHFJOOKI_H__ +#define CMDHFJOOKI_H__ + +#include "common.h" +int CmdHF_Jooki(const char *Cmd); +#endif diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index f5222fb9a..fa9b29b18 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3983,6 +3983,63 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHF14ADesBruteApps(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes bruteaid", + "Recover AIDs by bruteforce.\n" + "WARNING: This command takes a long time", + "hf mfdes bruteaid -> Search all apps\n" + "hf mfdes bruteaid -s F0000F -i 16 -> Search MAD range manually"); + + void *argtable[] = { + arg_param_begin, + arg_strx0("s", "start", "", "Starting App ID as hex bytes (3 bytes,big endian)"), + arg_strx0("e", "end", "", "Last App ID as hex bytes (3 bytes,big endian)"), + arg_int0("i", "step", "", "Increment step when bruteforcing (decimal integer)"), + arg_lit0("m", "mad", "Only bruteforce the MAD range"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint8_t startAid[3] = {0}; + uint8_t endAid[3] = {0xFF, 0xFF, 0xFF}; + int startLen = 0; + int endLen = 0; + CLIGetHexWithReturn(ctx, 1, startAid, &startLen); + CLIGetHexWithReturn(ctx, 2, endAid, &endLen); + uint32_t idIncrement = arg_get_int_def(ctx, 3, 1); + bool mad = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + // TODO: We need to check the tag version, EV1 should stop after 26 apps are found + if (mad) { + idIncrement = 0x10; + startAid[0] = 0xF0; + startAid[1] = 0x00; + startAid[2] = 0x0F; + } + uint32_t idStart = le24toh(startAid); + uint32_t idEnd = le24toh(endAid); + PrintAndLogEx(INFO, "Enumerating through all AIDs manually, this will take a while!"); + for (uint32_t id = idStart; id <= idEnd && id >= idStart; id += idIncrement) { + if (kbd_enter_pressed()) break; + int progress = ((id - idStart) * 100) / ((idEnd - idStart)); + PrintAndLogEx(INPLACE, "Progress: %d %%, current AID: %06X", progress, id); + uint8_t appId[3] = {0}; + htole24(id, appId); + sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, appId}; //0x5a + uint16_t sw = 0; + uint8_t data[255 * 5] = {0x00}; + uint32_t resplen = 0; + DESFIRESendApdu(!tag->rf_field_on, true, apdu, data, sizeof(data), &resplen, &sw); + if (sw == status(MFDES_S_OPERATION_OK)) { + printf("\33[2K\r"); // clear current line before printing + PrintAndLogEx(SUCCESS, "Got new APPID %06X", id); + } + } + PrintAndLogEx(SUCCESS, "Done"); + DropFieldDesfire(); + return PM3_SUCCESS; +} + static int CmdHF14ADesChangeKey(const char *Cmd) { //DropFieldDesfire(); // NR DESC KEYLENGHT @@ -4924,6 +4981,7 @@ static command_t CommandTable[] = { // {"ndef", CmdHF14aDesNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, // {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("AID") " -----------------------"}, + {"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"}, {"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"}, {"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"}, {"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"}, diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 9af773420..94fff01ea 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -115,6 +115,36 @@ static char *getUlev1CardSizeStr(uint8_t fsize) { return buf; } +int ul_read_uid(uint8_t *uid) { + if (uid == NULL) { + PrintAndLogEx(WARNING, "NUll parameter UID"); + return PM3_ESOFT; + } + // read uid from tag + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0); + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.oldarg[0]; + // 0: couldn't read + // 1: OK with ATS + // 2: OK, no ATS + // 3: proprietary Anticollision + if (select_status == 0) { + PrintAndLogEx(WARNING, "iso14443a card select failed"); + return PM3_ESOFT; + } + if (card.uidlen != 7) { + PrintAndLogEx(WARNING, "Wrong sized UID, expected 7bytes got %d", card.uidlen); + return PM3_ESOFT; + } + memcpy(uid, card.uid, 7); + return PM3_SUCCESS; +} + static void ul_switch_on_field(void) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0); @@ -1102,7 +1132,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { CLIParserFree(ctx); if (ak_len) { - if (ak_len != 16 && ak_len != 8) { + if (ak_len != 16 && ak_len != 4) { PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); return PM3_EINVARG; } @@ -2253,7 +2283,7 @@ static int CmdHF14AMfUeLoad(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, false); CLIParserFree(ctx); - PrintAndLogEx(HINT, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to .eml"); + PrintAndLogEx(HINT, "Hint: See " _YELLOW_("`script run data_mfu_bin2eml`") " to convert the .bin to .eml"); return CmdHF14AMfELoad(Cmd); } // @@ -2264,7 +2294,8 @@ static int CmdHF14AMfUSim(const char *Cmd) { CLIParserInit(&ctx, "hf mfu sim", "Simulate MIFARE Ultralight family type based upon\n" "ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n" - "from emulator memory. See `hf mfu eload` first", + "from emulator memory. See `hf mfu eload` first. \n" + "See `hf 14a sim -h` to see available types. You want 2 or 7 usually.", "hf mfu sim -t 2 --uid 1122344556677 -> MIFARE Ultralight\n" "hf mfu sim -t 7 --uid 1122344556677 -n 5 -> AMIIBO (NTAG 215), pack 0x8080" ); @@ -2598,7 +2629,7 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("u", "uid", "", "4|7 hex byte UID"), + arg_str0("u", "uid", "", "<4|7> hex byte UID"), arg_lit0("r", NULL, "read UID from tag"), arg_param_end }; @@ -2636,6 +2667,11 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { } ulen = card.uidlen; memcpy(uid, card.uid, card.uidlen); + } else { + if (ulen != 4 && ulen != 7) { + PrintAndLogEx(ERR, "Must supply 4 or 7 hex byte uid"); + return PM3_EINVARG; + } } uint8_t iv[8] = { 0x00 }; @@ -2757,34 +2793,18 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) { if (selftest) return generator_selftest(); - if (u_len != 7) { - PrintAndLogEx(WARNING, "Key must be 7 hex bytes"); - return PM3_EINVARG; - } - if (use_tag) { // read uid from tag - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0); - PacketResponseNG resp; - WaitForResponse(CMD_ACK, &resp); - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + int res = ul_read_uid(uid); + if (res != PM3_SUCCESS) { + return res; + } - uint64_t select_status = resp.oldarg[0]; - // 0: couldn't read - // 1: OK with ATS - // 2: OK, no ATS - // 3: proprietary Anticollision - if (select_status == 0) { - PrintAndLogEx(WARNING, "iso14443a card select failed"); - return PM3_ESOFT; + } else { + if (u_len != 7) { + PrintAndLogEx(WARNING, "Key must be 7 hex bytes"); + return PM3_EINVARG; } - if (card.uidlen != 7) { - PrintAndLogEx(WARNING, "Wrong sized UID, expected 7bytes got %d", card.uidlen); - return PM3_ESOFT; - } - memcpy(uid, card.uid, sizeof(uid)); } PrintAndLogEx(INFO, "---------------------------------"); @@ -3539,7 +3559,27 @@ static int CmdHF14MfuNDEF(const char *Cmd) { } DropField(); - status = NDEFDecodeAndPrint(records, (size_t)maxsize, true); + status = NDEFRecordsDecodeAndPrint(records, (size_t)maxsize); + if ( status != PM3_SUCCESS) { + status = NDEFDecodeAndPrint(records, (size_t)maxsize, true); + } + + char *jooki = strstr((char*)records, "s.jooki.rocks/s/?s="); + if (jooki) { + jooki += 17; + while(jooki) { + if ((*jooki) != '=') + jooki++; + else { + jooki++; + char s[17] = {0}; + strncpy(s, jooki, 16); + PrintAndLogEx(HINT, "Use `" _YELLOW_("hf jooki decode -d %s") "` to decode", s); + break; + } + } + } + free(records); return status; } diff --git a/client/src/cmdhfmfu.h b/client/src/cmdhfmfu.h index e3eae9e79..7b120115c 100644 --- a/client/src/cmdhfmfu.h +++ b/client/src/cmdhfmfu.h @@ -23,6 +23,7 @@ typedef struct { uint32_t GetHF14AMfU_Type(void); int ul_print_type(uint32_t tagtype, uint8_t spaces); void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage); +int ul_read_uid(uint8_t *uid); int CmdHFMFUltra(const char *Cmd); diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 274dc31b3..49da91a83 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -88,7 +88,8 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { sprintf(asBuff, "AT91SAM7S16 Rev A"); break; } - PrintAndLogEx(NORMAL, " --= uC: %s", asBuff); + PrintAndLogEx(NORMAL, " --= uC: " _YELLOW_("%s"), asBuff); + switch ((iChipID & 0xE0) >> 5) { case 1: sprintf(asBuff, "ARM946ES"); @@ -104,84 +105,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { break; } PrintAndLogEx(NORMAL, " --= Embedded Processor: %s", asBuff); - switch ((iChipID & 0xF00) >> 8) { - case 0: - mem_avail = 0; - break; - case 1: - mem_avail = 8; - break; - case 2: - mem_avail = 16; - break; - case 3: - mem_avail = 32; - break; - case 5: - mem_avail = 64; - break; - case 7: - mem_avail = 128; - break; - case 9: - mem_avail = 256; - break; - case 10: - mem_avail = 512; - break; - case 12: - mem_avail = 1024; - break; - case 14: - mem_avail = 2048; - break; - } - uint32_t mem_left = 0; - if (mem_avail > 0) - mem_left = (mem_avail * 1024) - mem_used; - - PrintAndLogEx(NORMAL, " --= Nonvolatile Program Memory Size: %uK bytes, Used: %u bytes (%2.0f%%) Free: %u bytes (%2.0f%%)", - mem_avail, - mem_used, - mem_avail == 0 ? 0.0f : (float)mem_used / (mem_avail * 1024) * 100, - mem_left, - mem_avail == 0 ? 0.0f : (float)mem_left / (mem_avail * 1024) * 100 - ); - - switch ((iChipID & 0xF000) >> 12) { - case 0: - sprintf(asBuff, "None"); - break; - case 1: - sprintf(asBuff, "8K bytes"); - break; - case 2: - sprintf(asBuff, "16K bytes"); - break; - case 3: - sprintf(asBuff, "32K bytes"); - break; - case 5: - sprintf(asBuff, "64K bytes"); - break; - case 7: - sprintf(asBuff, "128K bytes"); - break; - case 9: - sprintf(asBuff, "256K bytes"); - break; - case 10: - sprintf(asBuff, "512K bytes"); - break; - case 12: - sprintf(asBuff, "1024K bytes"); - break; - case 14: - sprintf(asBuff, "2048K bytes"); - break; - } - PrintAndLogEx(NORMAL, " --= Second Nonvolatile Program Memory Size: %s", asBuff); switch ((iChipID & 0xF0000) >> 16) { case 1: sprintf(asBuff, "1K bytes"); @@ -229,7 +153,8 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { sprintf(asBuff, "512K bytes"); break; } - PrintAndLogEx(NORMAL, " --= Internal SRAM Size: %s", asBuff); + PrintAndLogEx(NORMAL, " --= Internal SRAM size: %s", asBuff); + switch ((iChipID & 0xFF00000) >> 20) { case 0x19: sprintf(asBuff, "AT91SAM9xx Series"); @@ -289,7 +214,8 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { sprintf(asBuff, "AT75Cxx Series"); break; } - PrintAndLogEx(NORMAL, " --= Architecture Identifier: %s", asBuff); + PrintAndLogEx(NORMAL, " --= Architecture identifier: %s", asBuff); + switch ((iChipID & 0x70000000) >> 28) { case 0: sprintf(asBuff, "ROM"); @@ -307,7 +233,78 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { sprintf(asBuff, "SRAM emulating ROM"); break; } - PrintAndLogEx(NORMAL, " --= Nonvolatile Program Memory Type: %s", asBuff); + switch ((iChipID & 0xF00) >> 8) { + case 0: + mem_avail = 0; + break; + case 1: + mem_avail = 8; + break; + case 2: + mem_avail = 16; + break; + case 3: + mem_avail = 32; + break; + case 5: + mem_avail = 64; + break; + case 7: + mem_avail = 128; + break; + case 9: + mem_avail = 256; + break; + case 10: + mem_avail = 512; + break; + case 12: + mem_avail = 1024; + break; + case 14: + mem_avail = 2048; + break; + } + + PrintAndLogEx(NORMAL, " --= Nonvolatile program memory: " _YELLOW_("%uK") " bytes %s ( " _YELLOW_("%2.0f%%") " used )" + , mem_avail + , asBuff + , mem_avail == 0 ? 0.0f : (float)mem_used / (mem_avail * 1024) * 100 + ); + + switch ((iChipID & 0xF000) >> 12) { + case 0: + sprintf(asBuff, "None"); + break; + case 1: + sprintf(asBuff, "8K bytes"); + break; + case 2: + sprintf(asBuff, "16K bytes"); + break; + case 3: + sprintf(asBuff, "32K bytes"); + break; + case 5: + sprintf(asBuff, "64K bytes"); + break; + case 7: + sprintf(asBuff, "128K bytes"); + break; + case 9: + sprintf(asBuff, "256K bytes"); + break; + case 10: + sprintf(asBuff, "512K bytes"); + break; + case 12: + sprintf(asBuff, "1024K bytes"); + break; + case 14: + sprintf(asBuff, "2048K bytes"); + break; + } + PrintAndLogEx(NORMAL, " --= Second nonvolatile program memory size: %s", asBuff); } static int CmdDbg(const char *Cmd) { diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 00f0dea27..1e14f97eb 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -64,156 +64,29 @@ static bool g_lf_threshold_set = false; static int CmdHelp(const char *Cmd); -static int usage_lf_cmdread(void) { - PrintAndLogEx(NORMAL, "Usage: lf cmdread d z o [e ] c [q] [s #samples] [@]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " d delay OFF period, (0 for bitbang mode)"); - PrintAndLogEx(NORMAL, " z ZERO time period"); - PrintAndLogEx(NORMAL, " o ONE time period"); - PrintAndLogEx(NORMAL, " e Extra symbol definition and duration (up to %i)", LF_CMDREAD_MAX_EXTRA_SYMBOLS); - PrintAndLogEx(NORMAL, " b B period"); - PrintAndLogEx(NORMAL, " c Command symbols (0/1/...)"); - PrintAndLogEx(NORMAL, " q silent (optional)"); - PrintAndLogEx(NORMAL, " s #samples number of samples to collect (optional)"); - PrintAndLogEx(NORMAL, " @ run continuously until a key is pressed (optional)"); +// Informative user function. +// loop and wait for either keyboard press or pm3 button to exit +// if key event, send break loop cmd to Pm3 +int lfsim_wait_check(uint32_t cmd) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " ************* " _YELLOW_("All periods in decimal and in microseconds (us)")); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _CYAN_(" probing for Hitag 1/Hitag S") ":"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf cmdread d 50 z 116 o 166 e W 3000 c W00110")); - PrintAndLogEx(NORMAL, _CYAN_(" probing for Hitag 2") ":"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf cmdread d 50 z 116 o 166 e W 3000 c W11000")); - PrintAndLogEx(NORMAL, _CYAN_(" probing for Hitag 2, oscilloscope style") ":"); - PrintAndLogEx(NORMAL, _YELLOW_(" data plot")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf cmdread d 50 z 116 o 166 e W 3000 c W11000 q s 2000 @")); - PrintAndLogEx(NORMAL, _CYAN_(" probing for Hitag (us)") ":"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf cmdread d 48 z 112 o 176 e W 3000 e S 240 e E 336 c W0S00000010000E")); - PrintAndLogEx(NORMAL, "Extras:"); - PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")" to set parameters."); - return PM3_SUCCESS; -} -static int usage_lf_read(void) { - PrintAndLogEx(NORMAL, "Usage: lf read [h] [q] [s #samples] [@]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " q silent (optional)"); - PrintAndLogEx(NORMAL, " s #samples number of samples to collect (optional)"); - PrintAndLogEx(NORMAL, " @ run continuously until a key is pressed (optional)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf read"); - PrintAndLogEx(NORMAL, "- collecting quietly 12000 samples:"); - PrintAndLogEx(NORMAL, " lf read q s 12000 - "); - PrintAndLogEx(NORMAL, "- oscilloscope style:"); - PrintAndLogEx(NORMAL, " data plot"); - PrintAndLogEx(NORMAL, " lf read q s 3000 @"); - PrintAndLogEx(NORMAL, "Extras:"); - PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")" to set parameters."); - return PM3_SUCCESS; -} -static int usage_lf_sim(void) { - PrintAndLogEx(NORMAL, "Simulate low frequency tag from graphbuffer."); - PrintAndLogEx(NORMAL, "Usage: lf sim [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " Start gap (in microseconds)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf sim 240") " - start simulating with 240ms gap"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf sim")); - PrintAndLogEx(NORMAL, "Extras:"); - PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")" to set parameters."); - return PM3_SUCCESS; -} -static int usage_lf_sniff(void) { - PrintAndLogEx(NORMAL, "Sniff low frequency signal."); - PrintAndLogEx(NORMAL, "Usage: lf sniff [h] [q] [s #samples] [@]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " q silent (optional)"); - PrintAndLogEx(NORMAL, " s #samples number of samples to collect (optional)"); - PrintAndLogEx(NORMAL, " @ run continuously until a key is pressed (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf sniff"); - PrintAndLogEx(NORMAL, _CYAN_(" oscilloscope style") ":"); - PrintAndLogEx(NORMAL, _YELLOW_(" data plot")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf sniff q s 3000 @")); - PrintAndLogEx(NORMAL, "Extras:"); - PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")" to set parameters."); - PrintAndLogEx(NORMAL, " use " _YELLOW_("'data plot'")" to look at it"); - return PM3_SUCCESS; -} -static int usage_lf_config(void) { - PrintAndLogEx(NORMAL, "Usage: lf config [h] [L | H | q | f ] [b ] [d ] [a 0|1]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " L Low frequency (125 kHz)"); - PrintAndLogEx(NORMAL, " H High frequency (134 kHz)"); - PrintAndLogEx(NORMAL, " q Manually set freq divisor. %d -> 134 kHz, %d -> 125 kHz", LF_DIVISOR_134, LF_DIVISOR_125); - PrintAndLogEx(NORMAL, " f Manually set frequency in kHz"); - PrintAndLogEx(NORMAL, " b Sets resolution of bits per sample. Default (max): 8"); - PrintAndLogEx(NORMAL, " d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); - PrintAndLogEx(NORMAL, " a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1"); - PrintAndLogEx(NORMAL, " t Sets trigger threshold. 0 means no threshold (range: 0-128)"); - PrintAndLogEx(NORMAL, " s Sets a number of samples to skip before capture. Default: 0"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf config") " - shows current config"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf config b 8 L") " - samples at 125 kHz, 8bps."); - PrintAndLogEx(NORMAL, _YELLOW_(" lf config H b 4 d 3") " - samples at 134 kHz, averages three samples into one, stored with "); - PrintAndLogEx(NORMAL, " a resolution of 4 bits per sample."); - PrintAndLogEx(NORMAL, _YELLOW_(" lf read") " - performs a read (active field)"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf sniff") " - performs a sniff (no active field)"); - return PM3_SUCCESS; -} -static int usage_lf_simfsk(void) { - PrintAndLogEx(NORMAL, "Usage: lf simfsk [h] [c ] [H ] [L ] [d ]"); - PrintAndLogEx(NORMAL, "there are about four FSK modulations to know of."); - PrintAndLogEx(NORMAL, "FSK1 - where fc/8 = high and fc/5 = low"); - PrintAndLogEx(NORMAL, "FSK1a - is inverted FSK1, ie: fc/5 = high and fc/8 = low"); - PrintAndLogEx(NORMAL, "FSK2 - where fc/10 = high and fc/8 = low"); - PrintAndLogEx(NORMAL, "FSK2a - is inverted FSK2, ie: fc/10 = high and fc/8 = low"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " c Manually set clock - can autodetect if using DemodBuffer"); - PrintAndLogEx(NORMAL, " H Manually set the larger Field Clock"); - PrintAndLogEx(NORMAL, " L Manually set the smaller Field Clock"); - //PrintAndLogEx(NORMAL, " s TBD- -STT to enable a gap between playback repetitions - default: no gap"); - PrintAndLogEx(NORMAL, " d Data to sim as hex - omit to sim from DemodBuffer"); - PrintAndLogEx(NORMAL, "\n NOTE: if you set one clock manually set them all manually"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf simfsk c 40 H 8 L 5 d 010203") " - FSK1 rf/40 data 010203"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf simfsk c 40 H 5 L 8 d 010203") " - FSK1a rf/40 data 010203"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf simfsk c 64 H 10 L 8 d 010203") " - FSK2 rf/64 data 010203"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf simfsk c 64 H 8 L 10 d 010203") " - FSK2a rf/64 data 010203"); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_simask(void) { - PrintAndLogEx(NORMAL, "Usage: lf simask [c ] [i] [b|m|r] [s] [d ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " c Manually set clock - can autodetect if using DemodBuffer"); - PrintAndLogEx(NORMAL, " i invert data"); - PrintAndLogEx(NORMAL, " b sim ask/biphase"); - PrintAndLogEx(NORMAL, " m sim ask/manchester - Default"); - PrintAndLogEx(NORMAL, " r sim ask/raw"); - PrintAndLogEx(NORMAL, " s add t55xx Sequence Terminator gap - default: no gaps (only manchester)"); - PrintAndLogEx(NORMAL, " d Data to sim as hex - omit to sim from DemodBuffer"); - return PM3_SUCCESS; -} -static int usage_lf_simpsk(void) { - PrintAndLogEx(NORMAL, "Usage: lf simpsk [1|2|3] [c ] [i] [r ] [d ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " c Manually set clock - can autodetect if using DemodBuffer"); - PrintAndLogEx(NORMAL, " i invert data"); - PrintAndLogEx(NORMAL, " 1 set PSK1 (default)"); - PrintAndLogEx(NORMAL, " 2 set PSK2"); - PrintAndLogEx(NORMAL, " 3 set PSK3"); - PrintAndLogEx(NORMAL, " r 2|4|8 are valid carriers: default = 2"); - PrintAndLogEx(NORMAL, " d Data to sim as hex - omit to sim from DemodBuffer"); + PrintAndLogEx(INFO, "Press " _GREEN_("") " or pm3-button to abort simulation"); + + for (;;) { + if (kbd_enter_pressed()) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + PrintAndLogEx(DEBUG, "User aborted"); + break; + } + + PacketResponseNG resp; + if (WaitForResponseTimeout(cmd, &resp, 1000)) { + if (resp.status == PM3_EOPABORTED) { + PrintAndLogEx(DEBUG, "Button pressed, user aborted"); + break; + } + } + } + PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } @@ -336,14 +209,51 @@ static int CmdLFTune(const char *Cmd) { /* send a LF command before reading */ int CmdLFCommandRead(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf cmdread", + "Modulate LF reader field to send command before read. All periods in microseconds.\n" + " - use " _YELLOW_("`lf config`") _CYAN_(" to set parameters"), + "lf cmdread -d 50 -z 116 -o 166 -e W3000 -c W00110 --> probing for Hitag 1/S\n" + "lf cmdread -d 50 -z 116 -o 166 -e W3000 -c W11000 --> probing for Hitag 2\n" + "lf cmdread -d 50 -z 116 -o 166 -e W3000 -c W11000 -q -s 2000 -@ --> probing for Hitag 2, oscilloscope style\n" + "lf cmdread -d 48 -z 112 -o 176 -e W3000 -e S240 -e E336 -c W0S00000010000E --> probing for Hitag (us)\n" + ); - if (!session.pm3_present) return PM3_ENOTTY; + char div_str[70] = {0}; + sprintf(div_str, "Extra symbol definition and duration (up to %i)", LF_CMDREAD_MAX_EXTRA_SYMBOLS); - bool errors = false; - bool verbose = true; - bool continuous = false; - uint32_t samples = 0; - uint16_t datalen = 0; + void *argtable[] = { + arg_param_begin, + arg_u64_0("d", "duration", "", "delay OFF period, (0 for bitbang mode)"), + arg_str0("c", "cmd", "<0|1|...>", "command symbols"), + arg_strx0("e", "extra", "", div_str), + arg_u64_0("o", "one", "", "ONE time period"), + arg_u64_0("z", "zero", "", "ZERO time period"), + arg_u64_0("s", "samples", "", "number of samples to collect"), + arg_lit0("v", "verbose", "verbose output"), + arg_lit0("@", NULL, "continuous mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + uint32_t delay = arg_get_u32_def(ctx, 1, 0); + + int cmd_len = 128; + char cmd[128] = {0}; + CLIGetStrWithReturn(ctx, 2, (uint8_t *)cmd, &cmd_len); + + int extra_arg_len = 250; + char extra_arg[250] = {0}; + CLIGetStrWithReturn(ctx, 3, (uint8_t *)extra_arg, &extra_arg_len); + + uint16_t period_1 = arg_get_u32_def(ctx, 4, 0); + uint16_t period_0 = arg_get_u32_def(ctx, 5, 0); + uint32_t samples = arg_get_u32_def(ctx, 6, 0); + bool verbose = arg_get_lit(ctx, 7); + bool cm = arg_get_lit(ctx, 8); + CLIParserFree(ctx); + + if (session.pm3_present == false) + return PM3_ENOTTY; const uint8_t payload_header_size = 12 + (3 * LF_CMDREAD_MAX_EXTRA_SYMBOLS); struct p { @@ -356,76 +266,57 @@ int CmdLFCommandRead(const char *Cmd) { bool verbose : 1; uint8_t data[PM3_CMD_DATA_SIZE - payload_header_size]; } PACKED payload; + payload.delay = delay; + payload.period_1 = period_1; + payload.period_0 = period_0; payload.samples = samples; payload.verbose = verbose; - uint8_t index_extra = 0; + memcpy(payload.data, cmd, cmd_len); - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_cmdread(); - case 'c': // cmd bytes 1010 - datalen = param_getstr(Cmd, cmdp + 1, (char *)&payload.data, sizeof(payload.data)); - cmdp += 2; - break; - case 'd': // delay - payload.delay = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'z': // zero - payload.period_0 = param_get32ex(Cmd, cmdp + 1, 0, 10) & 0xFFFF; - cmdp += 2; - break; - case 'o': // ones - payload.period_1 = param_get32ex(Cmd, cmdp + 1, 0, 10) & 0xFFFF; - cmdp += 2; - break; - case 'e': // extra symbol definition - if (index_extra < LF_CMDREAD_MAX_EXTRA_SYMBOLS - 1) { - payload.symbol_extra[index_extra] = param_getchar(Cmd, cmdp + 1); - payload.period_extra[index_extra] = param_get32ex(Cmd, cmdp + 2, 0, 10) & 0xFFFF; - index_extra++; - cmdp += 3; - } else { - PrintAndLogEx(WARNING, "Too many extra symbols, please define up to %i symbols", LF_CMDREAD_MAX_EXTRA_SYMBOLS); - errors = true; - } - break; - case 's': - samples = param_get32ex(Cmd, cmdp + 1, 0, 10); - payload.samples = samples; - cmdp += 2; - break; - case 'q': - verbose = false; - payload.verbose = verbose; - cmdp++; - break; - case '@': - continuous = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; + // extra symbol definition + uint8_t index_extra = 0; + int i = 0; + for (; i < extra_arg_len;) { + + if (index_extra < LF_CMDREAD_MAX_EXTRA_SYMBOLS - 1) { + payload.symbol_extra[index_extra] = extra_arg[i]; + int tmp = atoi(extra_arg + (i + 1)); + payload.period_extra[index_extra] = tmp; + index_extra++; + i++; + while (extra_arg[i] >= 0x30 && extra_arg[i] <= 0x39) + i++; + + } else { + PrintAndLogEx(WARNING, "Too many extra symbols, please define up to %i symbols", LF_CMDREAD_MAX_EXTRA_SYMBOLS); } } // bitbang mode if (payload.delay == 0) { if (payload.period_0 < 7 || payload.period_1 < 7) { - PrintAndLogEx(WARNING, "warning periods cannot be less than 7us in bit bang mode"); + PrintAndLogEx(WARNING, "periods cannot be less than 7us in bit bang mode"); return PM3_EINVARG; } } - //Validations - if (errors || cmdp == 0) return usage_lf_cmdread(); - if (continuous) { - PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit"); + PrintAndLogEx(DEBUG, "Cmd read - settings"); + PrintAndLogEx(DEBUG, "-------------------"); + PrintAndLogEx(DEBUG, "delay: %u , zero %u , one %u , samples %u", payload.delay, payload.period_0, payload.period_1, payload.samples); + PrintAndLogEx(DEBUG, "Extra symbols"); + PrintAndLogEx(DEBUG, "-------------"); + for (i = 0; i < LF_CMDREAD_MAX_EXTRA_SYMBOLS; i++) { + if (payload.symbol_extra[i] == 0x00) + continue; + + PrintAndLogEx(DEBUG, " %c - %u", payload.symbol_extra[i], payload.period_extra[i]); } + PrintAndLogEx(DEBUG, "data: %s", payload.data); + + if (cm) { + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); + } + if (verbose) { PrintAndLogEx(SUCCESS, "Sending command..."); } @@ -433,11 +324,11 @@ int CmdLFCommandRead(const char *Cmd) { int ret = PM3_SUCCESS; do { clearCommandBuffer(); - SendCommandNG(CMD_LF_MOD_THEN_ACQ_RAW_ADC, (uint8_t *)&payload, payload_header_size + datalen); + SendCommandNG(CMD_LF_MOD_THEN_ACQ_RAW_ADC, (uint8_t *)&payload, payload_header_size + cmd_len); PacketResponseNG resp; - uint8_t i = 10; + i = 10; // 20sec wait loop while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) { if (verbose) { @@ -448,25 +339,23 @@ int CmdLFCommandRead(const char *Cmd) { if (verbose) { PrintAndLogEx(NORMAL, ""); } - if (resp.status == PM3_SUCCESS) { - if (i) { - if (verbose) { - PrintAndLogEx(SUCCESS, "downloading response signal data"); - } - getSamples(samples, false); - ret = PM3_SUCCESS; - } else { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return PM3_ETIMEOUT; - } - } else { + if (resp.status != PM3_SUCCESS) { PrintAndLogEx(WARNING, "command failed."); return PM3_ESOFT; } - if (kbd_enter_pressed()) { - break; + + if (i) { + if (verbose) { + PrintAndLogEx(SUCCESS, "downloading response signal data"); + } + getSamples(samples, false); + ret = PM3_SUCCESS; + } else { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return PM3_ETIMEOUT; } - } while (continuous); + + } while (cm && kbd_enter_pressed() == false); return ret; } @@ -576,14 +465,61 @@ int lf_config(sample_config *config) { } int CmdLFConfig(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf config", + "Get/Set config for LF sampling, bit/sample, decimation, frequency\n" + "These changes are temporary, will be reset after a power cycle.\n\n" + " - use " _YELLOW_("`lf read`") _CYAN_(" performs a read (active field)\n") + _CYAN_(" - use ") _YELLOW_("`lf sniff`") _CYAN_(" performs a sniff (no active field)"), + "lf config --> shows current config\n" + "lf config -b 8 --125 --> samples at 125 kHz, 8 bps\n" + "lf config -b 4 --134 --dec 3 --> samples at 134 kHz, averages three samples into one, stored with a resolution of 4 bits per sample\n" + "lf config --trig 20 -s 10000 --> trigger sampling when above 20, skip 10 000 first samples after triggered\n" + ); - if (!session.pm3_present) return PM3_ENOTTY; + char div_str[70] = {0}; + sprintf(div_str, "Manually set freq divisor. %d -> 134 kHz, %d -> 125 kHz", LF_DIVISOR_134, LF_DIVISOR_125); + + void *argtable[] = { + arg_param_begin, + arg_lit0(NULL, "125", "125 kHz frequency"), + arg_lit0(NULL, "134", "134 kHz frequency"), + arg_int0("a", "avg", "<0|1>", "averaging - if set, will average the stored sample value when decimating (default 1)"), + arg_int0("b", "bps", "<1-8>", "sets resolution of bits per sample (default 8)"), + arg_int0(NULL, "dec", "<1-8>", "sets decimation. A value of N saves only 1 in N samples (default 1)"), + arg_int0(NULL, "divisor", "<19-255>", div_str), + arg_int0("f", "freq", "<47-600>", "manually set frequency in kHz"), + arg_lit0("r", "reset", "reset values to defaults"), + arg_int0("s", "skip", "", "sets a number of samples to skip before capture (default 0)"), + arg_int0("t", "trig", "<0-128>", "sets trigger threshold. 0 means no threshold"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool use_125 = arg_get_lit(ctx, 1); + bool use_134 = arg_get_lit(ctx, 2); + int8_t avg = arg_get_int_def(ctx, 3, 0); + int8_t bps = arg_get_int_def(ctx, 4, -1); + int8_t dec = arg_get_int_def(ctx, 5, -1); + int16_t div = arg_get_int_def(ctx, 6, -1); + int16_t freq = arg_get_int_def(ctx, 7, -1); + bool reset = arg_get_lit(ctx, 8); + int32_t skip = arg_get_int_def(ctx, 9, -1); + int16_t trigg = arg_get_int_def(ctx, 10, -1); + CLIParserFree(ctx); + + if (session.pm3_present == false) + return PM3_ENOTTY; // if called with no params, just print the device config if (strlen(Cmd) == 0) { return lf_config(NULL); } + if (use_125 + use_134 > 1) { + PrintAndLogEx(ERR, "use only one of 125 or 134 params"); + return PM3_EINVARG; + } + sample_config config = { .decimation = -1, .bits_per_sample = -1, @@ -594,87 +530,60 @@ int CmdLFConfig(const char *Cmd) { .verbose = true }; - bool errors = false; + if (reset) { + config.decimation = 1; + config.bits_per_sample = 8; + config.averaging = 1, + config.divisor = LF_DIVISOR_125; + config.samples_to_skip = 0; + config.trigger_threshold = 0; + g_lf_threshold_set = false; + } - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (param_getchar(Cmd, cmdp)) { - case 'h': - return usage_lf_config(); - case 'H': - config.divisor = LF_DIVISOR_134; - cmdp++; - break; - case 'L': - config.divisor = LF_DIVISOR_125; - cmdp++; - break; - case 'q': - config.divisor = param_get8ex(Cmd, cmdp + 1, 95, 10); - if (config.divisor < 19) { - PrintAndLogEx(ERR, "divisor must be between 19 and 255"); - return PM3_EINVARG; - } - cmdp += 2; - break; - case 'f': { - int freq = param_get32ex(Cmd, cmdp + 1, 125, 10); - config.divisor = LF_FREQ2DIV(freq); - if (config.divisor < 19) { - PrintAndLogEx(ERR, "freq must be between 47 and 600"); - return PM3_EINVARG; - } - cmdp += 2; - break; - } - case 't': { - uint8_t trigg = 0; - errors |= param_getdec(Cmd, cmdp + 1, &trigg); - cmdp += 2; - if (!errors) { - config.trigger_threshold = trigg; - g_lf_threshold_set = (config.trigger_threshold > 0); - } - break; - } - case 'b': { - config.bits_per_sample = param_get8ex(Cmd, cmdp + 1, 8, 10); + if (use_125) + config.divisor = LF_DIVISOR_125; - // bps is limited to 8 - if (config.bits_per_sample >> 4) - config.bits_per_sample = 8; + if (use_134) + config.divisor = LF_DIVISOR_134; - cmdp += 2; - break; - } - case 'd': { - config.decimation = param_get8ex(Cmd, cmdp + 1, 1, 10); + config.averaging = (avg == 1); - // decimation is limited to 255 - if (config.decimation >> 4) - config.decimation = 8; + if (bps > -1) { + // bps is limited to 8 + config.bits_per_sample = (bps & 0x0F); + if (config.bits_per_sample > 8) + config.bits_per_sample = 8; + } - cmdp += 2; - break; - } - case 'a': - config.averaging = (param_getchar(Cmd, cmdp + 1) == '1'); - cmdp += 2; - break; - case 's': - config.samples_to_skip = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = 1; - break; + if (dec > -1) { + // decimation is limited to 8 + config.decimation = (dec & 0x0F); + if (config.decimation > 8) + config.decimation = 8; + } + + if (div > -1) { + config.divisor = div; + if (config.divisor < 19) { + PrintAndLogEx(ERR, "divisor must be between 19 and 255"); + return PM3_EINVARG; } } - // validations - if (errors) return usage_lf_config(); + if (freq > -1) { + config.divisor = LF_FREQ2DIV(freq); + if (config.divisor < 19) { + PrintAndLogEx(ERR, "freq must be between 47 and 600"); + return PM3_EINVARG; + } + } + if (trigg > -1) { + config.trigger_threshold = trigg; + g_lf_threshold_set = (config.trigger_threshold > 0); + } + + config.samples_to_skip = skip; return lf_config(&config); } @@ -709,49 +618,38 @@ int lf_read(bool verbose, uint32_t samples) { } int CmdLFRead(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf read", + "Sniff low frequency signal.\n" + " - use " _YELLOW_("`lf config`") _CYAN_(" to set parameters.\n") + _CYAN_(" - use ") _YELLOW_("`data plot`") _CYAN_(" to look at it"), + "lf read -v -s 12000 --> collect 12000 samples\n" + "lf read -s 3000 -@ --> oscilloscope style \n" + ); - if (!session.pm3_present) return PM3_ENOTTY; + void *argtable[] = { + arg_param_begin, + arg_u64_0("s", "samples", "", "number of samples to collect"), + arg_lit0("v", "verbose", "verbose output"), + arg_lit0("@", NULL, "continuous reading mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint32_t samples = arg_get_u32_def(ctx, 1, 0); + bool verbose = arg_get_lit(ctx, 2); + bool cm = arg_get_lit(ctx, 3); + CLIParserFree(ctx); - bool errors = false; - bool verbose = true; - bool continuous = false; - uint32_t samples = 0; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_read(); - case 's': - samples = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'q': - verbose = false; - cmdp++; - break; - case '@': - continuous = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + if (session.pm3_present == false) + return PM3_ENOTTY; - //Validations - if (errors) return usage_lf_read(); - if (continuous) { - PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit"); + if (cm) { + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); } int ret = PM3_SUCCESS; do { ret = lf_read(verbose, samples); - if (kbd_enter_pressed()) { - break; - } - } while (continuous); + } while (cm && kbd_enter_pressed() == false); return ret; } @@ -786,87 +684,56 @@ int lf_sniff(bool verbose, uint32_t samples) { } int CmdLFSniff(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf sniff", + "Sniff low frequency signal.\n" + " - use " _YELLOW_("`lf config`") _CYAN_(" to set parameters.\n") + _CYAN_(" - use ") _YELLOW_("`data plot`") _CYAN_(" to look at it"), + "lf sniff -v\n" + "lf sniff -s 3000 -@ --> oscilloscope style \n" + ); - if (!session.pm3_present) return PM3_ENOTTY; + void *argtable[] = { + arg_param_begin, + arg_u64_0("s", "samples", "", "number of samples to collect"), + arg_lit0("v", "verbose", "verbose output"), + arg_lit0("@", NULL, "continuous sniffing mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint32_t samples = arg_get_u32_def(ctx, 1, 0); + bool verbose = arg_get_lit(ctx, 2); + bool cm = arg_get_lit(ctx, 3); + CLIParserFree(ctx); - bool errors = false; - bool verbose = true; - bool continuous = false; - uint32_t samples = 0; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_sniff(); - case 's': - samples = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'q': - verbose = false; - cmdp++; - break; - case '@': - continuous = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + if (session.pm3_present == false) + return PM3_ENOTTY; - //Validations - if (errors) return usage_lf_sniff(); - if (continuous) { - PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit"); + if (cm) { + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); } int ret = PM3_SUCCESS; do { ret = lf_sniff(verbose, samples); - if (kbd_enter_pressed()) { - break; - } - } while (continuous); + } while (cm && !kbd_enter_pressed()); return ret; } -static void ChkBitstream(void) { +static void lf_chk_bitstream(void) { // convert to bitstream if necessary for (int i = 0; i < (int)(GraphTraceLen / 2); i++) { if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) { CmdGetBitStream(""); - PrintAndLogEx(INFO, "Converted to bitstream"); + PrintAndLogEx(INFO, "converted Graphbuffer to bitstream values (0|1)"); break; } } } -//Attempt to simulate any wave in buffer (one bit per output sample) -// converts GraphBuffer to bitstream (based on zero crossings) if needed. -int CmdLFSim(const char *Cmd) { - - if (!session.pm3_present) return PM3_ENOTTY; - - // sanity check - if (GraphTraceLen < 20) { - PrintAndLogEx(ERR, "No data in Graphbuffer"); - return PM3_ENODATA; - } - - uint8_t cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_sim(); - - uint16_t gap = param_get32ex(Cmd, 0, 0, 10) & 0xFFFF; - - // convert to bitstream if necessary - ChkBitstream(); - +// Uploads GraphBuffer to device, in order to be used for LF SIM. +int lfsim_upload_gb(void) { PrintAndLogEx(DEBUG, "DEBUG: Uploading %zu bytes", GraphTraceLen); - PacketResponseNG resp; - struct pupload { uint8_t flag; uint16_t offset; @@ -881,7 +748,10 @@ int CmdLFSim(const char *Cmd) { // fast push mode conn.block_after_ACK = true; + PacketResponseNG resp; + //can send only 512 bits at a time (1 byte sent per bit...) + PrintAndLogEx(INFO, "." NOLF); for (uint16_t i = 0; i < GraphTraceLen; i += PM3_CMD_DATA_SIZE - 3) { size_t len = MIN((GraphTraceLen - i), PM3_CMD_DATA_SIZE - 3); @@ -894,17 +764,54 @@ int CmdLFSim(const char *Cmd) { SendCommandNG(CMD_LF_UPLOAD_SIM_SAMPLES, (uint8_t *)&payload_up, sizeof(struct pupload)); WaitForResponse(CMD_LF_UPLOAD_SIM_SAMPLES, &resp); if (resp.status != PM3_SUCCESS) { - PrintAndLogEx(INFO, "Bigbuf is full."); + PrintAndLogEx(INFO, "Bigbuf is full"); break; } PrintAndLogEx(NORMAL, "." NOLF); payload_up.flag = 0; } + PrintAndLogEx(NORMAL, ""); // Disable fast mode before last command conn.block_after_ACK = false; - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Simulating"); + return PM3_SUCCESS; +} + +//Attempt to simulate any wave in buffer (one bit per output sample) +// converts GraphBuffer to bitstream (based on zero crossings) if needed. +int CmdLFSim(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf sim", + "Simulate low frequency tag from graphbuffer\n" + "Use " _YELLOW_("`lf config`") _CYAN_(" to set parameters"), + "lf sim\n" + "lf sim --gap 240 --> start simulating with 240ms gap" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_0("g", "gap", "", "start gap in microseconds"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint16_t gap = arg_get_u32_def(ctx, 1, 0); + CLIParserFree(ctx); + + if (session.pm3_present == false) { + PrintAndLogEx(DEBUG, "DEBUG: no proxmark present"); + return PM3_ENOTTY; + } + + // sanity check + if (GraphTraceLen < 20) { + PrintAndLogEx(ERR, "No data in Graphbuffer"); + return PM3_ENODATA; + } + + // convert to bitstream if necessary + lf_chk_bitstream(); + + lfsim_upload_gb(); struct p { uint16_t len; @@ -915,315 +822,343 @@ int CmdLFSim(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload)); - - WaitForResponse(CMD_LF_SIMULATE, &resp); - - PrintAndLogEx(INFO, "Done"); - if (resp.status != PM3_EOPABORTED) - return resp.status; - return PM3_SUCCESS; + return lfsim_wait_check(CMD_LF_SIMULATE); } // sim fsk data given clock, fcHigh, fcLow, invert // - allow pull data from DemodBuffer int CmdLFfskSim(const char *Cmd) { - //might be able to autodetect FCs and clock from Graphbuffer if using demod buffer - // otherwise will need FChigh, FClow, Clock, and bitstream - uint8_t fcHigh = 0, fcLow = 0, clk = 0; - bool errors = false, separator = false; - char hexData[64] = {0x00}; // store entered hex data - uint8_t data[255] = {0x00}; - int dataLen = 0; - uint8_t cmdp = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf simfsk", + "Simulate FSK tag from demodbuffer or input. There are about four FSK modulations to know of.\n" + "FSK1 - where fc/8 = high and fc/5 = low\n" + "FSK1a - is inverted FSK1, ie: fc/5 = high and fc/8 = low\n" + "FSK2 - where fc/10 = high and fc/8 = low\n" + "FSK2a - is inverted FSK2, ie: fc/10 = high and fc/8 = low\n\n" + "NOTE: if you set one clock manually set them all manually", + "lf simfsk -c 40 --high 8 --low 5 -d 010203 --> FSK1 rf/40 data 010203\n" + "lf simfsk -c 40 --high 5 --low 8 -d 010203 --> FSK1a rf/40 data 010203\n" + "lf simfsk -c 64 --high 10 --low 8 -d 010203 --> FSK2 rf/64 data 010203\n" + "lf simfsk -c 64 --high 8 --low 10 -d 010203 --> FSK2a rf/64 data 010203\n\n" + "lf simfsk -c 50 --high 10 --low 8 -d 1D5559555569A9A555A59569 --> simulate HID Prox tag manually\n" + "lf simfsk -c 50 --high 10 --low 8 --stt -d 011DB2487E8D811111111111 --> simulate AWID tag manually" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (param_getchar(Cmd, cmdp)) { - case 'h': - return usage_lf_simfsk(); - case 'c': - errors |= param_getdec(Cmd, cmdp + 1, &clk); - cmdp += 2; - break; - case 'H': - errors |= param_getdec(Cmd, cmdp + 1, &fcHigh); - cmdp += 2; - break; - case 'L': - errors |= param_getdec(Cmd, cmdp + 1, &fcLow); - cmdp += 2; - break; - case 's': - separator = true; - cmdp++; - break; - case 'd': - dataLen = param_getstr(Cmd, cmdp + 1, hexData, sizeof(hexData)); - if (dataLen == 0) - errors = true; - else - dataLen = hextobinarray((char *)data, hexData); + void *argtable[] = { + arg_param_begin, + arg_u64_0("c", "clk", "", "manually set clock - can autodetect if using DemodBuffer (default 64)"), + arg_u64_0(NULL, "low", "", "manually set larger Field Clock"), + arg_u64_0(NULL, "high", "", "manually set smaller Field Clock"), + arg_lit0(NULL, "stt", "TBD! - STT to enable a gap between playback repetitions (default: no gap)"), + arg_str0("d", "data", "", "data to sim - omit to use DemodBuffer"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint8_t clk = arg_get_u32_def(ctx, 1, 0); + uint8_t fclow = arg_get_u32_def(ctx, 2, 0); + uint8_t fchigh = arg_get_u32_def(ctx, 3, 0); + bool separator = arg_get_lit(ctx, 4); - if (dataLen == 0) errors = true; - if (errors) PrintAndLogEx(ERR, "Error getting hex data"); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + int raw_len = 64; + char raw[64] = {0}; + CLIGetStrWithReturn(ctx, 5, (uint8_t *)raw, &raw_len); + bool verbose = arg_get_lit(ctx, 6); + CLIParserFree(ctx); // No args - if (cmdp == 0 && DemodBufferLen == 0) return usage_lf_simfsk(); + if (raw_len == 0 && DemodBufferLen == 0) { + PrintAndLogEx(ERR, "No user supplied data nor inside Demodbuffer"); + return PM3_EINVARG; + } - //Validations - if (errors) return usage_lf_simfsk(); + if (verbose && separator) { + PrintAndLogEx(INFO, "STT gap isn't implemented yet. Skipping..."); + separator = 0; + } - int firstClockEdge = 0; - if (dataLen == 0) { //using DemodBuffer - if (clk == 0 || fcHigh == 0 || fcLow == 0) { //manual settings must set them all - uint8_t ans = fskClocks(&fcHigh, &fcLow, &clk, &firstClockEdge); - if (ans == 0) { - if (!fcHigh) fcHigh = 10; - if (!fcLow) fcLow = 8; - if (!clk) clk = 50; + uint8_t bs[256] = {0x00}; + int bs_len = hextobinarray((char *)bs, raw); + if (bs_len == 0) { + // Using data from DemodBuffer + // might be able to autodetect FC and clock from Graphbuffer if using demod buffer + // will need clock, fchigh, fclow and bitstream + PrintAndLogEx(INFO, "No user supplied data, using Demodbuffer..."); + + if (clk == 0 || fchigh == 0 || fclow == 0) { + int firstClockEdge = 0; + bool res = fskClocks(&fchigh, &fclow, &clk, &firstClockEdge); + if (res == false) { + clk = 0; + fchigh = 0; + fclow = 0; } } + PrintAndLogEx(DEBUG, "Detected rf/%u, High fc/%u, Low fc/%u, n %zu ", clk, fchigh, fclow, DemodBufferLen); + } else { - setDemodBuff(data, dataLen, 0); + setDemodBuff(bs, bs_len, 0); } //default if not found - if (clk == 0) clk = 50; - if (fcHigh == 0) fcHigh = 10; - if (fcLow == 0) fcLow = 8; + if (clk == 0) { + clk = 50; + PrintAndLogEx(DEBUG, "Autodetection of clock failed, falling back to rf/%u", clk); + } + + if (fchigh == 0) { + fchigh = 10; + PrintAndLogEx(DEBUG, "Autodetection of larger clock failed, falling back to fc/%u", fchigh); + } + + if (fclow == 0) { + fclow = 8; + PrintAndLogEx(DEBUG, "Autodetection of smaller clock failed, falling back to fc/%u", fclow); + } size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t))) { PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t)); + PrintAndLogEx(INFO, "Continuing with trimmed down data"); size = PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t); } lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + size); - payload->fchigh = fcHigh; - payload->fclow = fcLow; + payload->fchigh = fchigh; + payload->fclow = fclow; payload->separator = separator; payload->clock = clk; memcpy(payload->data, DemodBuffer, size); - PrintAndLogEx(INFO, "Simulating"); - clearCommandBuffer(); SendCommandNG(CMD_LF_FSK_SIMULATE, (uint8_t *)payload, sizeof(lf_fsksim_t) + size); free(payload); - setClockGrid(clk, 0); - PacketResponseNG resp; - WaitForResponse(CMD_LF_FSK_SIMULATE, &resp); - PrintAndLogEx(INFO, "Done"); - if (resp.status != PM3_EOPABORTED) - return resp.status; - return PM3_SUCCESS; + return lfsim_wait_check(CMD_LF_FSK_SIMULATE); } // sim ask data given clock, invert, manchester or raw, separator // - allow pull data from DemodBuffer int CmdLFaskSim(const char *Cmd) { - // autodetect clock from Graphbuffer if using demod buffer - // needs clock, invert, manchester/raw as m or r, separator as s, and bitstream - uint8_t encoding = 1, separator = 0, clk = 0, invert = 0; - bool errors = false; - char hexData[64] = {0x00}; - uint8_t data[255] = {0x00}; // store entered hex data - int dataLen = 0; - uint8_t cmdp = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf simask", + "Simulate ASK tag from demodbuffer or input", + "lf simask --clk 32 --am -d 0102030405 --> simulate ASK/MAN rf/32\n" + "lf simask --clk 32 --bi -d 0102030405 --> simulate ASK/BIPHASE rf/32\n\n" + "lf simask --clk 64 --am -d ffbd8001686f1924 --> simulate a EM410x tag\n" + "lf simask --clk 64 --am --stt -d 5649533200003F340000001B --> simulate a VISA2K tag" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_simask(); - case 'i': - invert = 1; - cmdp++; - break; - case 'c': - errors |= param_getdec(Cmd, cmdp + 1, &clk); - cmdp += 2; - break; - case 'b': - encoding = 2; //biphase - cmdp++; - break; - case 'm': - encoding = 1; //manchester - cmdp++; - break; - case 'r': - encoding = 0; //raw - cmdp++; - break; - case 's': - separator = 1; - cmdp++; - break; - case 'd': - dataLen = param_getstr(Cmd, cmdp + 1, hexData, sizeof(hexData)); - if (dataLen == 0) - errors = true; - else - dataLen = hextobinarray((char *)data, hexData); + void *argtable[] = { + arg_param_begin, + arg_lit0("i", "inv", "invert data"), + arg_u64_0("c", "clk", "", "manually set clock - can autodetect if using DemodBuffer (default 64)"), + arg_lit0(NULL, "bi", "ask/biphase encoding"), + arg_lit0(NULL, "am", "ask/manchester encoding (default)"), + arg_lit0(NULL, "ar", "ask/raw encoding"), + arg_lit0(NULL, "stt", "add t55xx Sequence Terminator gap - default: no gaps (only manchester)"), + arg_str0("d", "data", "", "data to sim - omit to use DemodBuffer"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool invert = arg_get_lit(ctx, 1); + uint8_t clk = arg_get_u32_def(ctx, 2, 0); + bool use_bi = arg_get_lit(ctx, 3); + bool use_am = arg_get_lit(ctx, 4); + bool use_ar = arg_get_lit(ctx, 5); + bool separator = arg_get_lit(ctx, 6); - if (dataLen == 0) errors = true; - if (errors) PrintAndLogEx(ERR, "Error getting hex data, datalen: %d", dataLen); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + int raw_len = 64; + char raw[64] = {0}; + CLIGetStrWithReturn(ctx, 7, (uint8_t *)raw, &raw_len); + bool verbose = arg_get_lit(ctx, 8); + CLIParserFree(ctx); + + if ((use_bi + use_am + use_ar) > 1) { + PrintAndLogEx(ERR, "only one encoding can be set"); + return PM3_EINVARG; } + uint8_t encoding = 1; + if (use_bi) + encoding = 2; + else if (use_ar) + encoding = 0; + // No args - if (cmdp == 0 && DemodBufferLen == 0) return usage_lf_simask(); - - //Validations - if (errors) return usage_lf_simask(); - - if (dataLen == 0) { //using DemodBuffer - if (clk == 0) - clk = GetAskClock("0", false); - } else { - setDemodBuff(data, dataLen, 0); + if (raw_len == 0 && DemodBufferLen == 0) { + PrintAndLogEx(ERR, "No user supplied data nor any inside Demodbuffer"); + return PM3_EINVARG; + } + + uint8_t bs[256] = {0x00}; + int bs_len = hextobinarray((char *)bs, raw); + if (bs_len == 0) { + // Using data from DemodBuffer + // might be able to autodetect FC and clock from Graphbuffer if using demod buffer + // will need carrier, clock, and bitstream + PrintAndLogEx(INFO, "No user supplied data, using Demodbuffer..."); + + int res = 0; + if (clk == 0) { + res = GetAskClock("0", verbose); + if (res < 1) { + clk = 64; + } else { + clk = (uint8_t)res; + } + } + + PrintAndLogEx(DEBUG, "Detected rf/%u, n %zu ", clk, DemodBufferLen); + + } else { + setDemodBuff(bs, bs_len, 0); + } + + + if (clk == 0) { + clk = 32; + PrintAndLogEx(DEBUG, "Autodetection of clock failed, falling back to rf/%u", clk); + } + + if (encoding == 0) { + clk /= 2; // askraw needs to double the clock speed + PrintAndLogEx(DEBUG, "ASK/RAW needs half rf. Using rf/%u", clk); } - if (clk == 0) clk = 64; - if (encoding == 0) clk /= 2; //askraw needs to double the clock speed size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t))) { PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t)); + PrintAndLogEx(INFO, "Continuing with trimmed down data"); size = PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t); } lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + size); - payload->encoding = encoding; + payload->encoding = encoding; payload->invert = invert; payload->separator = separator; payload->clock = clk; memcpy(payload->data, DemodBuffer, size); - PrintAndLogEx(INFO, "Simulating"); - clearCommandBuffer(); SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + size); free(payload); + setClockGrid(clk, 0); - PacketResponseNG resp; - WaitForResponse(CMD_LF_ASK_SIMULATE, &resp); - - PrintAndLogEx(INFO, "Done"); - if (resp.status != PM3_EOPABORTED) - return resp.status; - return PM3_SUCCESS; + return lfsim_wait_check(CMD_LF_ASK_SIMULATE); } // sim psk data given carrier, clock, invert // - allow pull data from DemodBuffer or parameters int CmdLFpskSim(const char *Cmd) { - //might be able to autodetect FC and clock from Graphbuffer if using demod buffer - //will need carrier, Clock, and bitstream - uint8_t carrier = 0, clk = 0; - uint8_t invert = 0; - bool errors = false; - char hexData[64] = {0x00}; // store entered hex data - uint8_t data[255] = {0x00}; - int dataLen = 0; - uint8_t cmdp = 0; - uint8_t pskType = 1; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_simpsk(); - case 'i': - invert = 1; - cmdp++; - break; - case 'c': - errors |= param_getdec(Cmd, cmdp + 1, &clk); - cmdp += 2; - break; - case 'r': - errors |= param_getdec(Cmd, cmdp + 1, &carrier); - cmdp += 2; - break; - case '1': - pskType = 1; - cmdp++; - break; - case '2': - pskType = 2; - cmdp++; - break; - case '3': - pskType = 3; - cmdp++; - break; - case 'd': - dataLen = param_getstr(Cmd, cmdp + 1, hexData, sizeof(hexData)); - if (dataLen == 0) - errors = true; - else - dataLen = hextobinarray((char *)data, hexData); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf simpsk", + "Simulate PSK tag from demodbuffer or input", + "lf simpsk -1 --clk 40 --fc 4 -d 01020304 --> simulate PSK1 rf/40 psksub fc/4, data 01020304\n\n" + "lf simpsk -1 --clk 32 --fc 2 -d a0000000bd989a11 --> simulate a indala tag manually" + ); - if (dataLen == 0) errors = true; - if (errors) PrintAndLogEx(ERR, "Error getting hex data"); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + void *argtable[] = { + arg_param_begin, + arg_lit0("1", "psk1", "set PSK1 (default)"), + arg_lit0("2", "psk2", "set PSK2"), + arg_lit0("3", "psk3", "set PSK3"), + arg_lit0("i", "inv", "invert data"), + arg_u64_0("c", "clk", "", "manually set clock - can autodetect if using DemodBuffer (default 32)"), + arg_u64_0(NULL, "fc", "", "2|4|8 are valid carriers (default 2)"), + arg_str0("d", "data", "", "data to sim - omit to use DemodBuffer"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool use_psk1 = arg_get_lit(ctx, 1); + bool use_psk2 = arg_get_lit(ctx, 2); + bool use_psk3 = arg_get_lit(ctx, 3); + bool invert = arg_get_lit(ctx, 4); + uint8_t clk = arg_get_u32_def(ctx, 5, 0); + uint8_t carrier = arg_get_u32_def(ctx, 6, 2); + int raw_len = 64; + char raw[64] = {0}; + CLIGetStrWithReturn(ctx, 7, (uint8_t *)raw, &raw_len); + bool verbose = arg_get_lit(ctx, 8); + CLIParserFree(ctx); + + if ((use_psk1 + use_psk2 + use_psk3) > 1) { + PrintAndLogEx(ERR, "only one PSK mode can be set"); + return PM3_EINVARG; } + + if (carrier != 2 && carrier != 4 && carrier != 8) { + PrintAndLogEx(ERR, "Wrong carrier given, expected <2|4|8>"); + return PM3_EINVARG; + } + + uint8_t psk_type = 1; + if (use_psk2) + psk_type = 2; + if (use_psk3) + psk_type = 3; + // No args - if (cmdp == 0 && DemodBufferLen == 0) - errors = true; + if (raw_len == 0 && DemodBufferLen == 0) { + PrintAndLogEx(ERR, "No user supplied data nor any inside Demodbuffer"); + return PM3_EINVARG; + } - //Validations - if (errors) return usage_lf_simpsk(); + uint8_t bs[256] = {0x00}; + int bs_len = hextobinarray((char *)bs, raw); - if (dataLen == 0) { //using DemodBuffer - PrintAndLogEx(INFO, "Getting Clocks"); + if (bs_len == 0) { + // Using data from DemodBuffer + // might be able to autodetect FC and clock from Graphbuffer if using demod buffer + // will need carrier, clock, and bitstream + PrintAndLogEx(INFO, "No user supplied data, using Demodbuffer..."); - if (clk == 0) clk = GetPskClock("", false); - PrintAndLogEx(INFO, "clk: %d", clk); + int res = 0; + if (clk == 0) { + res = GetPskClock("", verbose); + if (res < 1) { + clk = 32; + } else { + clk = (uint8_t)res; + } + } - if (!carrier) carrier = GetPskCarrier(false); - PrintAndLogEx(INFO, "carrier: %d", carrier); + if (carrier == 0) { + res = GetPskCarrier(verbose); + if (res < 1) { + carrier = 2; + } else { + carrier = (uint8_t)res; + } + } + + PrintAndLogEx(DEBUG, "Detected rf/%u, fc/%u, n %zu ", clk, carrier, DemodBufferLen); } else { - setDemodBuff(data, dataLen, 0); + setDemodBuff(bs, bs_len, 0); } - if (clk == 0) clk = 32; - - if (carrier != 2 && carrier != 4 && carrier != 8) - carrier = 2; - - if (pskType != 1) { - if (pskType == 2) { - //need to convert psk2 to psk1 data before sim - psk2TOpsk1(DemodBuffer, DemodBufferLen); - } else { - PrintAndLogEx(WARNING, "Sorry, PSK3 not yet available"); - } + if (clk == 0) { + clk = 32; + PrintAndLogEx(DEBUG, "Autodetection of clock failed, falling back to rf/%u", clk); } + + if (psk_type == 2) { + //need to convert psk2 to psk1 data before sim + psk2TOpsk1(DemodBuffer, DemodBufferLen); + } else if (psk_type == 3) { + PrintAndLogEx(INFO, "PSK3 not yet available. Falling back to PSK1"); + psk_type = 1; + } + size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t))) { PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t)); + PrintAndLogEx(INFO, "Continuing with trimmed down data"); size = PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t); } @@ -1232,20 +1167,12 @@ int CmdLFpskSim(const char *Cmd) { payload->invert = invert; payload->clock = clk; memcpy(payload->data, DemodBuffer, size); - - PrintAndLogEx(INFO, "Simulating"); - clearCommandBuffer(); SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + size); free(payload); + setClockGrid(clk, 0); - PacketResponseNG resp; - WaitForResponse(CMD_LF_PSK_SIMULATE, &resp); - - PrintAndLogEx(INFO, "Done"); - if (resp.status != PM3_EOPABORTED) - return resp.status; - return PM3_SUCCESS; + return lfsim_wait_check(CMD_LF_PSK_SIMULATE); } int CmdLFSimBidir(const char *Cmd) { @@ -1564,6 +1491,7 @@ out: } static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, {"-----------", CmdHelp, AlwaysAvailable, "-------------- " _CYAN_("Low Frequency") " --------------"}, {"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"}, {"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"}, @@ -1594,20 +1522,19 @@ static command_t CommandTable[] = { {"viking", CmdLFViking, AlwaysAvailable, "{ Viking RFIDs... }"}, {"visa2000", CmdLFVisa2k, AlwaysAvailable, "{ Visa2000 RFIDs... }"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"}, - {"help", CmdHelp, AlwaysAvailable, "This help"}, {"config", CmdLFConfig, IfPm3Lf, "Get/Set config for LF sampling, bit/sample, decimation, frequency"}, - {"cmdread", CmdLFCommandRead, IfPm3Lf, "Modulate LF reader field to send command before read (all periods in microseconds)"}, + {"cmdread", CmdLFCommandRead, IfPm3Lf, "Modulate LF reader field to send command before read"}, {"read", CmdLFRead, IfPm3Lf, "Read LF tag"}, {"search", CmdLFfind, AlwaysAvailable, "Read and Search for valid known tag"}, - {"sim", CmdLFSim, IfPm3Lf, "Simulate LF tag from buffer with optional GAP (in microseconds)"}, - {"simask", CmdLFaskSim, IfPm3Lf, "Simulate " _YELLOW_("LF ASK tag") " from demodbuffer or input"}, - {"simfsk", CmdLFfskSim, IfPm3Lf, "Simulate " _YELLOW_("LF FSK tag") " from demodbuffer or input"}, - {"simpsk", CmdLFpskSim, IfPm3Lf, "Simulate " _YELLOW_("LF PSK tag") " from demodbuffer or input"}, -// {"simnrz", CmdLFnrzSim, IfPm3Lf, "Simulate " _YELLOW_("LF NRZ tag") " from demodbuffer or input"}, + {"sim", CmdLFSim, IfPm3Lf, "Simulate LF tag from buffer"}, + {"simask", CmdLFaskSim, IfPm3Lf, "Simulate " _YELLOW_("ASK") " tag"}, + {"simfsk", CmdLFfskSim, IfPm3Lf, "Simulate " _YELLOW_("FSK") " tag"}, + {"simpsk", CmdLFpskSim, IfPm3Lf, "Simulate " _YELLOW_("PSK") " tag"}, +// {"simnrz", CmdLFnrzSim, IfPm3Lf, "Simulate " _YELLOW_("NRZ") " tag"}, {"simbidir", CmdLFSimBidir, IfPm3Lf, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, {"sniff", CmdLFSniff, IfPm3Lf, "Sniff LF traffic between reader and tag"}, {"tune", CmdLFTune, IfPm3Lf, "Continuously measure LF antenna tuning"}, -// {"vchdemod", CmdVchDemod, AlwaysAvailable, "['clone'] -- Demodulate samples for VeriChip"}, +// {"vchdemod", CmdVchDemod, AlwaysAvailable, "Demodulate samples for VeriChip"}, // {"flexdemod", CmdFlexdemod, AlwaysAvailable, "Demodulate samples for Motorola FlexPass"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlf.h b/client/src/cmdlf.h index bcc695764..c68289c45 100644 --- a/client/src/cmdlf.h +++ b/client/src/cmdlf.h @@ -36,5 +36,6 @@ int lf_read(bool verbose, uint32_t samples); int lf_sniff(bool verbose, uint32_t samples); int lf_config(sample_config *config); int lf_getconfig(sample_config *config); - +int lfsim_upload_gb(void); +int lfsim_wait_check(uint32_t cmd); #endif diff --git a/client/src/cmdlfawid.c b/client/src/cmdlfawid.c index c54c3cd1d..1a06e72e2 100644 --- a/client/src/cmdlfawid.c +++ b/client/src/cmdlfawid.c @@ -129,10 +129,7 @@ static int CmdAWIDWatch(const char *Cmd) { PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); clearCommandBuffer(); SendCommandNG(CMD_LF_AWID_WATCH, NULL, 0); - PacketResponseNG resp; - WaitForResponse(CMD_LF_AWID_WATCH, &resp); - PrintAndLogEx(INFO, "Done"); - return resp.status; + return lfsim_wait_check(CMD_LF_AWID_WATCH); } //by marshmellow @@ -438,8 +435,7 @@ static int CmdAWIDSim(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fmtlen, fc, cn); - PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command"); + PrintAndLogEx(SUCCESS, "Simulating "_YELLOW_("AWID %u") " -- FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fmtlen, fc, cn); // AWID uses: FSK2a fcHigh: 10, fcLow: 8, clk: 50, invert: 1 // arg1 --- fcHigh<<8 + fcLow @@ -456,13 +452,7 @@ static int CmdAWIDSim(const char *Cmd) { SendCommandNG(CMD_LF_FSK_SIMULATE, (uint8_t *)payload, sizeof(lf_fsksim_t) + sizeof(bs)); free(payload); - PacketResponseNG resp; - WaitForResponse(CMD_LF_FSK_SIMULATE, &resp); - - PrintAndLogEx(INFO, "Done"); - if (resp.status != PM3_EOPABORTED) - return resp.status; - return PM3_SUCCESS; + return lfsim_wait_check(CMD_LF_FSK_SIMULATE); } static int CmdAWIDBrute(const char *Cmd) { @@ -630,7 +620,7 @@ int getAWIDBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *bits) { if (bitLen != 88) return PM3_ESOFT; - PrintAndLogEx(SUCCESS, "awid raw bits:\n %s \n", sprint_bin(bits, bitLen)); + PrintAndLogEx(DEBUG, "awid raw bits:\n %s \n", sprint_bin(bits, bitLen)); return PM3_SUCCESS; } diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index c2ee95a9d..1c82aadce 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -286,14 +286,10 @@ static int CmdEM410xWatch(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); CLIParserFree(ctx); - PrintAndLogEx(SUCCESS, "Watching for EM410x cards - place tag on antenna"); - PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); + PrintAndLogEx(SUCCESS, "Watching for EM410x cards - place tag on Proxmark3 antenna"); clearCommandBuffer(); SendCommandNG(CMD_LF_EM410X_WATCH, NULL, 0); - PacketResponseNG resp; - WaitForResponse(CMD_LF_EM410X_WATCH, &resp); - PrintAndLogEx(INFO, "Done"); - return resp.status; + return lfsim_wait_check(CMD_LF_EM410X_WATCH); } //by marshmellow @@ -320,11 +316,11 @@ static int CmdEM410xDemod(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_u64_0(NULL, "clk", "", "optional - clock (default autodetect)"), - arg_u64_0(NULL, "err", "", "optional - maximum allowed errors (default 100)"), - arg_u64_0(NULL, "len", "", "optional - maximum length"), - arg_lit0("i", "invert", "optional - invert output"), - arg_lit0("a", "amp", "optional - amplify signal"), + arg_u64_0(NULL, "clk", "", "clock (default autodetect)"), + arg_u64_0(NULL, "err", "", "maximum allowed errors (default 100)"), + arg_u64_0(NULL, "len", "", "maximum length"), + arg_lit0("i", "invert", "invert output"), + arg_lit0("a", "amp", "amplify signal"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -359,12 +355,13 @@ static int CmdEM410xReader(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_u64_0(NULL, "clk", "", "optional - clock (default autodetect)"), - arg_u64_0(NULL, "err", "", "optional - maximum allowed errors (default 100)"), - arg_u64_0(NULL, "len", "", "optional - maximum length"), - arg_lit0("i", "invert", "optional - invert output"), - arg_lit0("a", "amp", "optional - amplify signal"), - arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_u64_0(NULL, "clk", "", "clock (default autodetect)"), + arg_u64_0(NULL, "err", "", "maximum allowed errors (default 100)"), + arg_u64_0(NULL, "len", "", "maximum length"), + arg_lit0("i", "invert", "invert output"), + arg_lit0("a", "amp", "amplify signal"), + arg_lit0("b", NULL, "break on first found"), + arg_lit0("@", NULL, "continuous reader mode"), arg_lit0("v", "verbose", "verbose output"), arg_param_end }; @@ -375,8 +372,9 @@ static int CmdEM410xReader(const char *Cmd) { size_t max_len = arg_get_u32_def(ctx, 3, 0); bool invert = arg_get_lit(ctx, 4); bool amplify = arg_get_lit(ctx, 5); - bool cm = arg_get_lit(ctx, 6); - bool verbose = arg_get_lit(ctx, 7); + bool break_first = arg_get_lit(ctx, 6); + bool cm = arg_get_lit(ctx, 7); + bool verbose = arg_get_lit(ctx, 8); CLIParserFree(ctx); if (cm) { @@ -388,6 +386,10 @@ static int CmdEM410xReader(const char *Cmd) { uint64_t lo = 0; lf_read(false, 12288); AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, verbose); + + if (break_first && g_em410xid != 0) { + break; + } } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; @@ -406,8 +408,8 @@ static int CmdEM410xSim(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_u64_0(NULL, "clk", "", "optional - clock [32|64] (default 64)"), - arg_str1("i", "id", "", "ID number (5 hex bytes)"), + arg_u64_0(NULL, "clk", "", "<32|64> clock (default 64)"), + arg_str1(NULL, "id", "", "ID number (5 hex bytes)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -425,11 +427,8 @@ static int CmdEM410xSim(const char *Cmd) { } PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%s")" clock: "_YELLOW_("%d"), sprint_hex_inrow(uid, sizeof(uid)), clk); - PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation"); - em410x_construct_emul_graph(uid, clk); - - CmdLFSim("0"); // 240 start_gap. + CmdLFSim(""); return PM3_SUCCESS; } @@ -445,8 +444,8 @@ static int CmdEM410xBrute(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_u64_1(NULL, "clk", "", "optional - clock [32|64] (default 64)"), - arg_u64_1(NULL, "delay", "", "optional - pause delay in milliseconds between UIDs simulation (default 1000ms)"), + arg_u64_0(NULL, "clk", "", "<32|64> clock (default 64)"), + arg_u64_0(NULL, "delay", "", "pause delay in milliseconds between UIDs simulation (default 1000ms)"), arg_str1("f", "file", "", "file with UIDs in HEX format, one per line"), arg_param_end }; @@ -536,13 +535,14 @@ static int CmdEM410xBrute(const char *Cmd) { uint8_t testuid[5]; for (uint32_t c = 0; c < uidcnt; ++c) { if (kbd_enter_pressed()) { - PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + PrintAndLogEx(INFO, "Aborted via keyboard!\n"); free(uidblock); return PM3_EOPABORTED; } memcpy(testuid, uidblock + 5 * c, 5); - PrintAndLogEx(INFO, "Bruteforce %d / %d: simulating UID " _YELLOW_("%s") + PrintAndLogEx(INFO, "Bruteforce %d / %u: simulating UID " _YELLOW_("%s") , c + 1 , uidcnt , sprint_hex_inrow(testuid, sizeof(testuid)) @@ -550,9 +550,25 @@ static int CmdEM410xBrute(const char *Cmd) { em410x_construct_emul_graph(testuid, clk); - CmdLFSim("0"); //240 start_gap. + lfsim_upload_gb(); - msleep(delay); + struct p { + uint16_t len; + uint16_t gap; + } PACKED payload; + payload.len = GraphTraceLen; + payload.gap = 0; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload)); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_LF_SIMULATE, &resp, delay)) { + if (resp.status == PM3_EOPABORTED) { + PrintAndLogEx(INFO, "Button pressed, user aborted"); + break; + } + } } free(uidblock); return PM3_SUCCESS; @@ -575,9 +591,10 @@ static int CmdEM410xSpoof(const char *Cmd) { CLIParserFree(ctx); // loops if the captured ID was in XL-format. - CmdEM410xReader("-@"); - PrintAndLogEx(SUCCESS, "# Replaying captured ID: "_YELLOW_("%010" PRIx64), g_em410xid); - CmdLFaskSim(""); + g_em410xid = 0; + CmdEM410xReader("-b@"); + PrintAndLogEx(SUCCESS, "Replaying captured ID "_YELLOW_("%010" PRIx64), g_em410xid); + CmdLFSim(""); return PM3_SUCCESS; } @@ -585,15 +602,15 @@ static int CmdEM410xClone(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 410x clone", "Writes EM410x ID to a T55x7 or Q5/T5555 tag", - "lf em 410x clone --uid 0F0368568B -> write id to T55x7 tag\n" - "lf em 410x clone --uid 0F0368568B --q5 -> write id to Q5/T5555 tag" + "lf em 410x clone --id 0F0368568B -> write id to T55x7 tag\n" + "lf em 410x clone --id 0F0368568B --q5 -> write id to Q5/T5555 tag" ); void *argtable[] = { arg_param_begin, - arg_u64_0(NULL, "clk", "", "optional - clock <16|32|40|64> (default 64)"), - arg_str1("u", "uid", "", "ID number (5 hex bytes)"), - arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_u64_0(NULL, "clk", "", "<16|32|40|64> clock (default 64)"), + arg_str1(NULL, "id", "", "ID number (5 hex bytes)"), + arg_lit0(NULL, "q5", "specify writing to Q5/T5555 tag"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); diff --git a/client/src/cmdlfgallagher.c b/client/src/cmdlfgallagher.c index 3e13aadf3..31d2b7d0a 100644 --- a/client/src/cmdlfgallagher.c +++ b/client/src/cmdlfgallagher.c @@ -29,8 +29,7 @@ static int CmdHelp(const char *Cmd); -static void descramble(uint8_t *arr, uint8_t len) { - +static void scramble(uint8_t *arr, uint8_t len) { uint8_t lut[] = { 0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c, 0x05, 0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04, 0x51, 0x2e, @@ -55,6 +54,31 @@ static void descramble(uint8_t *arr, uint8_t len) { } } +static void descramble(uint8_t *arr, uint8_t len) { + uint8_t lut[] = { + 0x2f, 0x6e, 0xdd, 0xdf, 0x1d, 0x0f, 0xb0, 0x76, 0xad, 0xaf, 0x7f, 0xbb, 0x77, 0x85, 0x11, 0x6d, + 0xf4, 0xd2, 0x84, 0x42, 0xeb, 0xf7, 0x34, 0x55, 0x4a, 0x3a, 0x10, 0x71, 0xe7, 0xa1, 0x62, 0x1a, + 0x3e, 0x4c, 0x14, 0xd3, 0x5e, 0xb2, 0x7d, 0x56, 0xbc, 0x27, 0x82, 0x60, 0xe3, 0xae, 0x1f, 0x9b, + 0xaa, 0x2b, 0x95, 0x49, 0x73, 0xe1, 0x92, 0x79, 0x91, 0x38, 0x6c, 0x19, 0x0e, 0xa9, 0xe2, 0x8d, + 0x66, 0xc7, 0x5a, 0xf5, 0x1c, 0x80, 0x99, 0xbe, 0x4e, 0x41, 0xf0, 0xe8, 0xa6, 0x20, 0xab, 0x87, + 0xc8, 0x1e, 0xa0, 0x59, 0x7b, 0x0c, 0xc3, 0x3c, 0x61, 0xcc, 0x40, 0x9e, 0x06, 0x52, 0x1b, 0x32, + 0x8c, 0x12, 0x93, 0xbf, 0xef, 0x3b, 0x25, 0x0d, 0xc2, 0x88, 0xd1, 0xe0, 0x07, 0x2d, 0x70, 0xc6, + 0x29, 0x6a, 0x4d, 0x47, 0x26, 0xa3, 0xe4, 0x8b, 0xf6, 0x97, 0x2c, 0x5d, 0x3d, 0xd7, 0x96, 0x28, + 0x02, 0x08, 0x30, 0xa7, 0x22, 0xc9, 0x65, 0xf8, 0xb7, 0xb4, 0x8a, 0xca, 0xb9, 0xf2, 0xd0, 0x17, + 0xff, 0x46, 0xfb, 0x9a, 0xba, 0x8f, 0xb6, 0x69, 0x68, 0x8e, 0x21, 0x6f, 0xc4, 0xcb, 0xb3, 0xce, + 0x51, 0xd4, 0x81, 0x00, 0x2e, 0x9c, 0x74, 0x63, 0x45, 0xd9, 0x16, 0x35, 0x5f, 0xed, 0x78, 0x9f, + 0x01, 0x48, 0x04, 0xc1, 0x33, 0xd6, 0x4f, 0x94, 0xde, 0x31, 0x9d, 0x0a, 0xac, 0x18, 0x4b, 0xcd, + 0x98, 0xb8, 0x37, 0xa2, 0x83, 0xec, 0x03, 0xd8, 0xda, 0xe5, 0x7a, 0x6b, 0x53, 0xd5, 0x15, 0xa4, + 0x43, 0xe9, 0x90, 0x67, 0x58, 0xc0, 0xa5, 0xfa, 0x2a, 0xb1, 0x75, 0x50, 0x39, 0x5c, 0xe6, 0xdc, + 0x89, 0xfc, 0xcf, 0xfe, 0xf9, 0x57, 0x54, 0x64, 0xa8, 0xee, 0x23, 0x0b, 0xf1, 0xea, 0xfd, 0xdb, + 0xbd, 0x09, 0xb5, 0x5b, 0x05, 0x86, 0x13, 0xf3, 0x24, 0xc5, 0x3f, 0x44, 0x72, 0x7c, 0x7e, 0x36 + }; + + for (int i = 0; i < len; i++) { + arr[i] = lut[arr[i]]; + } +} + //see ASK/MAN Demod for what args are accepted int demodGallagher(bool verbose) { (void) verbose; // unused so far @@ -81,7 +105,7 @@ int demodGallagher(bool verbose) { setDemodBuff(DemodBuffer, 96, ans); setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock)); - //got a good demod + // got a good demod uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32); uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32); @@ -89,34 +113,30 @@ int demodGallagher(bool verbose) { // bytes uint8_t arr[8] = {0}; for (int i = 0, pos = 0; i < ARRAYLEN(arr); i++) { - pos = (i * 8) + i; + pos = 16 + (9 * i); arr[i] = bytebits_to_byte(DemodBuffer + pos, 8); - PrintAndLogEx(NORMAL, "%d -" NOLF, pos); } - PrintAndLogEx(NORMAL, ""); // crc - uint8_t crc = bytebits_to_byte(DemodBuffer + 72, 8); + uint8_t crc = bytebits_to_byte(DemodBuffer + 16 + (9 * 8), 8); uint8_t calc_crc = CRC8Cardx(arr, ARRAYLEN(arr)); - PrintAndLogEx(INFO, " Before: %s", sprint_hex(arr, 8)); descramble(arr, ARRAYLEN(arr)); - PrintAndLogEx(INFO, " After : %s", sprint_hex(arr, 8)); // 4bit region code - uint8_t rc = (arr[3] & 0x0E) >> 1; + uint8_t rc = (arr[3] & 0x1E) >> 1; // 16bit FC uint16_t fc = (arr[5] & 0x0F) << 12 | arr[1] << 4 | ((arr[7] >> 4) & 0x0F); // 24bit CN - uint32_t cn = arr[0] << 16 | (arr[4] & 0x1F) << 11 | arr[2] << 3 | (arr[3] & 0xE0) >> 4; + uint32_t cn = arr[0] << 16 | (arr[4] & 0x1F) << 11 | arr[2] << 3 | (arr[3] & 0xE0) >> 5; // 4bit issue level uint8_t il = arr[7] & 0x0F; PrintAndLogEx(SUCCESS, "GALLAGHER - Region: " _GREEN_("%u") " FC: " _GREEN_("%u") " CN: " _GREEN_("%u") " Issue Level: " _GREEN_("%u"), rc, fc, cn, il); - PrintAndLogEx(SUCCESS, " Printed: " _GREEN_("%C%u"), rc + 0x40, fc); + PrintAndLogEx(SUCCESS, " Displayed: " _GREEN_("%C%u"), rc + 'A', fc); PrintAndLogEx(SUCCESS, " Raw: %08X%08X%08X", raw1, raw2, raw3); PrintAndLogEx(SUCCESS, " CRC: %02X - %02X (%s)", crc, calc_crc, (crc == calc_crc) ? "ok" : "fail"); return PM3_SUCCESS; @@ -165,6 +185,78 @@ static int CmdGallagherReader(const char *Cmd) { return PM3_SUCCESS; } +static bool isValidGallagherParams(int8_t rc, int32_t fc, int32_t cn, int8_t il) { + bool isValid = true; + + // if one is set, all must be set + if (rc < 0 || fc < 0 || cn < 0 || il < 0) { + PrintAndLogEx(FAILED, "If rc/fc/cn/il is specified, all must be set"); + isValid = false; + } + // validate input + if (rc > 0x0f) { + PrintAndLogEx(FAILED, "Region code must be less than 16 (4 bits)"); + isValid = false; + } + if (fc > 0xffff) { + PrintAndLogEx(FAILED, "Facility code must be less than 65536 (2 bytes)"); + isValid = false; + } + if (cn > 0xffffff) { + PrintAndLogEx(FAILED, "Card number must be less than 16777216 (3 bytes)"); + isValid = false; + } + if (il > 0x0f) { + PrintAndLogEx(FAILED, "Issue level must be less than 16 (4 bits)"); + isValid = false; + } + return isValid; +} + +static void setBitsInBlocks(uint32_t *blocks, uint8_t *pos, uint32_t data, uint8_t data_len) { + for (int i = data_len - 1; i >= 0; i--) { + uint8_t blk = *pos / 32; + uint8_t bitPos = 31 - *pos % 32; // fill from left + uint8_t bit = (data >> i) & 1; + blocks[blk] |= bit << bitPos; + (*pos)++; + } +} + +static void createBlocks(uint32_t *blocks, uint8_t rc, uint16_t fc, uint32_t cn, uint8_t il) { + // put data into the correct places (Gallagher obfuscation) + uint8_t arr[8] = {0}; + arr[0] = (cn & 0xffffff) >> 16; + arr[1] = (fc & 0xfff) >> 4; + arr[2] = (cn & 0x7ff) >> 3; + arr[3] = (cn & 0x7) << 5 | (rc & 0xf) << 1; + arr[4] = (cn & 0xffff) >> 11; + arr[5] = (fc & 0xffff) >> 12; + arr[6] = 0; + arr[7] = (fc & 0xf) << 4 | (il & 0xf); + + // more obfuscation + scramble(arr, ARRAYLEN(arr)); + + blocks[0] = blocks[1] = blocks[2] = 0; + uint8_t pos = 0; + + // magic prefix + setBitsInBlocks(blocks, &pos, 0x7fea, 16); + + for (int i = 0; i < ARRAYLEN(arr); i++) { + // data byte + setBitsInBlocks(blocks, &pos, arr[i], 8); + + // every byte is followed by a bit which is the inverse of the last bit + setBitsInBlocks(blocks, &pos, !(arr[i] & 0x1), 1); + } + + // checksum + uint8_t crc = CRC8Cardx(arr, ARRAYLEN(arr)); + setBitsInBlocks(blocks, &pos, crc, 8); +} + static int CmdGallagherClone(const char *Cmd) { CLIParserContext *ctx; @@ -172,14 +264,19 @@ static int CmdGallagherClone(const char *Cmd) { "clone a GALLAGHER tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", "lf gallagher clone --raw 0FFD5461A9DA1346B2D1AC32\n" "lf gallagher clone --q5 --raw 0FFD5461A9DA1346B2D1AC32 -> encode for Q5/T5555 tag\n" - "lf gallagher clone --em --raw 0FFD5461A9DA1346B2D1AC32 -> encode for EM4305/4469" + "lf gallagher clone --em --raw 0FFD5461A9DA1346B2D1AC32 -> encode for EM4305/4469\n" + "lf gallagher clone --rc 0 --fc 9876 --cn 1234 --il 1" ); void *argtable[] = { arg_param_begin, - arg_str1("r", "raw", "", "raw hex data. 12 bytes max"), + arg_str0("r", "raw", "", "raw hex data. 12 bytes max"), arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_int0(NULL, "rc", "", "Region code. 4 bits max"), + arg_int0(NULL, "fc", "", "Facility code. 2 bytes max"), + arg_int0(NULL, "cn", "", "Card number. 3 bytes max"), + arg_int0(NULL, "il", "", "Issue level. 4 bits max"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -187,19 +284,51 @@ static int CmdGallagherClone(const char *Cmd) { int raw_len = 0; // skip first block, 3*4 = 12 bytes left uint8_t raw[12] = {0}; - CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + int res = CLIParamHexToBuf(arg_get_str(ctx, 1), raw, sizeof raw, &raw_len); + if (res) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + bool q5 = arg_get_lit(ctx, 2); bool em = arg_get_lit(ctx, 3); + int16_t region_code = arg_get_int_def(ctx, 4, -1); + int32_t facility_code = arg_get_int_def(ctx, 5, -1); + uint64_t card_number = arg_get_int_def(ctx, 6, -1); + uint32_t issue_level = arg_get_int_def(ctx, 7, -1); CLIParserFree(ctx); + bool use_raw = raw_len > 0; + if (q5 && em) { PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); return PM3_EINVARG; } + if (region_code == -1 && facility_code == -1 && card_number == -1 && issue_level == -1) { + if (!use_raw) { + PrintAndLogEx(FAILED, "Must specify either raw data to clone, or rc/fc/cn/il"); + return PM3_EINVARG; + } + } else { + // --raw and --rc/fc/cn/il are mutually exclusive + if (use_raw) { + PrintAndLogEx(FAILED, "Can't specify both raw and rc/fc/cn/il at the same time"); + return PM3_EINVARG; + } + if (!isValidGallagherParams(region_code, facility_code, card_number, issue_level)) { + return PM3_EINVARG; + } + } + uint32_t blocks[4]; - for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { - blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); + if (use_raw) { + for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { + blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); + } + } else { + // fill blocks 1 to 3 with Gallagher data + createBlocks(blocks + 1, region_code, facility_code, card_number, issue_level); } //Pac - compat mode, NRZ, data rate 40, 3 data blocks @@ -217,10 +346,10 @@ static int CmdGallagherClone(const char *Cmd) { snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); } - PrintAndLogEx(INFO, "Preparing to clone Gallagher to " _YELLOW_("%s") " with raw hex", cardtype); + PrintAndLogEx(INFO, "Preparing to clone Gallagher to " _YELLOW_("%s") " from %s.", + cardtype, use_raw ? "raw hex" : "specified data"); print_blocks(blocks, ARRAYLEN(blocks)); - int res; if (em) { res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); } else { @@ -237,21 +366,69 @@ static int CmdGallagherSim(const char *Cmd) { CLIParserInit(&ctx, "lf gallagher sim", "Enables simulation of GALLAGHER card with specified card number.\n" "Simulation runs until the button is pressed or another USB command is issued.\n", - "lf gallagher sim --raw 0FFD5461A9DA1346B2D1AC32" + "lf gallagher sim --raw 0FFD5461A9DA1346B2D1AC32\n" + "lf gallagher sim --rc 0 --fc 9876 --cn 1234 --il 1" ); void *argtable[] = { arg_param_begin, - arg_str1("r", "raw", "", "raw hex data. 12 bytes max"), + arg_str0("r", "raw", "", "raw hex data. 12 bytes max"), + arg_int0(NULL, "rc", "", "Region code. 4 bits max"), + arg_int0(NULL, "fc", "", "Facility code. 2 bytes max"), + arg_int0(NULL, "cn", "", "Card number. 3 bytes max"), + arg_int0(NULL, "il", "", "Issue level. 4 bits max"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); + int raw_len = 0; // skip first block, 3*4 = 12 bytes left uint8_t raw[12] = {0}; CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + int res = CLIParamHexToBuf(arg_get_str(ctx, 1), raw, sizeof raw, &raw_len); + if (res) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + + int16_t region_code = arg_get_int_def(ctx, 2, -1); + int32_t facility_code = arg_get_int_def(ctx, 3, -1); + uint64_t card_number = arg_get_int_def(ctx, 4, -1); + uint32_t issue_level = arg_get_int_def(ctx, 5, -1); CLIParserFree(ctx); + bool use_raw = raw_len > 0; + + if (region_code == -1 && facility_code == -1 && card_number == -1 && issue_level == -1) { + if (!use_raw) { + PrintAndLogEx(FAILED, "Must specify either raw data to clone, or rc/fc/cn/il"); + return PM3_EINVARG; + } + } else { + // --raw and --rc/fc/cn/il are mutually exclusive + if (use_raw) { + PrintAndLogEx(FAILED, "Can't specify both raw and rc/fc/cn/il at the same time"); + return PM3_EINVARG; + } + if (!isValidGallagherParams(region_code, facility_code, card_number, issue_level)) { + return PM3_EINVARG; + } + } + + if (!use_raw) { + // generate Gallagher data + uint32_t blocks[3]; + createBlocks(blocks, region_code, facility_code, card_number, issue_level); + + // convert to the normal 'raw' format + for (int i = 0; i < ARRAYLEN(blocks); i++) { + raw[(4 * i) + 0] = (blocks[i] >> 24) & 0xff; + raw[(4 * i) + 1] = (blocks[i] >> 16) & 0xff; + raw[(4 * i) + 2] = (blocks[i] >> 8) & 0xff; + raw[(4 * i) + 3] = (blocks[i]) & 0xff; + } + } + // ASK/MAN sim. PrintAndLogEx(SUCCESS, "Simulating Gallagher - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw))); @@ -269,14 +446,7 @@ static int CmdGallagherSim(const char *Cmd) { SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs)); free(payload); - PacketResponseNG resp; - WaitForResponse(CMD_LF_ASK_SIMULATE, &resp); - - PrintAndLogEx(INFO, "Done"); - if (resp.status != PM3_EOPABORTED) - return resp.status; - - return PM3_SUCCESS; + return lfsim_wait_check(CMD_LF_ASK_SIMULATE); } static command_t CommandTable[] = { diff --git a/client/src/cmdlfhid.c b/client/src/cmdlfhid.c index 46a8febbe..47eeca45b 100644 --- a/client/src/cmdlfhid.c +++ b/client/src/cmdlfhid.c @@ -25,12 +25,12 @@ #include #include "cmdparser.h" // command_t #include "comms.h" -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "cliparser.h" #include "ui.h" #include "graph.h" -#include "cmddata.h" //for g_debugMode, demodbuff cmds -#include "cmdlf.h" // lf_read +#include "cmddata.h" // g_debugMode, demodbuff cmds +#include "cmdlf.h" // lf_read, lfsim_wait_check #include "util_posix.h" #include "lfdemod.h" #include "wiegand_formats.h" @@ -58,7 +58,7 @@ static int sendTry(uint8_t format_idx, wiegand_card_t *card, uint32_t delay, boo wiegand_message_t packed; memset(&packed, 0, sizeof(wiegand_message_t)); - if (HIDPack(format_idx, card, &packed) == false) { + if (HIDPack(format_idx, card, &packed, true) == false) { PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); return PM3_ESOFT; } @@ -223,10 +223,7 @@ static int CmdHIDWatch(const char *Cmd) { PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); clearCommandBuffer(); SendCommandNG(CMD_LF_HID_WATCH, NULL, 0); - PacketResponseNG resp; - WaitForResponse(CMD_LF_HID_WATCH, &resp); - PrintAndLogEx(INFO, "Done"); - return resp.status; + return lfsim_wait_check(CMD_LF_HID_WATCH); } static int CmdHIDSim(const char *Cmd) { @@ -287,7 +284,7 @@ static int CmdHIDSim(const char *Cmd) { packed.Mid = mid; packed.Bot = bot; } else { - if (HIDPack(format_idx, &card, &packed) == false) { + if (HIDPack(format_idx, &card, &packed, true) == false) { PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); return PM3_ESOFT; } @@ -300,8 +297,6 @@ static int CmdHIDSim(const char *Cmd) { PrintAndLogEx(INFO, "Simulating HID tag using raw " _GREEN_("%s"), raw); } - PrintAndLogEx(INFO, "Press pm3-button to abort simulation"); - lf_hidsim_t payload; payload.hi2 = packed.Top; payload.hi = packed.Mid; @@ -310,13 +305,7 @@ static int CmdHIDSim(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - WaitForResponse(CMD_LF_HID_SIMULATE, &resp); - PrintAndLogEx(INFO, "Done"); - if (resp.status != PM3_EOPABORTED) - return resp.status; - - return PM3_SUCCESS; + return lfsim_wait_check(CMD_LF_HID_SIMULATE); } static int CmdHIDClone(const char *Cmd) { @@ -401,7 +390,7 @@ static int CmdHIDClone(const char *Cmd) { packed.Mid = mid; packed.Bot = bot; } else { - if (HIDPack(format_idx, &card, &packed) == false) { + if (HIDPack(format_idx, &card, &packed, true) == false) { PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); return PM3_ESOFT; } diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c index da2662af1..b2719ba1e 100644 --- a/client/src/cmdlfindala.c +++ b/client/src/cmdlfindala.c @@ -544,7 +544,8 @@ static int CmdIndalaSim(const char *Cmd) { // raw param int raw_len = 0; - uint8_t raw[(7 * 4) + 1 ]; + uint8_t raw[(7 * 4) + 1]; + memset(raw, 0, sizeof(raw)); CLIGetHexWithReturn(ctx, 1, raw, &raw_len); bool is_long_uid = (raw_len == 28); @@ -569,15 +570,21 @@ static int CmdIndalaSim(const char *Cmd) { uint8_t bs[224]; memset(bs, 0x00, sizeof(bs)); - uint8_t counter = 223; - for (uint8_t i = 0; i < raw_len; i++) { + uint8_t counter = 0; + for (int8_t i = 0; i < raw_len; i++) { uint8_t tmp = raw[i]; - for (uint8_t j = 0; j < 8; j++) { - bs[counter--] = tmp & 1; - tmp >>= 1; - } + bs[counter++] = (tmp >> 7) & 1; + bs[counter++] = (tmp >> 6) & 1; + bs[counter++] = (tmp >> 5) & 1; + bs[counter++] = (tmp >> 4) & 1; + bs[counter++] = (tmp >> 3) & 1; + bs[counter++] = (tmp >> 2) & 1; + bs[counter++] = (tmp >> 1) & 1; + bs[counter++] = tmp & 1; } + // a0 00 00 00 bd 98 9a 11 + // indala PSK // It has to send either 64bits (8bytes) or 224bits (28bytes). Zero padding needed if not. // lf simpsk 1 c 32 r 2 d 0102030405060708 @@ -593,10 +600,10 @@ static int CmdIndalaSim(const char *Cmd) { payload->carrier = 2; payload->invert = 0; payload->clock = 32; - memcpy(payload->data, bs, sizeof(bs)); + memcpy(payload->data, bs, raw_len * 8); clearCommandBuffer(); - SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs)); + SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + (raw_len * 8)); free(payload); PacketResponseNG resp; diff --git a/client/src/cmdlfio.c b/client/src/cmdlfio.c index fd9ce6d1d..3752522ad 100644 --- a/client/src/cmdlfio.c +++ b/client/src/cmdlfio.c @@ -50,10 +50,7 @@ static int CmdIOProxWatch(const char *Cmd) { PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); clearCommandBuffer(); SendCommandNG(CMD_LF_IO_WATCH, NULL, 0); - PacketResponseNG resp; - WaitForResponse(CMD_LF_IO_WATCH, &resp); - PrintAndLogEx(INFO, "Done"); - return resp.status; + return lfsim_wait_check(CMD_LF_IO_WATCH); } //IO-Prox demod - FSK RF/64 with preamble of 000000001 diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 89204952d..46ef31744 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -98,7 +98,7 @@ static void arg_add_t55xx_downloadlink(void *at[], uint8_t *idx, uint8_t show, u at[n++] = arg_lit0(NULL, "r3", r3); if (show == T55XX_DLMODE_ALL) { - char *r4 = (char *)calloc(50, sizeof(uint8_t)); + char *r4 = (char *)calloc(56, sizeof(uint8_t)); sprintf(r4, "try all downlink modes %s", (dl_mode_def == 4) ? "(def)" : ""); at[n++] = arg_lit0(NULL, "all", r4); } @@ -106,7 +106,6 @@ static void arg_add_t55xx_downloadlink(void *at[], uint8_t *idx, uint8_t show, u *idx = n; } - static int usage_t55xx_config(void) { PrintAndLogEx(NORMAL, "Usage: lf t55xx config [c ] [d ] [i [0/1]] [o ] [Q5 [0/1]] [ST [0/1]]"); PrintAndLogEx(NORMAL, "Options:"); @@ -236,48 +235,6 @@ static int usage_t55xx_restore(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_t55xx_detect(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx detect [1] [r ] [p ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " 1 - if set, use Graphbuffer otherwise read data from tag."); - PrintAndLogEx(NORMAL, " p ] p "); - PrintAndLogEx(NORMAL, "This commands sends the Answer-On-Request command and leaves the readerfield ON afterwards."); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - this help"); - PrintAndLogEx(NORMAL, " p - password 4bytes (8 hex symbols)"); - print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx wakeup p 11223344") " - send wakeup password"); - return PM3_SUCCESS; -} - -static int usage_t55xx_dangerraw(void) { - PrintAndLogEx(NORMAL, "This command allows to emit arbitrary raw commands on T5577 and cut the field after arbitrary duration."); - PrintAndLogEx(NORMAL, _RED_("WARNING:") " this may lock definitively the tag in an unusable state!"); - PrintAndLogEx(NORMAL, "Uncontrolled usage can easily write an invalid configuration, activate lock bits,"); - PrintAndLogEx(NORMAL, "OTP bit, password protection bit, deactivate test-mode, lock your card forever."); - PrintAndLogEx(NORMAL, "Uncontrolled usage is known to the State of California to cause cancer."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf t55xx dangerraw [h] [b t ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " b - raw bitstream"); - PrintAndLogEx(NORMAL, " t - time in microseconds before dropping the field"); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} static int usage_t55xx_clonehelp(void) { PrintAndLogEx(NORMAL, "For cloning specific techs on T55xx tags, see commands available in corresponding LF sub-menus, e.g.:"); @@ -915,66 +872,156 @@ static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) { PrintAndLogEx(NORMAL, msg); } -// Define prototype to call from within detect. -static int CmdT55xxWakeUp(const char *Cmd); +static int CmdT55xxWakeUp(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx wakeup", + "This commands sends the Answer-On-Request command and leaves the readerfield ON afterwards", + "lf t55xx wakeup -p 11223344 --> send wakeup with password\n" + ); + + // 1 (help) + 2 (two user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[3 + 5] = { + arg_param_begin, + arg_str0("p", "pwd", "", "password (4 hex bytes)"), + arg_lit0("v", "verbose", "verbose output"), + }; + uint8_t idx = 3; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode); + CLIExecWithReturn(ctx, Cmd, argtable, true); + + uint32_t password = 0; + int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "Password should be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + bool verbose = arg_get_lit(ctx, 2); + bool r0 = arg_get_lit(ctx, 3); + bool r1 = arg_get_lit(ctx, 4); + bool r2 = arg_get_lit(ctx, 5); + bool r3 = arg_get_lit(ctx, 6); + CLIParserFree(ctx); + + if ((r0 + r1 + r2 + r3) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; + } + + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; + + struct p { + uint32_t password; + uint8_t flags; + } PACKED payload; + + payload.password = password; + payload.flags = (downlink_mode << 3); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_T55XX_WAKEUP, (uint8_t *)&payload, sizeof(payload)); + if (WaitForResponseTimeout(CMD_LF_T55XX_WAKEUP, NULL, 1000) == false) { + PrintAndLogEx(WARNING, "command execution time out"); + return PM3_ETIMEOUT; + } + + if (verbose) + PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now"); + + return PM3_SUCCESS; +} static int CmdT55xxDetect(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx detect", + "Try detecting the tag modulation from reading the configuration block", + "lf t55xx detect\n" + "lf t55xx detect -1\n" + "lf t55xx detect -p 11223344\n" + ); + + // 1 (help) + 2 (two user specified params) + (6 T55XX_DLMODE_ALL) + void *argtable[3 + 6] = { + arg_param_begin, + arg_lit0("1", NULL, "extract using data from graphbuffer"), + arg_str0("p", "pwd", "", "password (4 hex bytes)"), + }; + uint8_t idx = 3; + arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_ALL, config.downlink_mode); + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool use_gb = arg_get_lit(ctx, 1); - bool errors = false; - bool useGB = false; bool usepwd = false; + uint64_t password = -1; + uint32_t tmp_pwd = 0; + int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &tmp_pwd, 4, true); + if (res == 0 || res == 2) { + PrintAndLogEx(ERR, "Password should be 4 hex bytes"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (res == 1) { + usepwd = true; + password = tmp_pwd; + } + + bool r0 = arg_get_lit(ctx, 3); + bool r1 = arg_get_lit(ctx, 4); + bool r2 = arg_get_lit(ctx, 5); + bool r3 = arg_get_lit(ctx, 6); + bool ra = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + + if ((r0 + r1 + r2 + r3 + ra) > 1) { + PrintAndLogEx(FAILED, "Error multiple downlink encoding"); + return PM3_EINVARG; + } + + bool try_all_dl_modes = false; + uint8_t downlink_mode = config.downlink_mode; + if (r0) + downlink_mode = refFixedBit; + else if (r1) + downlink_mode = refLongLeading; + else if (r2) + downlink_mode = refLeading0; + else if (r3) + downlink_mode = ref1of4; + + if (ra) + try_all_dl_modes = true; + bool try_with_pwd = false; - bool try_all_dl_modes = true; bool found = false; bool usewake = false; - uint64_t password = -1; - uint8_t cmdp = 0; - uint8_t downlink_mode = 0; - char wakecmd[20] = { 0x00 }; - struct timespec sleepperiod; // Setup the 90ms time value to sleep for after the wake, to allow delay init to complete (~70ms) + struct timespec sleepperiod; sleepperiod.tv_sec = 0; sleepperiod.tv_nsec = 90000000; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_detect(); - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - sprintf(wakecmd, "p %08x q", (uint32_t)(password & 0xFFFFFFFF)); - usepwd = true; - cmdp += 2; - break; - case '1': - useGB = true; - cmdp++; - break; - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode <= 3) try_all_dl_modes = false; // User selected ONLY 1 so honor. - if (downlink_mode == 4) try_all_dl_modes = true; - if (downlink_mode > 3) downlink_mode = 0; - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - if (errors) return usage_t55xx_detect(); - - // detect called so clear data blocks T55x7_ClearAllBlockData(); // sanity check. - if (SanityOfflineCheck(useGB) != PM3_SUCCESS) + if (SanityOfflineCheck(use_gb) != PM3_SUCCESS) return PM3_ESOFT; - if (useGB == false) { + if (use_gb == false) { + + char wakecmd[20] = { 0x00 }; + sprintf(wakecmd, "-p %08" PRIx64, password); + // do ... while not found and not yet tried with wake (for AOR or Init Delay) do { // do ... while to check without password then loop back if password supplied @@ -987,7 +1034,7 @@ static int CmdT55xxDetect(const char *Cmd) { if (try_with_pwd) CmdT55xxWakeUp(wakecmd); else - CmdT55xxWakeUp("q"); + CmdT55xxWakeUp(""); // sleep 90 ms nanosleep(&sleepperiod, &sleepperiod); } @@ -999,7 +1046,6 @@ static int CmdT55xxDetect(const char *Cmd) { continue; found = true; - break; } } else { @@ -1008,7 +1054,7 @@ static int CmdT55xxDetect(const char *Cmd) { if (try_with_pwd) CmdT55xxWakeUp(wakecmd); else - CmdT55xxWakeUp("q"); + CmdT55xxWakeUp(""); // sleep 90 ms nanosleep(&sleepperiod, &sleepperiod); } @@ -1019,7 +1065,7 @@ static int CmdT55xxDetect(const char *Cmd) { } // toggle so we loop back if not found and try with pwd - if (!found && usepwd) + if (found == false && usepwd) try_with_pwd = !try_with_pwd; // force exit as detect block has been found @@ -1029,7 +1075,7 @@ static int CmdT55xxDetect(const char *Cmd) { } while (try_with_pwd); // Toggle so we loop back and try with wakeup. usewake = !usewake; - } while (!found && usewake); + } while (found == false && usewake); } else { found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig); } @@ -1553,63 +1599,6 @@ int printConfiguration(t55xx_conf_block_t b) { return PM3_SUCCESS; } -static int CmdT55xxWakeUp(const char *Cmd) { - - uint32_t password = 0; - uint8_t cmdp = 0; - bool errors = false; - uint8_t downlink_mode = config.downlink_mode; - bool quiet = false; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_wakup(); - case 'p': - password = param_get32ex(Cmd, cmdp + 1, 0, 16); - cmdp += 2; - break; - case 'r': - downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (downlink_mode > 3) - downlink_mode = 0; - - cmdp += 2; - break; - case 'q': - quiet = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - if (errors) return usage_t55xx_wakup(); - - struct p { - uint32_t password; - uint8_t flags; - } PACKED payload; - - payload.password = password; - payload.flags = (downlink_mode & 3) << 3; - - clearCommandBuffer(); - SendCommandNG(CMD_LF_T55XX_WAKEUP, (uint8_t *)&payload, sizeof(payload)); - if (!WaitForResponseTimeout(CMD_LF_T55XX_WAKEUP, NULL, 1000)) { - PrintAndLogEx(WARNING, "command execution time out"); - return PM3_ETIMEOUT; - } - - if (!quiet) - PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now"); - - return PM3_SUCCESS; -} - static int CmdT55xxWriteBlock(const char *Cmd) { uint8_t block = 0xFF; // default to invalid block uint32_t data = 0; // default to blank Block @@ -1695,59 +1684,48 @@ static int CmdT55xxWriteBlock(const char *Cmd) { } static int CmdT55xxDangerousRaw(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf t55xx dangerraw", + "This command allows to emit arbitrary raw commands on T5577 and cut the field after arbitrary duration.\n" + "Uncontrolled usage can easily write an invalid configuration, activate lock bits,\n" + "OTP bit, password protection bit, deactivate test-mode, lock your card forever.\n" + _RED_("WARNING:") _CYAN_(" this may lock definitively the tag in an unusable state!"), + "lf t55xx dangerraw -d 01000000000000010000100000000100000000 -t 3200\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("d", "data", NULL, "raw bit string"), + arg_int1("t", "time", "", "<0 - 200000> time in microseconds before dropping the field"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + // supports only default downlink mode t55xx_test_block_t ng; ng.time = 0; ng.bitlen = 0; memset(ng.data, 0x00, sizeof(ng.data)); - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_t55xx_dangerraw(); - case 't': - ng.time = param_get32ex(Cmd, cmdp + 1, 0, 10); - if (ng.time == 0 || ng.time > 200000) { - PrintAndLogEx(ERR, "Timing off 1..200000 limits, got %i", ng.time); - errors = true; - break; - } - cmdp += 2; - break; - case 'b': { - uint32_t n = param_getlength(Cmd, cmdp + 1); - if (n > 128) { - PrintAndLogEx(ERR, "Bitstream too long, max 128 bits, got %i", n); - errors = true; - break; - } - for (uint8_t i = 0; i < n; i++) { - char c = param_getchar_indx(Cmd, i, cmdp + 1); - if (c == '0') - ng.data[i] = 0; - else if (c == '1') - ng.data[i] = 1; - else { - PrintAndLogEx(ERR, "Unknown bit char '%c'", c); - errors = true; - break; - } - } - ng.bitlen = n; - cmdp += 2; - break; - } - default: - PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + int bin_len = 127; + uint8_t bin[128] = {0}; + CLIGetStrWithReturn(ctx, 1, bin, &bin_len); + + ng.time = arg_get_int_def(ctx, 2, 0); + CLIParserFree(ctx); + + if (ng.time == 0 || ng.time > 200000) { + PrintAndLogEx(ERR, "Timing off 1..200000 limits, got %i", ng.time); + return PM3_EINVARG; } - if (errors || ng.bitlen == 0 || ng.time == 0) { - return usage_t55xx_dangerraw(); + + int bs_len = binstring2binarray(ng.data, (char *)bin, bin_len); + if (bs_len == 0) { + return PM3_EINVARG; } + + ng.bitlen = bs_len; + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_T55XX_DANGERRAW, (uint8_t *)&ng, sizeof(ng)); @@ -2868,8 +2846,8 @@ static int CmdT55xxWipe(const char *Cmd) { "lf t55xx wipe -p 11223344 -> wipes a T55x7 tag, config block 0x000880E0, using pwd" ); - // 4 + (5 or 6) - void *argtable[9] = { + // 1 (help) + 3 (three user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[4 + 5] = { arg_param_begin, arg_str0("c", "cfg", "", "configuration block0 (4 hex bytes)"), arg_str0("p", "pwd", "", "password (4 hex bytes)"), @@ -2895,9 +2873,10 @@ static int CmdT55xxWipe(const char *Cmd) { res = arg_get_u32_hexstr_def(ctx, 2, 0x51243648, &password); if (res) { usepwd = true; + } - if (usepwd && res == 2) - PrintAndLogEx(WARNING, "Password should be 4 bytes, using default pwd"); + if (res == 2) { + PrintAndLogEx(WARNING, "Password should be 4 bytes, using default pwd"); } bool Q5 = arg_get_lit(ctx, 3); @@ -2978,11 +2957,14 @@ static int CmdT55xxChkPwds(const char *Cmd) { "lf t55xx chk --em aa11223344 -> try known pwdgen algo from some cloners based on EM4100 ID" ); - // Calculate size of argtable accordingly: - // 1 (help) + 3 (three user specified params) + ( 5 or 6 T55XX_DLMODE) - // 4 + (T55XX_DLMODE_xxx 5) - // 4 + (T55XX_DLMODE_ALL 6) == 10 - void *argtable[10] = { + /* + Calculate size of argtable accordingly: + 1 (help) + 3 (three user specified params) + ( 5 or 6 T55XX_DLMODE) + start index to call arg_add_t55xx_downloadlink() is 4 (1 + 3) given the above sample + */ + + // 1 (help) + 3 (three user specified params) + (6 T55XX_DLMODE_ALL) + void *argtable[4 + 6] = { arg_param_begin, arg_lit0("m", "fm", "use dictionary from flash memory (RDV4)"), arg_str0("f", "file", "", "file name"), @@ -2998,7 +2980,7 @@ static int CmdT55xxChkPwds(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, sizeof(filename), &fnlen); - // White cloner password based on EM4100 ID + // White cloner password based on EM4100 ID bool use_calc_password = false; uint32_t card_password = 0x00; uint64_t cardid = 0; @@ -3105,7 +3087,7 @@ static int CmdT55xxChkPwds(const char *Cmd) { } // to try each downlink mode for each password - int dl_mode; + int dl_mode; // try calculated password if (use_calc_password) { @@ -3198,6 +3180,7 @@ static int CmdT55xxBruteForce(const char *Cmd) { "lf t55xx bruteforce --r2 -s aaaaaa77 -e aaaaaa99\n" ); + // 1 (help) + 2 (two user specified params) + (6 T55XX_DLMODE_ALL) void *argtable[3 + 6] = { arg_param_begin, arg_str1("s", "start", "", "search start password (4 hex bytes)"), @@ -3324,8 +3307,8 @@ static int CmdT55xxRecoverPW(const char *Cmd) { "lf t55xx recoverpw -p 11223344 --r3\n" ); - // 2 + (5 or 6) - void *argtable[8] = { + // 1 (help) + 1 (one user specified params) + (6 T55XX_DLMODE_ALL) + void *argtable[2 + 6] = { arg_param_begin, arg_str0("p", "pwd", "", "password (4 hex bytes)"), }; @@ -3564,8 +3547,8 @@ static int CmdT55xxDetectPage1(const char *Cmd) { "lf t55xx p1detect -p 11223344 --r3\n" ); - // 2 + (5 or 6) - void *argtable[7] = { + // 1 (help) + 2 (two user specified params) + (5 T55XX_DLMODE_SINGLE) + void *argtable[3 + 5] = { arg_param_begin, arg_lit0("1", NULL, "extract using data from graphbuffer"), arg_str0("p", "pwd", "", "password (4 hex bytes)"), @@ -3662,6 +3645,7 @@ static int CmdT55xxSetDeviceConfig(const char *Cmd) { "lf t55xx deviceconfig -a 55 -b 14 -c 21 -d 30 -> default EM4305" ); + // 1 (help) + 9 (nine user specified params) + (5 T55XX_DLMODE_SINGLE) void *argtable[10 + 5] = { arg_param_begin, arg_int0("a", NULL, "<8..255>", "Set start gap"), @@ -3772,7 +3756,7 @@ static int CmdT55xxProtect(const char *Cmd) { "lf t55xx protect -p 11223344 -n 00000000 -> use pwd 11223344, sets new pwd 00000000" ); - // 4 + (5 or 6) + // 1 (help) + 3 (three user specified params) + (5 T55XX_DLMODE_SINGLE) void *argtable[4 + 5] = { arg_param_begin, arg_lit0("o", "override", "override safety check"), @@ -3927,10 +3911,10 @@ static int CmdT55xxSniff(const char *Cmd) { uint8_t width1 = 0; uint8_t width0 = 0; - if (opt_width0 > -1) + if (opt_width0 > -1) width0 = (uint8_t)opt_width0 & 0xFF; - if (opt_width1 > -1) + if (opt_width1 > -1) width1 = (uint8_t)opt_width1 & 0xFF; diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index c47eff9d3..4369d3a71 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -133,7 +133,7 @@ static uint16_t printHexLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trac return ret; } -static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes, uint32_t *prev_eot, bool use_us, +static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes, uint32_t *prev_eot, bool use_us, const uint64_t *mfDicKeys, uint32_t mfDicKeysCount) { // sanity check if (is_last_record(tracepos, traceLen)) { diff --git a/client/src/cmdwiegand.c b/client/src/cmdwiegand.c index 3fcce3214..55e4d6e9c 100644 --- a/client/src/cmdwiegand.c +++ b/client/src/cmdwiegand.c @@ -60,6 +60,7 @@ int CmdWiegandEncode(const char *Cmd) { arg_u64_0(NULL, "issue", "", "issue level"), arg_u64_0(NULL, "oem", "", "OEM code"), arg_str0("w", "wiegand", "", "see `wiegand list` for available formats"), + arg_lit0(NULL, "pre", "add HID preamble to wiegand"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -75,6 +76,7 @@ int CmdWiegandEncode(const char *Cmd) { int len = 0; char format[16] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)format, sizeof(format), &len); + bool preamble = arg_get_lit(ctx, 6); CLIParserFree(ctx); int idx = -1; @@ -89,14 +91,14 @@ int CmdWiegandEncode(const char *Cmd) { if (idx != -1) { wiegand_message_t packed; memset(&packed, 0, sizeof(wiegand_message_t)); - if (HIDPack(idx, &data, &packed) == false) { + if (HIDPack(idx, &data, &packed, preamble) == false) { PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); return PM3_ESOFT; } print_wiegand_code(&packed); } else { // try all formats and print only the ones that work. - HIDPackTryAll(&data); + HIDPackTryAll(&data, preamble); } return PM3_SUCCESS; } diff --git a/client/src/fileutils.c b/client/src/fileutils.c index d68c95563..137d2640b 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -77,6 +77,44 @@ struct wave_info_t { } PACKED audio_data; } PACKED; +/** + * @brief detects if file is of a supported filetype based on extension + * @param filename + * @return o + */ +DumpFileType_t getfiletype(const char *filename) { + // assume unknown file is BINARY + DumpFileType_t o = BIN; + if (filename == NULL) { + return o; + } + + size_t len = strlen(filename); + if (len > 4) { + // check if valid file extension and attempt to load data + char s[FILE_PATH_SIZE]; + memset(s, 0, sizeof(s)); + memcpy(s, filename, len); + str_lower(s); + + if (str_endswith(s, "bin")) { + o = BIN; + } else if (str_endswith(s, "eml")) { + o = EML; + } else if (str_endswith(s, "json")) { + o = JSON; + } else if (str_endswith(s, "dic")) { + o = DICTIONARY; + } else { + // mfd, trc, trace is binary + o = BIN; + // log is text + // .pm3 is text values of signal data + } + } + return o; +} + /** * @brief checks if a file exists * @param filename diff --git a/client/src/fileutils.h b/client/src/fileutils.h index 480cb013b..5e5cee664 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -272,4 +272,11 @@ mfu_df_e detect_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose); int searchAndList(const char *pm3dir, const char *ext); int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent); + +/** + * @brief detects if file is of a supported filetype based on extension + * @param filename + * @return + */ +DumpFileType_t getfiletype(const char *filename); #endif // FILEUTILS_H diff --git a/client/src/graph.c b/client/src/graph.c index 5c3221716..5a9fb3b33 100644 --- a/client/src/graph.c +++ b/client/src/graph.c @@ -352,7 +352,6 @@ bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge) { if (*rf1 == 0) { PrintAndLogEx(DEBUG, "DEBUG: Clock detect error"); - return false; } return true; diff --git a/client/src/util.c b/client/src/util.c index 1dad2cd4b..03a1e68f8 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -806,13 +806,29 @@ int binarraytohex(char *target, const size_t targetlen, char *source, size_t src // convert binary array to human readable binary void binarraytobinstring(char *target, char *source, int length) { - int i; - - for (i = 0 ; i < length ; ++i) + for (int i = 0 ; i < length; ++i) *(target++) = *(source++) + '0'; *target = '\0'; } +int binstring2binarray(uint8_t *target, char *source, int length) { + int count = 0; + char *start = source; + while (length--) { + char x = *(source++); + // convert from binary value + if (x >= '0' && x <= '1') + x -= '0'; + else { + PrintAndLogEx(WARNING, "(binstring2binarray) discovered unknown character %c %d at idx %d of %s", x, x, (int16_t)(source - start), start); + return 0; + } + *(target++) = x; + count++; + } + return count; +} + // return parity bit required to match type uint8_t GetParity(uint8_t *bits, uint8_t type, int length) { int x; diff --git a/client/src/util.h b/client/src/util.h index 573997d61..4d86553c2 100644 --- a/client/src/util.h +++ b/client/src/util.h @@ -83,6 +83,8 @@ int hextobinarray(char *target, char *source); int hextobinstring(char *target, char *source); int binarraytohex(char *target, const size_t targetlen, char *source, size_t srclen); void binarraytobinstring(char *target, char *source, int length); +int binstring2binarray(uint8_t *target, char *source, int length); + uint8_t GetParity(uint8_t *bits, uint8_t type, int length); void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length); void wiegand_add_parity_swapped(uint8_t *target, uint8_t *source, uint8_t length); diff --git a/client/src/wiegand_formats.c b/client/src/wiegand_formats.c index ba8169d37..2dfd39fbd 100644 --- a/client/src/wiegand_formats.c +++ b/client/src/wiegand_formats.c @@ -12,7 +12,7 @@ #include "commonutil.h" -static bool Pack_H10301(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_H10301(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0xFF) return false; // Can't encode FC. @@ -25,7 +25,9 @@ static bool Pack_H10301(wiegand_card_t *card, wiegand_message_t *packed) { packed->Bot |= (card->FacilityCode & 0xFF) << 17; packed->Bot |= oddparity32((packed->Bot >> 1) & 0xFFF) & 1; packed->Bot |= (evenparity32((packed->Bot >> 13) & 0xFFF) & 1) << 25; - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_H10301(wiegand_message_t *packed, wiegand_card_t *card) { @@ -40,7 +42,7 @@ static bool Unpack_H10301(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_Tecom27(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_Tecom27(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x7FF) return false; // Can't encode FC. @@ -51,7 +53,9 @@ static bool Pack_Tecom27(wiegand_card_t *card, wiegand_message_t *packed) { packed->Length = 27; set_nonlinear_field(packed, card->FacilityCode, 10, (uint8_t[]) {15, 19, 24, 23, 22, 18, 6, 10, 14, 3, 2}); set_nonlinear_field(packed, card->CardNumber, 16, (uint8_t[]) {0, 1, 13, 12, 9, 26, 20, 16, 17, 21, 25, 7, 8, 11, 4, 5}); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_Tecom27(wiegand_message_t *packed, wiegand_card_t *card) { @@ -64,7 +68,7 @@ static bool Unpack_Tecom27(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_2804W(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_2804W(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x0FF) return false; // Can't encode FC. @@ -84,7 +88,9 @@ static bool Pack_2804W(wiegand_card_t *card, wiegand_message_t *packed) { set_bit_by_position(packed, oddparity32(get_linear_field(packed, 0, 27)) , 27); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_2804W(wiegand_message_t *packed, wiegand_card_t *card) { @@ -101,7 +107,7 @@ static bool Unpack_2804W(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_ATSW30(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_ATSW30(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0xFFF) return false; // Can't encode FC. @@ -118,7 +124,9 @@ static bool Pack_ATSW30(wiegand_card_t *card, wiegand_message_t *packed) { set_bit_by_position(packed, oddparity32(get_linear_field(packed, 13, 16)) , 29); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_ATSW30(wiegand_message_t *packed, wiegand_card_t *card) { @@ -134,7 +142,7 @@ static bool Unpack_ATSW30(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_ADT31(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_ADT31(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x0F) return false; // Can't encode FC. @@ -146,7 +154,9 @@ static bool Pack_ADT31(wiegand_card_t *card, wiegand_message_t *packed) { set_linear_field(packed, card->FacilityCode, 1, 4); set_linear_field(packed, card->CardNumber, 5, 23); // Parity not known, but 4 bits are unused. - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_ADT31(wiegand_message_t *packed, wiegand_card_t *card) { @@ -158,7 +168,7 @@ static bool Unpack_ADT31(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_Kastle(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_Kastle(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x00FF) return false; // Can't encode FC. @@ -173,7 +183,9 @@ static bool Pack_Kastle(wiegand_card_t *card, wiegand_message_t *packed) { set_linear_field(packed, card->CardNumber, 15, 16); set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0); set_bit_by_position(packed, oddparity32(get_linear_field(packed, 14, 17)), 31); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_Kastle(wiegand_message_t *packed, wiegand_card_t *card) { @@ -191,7 +203,7 @@ static bool Unpack_Kastle(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_Kantech(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_Kantech(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0xFF) return false; // Can't encode FC. @@ -202,7 +214,9 @@ static bool Pack_Kantech(wiegand_card_t *card, wiegand_message_t *packed) { packed->Length = 32; set_linear_field(packed, card->FacilityCode, 7, 8); set_linear_field(packed, card->CardNumber, 15, 16); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_Kantech(wiegand_message_t *packed, wiegand_card_t *card) { @@ -214,7 +228,7 @@ static bool Unpack_Kantech(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x007F) return false; // Can't encode FC. @@ -227,7 +241,9 @@ static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed) { set_linear_field(packed, card->CardNumber, 8, 24); set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0); set_bit_by_position(packed, oddparity32(get_linear_field(packed, 16, 16)), 32); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_D10202(wiegand_message_t *packed, wiegand_card_t *card) { @@ -243,7 +259,7 @@ static bool Unpack_D10202(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_H10306(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_H10306(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0xFFFF) return false; // Can't encode FC. @@ -257,7 +273,9 @@ static bool Pack_H10306(wiegand_card_t *card, wiegand_message_t *packed) { packed->Mid |= (card->FacilityCode & 0x8000) >> 15; packed->Mid |= (evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xFFFE0000)) & 1) << 1; packed->Bot |= (oddparity32(packed->Bot & 0x0001FFFE) & 1); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_H10306(wiegand_message_t *packed, wiegand_card_t *card) { @@ -275,7 +293,7 @@ static bool Unpack_H10306(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_N10002(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_N10002(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0xFF) return false; // Can't encode FC. @@ -286,7 +304,9 @@ static bool Pack_N10002(wiegand_card_t *card, wiegand_message_t *packed) { packed->Length = 34; // Set number of bits set_linear_field(packed, card->FacilityCode, 9, 8); set_linear_field(packed, card->CardNumber, 17, 16); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_N10002(wiegand_message_t *packed, wiegand_card_t *card) { @@ -299,7 +319,7 @@ static bool Unpack_N10002(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_C1k35s(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_C1k35s(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0xFFF) return false; // Can't encode FC. @@ -314,7 +334,9 @@ static bool Pack_C1k35s(wiegand_card_t *card, wiegand_message_t *packed) { packed->Mid |= (evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xB6DB6DB6)) & 1) << 1; packed->Bot |= (oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0x6DB6DB6C)) & 1); packed->Mid |= (oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0xFFFFFFFF)) & 1) << 2; - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_C1k35s(wiegand_message_t *packed, wiegand_card_t *card) { @@ -331,7 +353,7 @@ static bool Unpack_C1k35s(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_H10320(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_H10320(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format) @@ -356,7 +378,9 @@ static bool Pack_H10320(wiegand_card_t *card, wiegand_message_t *packed) { set_bit_by_position(packed, evenparity32( get_nonlinear_field(packed, 8, (uint8_t[]) {3, 7, 11, 15, 19, 23, 29, 31}) ), 35); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_H10320(wiegand_message_t *packed, wiegand_card_t *card) { @@ -383,7 +407,7 @@ static bool Unpack_H10320(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_S12906(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_S12906(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0xFF) return false; // Can't encode FC. @@ -397,7 +421,9 @@ static bool Pack_S12906(wiegand_card_t *card, wiegand_message_t *packed) { set_linear_field(packed, card->CardNumber, 11, 24); set_bit_by_position(packed, oddparity32(get_linear_field(packed, 1, 17)), 0); set_bit_by_position(packed, oddparity32(get_linear_field(packed, 17, 18)), 35); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_S12906(wiegand_message_t *packed, wiegand_card_t *card) { @@ -414,7 +440,7 @@ static bool Unpack_S12906(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_Sie36(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_Sie36(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x0003FFFF) return false; // Can't encode FC. @@ -431,7 +457,9 @@ static bool Pack_Sie36(wiegand_card_t *card, wiegand_message_t *packed) { set_bit_by_position(packed, evenparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34})) , 35); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_Sie36(wiegand_message_t *packed, wiegand_card_t *card) { @@ -447,7 +475,7 @@ static bool Unpack_Sie36(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x000000FF) return false; // Can't encode FC. @@ -461,7 +489,9 @@ static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed) { set_linear_field(packed, card->CardNumber, 19, 16); set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 17)), 0); set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 17)), 35); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) { @@ -478,7 +508,7 @@ static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_H10302(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_H10302(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format) @@ -490,7 +520,9 @@ static bool Pack_H10302(wiegand_card_t *card, wiegand_message_t *packed) { set_linear_field(packed, card->CardNumber, 1, 35); set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0); set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_H10302(wiegand_message_t *packed, wiegand_card_t *card) { @@ -505,7 +537,7 @@ static bool Unpack_H10302(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x0000FFFF) return false; // Can't encode FC. @@ -520,7 +552,9 @@ static bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed) { set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0); set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_H10304(wiegand_message_t *packed, wiegand_card_t *card) { @@ -536,7 +570,7 @@ static bool Unpack_H10304(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_HGeneric37(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_HGeneric37(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0) return false; // Not used in this format @@ -553,25 +587,24 @@ static bool Pack_HGeneric37(wiegand_card_t *card, wiegand_message_t *packed) { // even1 set_bit_by_position(packed, evenparity32( - get_nonlinear_field(packed, 8, (uint8_t[]) {4, 8, 12, 16, 20, 24, 28, 32}) - ) + get_nonlinear_field(packed, 8, (uint8_t[]) {4, 8, 12, 16, 20, 24, 28, 32})) , 0 ); // odd1 set_bit_by_position(packed, oddparity32( - get_nonlinear_field(packed, 8, (uint8_t[]) {6, 10, 14, 18, 22, 26, 30, 34}) - ) + get_nonlinear_field(packed, 8, (uint8_t[]) {6, 10, 14, 18, 22, 26, 30, 34})) , 2 ); // even2 set_bit_by_position(packed, evenparity32( - get_nonlinear_field(packed, 8, (uint8_t[]) {7, 11, 15, 19, 23, 27, 31, 35}) - ) + get_nonlinear_field(packed, 8, (uint8_t[]) {7, 11, 15, 19, 23, 27, 31, 35})) , 3 ); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_HGeneric37(wiegand_message_t *packed, wiegand_card_t *card) { @@ -589,7 +622,7 @@ static bool Unpack_HGeneric37(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_MDI37(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_MDI37(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (card->FacilityCode > 0x0000F) return false; // Can't encode FC. @@ -604,7 +637,9 @@ static bool Pack_MDI37(wiegand_card_t *card, wiegand_message_t *packed) { set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0); set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_MDI37(wiegand_message_t *packed, wiegand_card_t *card) { @@ -622,7 +657,7 @@ static bool Unpack_MDI37(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_P10001(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_P10001(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); @@ -641,7 +676,9 @@ static bool Pack_P10001(wiegand_card_t *card, wiegand_message_t *packed) { get_linear_field(packed, 16, 8) ^ get_linear_field(packed, 24, 8) , 32, 8); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_P10001(wiegand_message_t *packed, wiegand_card_t *card) { @@ -661,7 +698,7 @@ static bool Unpack_P10001(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); @@ -677,7 +714,9 @@ static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed) { packed->Mid |= (evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6)) & 1) << 14; packed->Bot |= (oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C)) & 1); packed->Mid |= (oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF)) & 1) << 15; - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_C1k48s(wiegand_message_t *packed, wiegand_card_t *card) { @@ -694,7 +733,7 @@ static bool Unpack_C1k48s(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_CasiRusco40(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_CasiRusco40(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); @@ -706,7 +745,9 @@ static bool Pack_CasiRusco40(wiegand_card_t *card, wiegand_message_t *packed) { packed->Length = 40; // Set number of bits set_linear_field(packed, card->CardNumber, 1, 38); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_CasiRusco40(wiegand_message_t *packed, wiegand_card_t *card) { @@ -718,7 +759,7 @@ static bool Unpack_CasiRusco40(wiegand_message_t *packed, wiegand_card_t *card) return true; } -static bool Pack_Optus(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_Optus(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); @@ -731,7 +772,9 @@ static bool Pack_Optus(wiegand_card_t *card, wiegand_message_t *packed) { set_linear_field(packed, card->CardNumber, 1, 16); set_linear_field(packed, card->FacilityCode, 22, 11); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_Optus(wiegand_message_t *packed, wiegand_card_t *card) { @@ -744,7 +787,7 @@ static bool Unpack_Optus(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_Smartpass(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_Smartpass(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); @@ -758,7 +801,9 @@ static bool Pack_Smartpass(wiegand_card_t *card, wiegand_message_t *packed) { set_linear_field(packed, card->FacilityCode, 1, 13); set_linear_field(packed, card->IssueLevel, 14, 3); set_linear_field(packed, card->CardNumber, 17, 16); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_Smartpass(wiegand_message_t *packed, wiegand_card_t *card) { @@ -772,7 +817,7 @@ static bool Unpack_Smartpass(wiegand_message_t *packed, wiegand_card_t *card) { return true; } -static bool Pack_bqt(wiegand_card_t *card, wiegand_message_t *packed) { +static bool Pack_bqt(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); @@ -793,7 +838,9 @@ static bool Pack_bqt(wiegand_card_t *card, wiegand_message_t *packed) { oddparity32(get_linear_field(packed, 17, 16)) , 33); - return add_HID_header(packed); + if (preamble) + return add_HID_header(packed); + return true; } static bool Unpack_bqt(wiegand_message_t *packed, wiegand_card_t *card) { @@ -920,16 +967,16 @@ int HIDFindCardFormat(const char *format) { return -1; } -bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed) { +bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bool preamble) { memset(packed, 0, sizeof(wiegand_message_t)); if (format_idx < 0 || format_idx >= ARRAYLEN(FormatTable)) return false; - return FormatTable[format_idx].Pack(card, packed); + return FormatTable[format_idx].Pack(card, packed, preamble); } -void HIDPackTryAll(wiegand_card_t *card) { +void HIDPackTryAll(wiegand_card_t *card, bool preamble) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "%-10s %-30s --> Encoded wiegand", "Name", "Description"); @@ -939,7 +986,7 @@ void HIDPackTryAll(wiegand_card_t *card) { int i = 0; while (FormatTable[i].Name) { memset(&packed, 0, sizeof(wiegand_message_t)); - bool res = FormatTable[i].Pack(card, &packed); + bool res = FormatTable[i].Pack(card, &packed, preamble); if (res) { cardformat_t fmt = HIDGetCardFormat(i); print_desc_wiegand(&fmt, &packed); diff --git a/client/src/wiegand_formats.h b/client/src/wiegand_formats.h index 531de1e12..921b1840a 100644 --- a/client/src/wiegand_formats.h +++ b/client/src/wiegand_formats.h @@ -33,7 +33,7 @@ typedef struct { // Structure for defined Wiegand card formats available for packing/unpacking typedef struct { const char *Name; - bool (*Pack)(wiegand_card_t *card, wiegand_message_t *packed); + bool (*Pack)(wiegand_card_t *card, wiegand_message_t *packed, bool preamble); bool (*Unpack)(wiegand_message_t *packed, wiegand_card_t *card); const char *Descrp; cardformatdescriptor_t Fields; @@ -42,9 +42,9 @@ typedef struct { void HIDListFormats(void); int HIDFindCardFormat(const char *format); cardformat_t HIDGetCardFormat(int idx); -bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed); +bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bool preamble); bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity); -void HIDPackTryAll(wiegand_card_t *card); +void HIDPackTryAll(wiegand_card_t *card, bool preamble); void print_wiegand_code(wiegand_message_t *packed); void print_desc_wiegand(cardformat_t *fmt, wiegand_message_t *packed); #endif diff --git a/client/src/wiegand_formatutils.c b/client/src/wiegand_formatutils.c index 212a30151..5e36334bd 100644 --- a/client/src/wiegand_formatutils.c +++ b/client/src/wiegand_formatutils.c @@ -121,10 +121,10 @@ bool set_nonlinear_field(wiegand_message_t *data, uint64_t value, uint8_t numBit } static uint8_t get_length_from_header(wiegand_message_t *data) { -/** - * detect if message has "preamble" / "sentinel bit" - * - */ + /** + * detect if message has "preamble" / "sentinel bit" + * + */ uint8_t len = 0; diff --git a/common/crc.c b/common/crc.c index 22bfad035..a922df6e7 100644 --- a/common/crc.c +++ b/common/crc.c @@ -126,10 +126,10 @@ uint32_t CRC8Legic(uint8_t *buff, size_t size) { crc_update2(&crc, buff[i], 8); return reflect8(crc_finish(&crc)); } -// width=8 poly=0x107, init=0x2C refin=true refout=true xorout=0x0000 check=0 name="CRC-8/CARDX" +// width=8 poly=0x7, init=0x2C refin=false refout=false xorout=0x0000 check=0 name="CRC-8/CARDX" uint32_t CRC8Cardx(uint8_t *buff, size_t size) { crc_t crc; - crc_init_ref(&crc, 8, 0x107, 0x2C, 0, true, true); + crc_init_ref(&crc, 8, 0x7, 0x2C, 0, false, false); for (size_t i = 0; i < size; ++i) crc_update2(&crc, buff[i], 8); return crc_finish(&crc); diff --git a/common/generator.c b/common/generator.c index 90a3d92f6..85be456f4 100644 --- a/common/generator.c +++ b/common/generator.c @@ -465,7 +465,6 @@ int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint3 return PM3_SUCCESS; } - int mfc_generate4b_nuid(uint8_t *uid, uint8_t *nuid) { uint16_t crc; uint8_t b1, b2; @@ -481,6 +480,21 @@ int mfc_generate4b_nuid(uint8_t *uid, uint8_t *nuid) { return PM3_SUCCESS; } +int mfc_algo_touch_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key) { + if (uid == NULL) return PM3_EINVARG; + if (key == NULL) return PM3_EINVARG; + + *key = ( + (uint64_t)(uid[1] ^ uid[2] ^ uid[3]) << 40 | + (uint64_t)uid[1] << 32 | + (uint64_t)uid[2] << 24 | + (uint64_t)(((uid[0] + uid[1] + uid[2] + uid[3]) % 0x100) ^ uid[3]) << 16 | + (uint64_t)0 << 8 | + (uint64_t)0 + ); + return PM3_SUCCESS; +} + //------------------------------------ // Self tests //------------------------------------ diff --git a/common/generator.h b/common/generator.h index 601d36fda..e0c045426 100644 --- a/common/generator.h +++ b/common/generator.h @@ -43,6 +43,8 @@ int mfc_algo_sky_all(uint8_t *uid, uint8_t *keys); int mfc_generate4b_nuid(uint8_t *uid, uint8_t *nuid); +int mfc_algo_touch_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); + uint32_t lf_t55xx_white_pwdgen(uint32_t id); int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint32_t aid, uint8_t *kdfInputOut, uint8_t *kdfInputLen); diff --git a/common/iso15693tools.c b/common/iso15693tools.c index aa5119533..494242135 100644 --- a/common/iso15693tools.c +++ b/common/iso15693tools.c @@ -23,7 +23,7 @@ char *iso15693_sprintUID(char *dest, uint8_t *uid) { sprintf(dest, "%02X %02X %02X %02X %02X %02X %02X %02X", uid[7], uid[6], uid[5], uid[4], uid[3], uid[2], uid[1], uid[0] - ); + ); } return dest; } diff --git a/doc/cheatsheet.md b/doc/cheatsheet.md index 1220bf173..68a8e330e 100644 --- a/doc/cheatsheet.md +++ b/doc/cheatsheet.md @@ -332,9 +332,9 @@ pm3 --> hf mfu info Clone MIFARE Ultralight EV1 Sequence ``` pm3 --> hf mfu dump -k FFFFFFFF -pm3 --> script run hf_mfu_dumptoemulator -i hf-mfu-XXXX-dump.bin -o hf-mfu-XXXX-dump.eml +pm3 --> script run data_mfu_bin2eml -i hf-mfu-XXXX-dump.bin -o hf-mfu-XXXX-dump.eml pm3 --> hf mfu eload -u -f hf-mfu-XXXX-dump.eml -pm3 --> hf mfu sim -t 7 -f hf-mfu-XXXX-dump.eml +pm3 --> hf mfu sim -t 7 ``` Bruteforce MIFARE Classic card numbers from 11223344 to 11223346 diff --git a/doc/cliparser.md b/doc/cliparser.md index 1f28b9f82..a837a5afc 100644 --- a/doc/cliparser.md +++ b/doc/cliparser.md @@ -55,10 +55,14 @@ It will also add the `-h --help` option automatic. -h --help : help --cn : card number --fn : facility number - --q5 : target is lf q5 card + --q5 : target is LF T5555/Q5 card + --em : target is LF EM4305/4469 card --raw : raw data + -d --data : hex data supplied + -f --file : filename supplied -k --key : key supplied -n --keyno : key number to use + -p --pwd : password supplied -v --verbose : flag when output should provide more information, not considered debug. -1 --buffer : use the sample buffer diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 0738d589e..c52d35d69 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -93,14 +93,6 @@ hf mf gen3uid hf mf gen3blk hf mf gen3freeze hf mf ice -lf config -lf cmdread -lf read -lf sim -lf simask -lf simfsk -lf simpsk -lf sniff lf em 410x lf em 4x05 lf em 4x50 @@ -111,15 +103,11 @@ lf hitag writer lf hitag dump lf hitag cc lf t55xx config -lf t55xx dangerraw -lf t55xx detect lf t55xx dump lf t55xx info lf t55xx read lf t55xx resetread lf t55xx restore lf t55xx trace -lf t55xx wakeup lf t55xx write -lf t55xx special script run diff --git a/doc/commands.md b/doc/commands.md index 3c55c5368..c6411b58c 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -433,6 +433,7 @@ Check column "offline" for their availability. |`hf mfdes getuid `|N |`Get random uid` |`hf mfdes info `|N |`Tag information` |`hf mfdes list `|Y |`List DESFire (ISO 14443A) history` +|`hf mfdes bruteaid `|N |`Recover AIDs by bruteforce` |`hf mfdes createaid `|N |`Create Application ID` |`hf mfdes deleteaid `|N |`Delete Application ID` |`hf mfdes selectaid `|N |`Select Application ID` @@ -534,13 +535,13 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf help `|Y |`This help` |`lf config `|N |`Get/Set config for LF sampling, bit/sample, decimation, frequency` -|`lf cmdread `|N |`Modulate LF reader field to send command before read (all periods in microseconds)` +|`lf cmdread `|N |`Modulate LF reader field to send command before read` |`lf read `|N |`Read LF tag` -|`lf search `|Y |`Read and Search for valid known tag (in offline mode it you can load first then search)` -|`lf sim `|N |`Simulate LF tag from buffer with optional GAP (in microseconds)` -|`lf simask `|N |`Simulate LF ASK tag from demodbuffer or input` -|`lf simfsk `|N |`Simulate LF FSK tag from demodbuffer or input` -|`lf simpsk `|N |`Simulate LF PSK tag from demodbuffer or input` +|`lf search `|Y |`Read and Search for valid known tag` +|`lf sim `|N |`Simulate LF tag from buffer` +|`lf simask `|N |`Simulate ASK tag` +|`lf simfsk `|N |`Simulate FSK tag` +|`lf simpsk `|N |`Simulate PSK tag` |`lf simbidir `|N |`Simulate LF tag (with bidirectional data transmission between reader and tag)` |`lf sniff `|N |`Sniff LF traffic between reader and tag` |`lf tune `|N |`Continuously measure LF antenna tuning` diff --git a/doc/jtag_notes.md b/doc/jtag_notes.md index f7392d53f..9029958e6 100644 --- a/doc/jtag_notes.md +++ b/doc/jtag_notes.md @@ -8,7 +8,7 @@ The RDV4 repository contains helper scripts for JTAG flashing. * Get OpenOCD, e.g.: `apt-get install openocd` * Create `tools/jtag_openocd/openocd_configuration` by copying [`tools/jtag_openocd/openocd_configuration.sample`](/tools/jtag_openocd/openocd_configuration.sample) -* Tune it to fit your JTAG tool: adapt `CONFIG_IF` to refer to the `interface-*.cfg` file corresponding to your JTAG tool. By default `openocd_configuration.sample` is set up to work with the J-Link. +* Tune it to fit your JTAG tool: adapt `CONFIG_IF` to refer to your JTAG tool. `openocd_configuration.sample` contains several examples and is set up by default to work with the J-Link. * Wire the Proxmark3 to the JTAG tool. How to do it depends on the tool. See below for examples. **Warning:** don't plug the Proxmark3 on USB if the tool delivers already the voltage to the Proxmark3, which is most probably the case. * Then just run @@ -25,7 +25,7 @@ For advanced usages there are also `openocd_flash_dump.sh` for dumping the conte The RDV4 JTAG header is quite smaller compared to other Proxmark3 platforms. If you're using a J-Link, there is a [convenient adapter](https://github.com/RfidResearchGroup/proxmark3/wiki/Tools#jtag-adapter) made by Proxgrind. -You can also make yours with some 1.27mm headers (look for `1.27mm header` on Aliexpress) or Pogo pins. +You can also make yours with some 1.27mm headers (look for `1.27mm header` on Aliexpress) or Pogo pins or buy an already made clip, e.g. search `dykb clamp` on Aliexpress and take a 1.27mm single-row 6P version. ## JLink pinout diff --git a/pm3 b/pm3 index 1ee2ebeb8..6aadf2eb7 100755 --- a/pm3 +++ b/pm3 @@ -148,7 +148,7 @@ function get_pm3_list_Windows { fi # Normal SERIAL PORTS (COM) - for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do + 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/ */} PM3LIST+=("$DEV") if [ ${#PM3LIST[*]} -ge "$N" ]; then @@ -192,7 +192,7 @@ function get_pm3_list_WSL { fi # Normal SERIAL PORTS (COM) - for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_9AC4&PID_4B8F*' | Select DeviceID" 2>/dev/null | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p'); do + 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 DeviceID" 2>/dev/null | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p'); do # ttyS counterpart takes some more time to appear if [ -e "$DEV" ]; then PM3LIST+=("$DEV") diff --git a/tools/Makefile b/tools/Makefile index df6a0682f..b0d043ad3 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -18,3 +18,13 @@ get_xorsearch: # unzzip-big XORSearch_V1_11_2.zip # linux # gunzip XORSearch_V1_11_2.zip + +# Python impl of NDEF FORUM 1-5 protocol +get_nfcpy: + $(MKDIR) nfcpy + $(GIT) https://github.com/nfcpy/nfcpy.git + +# Python tool to create, modify and print NDEF records +get_ndeftool: + $(MKDIR) ndeftool + $(GIT) https://github.com/nfcpy/ndeftool.git diff --git a/tools/hitag2crack/crack5opencl/opencl.c b/tools/hitag2crack/crack5opencl/opencl.c index 98b85714e..31cad1334 100644 --- a/tools/hitag2crack/crack5opencl/opencl.c +++ b/tools/hitag2crack/crack5opencl/opencl.c @@ -254,7 +254,8 @@ int discoverDevices(unsigned int profile_selected, uint32_t device_types_selecte if (verbose) printf("%14s: %s\n", "Device Type", (device_type & CL_DEVICE_TYPE_GPU) ? "GPU" : (device_type & CL_DEVICE_TYPE_CPU) ? "CPU" : "Other"); - (*cd_ctx)[platform_idx].device[device_idx].selected = plat_dev_enabled(global_device_id, dev_sel, dev_cnt, (unsigned int) device_type, device_types_selected); + if ((*cd_ctx)[platform_idx].selected == false)(*cd_ctx)[platform_idx].device[device_idx].selected = false; + else (*cd_ctx)[platform_idx].device[device_idx].selected = plat_dev_enabled(global_device_id, dev_sel, dev_cnt, (unsigned int) device_type, device_types_selected); global_device_id++; if ((*cd_ctx)[platform_idx].device[device_idx].selected)(*selected_devices_cnt)++; continue; diff --git a/tools/jtag_openocd/chip-at91sam7s.cfg b/tools/jtag_openocd/board-at91sam7s.cfg similarity index 82% rename from tools/jtag_openocd/chip-at91sam7s.cfg rename to tools/jtag_openocd/board-at91sam7s.cfg index 7c546e45a..9f570632a 100644 --- a/tools/jtag_openocd/chip-at91sam7s.cfg +++ b/tools/jtag_openocd/board-at91sam7s.cfg @@ -28,3 +28,7 @@ gdb_memory_map enable sam7x.cpu configure -work-area-virt 0 -work-area-phys 0x00200000 -work-area-size 0x10000 -work-area-backup 0 flash bank sam7x.flash.0 at91sam7 0 0 0 0 sam7x.cpu 0 0 0 0 0 0 0 18432 flash bank sam7x.flash.1 at91sam7 0 0 0 0 sam7x.cpu 1 0 0 0 0 0 0 18432 +transport select jtag +# Since some 0.10.0 versions, "adapter_khz" is deprecated in favor of "adapter speed" but there are also some 0.10.0 not recognizing "adapter speed" so we'll stick to "adapter_khz" for now... +# adapter speed 1000 +adapter_khz 1000 diff --git a/tools/jtag_openocd/interface-armusbocd.cfg b/tools/jtag_openocd/interface-armusbocd.cfg deleted file mode 100644 index 4820136f0..000000000 --- a/tools/jtag_openocd/interface-armusbocd.cfg +++ /dev/null @@ -1,8 +0,0 @@ -# Commands specific to the Olimex ARM-USB-OCD Dongle -interface ft2232 -ft2232_device_desc "Olimex OpenOCD JTAG" -ft2232_layout "olimex-jtag" -ft2232_vid_pid 0x15BA 0x0003 -jtag_speed 2 -jtag_nsrst_delay 200 -jtag_ntrst_delay 200 diff --git a/tools/jtag_openocd/interface-busblaster.cfg b/tools/jtag_openocd/interface-busblaster.cfg deleted file mode 100644 index bd1df2c5f..000000000 --- a/tools/jtag_openocd/interface-busblaster.cfg +++ /dev/null @@ -1,10 +0,0 @@ -# Commands specific to the Bus Blaster -interface ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 - -ftdi_layout_init 0x0c08 0x0f1b -ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 -ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 - -adapter_khz 1000 diff --git a/tools/jtag_openocd/interface-buspirate.cfg b/tools/jtag_openocd/interface-buspirate.cfg index 8eccadd79..cb14b2365 100644 --- a/tools/jtag_openocd/interface-buspirate.cfg +++ b/tools/jtag_openocd/interface-buspirate.cfg @@ -1,10 +1,8 @@ # Commands specific to the BusPirate -interface buspirate -buspirate_port /dev/ttyUSB0 -adapter_khz 1000 -# Communication speed -buspirate_speed normal # or fast +source [find interface/buspirate.cfg] + +buspirate_port /dev/ttyUSB0 # Voltage regulator: enabled = 1 or disabled = 0 buspirate_vreg 1 diff --git a/tools/jtag_openocd/interface-c232hm.cfg b/tools/jtag_openocd/interface-c232hm.cfg index f4d0f471a..af37913de 100644 --- a/tools/jtag_openocd/interface-c232hm.cfg +++ b/tools/jtag_openocd/interface-c232hm.cfg @@ -11,13 +11,4 @@ # Black <> GND # Red <> 3.3 (don't connect if C232HM-EDSL-0! power via USB instead) -interface ftdi -#ftdi_device_desc "C232HM-DDHSL-0" -#ftdi_device_desc "C232HM-EDHSL-0" -ftdi_vid_pid 0x0403 0x6014 - -ftdi_layout_init 0x0008 0x400b -ftdi_layout_signal LED -ndata 0x4000 - -transport select jtag -adapter_khz 1000 +source [find interface/ftdi/c232hm.cfg] diff --git a/tools/jtag_openocd/interface-jlink.cfg b/tools/jtag_openocd/interface-jlink.cfg deleted file mode 100644 index 011cb7844..000000000 --- a/tools/jtag_openocd/interface-jlink.cfg +++ /dev/null @@ -1,4 +0,0 @@ -# Commands specific to the Segger J-Link -interface jlink -transport select jtag -adapter_khz 1000 diff --git a/tools/jtag_openocd/interface-jtagkey.cfg b/tools/jtag_openocd/interface-jtagkey.cfg deleted file mode 100644 index 420e6e97e..000000000 --- a/tools/jtag_openocd/interface-jtagkey.cfg +++ /dev/null @@ -1,8 +0,0 @@ -# Commands specific to the Amontec JTAGKey -interface ft2232 -ft2232_device_desc "Amontec JTAGkey A" -ft2232_layout jtagkey -ft2232_vid_pid 0x0403 0xcff8 -jtag_khz 200 -jtag_nsrst_delay 200 -jtag_ntrst_delay 200 diff --git a/tools/jtag_openocd/interface-raspberrypi.cfg b/tools/jtag_openocd/interface-raspberrypi.cfg index 984afe41b..6cb9af881 100644 --- a/tools/jtag_openocd/interface-raspberrypi.cfg +++ b/tools/jtag_openocd/interface-raspberrypi.cfg @@ -12,26 +12,7 @@ # 6 <> GND # 1 <> 3.3 -interface bcm2835gpio - -# This file is meant for first versions of Raspberry Pi -# You can check yours with: -# dd if=/proc/device-tree/soc/ranges bs=4 skip=1 count=1 2>/dev/null|xxd -p -# if it returns 20000000, you're fine -# if it returns 3F000000, use interface-raspberrypi2.cfg -bcm2835gpio_peripheral_base 0x20000000 - -# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET -# These depend on system clock, calibrated for stock 700MHz -# bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET -bcm2835gpio_speed_coeffs 113714 28 - -# Each of the JTAG lines need a gpio number set: tck tms tdi tdo -# Header pin numbers: 23 22 19 21 -bcm2835gpio_jtag_nums 11 25 10 9 +source [find interface/raspberrypi-native.cfg] bcm2835gpio_srst_num 18 reset_config srst_only srst_push_pull - -transport select jtag -adapter_khz 1000 diff --git a/tools/jtag_openocd/interface-raspberrypi2.cfg b/tools/jtag_openocd/interface-raspberrypi2.cfg index dc97479d5..52cb74ea9 100644 --- a/tools/jtag_openocd/interface-raspberrypi2.cfg +++ b/tools/jtag_openocd/interface-raspberrypi2.cfg @@ -12,26 +12,7 @@ # 6 <> GND # 1 <> 3.3 -interface bcm2835gpio - -# This file is meant for recent versions of Raspberry Pi -# You can check yours with: -# dd if=/proc/device-tree/soc/ranges bs=4 skip=1 count=1 2>/dev/null|xxd -p -# if it returns 20000000, use interface-raspberrypi.cfg -# if it returns 3F000000, you're fine -bcm2835gpio_peripheral_base 0x3F000000 - -# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET -# These depend on system clock, calibrated for stock 700MHz -# bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET -bcm2835gpio_speed_coeffs 146203 36 - -# Each of the JTAG lines need a gpio number set: tck tms tdi tdo -# Header pin numbers: 23 22 19 21 -bcm2835gpio_jtag_nums 11 25 10 9 +source [find interface/raspberrypi2-native.cfg] bcm2835gpio_srst_num 18 reset_config srst_only srst_push_pull - -transport select jtag -adapter_khz 1000 diff --git a/tools/jtag_openocd/interface-shikra.cfg b/tools/jtag_openocd/interface-shikra.cfg deleted file mode 100644 index ba4b21419..000000000 --- a/tools/jtag_openocd/interface-shikra.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# Commands specific to the Shikra -interface ftdi -transport select jtag -ftdi_vid_pid 0x0403 0x6014 -ftdi_layout_init 0x0c08 0x0f1b -adapter_khz 2000 diff --git a/tools/jtag_openocd/interface-wiggler.cfg b/tools/jtag_openocd/interface-wiggler.cfg deleted file mode 100644 index ce9a1da06..000000000 --- a/tools/jtag_openocd/interface-wiggler.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Commands specific to the Wiggler -interface parport -parport_port 0x378 -parport_cable wiggler -jtag_speed 0 -jtag_nsrst_delay 200 -jtag_ntrst_delay 200 diff --git a/tools/jtag_openocd/openocd_configuration.sample b/tools/jtag_openocd/openocd_configuration.sample index 466e28d9b..10262de65 100644 --- a/tools/jtag_openocd/openocd_configuration.sample +++ b/tools/jtag_openocd/openocd_configuration.sample @@ -1,7 +1,34 @@ CONFIG_GEN=general.cfg -CONFIG_CHIP=chip-at91sam7s.cfg +CONFIG_BOARD=board-at91sam7s.cfg IMAGE=../../recovery/proxmark3_recovery.bin DUMP="dump_$(date +'%Y%m%d-%H%M%S').bin" -# Example using Segger Jlink: -CONFIG_IF=interface-jlink.cfg +# One can use openocd-provided interfaces or local interface files +# Here are a few examples + +# Segger Jlink: +CONFIG_IF=interface/jlink.cfg + +# Raspberry Pi models Pi1, Pi2 and Pi Zero (read interface-raspberrypi.cfg for pinout) +#CONFIG_IF=interface-raspberrypi.cfg + +# Raspberry Pi models 2+ and above (read interface-raspberrypi2.cfg for pinout) +#CONFIG_IF=interface-raspberrypi2.cfg + +# DP BusBlaster: +#CONFIG_IF=interface/ftdi/dp_busblaster.cfg + +# BusPirate: +#CONFIG_IF=interface-buspirate.cfg + +# C232HM-DDHSL-0 and C232HM-EDSL-0 (beware! read interface-c232hm.cfg instructions) +#CONFIG_IF=interface-c232hm.cfg + +# Olimex ARM-USB-OCD Dongle: +#CONFIG_IF=interface/ftdi/olimex-arm-usb-ocd.cfg + +# Amontec JTAGKey: +#CONFIG_IF=interface/ftdi/jtagkey.cfg + +# Wiggler: +#CONFIG_IF=interface/parport.cfg diff --git a/tools/jtag_openocd/openocd_flash_dump.sh b/tools/jtag_openocd/openocd_flash_dump.sh index 4791b9112..040c8530c 100755 --- a/tools/jtag_openocd/openocd_flash_dump.sh +++ b/tools/jtag_openocd/openocd_flash_dump.sh @@ -7,4 +7,4 @@ if [ -e "$DUMP" ]; then echo "$DUMP exists already. Abort!" exit 1 fi -openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_CHIP -c "init;halt;dump_image $DUMP 0x100000 0x80000;exit" +openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_BOARD -c "init;halt;dump_image $DUMP 0x100000 0x80000;exit" diff --git a/tools/jtag_openocd/openocd_flash_recovery.sh b/tools/jtag_openocd/openocd_flash_recovery.sh index 490cf4abd..d902274db 100755 --- a/tools/jtag_openocd/openocd_flash_recovery.sh +++ b/tools/jtag_openocd/openocd_flash_recovery.sh @@ -7,4 +7,4 @@ if [ ! -e "$IMAGE" ]; then echo "$IMAGE missing. Abort!" exit 1 fi -openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_CHIP -c "init;halt;flash erase_sector 0 0 15;flash erase_sector 1 0 15;flash write_image $IMAGE 0x100000;exit" +openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_BOARD -c "init;halt;flash erase_sector 0 0 15;flash erase_sector 1 0 15;flash write_image $IMAGE 0x100000;exit" diff --git a/tools/jtag_openocd/openocd_interactive.sh b/tools/jtag_openocd/openocd_interactive.sh index 995ee6913..c4f7e4142 100755 --- a/tools/jtag_openocd/openocd_interactive.sh +++ b/tools/jtag_openocd/openocd_interactive.sh @@ -6,4 +6,4 @@ cd $(dirname "$0") echo "*********************************************" echo "Connect to OpenOCD via: telnet localhost $(awk '/^telnet_port/{print$2}' $CONFIG_GEN)" echo "*********************************************" -openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_CHIP +openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_BOARD diff --git a/tools/pm3_tests.sh b/tools/pm3_tests.sh index 0ef81b7c5..da5ea56a5 100755 --- a/tools/pm3_tests.sh +++ b/tools/pm3_tests.sh @@ -343,6 +343,8 @@ while true; do if ! CheckExecute "reveng -g test" "$CLIENTBIN -c 'reveng -g abda202c'" "CRC-16/ISO-IEC-14443-3-A"; then break; fi if ! CheckExecute "reveng -w test" "$CLIENTBIN -c 'reveng -w 8 -s 01020304e3 010204039d'" "CRC-8/SMBUS"; then break; fi if ! CheckExecute "mfu pwdgen test" "$CLIENTBIN -c 'hf mfu pwdgen -t'" "Selftest OK"; then break; fi + if ! CheckExecute "mfu keygen test" "$CLIENTBIN -c 'hf mfu keygen --uid 11223344556677'" "80 B1 C2 71 D8 A0"; then break; fi + if ! CheckExecute "jooki encode test" "$CLIENTBIN -c 'hf jooki encode -t'" "04 28 F4 DA F0 4A 81 ( ok )"; then break; fi if ! CheckExecute "trace load/list 14a" "$CLIENTBIN -c 'trace load -f traces/hf_14a_mfu.trace; trace list -1 -t 14a;'" "READBLOCK(8)"; then break; fi if ! CheckExecute "trace load/list x" "$CLIENTBIN -c 'trace load -f traces/hf_14a_mfu.trace; trace list -x1 -t 14a;'" "0.0101840425"; then break; fi @@ -382,7 +384,7 @@ while true; do "temperature 95.2 F / 35.1 C"; then break; fi if ! CheckExecute slow "lf T55 gallagher test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gallagher.pm3; lf search -1'" "GALLAGHER ID found"; then break; fi if ! CheckExecute slow "lf T55 gallagher test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gallagher.pm3; lf gallagher demod'" \ - "GALLAGHER - Region: 0 FC: 27865 CN: 682758 Issue Level: 13"; then break; fi + "GALLAGHER - Region: 1 FC: 16640 CN: 201 Issue Level: 1"; then break; fi if ! CheckExecute slow "lf T55 gproxii test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gproxii.pm3; lf search -1'" "Guardall G-Prox II ID found"; then break; fi if ! CheckExecute slow "lf T55 gproxii test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gproxii.pm3; lf gproxii demod'" \ "G-Prox-II - len: 26 FC: 123 Card: 11223, Raw: f98c7038c63356c7ac26398c"; then break; fi