diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..d3d86ee80 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,55 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Attach", + "type": "cppdbg", + "request": "attach", + "program": "${cwd}/client/proxmark3", + //"processId": "${command:pickProcess}", + "processId": "${input:ProcessID}", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + },{ + "name": "(gdb) Build & Launch", + "type": "cppdbg", + "request": "launch", + "program": "${cwd}/client/proxmark3", + "args": ["/dev/ttyACM0"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "client: Debug: clean & make", + "miDebuggerPath": "/usr/bin/gdb" + } + ], + "inputs": [ + { + // Using Extension "Tasks Shell Input" https://marketplace.visualstudio.com/items?itemName=augustocdias.tasks-shell-input + "id": "ProcessID", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "pgrep -n proxmark3", + } + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 20b68be0e..155aa80cd 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,24 +4,82 @@ "version": "2.0.0", "tasks": [ { - "label": "build", + "label": "all: Make & run", "type": "shell", - "command": "make clean && make all -j$(nproc --all)", + "command": "make -j && ./pm3", "problemMatcher": [ "$gcc" - ] + ], + "group": { + "kind": "build", + "isDefault": true + } }, { - "label": "flash fullimage", + "label": "choose: Make", "type": "shell", - "command": "sudo ./pm3-flash-fullimage", + "command": "make ${input:componentType} -j", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: make", + "type": "shell", + "command": "make client -j DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: clean & make", + "type": "shell", + "command": "make client/clean && make client -j DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "fullimage: Make & Flash", + "type": "shell", + "command": "make fullimage && ./pm3-flash-fullimage", "problemMatcher": [] }, { - "label": "FLASH BOOTROM", + "label": "BOOTROM: Make & Flash", "type": "shell", - "command": "sudo ./pm3-flash-bootrom", + "command": "make bootrom && ./pm3-flash-bootrom", "problemMatcher": [] + }, + { + "label": "Run client", + "type": "shell", + "command": "./pm3", + "problemMatcher": [] + } + ], + "inputs": [ + { + "type": "pickString", + "id": "componentType", + "description": "What Makefile target do you want to execute?", + "options": [ + "all", + "client", + "bootrom", + "fullimage", + "recovery", + "clean", + "install", + "uninstall", + "style", + "miscchecks", + "check", + ], + "default": "all" } ] } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e5f00a78..d7bdfe891 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Removed 'hf iclass replay' - use the 'hf iclass dump' or 'hf iclass rdbl' with option "n" instead (@iceman1001). Concept taken from official repo (@pwpiwi) - Add low level support for 14b' aka Innovatron (@doegox) - Add doc/cliparser.md (@mwalker33) - Add `hf 14b apdu` - send APDU over ISO14443B (@iceman1001) diff --git a/Makefile.defs b/Makefile.defs index 06eb2e36f..16d5ec9e5 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -27,6 +27,9 @@ LD = g++ SH = sh BASH = bash PERL = perl +CCC =foo +CC_VERSION = $(shell $(CC) -dumpversion 2>/dev/null|sed 's/\..*//') +CC_VERSION := $(or $(strip $(CC_VERSION)),0) PATHSEP=/ PREFIX ?= /usr/local @@ -40,17 +43,29 @@ INSTALLDOCSRELPATH ?= share/doc/proxmark3 platform = $(shell uname) DETECTED_OS=$(platform) -ifeq ($(platform),Darwin) - AR= /usr/bin/ar rcs - RANLIB= /usr/bin/ranlib +ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1) + DETECTED_COMPILER = clang else - AR= ar rcs - RANLIB= ranlib + DETECTED_COMPILER = gcc endif -DEFCXXFLAGS = -Wall -Werror -O3 -pipe -DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe -DEFLDFLAGS = +ifeq ($(platform),Darwin) + AR= /usr/bin/ar rcs + RANLIB= /usr/bin/ranlib +else + AR= ar rcs + RANLIB= ranlib +endif + +ifeq ($(DEBUG),1) + DEFCXXFLAGS = -g -O0 -pipe + DEFCFLAGS = -g -O0 -fstrict-aliasing -pipe + DEFLDFLAGS = +else + DEFCXXFLAGS = -Wall -Werror -O3 -pipe + DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe + DEFLDFLAGS = +endif # Next ones are activated only if SANITIZE=1 ifeq ($(SANITIZE),1) DEFCFLAGS += -g -fsanitize=address -fno-omit-frame-pointer @@ -62,12 +77,18 @@ DEFCFLAGS += -Wbad-function-cast -Wredundant-decls -Wmissing-prototypes -Wchar-s # Some more warnings we need first to eliminate, so temporarely tolerated: DEFCFLAGS += -Wcast-align -Wno-error=cast-align DEFCFLAGS += -Wswitch-enum -Wno-error=switch-enum - +# GCC 10 has issues with false positives on stringop-overflow, let's disable them for now (cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335) +# beware these flags didn't exist for GCC < 7 +ifeq ($(shell expr $(CC_VERSION) \>= 10), 1) + ifneq ($(DETECTED_COMPILER), clang) + DEFCFLAGS += -Wno-stringop-overflow -Wno-error=stringop-overflow + endif +endif ifeq ($(platform),Darwin) -# their readline has strict-prototype issues -DEFCFLAGS += -Wno-strict-prototypes + # their readline has strict-prototype issues + DEFCFLAGS += -Wno-strict-prototypes else -DEFCFLAGS += -Wstrict-prototypes + DEFCFLAGS += -Wstrict-prototypes endif # Next ones are activated only if GCCEXTRA=1 or CLANGEXTRA=1 diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 00de115e6..0c06bc90b 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -302,15 +302,17 @@ static int reader_dump_mode(void) { Iso15693InitReader(); set_tracing(false); + + picopass_hdr *hdr = (picopass_hdr *)card_data; + // select tag. uint32_t eof_time = 0; - bool res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time); + bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time); if (res == false) { switch_off(); continue; } - picopass_hdr *hdr = (picopass_hdr *)card_data; // sanity check of CSN. if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) { switch_off(); @@ -366,7 +368,7 @@ static int reader_dump_mode(void) { auth.use_credit_key = true; memcpy(auth.key, aa2_key, sizeof(auth.key)); - res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time); + res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time); if (res) { // sanity check of CSN. diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 9aa65de03..f5eacc363 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -970,6 +970,23 @@ static void PacketReceived(PacketCommandNG *packet) { ); break; } + case CMD_LF_EM4X_LOGIN: { + struct p { + uint32_t password; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + EM4xLogin(payload->password); + break; + } + case CMD_LF_EM4X_BF: { + struct p { + uint32_t start_pwd; + uint32_t n; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + EM4xBruteforce(payload->start_pwd, payload->n); + break; + } case CMD_LF_EM4X_READWORD: { struct p { uint32_t password; @@ -1242,7 +1259,11 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ISO14443A_ANTIFUZZ: { - iso14443a_antifuzz(packet->oldarg[0]); + struct p { + uint8_t flag; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + iso14443a_antifuzz(payload->flag); break; } case CMD_HF_EPA_COLLECT_NONCE: { @@ -1473,12 +1494,12 @@ static void PacketReceived(PacketCommandNG *packet) { MifareU_Otp_Tearoff(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); break; } - case CMD_HF_MFU_COUNTER_TEAROFF: { + case CMD_HF_MFU_COUNTER_TEAROFF: { struct p { uint8_t counter; uint32_t tearoff_time; } PACKED; - struct p *payload = (struct p *) packet->data.asBytes; + struct p *payload = (struct p *) packet->data.asBytes; MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time); break; } @@ -1512,6 +1533,14 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ICLASS_SIMULATE: { + /* + struct p { + uint8_t reader[4]; + uint8_t mac[4]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + */ + SimulateIClass(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); break; } @@ -1519,15 +1548,6 @@ static void PacketReceived(PacketCommandNG *packet) { ReaderIClass(packet->oldarg[0]); break; } - case CMD_HF_ICLASS_REPLAY: { - struct p { - uint8_t reader[4]; - uint8_t mac[4]; - } PACKED; - struct p *payload = (struct p *) packet->data.asBytes; - ReaderIClass_Replay(payload->reader, payload->mac); - break; - } case CMD_HF_ICLASS_EML_MEMSET: { //iceman, should call FPGADOWNLOAD before, since it corrupts BigBuf FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -1554,18 +1574,8 @@ static void PacketReceived(PacketCommandNG *packet) { iClass_Dump(packet->data.asBytes); break; } - case CMD_HF_ICLASS_CLONE: { - struct p { - uint8_t startblock; - uint8_t endblock; - uint8_t data[]; - } PACKED; - struct p *payload = (struct p *)packet->data.asBytes; - iClass_Clone(payload->startblock, payload->endblock, payload->data); - break; - } case CMD_HF_ICLASS_RESTORE: { - iClass_Restore(packet->data.asBytes); + iClass_Restore((iclass_restore_req_t *)packet->data.asBytes); break; } #endif @@ -1607,7 +1617,11 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_SMART_SETCLOCK: { - SmartCardSetClock(packet->oldarg[0]); + struct p { + uint32_t new_clk; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + SmartCardSetClock(payload->new_clk); break; } case CMD_SMART_RAW: { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 3f0ad9b6b..27f5a08d9 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -14,6 +14,7 @@ #include "lfadc.h" #include "commonutil.h" #include "em4x50.h" +#include "appmain.h" // tear // 4 data bytes // + byte with row parities @@ -470,10 +471,12 @@ static bool find_double_listen_window(bool bcommand) { if (bcommand) { +// SpinDelay(10); + // data transmission from card has to be stopped, because // a commamd shall be issued - // unfortunately the posititon in listen window (where + // unfortunately the position in listen window (where // command request has to be sent) has gone, so if a // second window follows - sync on this to issue a command @@ -519,7 +522,7 @@ static bool find_em4x50_tag(void) { static bool request_receive_mode(void) { // To issue a command we have to find a listen window first. - // Because identification and sychronization at the same time is not + // Because identification and synchronization at the same time is not // possible when using pulse lengths a double listen window is used. bool bcommand = true; return find_double_listen_window(bcommand); @@ -556,7 +559,7 @@ static bool check_ack(bool bliw) { // "bit" of listen window) wait_timer(FPGA_TIMER_0, T0 * 2 * EM4X50_T_TAG_FULL_PERIOD); - // check for listen window (if first bit cannot be inerpreted + // check for listen window (if first bit cannot be interpreted // as a valid bit it must belong to a listen window) if (get_next_bit() == EM4X50_BIT_OTHER) { @@ -727,7 +730,7 @@ static bool standard_read(int *now) { int fwr = *now; uint8_t bits[EM4X50_TAG_WORD] = {0}; - // start with the identification of two succsessive listening windows + // start with the identification of two successive listening windows if (find_double_listen_window(false)) { // read and save words until following double listen window is detected @@ -816,7 +819,7 @@ void em4x50_info(em4x50_data_t *etd) { status = (bsuccess << 1) + blogin; lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238); + reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)tag.sectors, 238); } void em4x50_read(em4x50_data_t *etd) { @@ -860,14 +863,13 @@ void em4x50_read(em4x50_data_t *etd) { status = (now << 2) + (bsuccess << 1) + blogin; lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238); + reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)tag.sectors, 238); } //============================================================================== // write functions //============================================================================== - -static bool write(uint8_t word[4], uint8_t address) { +static int write(uint8_t word[4], uint8_t address) { // writes to specified
@@ -882,17 +884,23 @@ static bool write(uint8_t word[4], uint8_t address) { // send data em4x50_send_word(word); - // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred + reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0); + return PM3_ETEAROFF; + } else { - // look for ACK sequence - if (check_ack(false)) { + // wait for T0 * EM4X50_T_TAG_TWA (write access time) + wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); - // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) - // for saving data and should return with ACK - if (check_ack(false)) - return true; + // look for ACK sequence + if (check_ack(false)) { + // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) + // for saving data and should return with ACK + if (check_ack(false)) + return PM3_SUCCESS; + + } } } else { @@ -900,10 +908,10 @@ static bool write(uint8_t word[4], uint8_t address) { Dbprintf("error in command request"); } - return false; + return PM3_ESOFT; } -static bool write_password(uint8_t password[4], uint8_t new_password[4]) { +static int write_password(uint8_t password[4], uint8_t new_password[4]) { // changes password from to @@ -915,23 +923,29 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) { // send address data em4x50_send_word(password); - // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred + reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0); + return PM3_ETEAROFF; + } else { - // look for ACK sequence and send rm request - // during following listen window - if (check_ack(true)) { + // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) + wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP); - // send new password - em4x50_send_word(new_password); + // look for ACK sequence and send rm request + // during following listen window + if (check_ack(true)) { - // wait for T0 * EM4X50_T_TAG_TWA (write access time) - wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); + // send new password + em4x50_send_word(new_password); + + // wait for T0 * EM4X50_T_TAG_TWA (write access time) + wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); - if (check_ack(false)) if (check_ack(false)) - return true; + if (check_ack(false)) + return PM3_SUCCESS; + } } } else { @@ -939,7 +953,7 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) { Dbprintf("error in command request"); } - return false; + return PM3_ESOFT; } void em4x50_write(em4x50_data_t *etd) { @@ -966,8 +980,13 @@ void em4x50_write(em4x50_data_t *etd) { blogin = login(etd->password); // write word to given address - if (write(etd->word, etd->address)) { + int res = write(etd->word, etd->address); + if (res == PM3_ETEAROFF) { + lf_finalize(); + return; + } + if (res == PM3_SUCCESS) { // to verify result reset EM4x50 if (reset()) { @@ -996,14 +1015,13 @@ void em4x50_write(em4x50_data_t *etd) { } status = (bsuccess << 1) + blogin; - lf_finalize(); - reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238); + reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)tag.sectors, 238); } void em4x50_write_password(em4x50_data_t *etd) { - // sinmple change of password + // simple change of password bool bsuccess = false; @@ -1015,12 +1033,18 @@ void em4x50_write_password(em4x50_data_t *etd) { // login and change password if (login(etd->password)) { - bsuccess = write_password(etd->password, etd->new_password); + + int res = write_password(etd->password, etd->new_password); + if (res == PM3_ETEAROFF) { + lf_finalize(); + return; + } + bsuccess = (res == PM3_SUCCESS); } } lf_finalize(); - reply_ng(CMD_ACK, bsuccess, 0, 0); + reply_ng(CMD_LF_EM4X50_WRITE_PASSWORD, bsuccess, 0, 0); } void em4x50_wipe(em4x50_data_t *etd) { @@ -1049,7 +1073,7 @@ void em4x50_wipe(em4x50_data_t *etd) { // to verify result reset EM4x50 if (reset()) { - // login not necessary because protectd word has been set to 0 + // login not necessary because protected word has been set to 0 // -> no read protected words // -> selective read can be called immediately if (selective_read(addresses)) { @@ -1078,5 +1102,5 @@ void em4x50_wipe(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238); + reply_ng(CMD_LF_EM4X50_WIPE, bsuccess, (uint8_t *)tag.sectors, 238); } diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 1ca742893..92737214a 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -47,12 +47,6 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) { #define I2C_DELAY_2CLK I2CSpinDelayClk(2) #define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x)) -#define I2C_DELAY_100us I2CSpinDelayClk( 100 / 3) -#define I2C_DELAY_600us I2CSpinDelayClk( 600 / 3) -#define I2C_DELAY_10ms I2CSpinDelayClk( 10 * 1000 / 3 ) -#define I2C_DELAY_30ms I2CSpinDelayClk( 30 * 1000 / 3 ) -#define I2C_DELAY_100ms I2CSpinDelayClk( 100 * 1000 / 3) - #define ISO7618_MAX_FRAME 255 // try i2c bus recovery at 100kHz = 5us high, 5us low @@ -134,11 +128,11 @@ void I2C_Reset_EnterMainProgram(void) { StartTicks(); I2C_init(); I2C_SetResetStatus(0, 0, 0); - I2C_DELAY_30ms; + WaitMS(30); I2C_SetResetStatus(1, 0, 0); - I2C_DELAY_30ms; + WaitMS(30); I2C_SetResetStatus(1, 1, 1); - I2C_DELAY_10ms; + WaitMS(10); } // Reset the SIM_Adapter, then enter the bootloader program @@ -147,9 +141,9 @@ void I2C_Reset_EnterBootloader(void) { StartTicks(); I2C_init(); I2C_SetResetStatus(0, 1, 1); - I2C_DELAY_100ms; + WaitMS(100); I2C_SetResetStatus(1, 1, 1); - I2C_DELAY_10ms; + WaitMS(10); } // Wait for the clock to go High. @@ -187,13 +181,13 @@ static bool WaitSCL_L(void) { // It timeout reading response from card // Which ever comes first static bool WaitSCL_L_timeout(void) { - volatile uint32_t delay = 18000; + volatile uint32_t delay = 1800; while (delay--) { // exit on SCL LOW if (!SCL_read) return true; - I2C_DELAY_100us; + WaitMS(1); } return (delay == 0); } @@ -225,7 +219,7 @@ static bool I2C_WaitForSim(void) { // 8051 speaks with smart card. // 1000*50*3.07 = 153.5ms // 1byte transfer == 1ms with max frame being 256bytes - if (!WaitSCL_H_delay(30 * 1000 * 50)) + if (!WaitSCL_H_delay(20 * 1000 * 50)) return false; return true; @@ -440,8 +434,7 @@ int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d // extra wait 500us (514us measured) // 200us (xx measured) -// WaitUS(600); - I2C_DELAY_600us; + WaitUS(600); bool bBreak = true; uint16_t readcount = 0; @@ -641,6 +634,9 @@ bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) { len = I2C_BufferRead(dest, *destlen, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN); + + LED_C_ON(); + if (len > 1) { break; } else if (len == 1) { @@ -674,7 +670,7 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) { // 1byte = 1ms , max frame 256bytes. Should wait 256ms atleast just in case. if (I2C_WaitForSim() == false) return false; - + // read bytes from module uint8_t len = sizeof(card_ptr->atr); if (sc_rx_bytes(card_ptr->atr, &len) == false) @@ -713,12 +709,12 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) { } void SmartCardAtr(void) { - smart_card_atr_t card; LED_D_ON(); set_tracing(true); I2C_Reset_EnterMainProgram(); - bool isOK = GetATR(&card, true); - reply_mix(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); + smart_card_atr_t card; + int res = GetATR(&card, true) ? PM3_SUCCESS : PM3_ETIMEOUT; + reply_ng(CMD_SMART_ATR, res, (uint8_t*)&card, sizeof(smart_card_atr_t)); set_tracing(false); LEDsoff(); } @@ -811,8 +807,7 @@ void SmartCardUpgrade(uint64_t arg0) { } // writing takes time. -// WaitMS(50); - I2C_DELAY_100ms; + WaitMS(100); // read res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT); @@ -844,12 +839,10 @@ void SmartCardSetClock(uint64_t arg0) { LED_D_ON(); set_tracing(true); I2C_Reset_EnterMainProgram(); - // Send SIM CLC // start [C0 05 xx] stop I2C_WriteByte(arg0, I2C_DEVICE_CMD_SIM_CLC, I2C_DEVICE_ADDRESS_MAIN); - - reply_mix(CMD_ACK, 1, 0, 0, 0, 0); + reply_ng(CMD_SMART_SETCLOCK, PM3_SUCCESS, NULL, 0); set_tracing(false); LEDsoff(); } diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 7f22b59cc..03f7dcbba 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1276,7 +1276,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t * * @return false = fail * true = Got all. */ -static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time, uint8_t *status) { +static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) { static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; @@ -1286,8 +1286,6 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; - picopass_hdr *hdr = (picopass_hdr *)card_data; - // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used // bit 7: parity. if (use_credit_key) @@ -1370,6 +1368,8 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 } else { + // on NON_SECURE_PAGEMODE cards, AIA is on block2.. + // read App Issuer Area block 2 read_aia[1] = 0x02; read_aia[2] = 0x61; @@ -1385,23 +1385,23 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 if (status) { *status |= FLAG_ICLASS_AIA; - memcpy(card_data + (8 * 2), resp, 8); + memcpy(hdr->epurse, resp, sizeof(hdr->epurse)); } } return true; } -bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { +bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time) { uint8_t result = 0; - return select_iclass_tag_ex(card_data, use_credit_key, eof_time, &result); + return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result); } // Reader iClass Anticollission // turn off afterwards void ReaderIClass(uint8_t flags) { - uint8_t card_data[6 * 8] = {0xFF}; + picopass_hdr hdr = {0}; // uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; memset(resp, 0xFF, sizeof(resp)); @@ -1419,14 +1419,13 @@ void ReaderIClass(uint8_t flags) { uint8_t result_status = 0; uint32_t eof_time = 0; - bool status = select_iclass_tag_ex(card_data, use_credit_key, &eof_time, &result_status); + bool status = select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &result_status); if (status == false) { - reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); + reply_mix(CMD_ACK, 0xFF, 0, 0, NULL, 0); switch_off(); return; } - // Page mapping for secure mode // 0 : CSN // 1 : Configuration @@ -1444,7 +1443,7 @@ void ReaderIClass(uint8_t flags) { // with 0xFF:s in block 3 and 4. LED_B_ON(); - reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + reply_mix(CMD_ACK, result_status, 0, 0, (uint8_t *)&hdr, sizeof(hdr)); //Send back to client, but don't bother if we already sent this - // only useful if looping in arm (not try_once && not abort_after_read) @@ -1470,101 +1469,6 @@ void ReaderIClass(uint8_t flags) { switch_off(); } -// turn off afterwards -void ReaderIClass_Replay(uint8_t *rnr, uint8_t *mac) { - - BigBuf_free(); - - uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - memcpy(check + 1, rnr, 4); - memcpy(check + 5, mac, 4); - - uint8_t *card_data = BigBuf_malloc(ICLASS_16KS_SIZE); - if (card_data == NULL) { - DbpString("fail to allocate memory"); - reply_ng(CMD_HF_ICLASS_REPLAY, PM3_EMALLOC, NULL, 0); - return; - } - memset(card_data, 0xFF, ICLASS_16KS_SIZE); - - uint32_t start_time = 0; - uint32_t eof_time = 0; - - Iso15693InitReader(); - - picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, false, &eof_time); - if (res == false) { - reply_ng(CMD_HF_ICLASS_REPLAY, PM3_ETIMEOUT, NULL, 0); - switch_off(); - return; - } - - uint8_t resp[10] = {0}; - - //for now replay captured auth (as cc not updated) - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - if (res == false) { - reply_ng(CMD_HF_ICLASS_REPLAY, PM3_ETIMEOUT, NULL, 0); - switch_off(); - return; - } - - uint8_t mem = hdr.conf.mem_config; - uint8_t cardsize = ((mem & 0x80) == 0x80) ? 255 : 32; - - /* - static struct memory_t { - int k16; - int book; - int k2; - int lockauth; - int keyaccess; - } memory; - - // memory.k16 = ((mem & 0x80) == 0x80); - // memory.book = ((mem & 0x20) == 0x20); - // memory.k2 = ((mem & 0x08) == 0x08); - // memory.lockauth = ((mem & 0x02) == 0x02); - // memory.keyaccess = ((mem & 0x01) == 0x01); - // uint8_t cardsize = memory.k16 ? 255 : 32; - */ - - bool dumpsuccess = true; - - // main read loop - uint16_t i; - for (i = 0; i <= cardsize; i++) { - - uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, i, 0x00, 0x00}; - AddCrc(c + 1, 1); - - res = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - if (res) { - memcpy(card_data + (8 * i), resp, 8); - } else { - Dbprintf("failed to read block %u ( 0x%02x)", i, i); - dumpsuccess = false; - } - } - - struct p { - bool isOK; - uint16_t block_cnt; - uint32_t bb_offset; - } PACKED response; - - response.isOK = dumpsuccess; - response.block_cnt = i; - response.bb_offset = card_data - BigBuf_get_addr(); - reply_ng(CMD_HF_ICLASS_REPLAY, PM3_SUCCESS, (uint8_t *)&response, sizeof(response)); - - BigBuf_free(); - switch_off(); -} - // used with function select_and_auth (cmdhficlass.c) // which needs to authenticate before doing more things like read/write // selects and authenticate to a card, sends back div_key and mac to client. @@ -1585,24 +1489,30 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint memcpy(ccnr, hdr->epurse, sizeof(hdr->epurse)); - if (payload->use_raw) - memcpy(div_key, payload->key, 8); - else - iclass_calc_div_key(hdr->csn, payload->key, div_key, payload->use_elite); + if (payload->use_replay) { - if (payload->use_credit_key) - memcpy(hdr->key_c, div_key, sizeof(hdr->key_c)); - else - memcpy(hdr->key_d, div_key, sizeof(hdr->key_d)); + memcpy(pmac, payload->key + 4, 4); + memcpy(cmd_check + 1, payload->key, 8); - opt_doReaderMAC(ccnr, div_key, pmac); + } else { + if (payload->use_raw) + memcpy(div_key, payload->key, 8); + else + iclass_calc_div_key(hdr->csn, payload->key, div_key, payload->use_elite); - // copy MAC to check command (readersignature) - cmd_check[5] = pmac[0]; - cmd_check[6] = pmac[1]; - cmd_check[7] = pmac[2]; - cmd_check[8] = pmac[3]; + if (payload->use_credit_key) + memcpy(hdr->key_c, div_key, sizeof(hdr->key_c)); + else + memcpy(hdr->key_d, div_key, sizeof(hdr->key_d)); + opt_doReaderMAC(ccnr, div_key, pmac); + + // copy MAC to check command (readersignature) + cmd_check[5] = pmac[0]; + cmd_check[6] = pmac[1]; + cmd_check[7] = pmac[2]; + cmd_check[8] = pmac[3]; + } return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time); } @@ -1632,7 +1542,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK; // select card / e-purse - uint8_t card_data[6 * 8] = {0}; + picopass_hdr hdr = {0}; iclass_premac_t *keys = (iclass_premac_t *)datain; @@ -1646,7 +1556,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { uint32_t start_time = 0, eof_time = 0; - if (select_iclass_tag(card_data, use_credit_key, &eof_time) == false) + if (select_iclass_tag(&hdr, use_credit_key, &eof_time) == false) goto out; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -1723,7 +1633,7 @@ void iClass_ReadBlock(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, payload->use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time); if (res == false) { if (payload->send_reply) { response.isOK = res; @@ -1796,7 +1706,7 @@ void iClass_Dump(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, req->use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time); if (res == false) { if (req->send_reply) { reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0); @@ -1866,10 +1776,12 @@ void iClass_Dump(uint8_t *msg) { BigBuf_free(); } -static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data) { +static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac) { + // write command: cmd, 1 blockno, 8 data, 4 mac uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; - memcpy(write + 2, data, 12); // data + mac + memcpy(write + 2, data, 8); + memcpy(write + 10, mac, 4); AddCrc(write + 1, 13); uint8_t resp[10] = {0}; @@ -1914,7 +1826,7 @@ void iClass_WriteBlock(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, payload->req.use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time); if (res == false) { goto out; } @@ -1937,10 +1849,14 @@ void iClass_WriteBlock(uint8_t *msg) { wb[0] = payload->req.blockno; memcpy(wb + 1, payload->data, 8); - if (payload->req.use_credit_key) - doMAC_N(wb, sizeof(wb), hdr.key_c, mac); - else - doMAC_N(wb, sizeof(wb), hdr.key_d, mac); + if (payload->req.use_replay) { + doMAC_N(wb, sizeof(wb), payload->req.key + 4, mac); + } else { + if (payload->req.use_credit_key) + doMAC_N(wb, sizeof(wb), hdr.key_c, mac); + else + doMAC_N(wb, sizeof(wb), hdr.key_d, mac); + } memcpy(write + 2, payload->data, 8); // data memcpy(write + 10, mac, sizeof(mac)); // mac @@ -1949,8 +1865,29 @@ void iClass_WriteBlock(uint8_t *msg) { start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; uint8_t resp[10] = {0}; - res = iclass_send_cmd_with_retries(write, sizeof(write), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time); - if (res == false) { + + uint8_t tries = 3; + while (tries-- > 0) { + + iclass_send_as_reader(write, sizeof(write), &start_time, &eof_time); + + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + res = false; + switch_off(); + if (payload->req.send_reply) + reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t)); + return; + } else { + + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time) == 10) { + res = true; + break; + } + } + } + + if (tries == 0) { + res = false; goto out; } @@ -1983,29 +1920,75 @@ out: reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t)); } -// turn off afterwards -void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { -} +void iClass_Restore(iclass_restore_req_t *msg) { -void iClass_Restore(uint8_t *msg) { + // sanitation + if (msg == NULL) { + reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0); + return; + } - iclass_restore_req_t *cmd = (iclass_restore_req_t *)msg; -// iclass_auth_req_t *req = &cmd->req; + if (msg->item_cnt == 0) { + if (msg->req.send_reply) { + reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0); + } + return; + } LED_A_ON(); - uint16_t written = 0; - uint16_t total_blocks = (cmd->end_block - cmd->start_block) + 1; - for (uint8_t b = cmd->start_block; b < total_blocks; b++) { + Iso15693InitReader(); - if (iclass_writeblock_ext(b, cmd->data + ((b - cmd->start_block) * 12))) { - Dbprintf("Write block [%02x] successful", b); - written++; - } else { - Dbprintf("Write block [%02x] failed", b); + uint16_t written = 0; + uint32_t eof_time = 0; + picopass_hdr hdr = {0}; + + // select + bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time); + if (res == false) { + goto out; + } + + // authenticate + uint8_t mac[4] = {0}; + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + // authenticate + if (msg->req.do_auth) { + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac); + if (res == false) { + goto out; } } + // main loop + for (uint8_t i = 0; i < msg->item_cnt; i++) { + + iclass_restore_item_t item = msg->blocks[i]; + + // calc new mac for data, using 1b blockno, 8b data, + uint8_t wb[9] = {0}; + wb[0] = item.blockno; + memcpy(wb + 1, item.data, 8); + + if (msg->req.use_credit_key) + doMAC_N(wb, sizeof(wb), hdr.key_c, mac); + else + doMAC_N(wb, sizeof(wb), hdr.key_d, mac); + + // data + mac + if (iclass_writeblock_ext(item.blockno, item.data, mac)) { + Dbprintf("Write block [%02x] " _GREEN_("successful"), item.blockno); + written++; + } else { + Dbprintf("Write block [%02x] " _RED_("failed"), item.blockno); + } + } + +out: + switch_off(); - uint8_t isOK = (written == total_blocks) ? 1 : 0; - reply_ng(CMD_HF_ICLASS_CLONE, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); + if (msg->req.send_reply) { + int isOK = (written == msg->item_cnt) ? PM3_SUCCESS : PM3_ESOFT; + reply_ng(CMD_HF_ICLASS_RESTORE, isOK, NULL, 0); + } } diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 3776aa385..1895ebbf6 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -17,13 +17,11 @@ void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string); void ReaderIClass(uint8_t arg0); -void ReaderIClass_Replay(uint8_t *rnr, uint8_t *mac); void iClass_WriteBlock(uint8_t *msg); void iClass_Dump(uint8_t *msg); -void iClass_Restore(uint8_t *msg); -void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); +void iClass_Restore(iclass_restore_req_t *msg); int do_iclass_simulation_nonsec(void); int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf); @@ -37,6 +35,6 @@ bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out); void iClass_ReadBlock(uint8_t *msg); bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time); -bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time); +bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time); bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out); #endif diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 19c16f656..fe8831470 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1778,9 +1778,10 @@ static void PrepareDelayedTransfer(uint16_t delay) { //------------------------------------------------------------------------------------- static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) { - if (!hf_field_active) + if (!hf_field_active) { + Dbprintf("Warning: HF field is off, ignoring TransmitFor14443a command"); return; - + } FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); if (timing) { @@ -2189,8 +2190,10 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start //----------------------------------------------------------------------------- bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint8_t *received_len) { - if (!hf_field_active) + if (!hf_field_active) { + Dbprintf("Warning: HF field is off, ignoring GetIso14443aAnswerFromTag_Thinfilm command"); return false; + } // Set FPGA mode to "reader listen mode", no modulation (listen // only, since we are receiving, not transmitting). @@ -2390,7 +2393,7 @@ void iso14443a_antifuzz(uint32_t flags) { } } - reply_old(CMD_ACK, 1, 0, 0, 0, 0); + reply_ng(CMD_HF_ISO14443A_ANTIFUZZ, PM3_SUCCESS, NULL, 0); switch_off(); BigBuf_free_keep_EM(); } @@ -2624,13 +2627,13 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 } // else force RATS // RATS, Request for answer to select - if (!no_rats) { - uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0 + if (no_rats == false) { + uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0 AddCrc14A(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); int len = ReaderReceive(resp, resp_par); - - if (!len) return 0; + if (len == 0) + return 0; if (p_card) { memcpy(p_card->ats, resp, sizeof(p_card->ats)); @@ -2932,7 +2935,7 @@ void ReaderIso14443a(PacketCommandNG *c) { if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured FpgaDisableTracing(); - reply_old(CMD_ACK, 0, 0, 0, NULL, 0); + reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); } else { arg0 = ReaderReceive(buf, par); FpgaDisableTracing(); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 976e13148..64c0ba67f 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -1895,12 +1895,17 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { uint32_t eof_time = 0; CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time); - eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; - status = Get14443bAnswerFromTag(buf, sizeof(buf), 5 * ISO14443B_READER_TIMEOUT, &eof_time); // raw - FpgaDisableTracing(); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + FpgaDisableTracing(); + reply_mix(CMD_HF_ISO14443B_COMMAND, -2, 0, 0, NULL, 0); + } else { + eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; + status = Get14443bAnswerFromTag(buf, sizeof(buf), 5 * ISO14443B_READER_TIMEOUT, &eof_time); // raw + FpgaDisableTracing(); - sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); - reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen); + sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); + reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen); + } } out: diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index e84edd8a0..5861b3d17 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -290,6 +290,7 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { LED_B_OFF(); *start_time = *start_time + DELAY_ARM_TO_TAG; + FpgaDisableTracing(); } //----------------------------------------------------------------------------- @@ -732,6 +733,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo } FpgaDisableSscDma(); + FpgaDisableTracing(); uint32_t sof_time = *eof_time - (dt->len * 8 * 8 * 16) // time for byte transfers @@ -1469,17 +1471,22 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t // low speed (1 out of 256) CodeIso15693AsReader256(send, sendlen); } - + int res = 0; tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, &start_time); - *eof_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF - LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true); - int res = 0; - if (recv != NULL) { - res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + + res = PM3_ETEAROFF; + + } else { + + *eof_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF + LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true); + if (recv != NULL) { + res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + } } - FpgaDisableTracing(); return res; } @@ -1495,7 +1502,6 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui if (recv != NULL) { res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); } - FpgaDisableTracing(); return res; } @@ -1588,41 +1594,49 @@ void ReaderIso15693(uint32_t parameter) { BuildIdentifyRequest(cmd); uint32_t start_time = 0; uint32_t eof_time; - int answerLen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + int recvlen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time); - // we should do a better check than this - if (answerLen >= 12) { - uint8_t uid[8]; - uid[0] = answer[9]; // always E0 - uid[1] = answer[8]; // IC Manufacturer code - uid[2] = answer[7]; - uid[3] = answer[6]; - uid[4] = answer[5]; - uid[5] = answer[4]; - uid[6] = answer[3]; - uid[7] = answer[2]; + if (recvlen == PM3_ETEAROFF) { // tearoff occured + reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0); + } else { - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X", - uid[0], uid[1], uid[2], uid[3], - uid[4], uid[5], uid[5], uid[6] - ); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + // we should do a better check than this + if (recvlen >= 12) { + uint8_t uid[8]; + uid[0] = answer[9]; // always E0 + uid[1] = answer[8]; // IC Manufacturer code + uid[2] = answer[7]; + uid[3] = answer[6]; + uid[4] = answer[5]; + uid[5] = answer[4]; + uid[6] = answer[3]; + uid[7] = answer[2]; + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X", + uid[0], uid[1], uid[2], uid[3], + uid[4], uid[5], uid[5], uid[6] + ); + } + // send UID back to client. + // arg0 = 1 = OK + // arg1 = len of response (12 bytes) + // arg2 = rtf + // asbytes = uid. + reply_mix(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid)); + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[+] %d octets read from IDENTIFY request:", recvlen); + DbdecodeIso15693Answer(recvlen, answer); + Dbhexdump(recvlen, answer, true); + } + } else { + DbpString("Failed to select card"); + reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); } - // send UID back to client. - // arg0 = 1 = OK - // arg1 = len of response (12 bytes) - // arg2 = rtf - // asbytes = uid. - reply_mix(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid)); } - - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("[+] %d octets read from IDENTIFY request:", answerLen); - DbdecodeIso15693Answer(answerLen, answer); - Dbhexdump(answerLen, answer, true); - } - switch_off(); BigBuf_free(); } @@ -1694,6 +1708,11 @@ void SimTagIso15693(uint8_t *uid) { bool exit_loop = false; while (exit_loop == false) { + + button_pressed = BUTTON_PRESS(); + if (button_pressed || data_available()) + break; + WDT_HIT(); // find reader field @@ -1767,6 +1786,11 @@ void BruteforceIso15693Afi(uint32_t speed) { if (recvlen >= 12) { Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, recv + 2)); + } else { + DbpString("Failed to select card"); + reply_ng(CMD_ACK, PM3_ESOFT, NULL, 0); + switch_off(); + return; } // now with AFI @@ -1816,10 +1840,9 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint LED_A_ON(); - int recvlen = 0; uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - uint32_t eof_time = 0; uint16_t timeout; + uint32_t eof_time = 0; bool request_answer = false; switch (data[1]) { @@ -1837,43 +1860,29 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint timeout = ISO15693_READER_TIMEOUT; } - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("SEND:"); - Dbhexdump(datalen, data, false); - } - uint32_t start_time = 0; - recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time); + int recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time); - // send a single EOF to get the tag response - if (request_answer) { - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time); + if (recvlen == PM3_ETEAROFF) { // tearoff occured + reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0); + } else { + + // send a single EOF to get the tag response + if (request_answer) { + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time); + } + + if (recv) { + recvlen = MIN(recvlen, ISO15693_MAX_RESPONSE_LENGTH); + reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); + } else { + reply_mix(CMD_ACK, 1, 0, 0, NULL, 0); + } } - - // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); - - if (recv) { - - if (recvlen > ISO15693_MAX_RESPONSE_LENGTH) { - recvlen = ISO15693_MAX_RESPONSE_LENGTH; - } - reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); - - if (DBGLEVEL >= DBG_EXTENDED) { - - Dbprintf("RECV:"); - if (recvlen > 0) { - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } - } - } else { - reply_mix(CMD_ACK, 1, 0, 0, 0, 0); - } } /* diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 03e322681..a6fbb7bba 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -2467,7 +2467,7 @@ static uint8_t Prepare_Data(uint16_t data_low, uint16_t data_hi) { // Requires: forwarLink_data filled with valid bits (1 bit per byte) // fwd_bit_count set with number of bits to be sent //==================================================================== -static void SendForward(uint8_t fwd_bit_count) { +static void SendForward(uint8_t fwd_bit_count, bool fast) { // iceman, 21.3us increments for the USclock verification. // 55FC * 8us == 440us / 21.3 === 20.65 steps. could be too short. Go for 56FC instead @@ -2480,9 +2480,10 @@ static void SendForward(uint8_t fwd_bit_count) { fwd_write_ptr = forwardLink_data; fwd_bit_sz = fwd_bit_count; - // Set up FPGA, 125kHz or 95 divisor - LFSetupFPGAForADC(LF_DIVISOR_125, true); - + if (! fast) { + // Set up FPGA, 125kHz or 95 divisor + LFSetupFPGAForADC(LF_DIVISOR_125, true); + } // force 1st mod pulse (start gap must be longer for 4305) fwd_bit_sz--; //prepare next bit modulation fwd_write_ptr++; @@ -2490,28 +2491,98 @@ static void SendForward(uint8_t fwd_bit_count) { TurnReadLF_off(EM_START_GAP); TurnReadLFOn(18 * 8); - // now start writting with bitbanging the antenna. (each bit should be 32*8 total length) + // now start writing with bitbanging the antenna. (each bit should be 32*8 total length) while (fwd_bit_sz-- > 0) { //prepare next bit modulation if (((*fwd_write_ptr++) & 1) == 1) { WaitUS(32 * 8); } else { TurnReadLF_off(23 * 8); - TurnReadLFOn((32 - 23) * 8); + TurnReadLFOn(18 * 8); } } } -static void EM4xLogin(uint32_t pwd) { +static void EM4xLoginEx(uint32_t pwd) { forward_ptr = forwardLink_data; uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN); len += Prepare_Data(pwd & 0xFFFF, pwd >> 16); - SendForward(len); + SendForward(len, false); //WaitUS(20); // no wait for login command. // should receive // 0000 1010 ok // 0000 0001 fail } +void EM4xBruteforce(uint32_t start_pwd, uint32_t n) { + // With current timing, 18.6 ms per test = 53.8 pwds/s + reply_ng(CMD_LF_EM4X_BF, PM3_SUCCESS, NULL, 0); + StartTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitMS(20); + LED_A_ON(); + LFSetupFPGAForADC(LF_DIVISOR_125, true); + uint32_t candidates_found = 0; + for (uint32_t pwd = start_pwd; pwd < 0xFFFFFFFF; pwd++) { + if (((pwd - start_pwd) & 0x3F) == 0x00) { + WDT_HIT(); + if (BUTTON_PRESS() || data_available()) { + Dbprintf("EM4x05 Bruteforce Interrupted"); + break; + } + } + // Report progress every 256 attempts + if (((pwd - start_pwd) & 0xFF) == 0x00) { + Dbprintf("Trying: %06Xxx", pwd >> 8); + } + clear_trace(); + + forward_ptr = forwardLink_data; + uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN); + len += Prepare_Data(pwd & 0xFFFF, pwd >> 16); + SendForward(len, true); + + WaitUS(400); + DoPartialAcquisition(0, false, 350, 1000); + uint8_t *mem = BigBuf_get_addr(); + if (mem[334] < 128) { + candidates_found++; + Dbprintf("Password candidate: " _GREEN_("%08X"), pwd); + if ((n != 0) && (candidates_found == n)) { + Dbprintf("EM4x05 Bruteforce Stopped. %i candidate%s found", candidates_found, candidates_found > 1 ? "s" : ""); + break; + } + } + // Beware: if smaller, tag might not have time to be back in listening state yet + WaitMS(1); + } + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +void EM4xLogin(uint32_t pwd) { + + StartTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitMS(20); + + LED_A_ON(); + + // clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + EM4xLoginEx(pwd); + + WaitUS(400); + // We need to acquire more than needed, to help demodulators finding the proper modulation + DoPartialAcquisition(0, false, 6000, 1000); + + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_LF_EM4X_LOGIN, PM3_SUCCESS, NULL, 0); + LEDsoff(); +} + void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { StartTicks(); @@ -2529,17 +2600,17 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { * 0000 1010 ok * 0000 0001 fail **/ - if (usepwd) EM4xLogin(pwd); + if (usepwd) EM4xLoginEx(pwd); forward_ptr = forwardLink_data; uint8_t len = Prepare_Cmd(FWD_CMD_READ); len += Prepare_Addr(addr); - SendForward(len); + SendForward(len, false); WaitUS(400); - DoPartialAcquisition(20, false, 6000, 1000); + DoPartialAcquisition(0, false, 6000, 1000); StopTicks(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -2564,14 +2635,14 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { * 0000 1010 ok. * 0000 0001 fail **/ - if (usepwd) EM4xLogin(pwd); + if (usepwd) EM4xLoginEx(pwd); forward_ptr = forwardLink_data; uint8_t len = Prepare_Cmd(FWD_CMD_WRITE); len += Prepare_Addr(addr); len += Prepare_Data(data & 0xFFFF, data >> 16); - SendForward(len); + SendForward(len, false); if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured StopTicks(); @@ -2607,13 +2678,13 @@ void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) { * 0000 1010 ok. * 0000 0001 fail **/ - if (usepwd) EM4xLogin(pwd); + if (usepwd) EM4xLoginEx(pwd); forward_ptr = forwardLink_data; uint8_t len = Prepare_Cmd(FWD_CMD_PROTECT); len += Prepare_Data(data & 0xFFFF, data >> 16); - SendForward(len); + SendForward(len, false); if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured StopTicks(); diff --git a/armsrc/lfops.h b/armsrc/lfops.h index 1c191d65d..0ec050158 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -56,6 +56,8 @@ void T55xxDangerousRawTest(uint8_t *data); void TurnReadLFOn(uint32_t delay); +void EM4xLogin(uint32_t pwd); +void EM4xBruteforce(uint32_t start_pwd, uint32_t n); void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd); void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd); void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index f442166f4..11c89a98b 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2752,15 +2752,15 @@ void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) { // Send MFU counter increase cmd uint8_t cmd[] = { - MIFARE_ULEV1_INCR_CNT, - counter, - 0, // lsb - 0, - 0, // msb - 0, // rfu - 0, - 0, - }; + MIFARE_ULEV1_INCR_CNT, + counter, + 0, // lsb + 0, + 0, // msb + 0, // rfu + 0, + 0, + }; AddCrc14A(cmd, sizeof(cmd) - 2); // anticollision / select card diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index e7262ba33..6d4abf82d 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -18,6 +18,7 @@ # -DANDROID_NATIVE_API_LEVEL=android-19 \ # -DSKIPBT=1 -DSKIPPYTHON=1 -DSKIPPTHREAD=1 .. +message(STATUS "CMake ${CMAKE_VERSION}") cmake_minimum_required(VERSION 3.10) project(proxmark3) SET (PM3_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..) @@ -248,6 +249,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdlfcotag.c ${PM3_ROOT}/client/src/cmdlfdestron.c ${PM3_ROOT}/client/src/cmdlfem4x.c + ${PM3_ROOT}/client/src/cmdlfem4x05.c ${PM3_ROOT}/client/src/cmdlfem4x50.c ${PM3_ROOT}/client/src/cmdlffdxb.c ${PM3_ROOT}/client/src/cmdlfgallagher.c @@ -495,20 +497,10 @@ if (NOT APPLE) set(ADDITIONAL_LNK ${ADDITIONAL_LNK} -Wl,--as-needed -latomic -Wl,--no-as-needed) endif (NOT APPLE) - -find_library(pm3rrg_rdv4_cliparser REQUIRED) -find_library(pm3rrg_rdv4_tinycbor REQUIRED) -find_library(pm3rrg_rdv4_lua REQUIRED) -find_library(pm3rrg_rdv4_mbedtls REQUIRED) -find_library(pm3rrg_rdv4_reveng REQUIRED) -find_library(pm3rrg_rdv4_hardnested REQUIRED) - if (NOT JANSSON_FOUND) - find_library(pm3rrg_rdv4_jansson REQUIRED) set(ADDITIONAL_LNK pm3rrg_rdv4_jansson ${ADDITIONAL_LNK}) endif (NOT JANSSON_FOUND) if (NOT WHEREAMI_FOUND) - find_library(pm3rrg_rdv4_whereami REQUIRED) set(ADDITIONAL_LNK pm3rrg_rdv4_whereami ${ADDITIONAL_LNK}) endif (NOT WHEREAMI_FOUND) diff --git a/client/Makefile b/client/Makefile index 27702a9d6..b4393ad36 100644 --- a/client/Makefile +++ b/client/Makefile @@ -443,6 +443,7 @@ SRCS = aidsearch.c \ cmdlfcotag.c \ cmdlfdestron.c \ cmdlfem4x.c \ + cmdlfem4x05.c \ cmdlfem4x50.c \ cmdlffdxb.c \ cmdlfguard.c \ diff --git a/client/android/CMakeLists.txt b/client/android/CMakeLists.txt index b3f432c6c..69e71d5d5 100644 --- a/client/android/CMakeLists.txt +++ b/client/android/CMakeLists.txt @@ -1,4 +1,5 @@ # version +message(STATUS "CMake ${CMAKE_VERSION}") cmake_minimum_required(VERSION 3.4.1) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -fvisibility=hidden -w") @@ -12,7 +13,6 @@ add_subdirectory(../deps deps) if (CMAKE_MAKE_PROGRAM MATCHES ".*ninja.*") set(BZIP2_INCLUDE_DIRS ${BZIP2_ROOT}) set(BZIP2_LIBRARIES pm3rrg_rdv4_bzip2) - find_library(pm3rrg_rdv4_bzip2 REQUIRED) elseif (UNIX) # Cross compile at Unix Makefile System. # bzip2 dep. include(ExternalProject) @@ -190,15 +190,6 @@ target_include_directories(pm3rrg_rdv4 PRIVATE ${PM3_ROOT}/common_fpga ${PM3_ROOT}/client/src) -find_library(pm3rrg_rdv4_cliparser REQUIRED) -find_library(pm3rrg_rdv4_jansson REQUIRED) -find_library(pm3rrg_rdv4_tinycbor REQUIRED) -find_library(pm3rrg_rdv4_lua REQUIRED) -find_library(pm3rrg_rdv4_mbedtls REQUIRED) -find_library(pm3rrg_rdv4_reveng REQUIRED) -find_library(pm3rrg_rdv4_hardnested REQUIRED) -find_library(pm3rrg_rdv4_whereami REQUIRED) - target_link_libraries(pm3rrg_rdv4 ${BZIP2_LIBRARIES} pm3rrg_rdv4_hardnested diff --git a/client/deps/amiibo.cmake b/client/deps/amiibo.cmake index 234547cd1..491d90d60 100644 --- a/client/deps/amiibo.cmake +++ b/client/deps/amiibo.cmake @@ -14,7 +14,6 @@ add_library(pm3rrg_rdv4_amiibo STATIC if (NOT TARGET pm3rrg_rdv4_mbedtls) include(mbedtls.cmake) endif() -find_library(pm3rrg_rdv4_mbedtls REQUIRED) target_link_libraries(pm3rrg_rdv4_amiibo PRIVATE m pm3rrg_rdv4_mbedtls) diff --git a/client/deps/cliparser.cmake b/client/deps/cliparser.cmake index b16451c07..fccae33b7 100644 --- a/client/deps/cliparser.cmake +++ b/client/deps/cliparser.cmake @@ -3,6 +3,7 @@ add_library(pm3rrg_rdv4_cliparser STATIC cliparser/cliparser.c ) +target_compile_definitions(pm3rrg_rdv4_cliparser PRIVATE _ISOC99_SOURCE) target_include_directories(pm3rrg_rdv4_cliparser PRIVATE ../../common ../../include diff --git a/client/deps/cliparser/Makefile b/client/deps/cliparser/Makefile index 4873372c4..1994992f9 100644 --- a/client/deps/cliparser/Makefile +++ b/client/deps/cliparser/Makefile @@ -9,3 +9,12 @@ MYSRCS = \ LIB_A = libcliparser.a include ../../../Makefile.host + +$(info PLATFORM $(platform)) +ifneq (,$(findstring MINGW,$(platform))) + # Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z) + # and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1 + # FTR __USE_MINGW_ANSI_STDIO seems deprecated in Mingw32 + # but not Mingw64 https://fr.osdn.net/projects/mingw/lists/archive/users/2019-January/000199.html + CFLAGS += -D_ISOC99_SOURCE +endif diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index cc82fc334..e96f100bb 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -11,8 +11,10 @@ #include "cliparser.h" #include #include -#include // Get color constants -#include // get PrintAndLogEx +#include // Get color constants +#include // get PrintAndLogEx +#include // tolower +#include // PRIu64 #ifndef ARRAYLEN # define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0])) @@ -125,7 +127,6 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta return 0; } - enum ParserState { PS_FIRST, PS_ARGUMENT, @@ -203,34 +204,33 @@ int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtab int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) { *datalen = 0; - int ibuf = 0; - uint8_t tmp_buf[512] = {0}; - int res = CLIParamStrToBuf(argstr, tmp_buf, maxdatalen * 2, &ibuf); // *2 because here HEX + int tmplen = 0; + uint8_t tmpstr[(256 * 2) + 1] = {0}; + + // concat all strings in argstr into tmpstr[] + // + int res = CLIParamStrToBuf(argstr, tmpstr, sizeof(tmpstr), &tmplen); if (res) { - printf("Parameter error: buffer overflow.\n"); - fflush(stdout); return res; } - if (ibuf == 0) { + if (tmplen == 0) { return res; } - switch (param_gethex_to_eol((char *)tmp_buf, 0, data, maxdatalen, datalen)) { + res = param_gethex_to_eol((char *)tmpstr, 0, data, maxdatalen, datalen); + switch (res) { case 1: - printf("Parameter error: Invalid HEX value.\n"); - fflush(stdout); - return 1; + printf("Parameter error: Invalid HEX value\n"); + break; case 2: - printf("Parameter error: parameter too large.\n"); - fflush(stdout); - return 2; + printf("Parameter error: parameter too large\n"); + break; case 3: - printf("Parameter error: Hex string must have even number of digits.\n"); - fflush(stdout); - return 3; + printf("Parameter error: Hex string must have EVEN number of digits\n"); + break; } - - return 0; + fflush(stdout); + return res; } int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) { @@ -238,28 +238,55 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int if (!argstr->count) return 0; - uint8_t tmp_buf[512] = {0}; + uint8_t tmpstr[(256 * 2) + 1] = {0}; int ibuf = 0; for (int i = 0; i < argstr->count; i++) { + int len = strlen(argstr->sval[i]); - memcpy(&tmp_buf[ibuf], argstr->sval[i], len); + + if (len > ((sizeof(tmpstr) / 2) - ibuf)) { + printf("Parameter error: string too long (%i chars), expect MAX %zu chars\n", len + ibuf, (sizeof(tmpstr) / 2)); + fflush(stdout); + return 2; + } + + memcpy(&tmpstr[ibuf], argstr->sval[i], len); + ibuf += len; } - tmp_buf[ibuf] = 0; - if (!ibuf) + ibuf = MIN(ibuf, (sizeof(tmpstr) / 2)); + tmpstr[ibuf] = 0; + + if (ibuf == 0) return 0; - if (ibuf + 1 > maxdatalen) { - printf("Parameter error: string too long, expect max %i chars\n", maxdatalen - 1); + if (ibuf > maxdatalen) { + printf("Parameter error: string too long (%i chars), expected MAX %i chars\n", ibuf, maxdatalen); fflush(stdout); return 2; } - memcpy(data, tmp_buf, ibuf + 1); + memcpy(data, tmpstr, ibuf + 1); *datalen = ibuf; return 0; } +uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def) { + uint64_t rv = 0; + uint8_t data[8]; + int datalen = 0; + int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), &datalen); + if (res == 0 && datalen > 0) { + for (uint8_t i = 0; i < datalen; i++) { + rv <<= 8; + rv |= data[i]; + } + } else { + rv = def; + } + return rv; +} + diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index 68beca038..996ad81ef 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -49,7 +49,7 @@ #define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} -#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} +#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), (*datalen), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} typedef struct { void **argtable; @@ -66,4 +66,6 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); + +uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def); #endif diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index 58c2c40bc..cf40e63fd 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -1203,3 +1203,9 @@ FEE2A3FBC5B6 # taurus avm # 005078565703 +# +# Ving? +# +0602721E8F06 +FC0B50AF8700 +F7BA51A9434E \ No newline at end of file diff --git a/client/dictionaries/t55xx_default_pwds.dic b/client/dictionaries/t55xx_default_pwds.dic index c35014d79..6e7a69583 100644 --- a/client/dictionaries/t55xx_default_pwds.dic +++ b/client/dictionaries/t55xx_default_pwds.dic @@ -26,6 +26,8 @@ A5B4C3D2 50520901 # default PROX 50524F58 +# blue gun EM4305 +F9DCEBA0 # Default pwd, simple: 00000000 11111111 @@ -45,9 +47,6 @@ EEEEEEEE FFFFFFFF a0a1a2a3 b0b1b2b3 -aabbccdd -bbccddee -ccddeeff 50415353 00000001 00000002 @@ -123,3 +122,7 @@ b5f44686 # seeds ul-ev1 C6EF3720 # TEA 7854794A # xbox tea constant :) F1EA5EED # burtle +69314718 # ln2 +57721566 # euler constant (dec) +93C467E3 # euler constant (hex) +27182818 # natural log diff --git a/client/luascripts/hf_mf_format.lua b/client/luascripts/hf_mf_format.lua index d949c25f2..0bde3c2d1 100644 --- a/client/luascripts/hf_mf_format.lua +++ b/client/luascripts/hf_mf_format.lua @@ -36,7 +36,7 @@ arguments = [[ -k - the current six byte key with write access -n - the new key that will be written to the card -a - the new access bytes that will be written to the card - -x - execute the commands aswell. + -x - execute the commands as well. ]] local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds diff --git a/client/luascripts/lf_em_tearoff_protect.lua b/client/luascripts/lf_em_tearoff_protect.lua index 49ee99cec..8d18ec5da 100644 --- a/client/luascripts/lf_em_tearoff_protect.lua +++ b/client/luascripts/lf_em_tearoff_protect.lua @@ -36,7 +36,7 @@ arguments = [[ end ]] -local set_tearoff_delay = 'hw tearoff -s --on --delay %d' +local set_tearoff_delay = 'hw tearoff --on --delay %d' local wr_template = 'lf em 4x05_write %s %s %s' --- @@ -250,6 +250,10 @@ local function main(args) local wordstr14b = ('%08X'):format(word14b) if (wordstr14b == '00000000') then reset(wr_value, password) + word14b, err14b = core.em4x05_read(14, password) + if err14b then + return oops(err14b) + end end if (wordstr14b ~= rd_value) then local word15b, err15b = core.em4x05_read(15, password) @@ -299,17 +303,17 @@ local function main(args) else print(('[=] Status: failed to commit => '..ansicolors.red..'FAIL: '..ansicolors.reset..'14: %08X 15: %08X'):format(word14b, word15b)) end + if auto then + n = 0 + ed = sd + else + tries = 0 + soon = 0 + late = 0 + end else print(('[=] Status: 15 bitflipped but inactive => '..ansicolors.yellow..'PROMISING: '..ansicolors.reset..'14: %08X 15: '..ansicolors.cyan..'%08X'..ansicolors.reset):format(word14, word15)) end - if auto then - n = 0 - ed = sd - else - tries = 0 - soon = 0 - late = 0 - end end end if not auto then diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index dcd85c5d5..8249c28af 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -57,7 +57,7 @@ static int usage_hf_search(void) { } static int usage_hf_sniff(void) { - PrintAndLogEx(NORMAL, "The high frequence sniffer will assign all available memory on device for sniffed data"); + PrintAndLogEx(NORMAL, "The high frequency sniffer will assign all available memory on device for sniffed data"); PrintAndLogEx(NORMAL, "Use " _YELLOW_("'data samples'")" command to download from device, and " _YELLOW_("'data plot'")" to look at it"); PrintAndLogEx(NORMAL, "Press button to quit the sniffing.\n"); PrintAndLogEx(NORMAL, "Usage: hf sniff "); @@ -311,19 +311,8 @@ int CmdHFSniff(const char *Cmd) { return PM3_SUCCESS; } -int CmdHFPlot(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf plot", - "Plots HF signal after RF signal path and A/D conversion.", - "This can be used after any hf command and will show the last few milliseconds of the HF signal.\n" - "Note: If the last hf command terminated because of a timeout you will most probably see nothing.\n"); - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - +int handle_hf_plot(void) { + uint8_t buf[FPGA_TRACE_SIZE]; PacketResponseNG response; @@ -333,7 +322,7 @@ int CmdHFPlot(const char *Cmd) { } for (size_t i = 0; i < FPGA_TRACE_SIZE; i++) { - GraphBuffer[i] = ((int)buf[i]) - 127; + GraphBuffer[i] = ((int)buf[i]) - 128; } GraphTraceLen = FPGA_TRACE_SIZE; @@ -349,14 +338,31 @@ int CmdHFPlot(const char *Cmd) { return PM3_SUCCESS; } +int CmdHFPlot(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf plot", + "Plots HF signal after RF signal path and A/D conversion.", + "This can be used after any hf command and will show the last few milliseconds of the HF signal.\n" + "Note: If the last hf command terminated because of a timeout you will most probably see nothing.\n"); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + return handle_hf_plot(); +} + static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, + + {"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("High Frequency") " -----------------------"}, {"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"}, {"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"}, {"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"}, // {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"}, {"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"}, - {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / Felica RFIDs... }"}, + {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"}, {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, {"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"}, {"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"}, @@ -369,6 +375,8 @@ static command_t CommandTable[] = { {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, {"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"}, + {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"}, {"plot", CmdHFPlot, IfPm3Hfplot, "Plot signal"}, {"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"}, diff --git a/client/src/cmdhf.h b/client/src/cmdhf.h index 09af16d5e..c54fd076c 100644 --- a/client/src/cmdhf.h +++ b/client/src/cmdhf.h @@ -19,4 +19,5 @@ int CmdHFSearch(const char *Cmd); int CmdHFSniff(const char *Cmd); int CmdHFPlot(const char *Cmd); +int handle_hf_plot(void); #endif diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 2b65be89c..68a324952 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -27,6 +27,8 @@ #include "crc16.h" #include "util_posix.h" // msclock #include "aidsearch.h" +#include "cmdhf.h" // handle HF plot + bool APDUInFramingEnable = true; @@ -265,6 +267,7 @@ static int usage_hf_14a_reader(void) { PrintAndLogEx(NORMAL, " s silent (no messages)"); PrintAndLogEx(NORMAL, " x just drop the signal field"); PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)"); + PrintAndLogEx(NORMAL, " @ continuous mode. Updates hf plot as well"); return PM3_SUCCESS; } @@ -475,9 +478,9 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { static int CmdHF14AReader(const char *Cmd) { uint32_t cm = ISO14A_CONNECT; - bool disconnectAfter = true, silent = false; + bool disconnectAfter = true, silent = false, continuous = false; int cmdp = 0; - + int res = PM3_SUCCESS; while (param_getchar(Cmd, cmdp) != 0x00) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': @@ -494,6 +497,9 @@ static int CmdHF14AReader(const char *Cmd) { case 'x': cm &= ~ISO14A_CONNECT; break; + case '@': + continuous = true; + break; default: PrintAndLogEx(WARNING, "Unknown command."); return PM3_EINVARG; @@ -503,60 +509,86 @@ static int CmdHF14AReader(const char *Cmd) { if (!disconnectAfter) cm |= ISO14A_NO_DISCONNECT; - - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); - - if (ISO14A_CONNECT & cm) { - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); - return PM3_ESOFT; - } - - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - - /* - 0: couldn't read - 1: OK, with ATS - 2: OK, no ATS - 3: proprietary Anticollision - */ - uint64_t select_status = resp.oldarg[0]; - - if (select_status == 0) { - if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); - return PM3_ESOFT; - } - - if (select_status == 3) { - PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]); - DropField(); - return PM3_ESOFT; - } - - PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]); - PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]); - - if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLogEx(SUCCESS, " ATS: " _GREEN_("%s"), sprint_hex(card.ats, card.ats_len)); - } - - if (!disconnectAfter) { - if (!silent) PrintAndLogEx(SUCCESS, "Card is selected. You can now start sending commands"); - } + if (continuous) { + PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit"); } + do { + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); + + if (ISO14A_CONNECT & cm) { + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); + DropField(); + res = PM3_ESOFT; + goto plot; + } + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + /* + 0: couldn't read + 1: OK, with ATS + 2: OK, no ATS + 3: proprietary Anticollision + */ + uint64_t select_status = resp.oldarg[0]; + + if (select_status == 0) { + if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); + DropField(); + res = PM3_ESOFT; + goto plot; + } + + if (select_status == 3) { + if (!(silent && continuous)) { + PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]); + } + DropField(); + res = PM3_ESOFT; + goto plot; + } + if (!(silent && continuous)) { + PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]); + PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]); + + if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + PrintAndLogEx(SUCCESS, " ATS: " _GREEN_("%s"), sprint_hex(card.ats, card.ats_len)); + } + } + if (!disconnectAfter) { + if (!silent) PrintAndLogEx(SUCCESS, "Card is selected. You can now start sending commands"); + } + } +plot: + if (continuous) { + res = handle_hf_plot(); + if (res != PM3_SUCCESS) { + break; + } + } + + if (kbd_enter_pressed()) { + break; + } + + } while (continuous); if (disconnectAfter) { - if (!silent) PrintAndLogEx(INFO, "field dropped."); + if (silent == false) { + PrintAndLogEx(INFO, "field dropped."); + } } - return PM3_SUCCESS; + if (continuous) + return PM3_SUCCESS; + else + return res; } static int CmdHF14AInfo(const char *Cmd) { @@ -1338,7 +1370,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) { if (!res && datalen > 0) waitCmd(0, timeout); } - return 0; + return PM3_SUCCESS; } static int waitCmd(uint8_t iSelect, uint32_t timeout) { @@ -1398,16 +1430,20 @@ static int CmdHF14AAntiFuzz(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t arg0 = FLAG_4B_UID_IN_DATA; + struct { + uint8_t flag; + } PACKED param; + param.flag = FLAG_4B_UID_IN_DATA; + if (arg_get_lit(ctx, 2)) - arg0 = FLAG_7B_UID_IN_DATA; + param.flag = FLAG_7B_UID_IN_DATA; if (arg_get_lit(ctx, 3)) - arg0 = FLAG_10B_UID_IN_DATA; + param.flag = FLAG_10B_UID_IN_DATA; CLIParserFree(ctx); clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_ANTIFUZZ, arg0, 0, 0, NULL, 0); - return 0; + SendCommandNG(CMD_HF_ISO14443A_ANTIFUZZ, (uint8_t*)¶m, sizeof(param)); + return PM3_SUCCESS; } static int CmdHF14AChaining(const char *Cmd) { @@ -1438,7 +1474,7 @@ static int CmdHF14AChaining(const char *Cmd) { PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", APDUInFramingEnable ? "enabled" : "disabled"); - return 0; + return PM3_SUCCESS; } static void printTag(const char *tag) { @@ -1681,10 +1717,16 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } getTagLabel(card.uid[0], card.uid[1]); break; - case 0x57: // Qualcomm + case 0x46: + if (memcmp(card.uid, "FSTN10m", 7) == 0) { + isMifareClassic = false; + printTag("Waveshare NFC-Powered e-Paper 1.54\" (please disregard MANUFACTURER mapping above)"); + } + break; + case 0x57: if (memcmp(card.uid, "WSDZ10m", 7) == 0) { isMifareClassic = false; - printTag("Waveshare NFC-Powered e-Paper"); + printTag("Waveshare NFC-Powered e-Paper (please disregard MANUFACTURER mapping above)"); } break; default: @@ -1831,11 +1873,47 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2) { const char *tip = ""; if (card.ats[0] - pos >= 7) { - if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { - tip = "-> MIFARE Plus X 2K or 4K"; - } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { - tip = "-> MIFARE Plus S 2K or 4K"; + + if ((card.sak & 0x70) == 0x40) { // and no GetVersion().. + + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + tip = "-> MIFARE Plus X 2K/4K (SL3)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + + if ((card.atqa[0] & 0x02) == 0x02) + tip = "-> MIFARE Plus S 2K (SL3)"; + else if ((card.atqa[0] & 0x04) == 0x04) + tip = "-> MIFARE Plus S 4K (SL3)"; + + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) { + tip = "-> MIFARE Plus SE 1K (17pF)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) { + tip = "-> MIFARE Plus SE 1K (70pF)"; + } + + } else { //SAK B4,5,6 + + if ((card.sak & 0x20) == 0x20) { // and no GetVersion().. + + + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + tip = "-> MIFARE Plus X 2K (SL1)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + tip = "-> MIFARE Plus S 2K (SL1)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) { + tip = "-> MIFARE Plus SE 1K (17pF)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) { + tip = "-> MIFARE Plus SE 1K (70pF)"; + } + } else { + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + tip = "-> MIFARE Plus X 4K (SL1)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + tip = "-> MIFARE Plus S 4K (SL1)"; + } + } } + } PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); if (card.ats[pos] == 0xC1) { diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 9056b26a9..73f8c2a8f 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -130,7 +130,6 @@ static int CmdHF14BSim(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b sim", "Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI", - "hf 14b sim\n" "hf 14b sim -u 11AA33BB" ); @@ -139,7 +138,7 @@ static int CmdHF14BSim(const char *Cmd) { arg_strx0("u", "uid", "hex", "4byte UID/PUPI"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIExecWithReturn(ctx, Cmd, argtable, false); uint8_t pupi[4]; int n = 0; @@ -150,6 +149,9 @@ static int CmdHF14BSim(const char *Cmd) { PrintAndLogEx(FAILED, "failed to read pupi"); return PM3_EINVARG; } + + PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi))); + PrintAndLogEx(INFO, "Press pm3-button to abort simulation"); clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); return PM3_SUCCESS; diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 238aad435..0129dbaf5 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -34,6 +34,7 @@ #include "crc16.h" // iso15 crc #include "cmddata.h" // getsamples #include "fileutils.h" // savefileEML +#include "cliparser.h" #define FrameSOF Iso15693FrameSOF #define Logic0 Iso15693Logic0 @@ -209,16 +210,6 @@ const productName_t uidmapping[] = { static int CmdHF15Help(const char *Cmd); -static int usage_15_demod(void) { - PrintAndLogEx(NORMAL, "Tries to demodulate / decode ISO15693, from downloaded samples.\n" - "Gather samples with 'hf 15 read' / 'hf 15 record'"); - return PM3_SUCCESS; -} -static int usage_15_samples(void) { - PrintAndLogEx(NORMAL, "Acquire samples as Reader (enables carrier, send inquiry\n" - "and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal"); - return PM3_SUCCESS; -} static int usage_15_info(void) { PrintAndLogEx(NORMAL, "Uses the optional command 'get_systeminfo' 0x2B to try and extract information\n" "command may fail, depending on tag.\n" @@ -235,36 +226,7 @@ static int usage_15_info(void) { _YELLOW_("\thf 15 info u")); return PM3_SUCCESS; } -static int usage_15_record(void) { - PrintAndLogEx(NORMAL, "Record activity without enabling carrier"); - return PM3_SUCCESS; -} -static int usage_15_reader(void) { - PrintAndLogEx(NORMAL, "This command identifies a ISO 15693 tag\n" - "\n" - "Usage: hf 15 reader [h]\n" - "Options:\n" - "\th this help\n" - "\t1 read once\n" - "\n" - "Example:\n" - _YELLOW_("\thf 15 reader\n") - _YELLOW_("\thf 15 reader 1\n")); - return PM3_SUCCESS; -} -static int usage_15_sim(void) { - PrintAndLogEx(NORMAL, "Usage: hf 15 sim \n" - "\n" - "Example:\n" - _YELLOW_("\thf 15 sim E016240000000000")); - return PM3_SUCCESS; -} -static int usage_15_findafi(void) { - PrintAndLogEx(NORMAL, "This command attempts to brute force AFI of an ISO15693 tag\n" - "\n" - "Usage: hf 15 findafi"); - return PM3_SUCCESS; -} + static int usage_15_writeafi(void) { PrintAndLogEx(NORMAL, "Usage: hf 15 writeafi \n" "\tuid (either): \n" @@ -323,7 +285,7 @@ static int usage_15_raw(void) { return PM3_SUCCESS; } static int usage_15_read(void) { - PrintAndLogEx(NORMAL, "Usage: hf 15 read [options] \n" + PrintAndLogEx(NORMAL, "Usage: hf 15 rdbl [options] \n" "Options:\n" "\t-2 use slower '1 out of 256' mode\n" "\tuid (either): \n" @@ -334,7 +296,7 @@ static int usage_15_read(void) { return PM3_SUCCESS; } static int usage_15_write(void) { - PrintAndLogEx(NORMAL, "Usage: hf 15 write [options] \n" + PrintAndLogEx(NORMAL, "Usage: hf 15 wrbl [options] \n" "Options:\n" "\t-2 use slower '1 out of 256' mode\n" "\t-o set OPTION Flag (needed for TI)\n" @@ -358,17 +320,6 @@ static int usage_15_readmulti(void) { "\t 1-6, number of pages"); return PM3_SUCCESS; } -static int usage_15_csetuid(void) { - PrintAndLogEx(NORMAL, "Set UID for magic Chinese card (only works with such cards)\n" - "\n" - "Usage: hf 15 csetuid \n" - "Options:\n" - "\tuid : <8B hex> full UID eg E011223344556677\n" - "\n" - "Example:\n" - _YELLOW_("\thf 15 csetuid E011223344556677")); - return PM3_SUCCESS; -} static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { @@ -691,17 +642,31 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t } // Mode 3 -//helptext static int CmdHF15Demod(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_demod(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 demod", + "Tries to demodulate / decode ISO15693, from downloaded samples.\n" + "Gather samples with 'hf 15 samples' / 'hf 15 sniff'", + "hf 15 demod\n"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); // The sampling rate is 106.353 ksps/s, for T = 18.8 us int i, j; int max = 0, maxPos = 0; int skip = 4; - if (GraphTraceLen < 1000) return PM3_ESOFT; + if (GraphTraceLen < 1000) { + PrintAndLogEx(FAILED, "Too few samples in GraphBuffer. Need more than 1000"); + PrintAndLogEx(HINT, "Run " _YELLOW_("`hf 15 samples`") " to collect and download data"); + return PM3_ESOFT; + } // First, correlate for SOF for (i = 0; i < 1000; i++) { @@ -719,7 +684,7 @@ static int CmdHF15Demod(const char *Cmd) { i = maxPos + ARRAYLEN(FrameSOF) / skip; int k = 0; - uint8_t outBuf[20]; + uint8_t outBuf[2048] = {0}; memset(outBuf, 0, sizeof(outBuf)); uint8_t mask = 0x01; for (;;) { @@ -746,40 +711,80 @@ static int CmdHF15Demod(const char *Cmd) { } else { i += ARRAYLEN(Logic0) / skip; } + mask <<= 1; if (mask == 0) { k++; mask = 0x01; } + if ((i + (int)ARRAYLEN(FrameEOF)) >= GraphTraceLen) { PrintAndLogEx(INFO, "ran off end!"); break; } + + if (k > 2048) { + PrintAndLogEx(INFO, "ran out of buffer"); + break; + } } if (mask != 0x01) { PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)"); PrintAndLogEx(INFO, " mask = %02x", mask); } - PrintAndLogEx(INFO, "%d octets", k); - for (i = 0; i < k; i++) - PrintAndLogEx(SUCCESS, "# %2d: %02x ", i, outBuf[i]); + if (k == 0) { + return PM3_SUCCESS; + } - PrintAndLogEx(SUCCESS, "CRC %04x", Crc15(outBuf, k - 2)); + i = 0; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Got %d octets, decoded as following", k); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " idx | data"); + PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------"); + if (k / 16 > 0) { + for (; i < k; i += 16) { + PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, 16)); + } + } + + uint8_t mod = (k % 16); + if (mod > 0) { + PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, mod)); + } + PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------"); + if (k > 2) { + PrintAndLogEx(SUCCESS, "--> CRC %04x", Crc15(outBuf, k - 2)); + } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } // * Acquire Samples as Reader (enables carrier, sends inquiry) //helptext static int CmdHF15Samples(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_samples(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 samples", + "Acquire samples as Reader (enables carrier, send inquiry\n" + "and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal", + "hf 15 samples"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIParserFree(ctx); clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_ACQ_RAW_ADC, NULL, 0); getSamples(0, true); + + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 15 demod") "` to decode signal"); return PM3_SUCCESS; } @@ -816,6 +821,10 @@ static int NxpSysInfo(uint8_t *uid) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } + if (status < 2) { PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command"); return PM3_EWRONGANSWER; @@ -975,6 +984,9 @@ static int CmdHF15Info(const char *Cmd) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } if (status < 2) { PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", status); return PM3_EWRONGANSWER; @@ -1033,11 +1045,19 @@ static int CmdHF15Info(const char *Cmd) { return PM3_SUCCESS; } -// Record Activity without enabling carrier -//helptext +// Sniff Activity without enabling carrier static int CmdHF15Sniff(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_record(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 sniff", + "Sniff activity without enabling carrier", + "hf 15 sniff\n"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); PacketResponseNG resp; clearCommandBuffer(); @@ -1051,30 +1071,58 @@ static int CmdHF15Sniff(const char *Cmd) { } static int CmdHF15Reader(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_reader(); - bool loop_read = (cmdp == '1') ? false : true; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 reader", + "Act as a ISO15693 reader. Look for ISO15693 tags until Enter or the pm3 button is pressed\n", + "hf 15 reader\n" + "hf 15 reader -1"); - readHF15Uid(loop_read, true); + void *argtable[] = { + arg_param_begin, + arg_lit0("1", "one", "read once"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool read_once = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + PrintAndLogEx(INFO, "Starting ISO15 reader mode"); + PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); + readHF15Uid(!read_once, true); return PM3_SUCCESS; } // Simulation is still not working very good // helptext static int CmdHF15Sim(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_sim(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 sim", + "Simulate a ISO15693 tag\n", + "hf 15 sim -u E011223344556677"); + + void *argtable[] = { + arg_param_begin, + arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); struct { uint8_t uid[8]; } PACKED payload; - if (param_gethex(Cmd, 0, payload.uid, 16)) { + int uidlen = 0; + CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen); + CLIParserFree(ctx); + + if (uidlen != 8) { PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); return PM3_EINVARG; } PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid)); + PrintAndLogEx(INFO, "press " _YELLOW_("`Pm3 button`") " to cancel"); PacketResponseNG resp; clearCommandBuffer(); @@ -1087,17 +1135,25 @@ static int CmdHF15Sim(const char *Cmd) { // (There is no standard way of reading the AFI, although some tags support this) // helptext static int CmdHF15FindAfi(const char *Cmd) { - PacketResponseNG resp; - uint32_t timeout = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 findafi", + "This command attempts to brute force AFI of an ISO15693 tag\n", + "hf 15 findafi"); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_findafi(); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIParserFree(ctx); PrintAndLogEx(SUCCESS, "press pm3-button to cancel"); clearCommandBuffer(); + PacketResponseNG resp; SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0); + uint32_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { timeout++; @@ -1153,9 +1209,13 @@ static int CmdHF15WriteAfi(const char *Cmd) { DropField(); return PM3_ETIMEOUT; } - DropField(); + int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } + uint8_t *data = resp.data.asBytes; if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { @@ -1212,6 +1272,10 @@ static int CmdHF15WriteDsfid(const char *Cmd) { } DropField(); + int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } uint8_t *data = resp.data.asBytes; @@ -1296,6 +1360,9 @@ static int CmdHF15Dump(const char *Cmd) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { int len = resp.oldarg[0]; + if (len == PM3_ETEAROFF) { + continue; + } if (len < 2) { PrintAndLogEx(FAILED, "iso15693 command failed"); continue; @@ -1321,6 +1388,7 @@ static int CmdHF15Dump(const char *Cmd) { blocknum++; PrintAndLogEx(NORMAL, "." NOLF); + fflush(stdout); } } @@ -1419,6 +1487,10 @@ static int CmdHF15Raw(const char *Cmd) { if (reply) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { int len = resp.oldarg[0]; + if (len == PM3_ETEAROFF) { + DropField(); + return len; + } if (len < 2) { PrintAndLogEx(WARNING, "command failed"); } else { @@ -1491,6 +1563,10 @@ static int CmdHF15Readmulti(const char *Cmd) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } + if (status < 2) { PrintAndLogEx(FAILED, "iso15693 card readmulti failed"); return PM3_EWRONGANSWER; @@ -1574,6 +1650,9 @@ static int CmdHF15Read(const char *Cmd) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } if (status < 2) { PrintAndLogEx(ERR, "iso15693 command failed"); return PM3_EWRONGANSWER; @@ -1661,6 +1740,10 @@ static int CmdHF15Write(const char *Cmd) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } + if (status < 2) { PrintAndLogEx(FAILED, "iso15693 command failed"); return PM3_EWRONGANSWER; @@ -1806,16 +1889,28 @@ static int CmdHF15Restore(const char *Cmd) { */ static int CmdHF15CSetUID(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_csetuid(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 csetuid", + "Set UID for magic Chinese card (only works with such cards)\n", + "hf 15 csetuid -u E011223344556677"); + void *argtable[] = { + arg_param_begin, + arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); struct { uint8_t uid[8]; } PACKED payload; - if (param_gethex(Cmd, 0, payload.uid, 16)) { - PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); + int uidlen = 0; + CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen); + CLIParserFree(ctx); + + if (uidlen != 8) { + PrintAndLogEx(WARNING, "UID must include 16 HEX symbols got "); return PM3_EINVARG; } @@ -1838,9 +1933,10 @@ static int CmdHF15CSetUID(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_CSETUID, (uint8_t *)&payload, sizeof(payload)); - if (WaitForResponseTimeout(CMD_HF_ISO15693_CSETUID, &resp, 2000) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply"); + DropField(); + return PM3_ESOFT; } PrintAndLogEx(INFO, "getting updated card details..."); @@ -1876,13 +1972,13 @@ static command_t CommandTable[] = { {"info", CmdHF15Info, IfPm3Iso15693, "Tag information"}, {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"}, {"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"}, - {"read", CmdHF15Read, IfPm3Iso15693, "Read a block"}, + {"rdbl", CmdHF15Read, IfPm3Iso15693, "Read a block"}, {"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"}, {"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"}, {"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"}, {"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"}, {"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"}, - {"write", CmdHF15Write, IfPm3Iso15693, "Write a block"}, + {"wrbl", CmdHF15Write, IfPm3Iso15693, "Write a block"}, {"-----------", CmdHF15Help, IfPm3Iso15693, "----------------------- " _CYAN_("afi") " -----------------------"}, {"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"}, {"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"}, diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index 009a14e9f..53cb10c98 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -209,6 +209,7 @@ static int cmd_hf_fido_register(const char *cmd) { if (paramsPlain) { memset(cdata, 0x00, 32); + chlen = sizeof(cdata); CLIGetStrWithReturn(ctx, 6, cdata, &chlen); if (chlen > 16) { PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen); @@ -216,6 +217,7 @@ static int cmd_hf_fido_register(const char *cmd) { return PM3_EINVARG; } } else { + chlen = sizeof(cdata); CLIGetHexWithReturn(ctx, 6, cdata, &chlen); if (chlen && chlen != 32) { PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only."); @@ -229,6 +231,7 @@ static int cmd_hf_fido_register(const char *cmd) { if (paramsPlain) { memset(adata, 0x00, 32); + applen = sizeof(adata); CLIGetStrWithReturn(ctx, 7, adata, &applen); if (applen > 16) { PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen); @@ -236,6 +239,7 @@ static int cmd_hf_fido_register(const char *cmd) { return PM3_EINVARG; } } else { + applen = sizeof(adata); CLIGetHexWithReturn(ctx, 7, adata, &applen); if (applen && applen != 32) { PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only."); @@ -485,6 +489,7 @@ static int cmd_hf_fido_authenticate(const char *cmd) { if (paramsPlain) { memset(hdata, 0x00, 32); + hdatalen = sizeof(hdata); CLIGetStrWithReturn(ctx, 9, hdata, &hdatalen); if (hdatalen > 16) { PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); @@ -492,6 +497,7 @@ static int cmd_hf_fido_authenticate(const char *cmd) { return PM3_EINVARG; } } else { + hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen); if (hdatalen && hdatalen != 32) { PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only."); @@ -505,6 +511,7 @@ static int cmd_hf_fido_authenticate(const char *cmd) { if (paramsPlain) { memset(hdata, 0x00, 32); + hdatalen = sizeof(hdata); CLIGetStrWithReturn(ctx, 11, hdata, &hdatalen); if (hdatalen > 16) { PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); @@ -512,6 +519,7 @@ static int cmd_hf_fido_authenticate(const char *cmd) { return PM3_EINVARG; } } else { + hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen); if (hdatalen && hdatalen != 32) { PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only."); @@ -693,6 +701,7 @@ static int cmd_hf_fido_2make_credential(const char *cmd) { uint8_t jsonname[FILE_PATH_SIZE] = {0}; char *cjsonname = (char *)jsonname; int jsonnamelen = 0; + jsonnamelen = sizeof(jsonname); CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen); if (!jsonnamelen) { @@ -817,7 +826,7 @@ static int cmd_hf_fido_2get_assertion(const char *cmd) { uint8_t jsonname[FILE_PATH_SIZE] = {0}; char *cjsonname = (char *)jsonname; - int jsonnamelen = 0; + int jsonnamelen = sizeof(jsonname); CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen); if (!jsonnamelen) { @@ -915,7 +924,7 @@ static int cmd_hf_fido_2get_assertion(const char *cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help."}, - {"info", cmd_hf_fido_list, IfPm3Iso14443a, "List ISO 14443A history"}, + {"list", cmd_hf_fido_list, IfPm3Iso14443a, "List ISO 14443A history"}, {"info", cmd_hf_fido_info, IfPm3Iso14443a, "Info about FIDO tag."}, {"reg", cmd_hf_fido_register, IfPm3Iso14443a, "FIDO U2F Registration Message."}, {"auth", cmd_hf_fido_authenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."}, diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 28b710fe8..00c0010b2 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -155,10 +155,11 @@ static int usage_hf_iclass_dump(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : Show this help"); PrintAndLogEx(NORMAL, " f : specify a filename to save dump to"); - PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay"); PrintAndLogEx(NORMAL, " c : credit key as 16 hex symbols or 1 hex to select key from memory"); PrintAndLogEx(NORMAL, " e : elite computations applied to key"); PrintAndLogEx(NORMAL, " r : raw, the key is interpreted as raw block 3/4"); + PrintAndLogEx(NORMAL, " n : replay of NR/MAC"); PrintAndLogEx(NORMAL, " v : verbose output"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); @@ -195,10 +196,11 @@ static int usage_hf_iclass_writeblock(void) { PrintAndLogEx(NORMAL, " h : Show this help"); PrintAndLogEx(NORMAL, " b : The block number as 2 hex symbols"); PrintAndLogEx(NORMAL, " d : set the Data to write as 16 hex symbols"); - PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay"); PrintAndLogEx(NORMAL, " c : credit key assumed\n"); PrintAndLogEx(NORMAL, " e : elite computations applied to key"); PrintAndLogEx(NORMAL, " r : raw, no computations applied to key (raw)"); +// PrintAndLogEx(NORMAL, " n : replay of NR/MAC"); PrintAndLogEx(NORMAL, " v : verbose output"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass wrbl b 0A d AAAAAAAAAAAAAAAA k 001122334455667B")); @@ -213,10 +215,11 @@ static int usage_hf_iclass_readblock(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : Show this help"); PrintAndLogEx(NORMAL, " b : The block number as 2 hex symbols"); - PrintAndLogEx(NORMAL, " k : Access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay"); PrintAndLogEx(NORMAL, " c : credit key assumed\n"); PrintAndLogEx(NORMAL, " e : elite computations applied to key"); PrintAndLogEx(NORMAL, " r : raw, no computations applied to key"); + PrintAndLogEx(NORMAL, " n : replay of NR/MAC"); PrintAndLogEx(NORMAL, " v : verbose output"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass rdbl b 06 k 0011223344556677")); @@ -269,29 +272,6 @@ static int usage_hf_iclass_managekeys(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_hf_iclass_reader(void) { - PrintAndLogEx(NORMAL, "Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass reader [h] [1]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h Show this help"); - PrintAndLogEx(NORMAL, " 1 read only 1 tag"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass reader 1")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_iclass_replay(void) { - PrintAndLogEx(NORMAL, "Replay a collected mac message\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass replay [h] [m ]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h Show this help"); - PrintAndLogEx(NORMAL, " r Reader nonce bytes to replay (8 hexsymbols)"); - PrintAndLogEx(NORMAL, " m Mac bytes to replay (8 hexsymbols)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass replay r 00000000 m 89cb984b")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} static int usage_hf_iclass_loclass(void) { PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack"); PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of"); @@ -346,7 +326,6 @@ static int usage_hf_iclass_lookup(void) { return PM3_SUCCESS; } - static int cmp_uint32(const void *a, const void *b) { const iclass_prekey_t *x = (const iclass_prekey_t *)a; @@ -445,57 +424,55 @@ uint8_t get_pagemap(const picopass_hdr *hdr) { } static void fuse_config(const picopass_hdr *hdr) { + + uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]); + + PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8)); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "..................... app limit", hdr->conf.app_limit); + PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses); + uint8_t fuses = hdr->conf.fuses; + PrintAndLogEx(INFO, " Fuses:"); if (isset(fuses, FUSE_FPERS)) - PrintAndLogEx(SUCCESS, " Mode: " _GREEN_("Personalization (programmable)")); + PrintAndLogEx(SUCCESS, " mode......... " _GREEN_("Personalization (programmable)")); else - PrintAndLogEx(SUCCESS, " Mode: " _YELLOW_("Application (locked)")); + PrintAndLogEx(SUCCESS, " mode......... " _YELLOW_("Application (locked)")); if (isset(fuses, FUSE_CODING1)) { - PrintAndLogEx(SUCCESS, "Coding: RFU"); + PrintAndLogEx(SUCCESS, " coding...... RFU"); } else { if (isset(fuses, FUSE_CODING0)) - PrintAndLogEx(SUCCESS, "Coding: " _YELLOW_("ISO 14443-2 B / 15693")); + PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-2 B / 15693")); else - PrintAndLogEx(SUCCESS, "Coding: " _YELLOW_("ISO 14443-B only")); + PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-B only")); } uint8_t pagemap = get_pagemap(hdr); switch (pagemap) { case 0x0: - PrintAndLogEx(INFO, " Crypt: No auth possible. Read only if RA is enabled"); + PrintAndLogEx(INFO, " crypt........ No auth possible. Read only if RA is enabled"); break; case 0x1: - PrintAndLogEx(SUCCESS, " Crypt: Non secured page"); + PrintAndLogEx(SUCCESS, " crypt........ Non secured page"); break; case 0x2: - PrintAndLogEx(INFO, " Crypt: Secured page, keys locked"); + PrintAndLogEx(INFO, " crypt........ Secured page, keys locked"); break; case 0x03: - PrintAndLogEx(SUCCESS, " Crypt: Secured page, " _GREEN_("keys not locked")); + PrintAndLogEx(SUCCESS, " crypt........ Secured page, " _GREEN_("keys not locked")); break; } if (isset(fuses, FUSE_RA)) - PrintAndLogEx(SUCCESS, " RA: Read access enabled"); + PrintAndLogEx(SUCCESS, " RA........... Read access enabled (non-secure mode)"); else - PrintAndLogEx(INFO, " RA: Read access not enabled"); - - PrintAndLogEx(INFO, - "App limit " _YELLOW_("0x%02X") ", OTP " _YELLOW_("0x%02X%02X") ", Block write lock " _YELLOW_("0x%02X") - , hdr->conf.app_limit - , hdr->conf.otp[1] - , hdr->conf.otp[0] - , hdr->conf.block_writelock - ); - PrintAndLogEx(INFO, - " Chip " _YELLOW_("0x%02X") ", Mem " _YELLOW_("0x%02X") ", EAS " _YELLOW_("0x%02X") ", Fuses " _YELLOW_("0x%02X") - , hdr->conf.chip_config - , hdr->conf.mem_config - , hdr->conf.eas - , hdr->conf.fuses - ); + PrintAndLogEx(INFO, " RA........... Read access not enabled"); } static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb) { @@ -556,51 +533,51 @@ static void mem_app_config(const picopass_hdr *hdr) { uint8_t app2_limit = card_app2_limit[type]; uint8_t pagemap = get_pagemap(hdr); - PrintAndLogEx(INFO, "------ " _CYAN_("Memory") " ------"); + PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Memory") " --------------------------"); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - PrintAndLogEx(INFO, " %u KBits (%u bytes)", kb, app2_limit * 8); + PrintAndLogEx(INFO, " %u KBits ( " _YELLOW_("%u") " bytes )", kb, app2_limit * 8); PrintAndLogEx(INFO, " Tag has not App Areas"); return; } - PrintAndLogEx(INFO, " %u KBits/%u App Areas (%u bytes)", kb, app_areas, (app2_limit + 1) * 8); + PrintAndLogEx(INFO, " %u KBits/%u App Areas ( " _YELLOW_("%u") " bytes )", kb, app_areas, (app2_limit + 1) * 8); PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit, app1_limit + 5, app1_limit + 5); PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit); - PrintAndLogEx(INFO, "------ " _CYAN_("KeyAccess") " ------"); - PrintAndLogEx(INFO, " Kd = Debit key (AA1), Kc = Credit key (AA2)"); + PrintAndLogEx(INFO, "------------------------- " _CYAN_("KeyAccess") " ------------------------"); + PrintAndLogEx(INFO, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *"); uint8_t book = isset(mem, 0x20); if (book) { - PrintAndLogEx(INFO, " Read A - Kd"); - PrintAndLogEx(INFO, " Read B - Kc"); - PrintAndLogEx(INFO, " Write A - Kd"); - PrintAndLogEx(INFO, " Write B - Kc"); - PrintAndLogEx(INFO, " Debit - Kd or Kc"); - PrintAndLogEx(INFO, " Credit - Kc"); + PrintAndLogEx(INFO, " Read A....... debit"); + PrintAndLogEx(INFO, " Read B....... credit"); + PrintAndLogEx(INFO, " Write A...... debit"); + PrintAndLogEx(INFO, " Write B...... credit"); + PrintAndLogEx(INFO, " Debit........ debit or credit"); + PrintAndLogEx(INFO, " Credit....... credit"); } else { - PrintAndLogEx(INFO, " Read A - Kd or Kc"); - PrintAndLogEx(INFO, " Read B - Kd or Kc"); - PrintAndLogEx(INFO, " Write A - Kc"); - PrintAndLogEx(INFO, " Write B - Kc"); - PrintAndLogEx(INFO, " Debit - Kd or Kc"); - PrintAndLogEx(INFO, " Credit - Kc"); + PrintAndLogEx(INFO, " Read A....... debit or credit"); + PrintAndLogEx(INFO, " Read B....... debit or credit"); + PrintAndLogEx(INFO, " Write A...... credit"); + PrintAndLogEx(INFO, " Write B...... credit"); + PrintAndLogEx(INFO, " Debit........ debit or credit"); + PrintAndLogEx(INFO, " Credit....... credit"); } } static void print_picopass_info(const picopass_hdr *hdr) { - PrintAndLogEx(INFO, "------ " _CYAN_("card configuration") " ------"); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------"); fuse_config(hdr); mem_app_config(hdr); } static void print_picopass_header(const picopass_hdr *hdr) { - PrintAndLogEx(INFO, "------------ " _CYAN_("card") " -------------"); - PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn))); - PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); - PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); - PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); - PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); - PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); + PrintAndLogEx(INFO, "--------------------------- " _CYAN_("card") " ---------------------------"); + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); + PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); + PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); + PrintAndLogEx(SUCCESS, " Kd: %s Debit key, hidden", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); + PrintAndLogEx(SUCCESS, " Kc: %s Credit key, hidden", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); + PrintAndLogEx(SUCCESS, " AIA: %s Application Issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); } static int CmdHFiClassList(const char *Cmd) { @@ -738,7 +715,7 @@ static int CmdHFiClassSim(const char *Cmd) { return PM3_EMALLOC; } - memset(dump, 0, datalen);//<-- Need zeroes for the EPURSE - field (offical) + memset(dump, 0, datalen);//<-- Need zeroes for the EPURSE - field (official) uint8_t i = 0; for (i = 0 ; i < NUM_CSNS ; i++) { @@ -826,6 +803,8 @@ static int CmdHFiClassSim(const char *Cmd) { case ICLASS_SIM_MODE_CSN_DEFAULT: case ICLASS_SIM_MODE_FULL: default: { + PrintAndLogEx(INFO, "Starting iCLASS simulation"); + PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); uint8_t numberOfCSNs = 0; clearCommandBuffer(); SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 1, CSN, 8); @@ -883,136 +862,25 @@ int read_iclass_csn(bool loop, bool verbose) { } static int CmdHFiClassReader(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_iclass_reader(); - bool loop_read = (cmdp == '1') ? false : true; - return read_iclass_csn(loop_read, true); -} + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass reader", + "Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed\n", + "hf iclass reader\n" + "hf iclass reader -1"); -static int CmdHFiClassReader_Replay(const char *Cmd) { + void *argtable[] = { + arg_param_begin, + arg_lit0("1", "one", "read once"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool read_once = arg_get_lit(ctx, 1); + CLIParserFree(ctx); - struct { - uint8_t reader[4]; - uint8_t mac[4]; - } PACKED payload; - - - bool got_rnr, got_mac; - got_rnr = got_mac = false; - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': { - return usage_hf_iclass_replay(); - } - case 'r': { - if (param_gethex(Cmd, cmdp + 1, payload.reader, 8)) { - PrintAndLogEx(FAILED, "Reader Nr must include 8 HEX symbols"); - errors = true; - } else { - got_rnr = true; - } - cmdp += 2; - break; - } - case 'm': { - if (param_gethex(Cmd, cmdp + 1, payload.mac, 8)) { - PrintAndLogEx(FAILED, "Reader MAC must include 8 HEX symbols"); - errors = true; - } else { - got_mac = true; - } - cmdp += 2; - break; - } - default: { - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - } - - //Validations - if (errors || cmdp == 0) { - return usage_hf_iclass_replay(); - } - - if (got_rnr == false || got_mac == false) { - PrintAndLogEx(FAILED, "Reader Nr and MAC is needed"); - return PM3_EINVARG; - } - - PacketResponseNG resp; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_REPLAY, (uint8_t *)&payload, sizeof(payload)); - - while (true) { - PrintAndLogEx(NORMAL, "." NOLF); - - if (kbd_enter_pressed()) { - PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); - DropField(); - return PM3_EOPABORTED; - } - - if (WaitForResponseTimeout(CMD_HF_ICLASS_REPLAY, &resp, 2000)) - break; - } - - PrintAndLogEx(NORMAL, ""); - if (resp.status != PM3_SUCCESS) { - PrintAndLogEx(ERR, "failed to communicate with card"); - return resp.status; - } - - struct p_resp { - bool isOK; - uint16_t block_cnt; - uint32_t bb_offset; - } PACKED; - struct p_resp *packet = (struct p_resp *)resp.data.asBytes; - - if (packet->isOK == false) { - PrintAndLogEx(WARNING, "replay reading blocks failed"); - return PM3_ESOFT; - } - - uint32_t startindex = packet->bb_offset; - uint32_t bytes_got = (packet->block_cnt * 8); - - uint8_t tag_data[0x100 * 8]; - memset(tag_data, 0xFF, sizeof(tag_data)); - - // response ok - now get bigbuf content of the dump - if (!GetFromDevice(BIG_BUF, tag_data, sizeof(tag_data), startindex, NULL, 0, NULL, 2500, false)) { - PrintAndLogEx(WARNING, "command execution time out"); - return PM3_ETIMEOUT; - } - - // print the dump - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); - PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(tag_data, 8)); - printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got); - - // use CSN as filename - char filename[FILE_PATH_SIZE] = {0}; - strcat(filename, "hf-iclass-"); - FillFileNameByUID(filename, tag_data, "-dump", 8); - - // save the dump to .bin file - PrintAndLogEx(SUCCESS, "saving dump file - %u blocks read", bytes_got / 8); - saveFile(filename, ".bin", tag_data, bytes_got); - saveFileEML(filename, tag_data, bytes_got, 8); - saveFileJSON(filename, jsfIclass, tag_data, bytes_got, NULL); - - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt") "` to decrypt dump file"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view") "` to view dump file"); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; + PrintAndLogEx(INFO, "Starting iCLASS reader mode"); + PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); + return read_iclass_csn(!read_once, true); } static int CmdHFiClassELoad(const char *Cmd) { @@ -1251,27 +1119,11 @@ static int CmdHFiClassEView(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - uint8_t *csn = dump; - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); - PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(csn, 8)); printIclassDumpContents(dump, 1, blocks, bytes); - - /* - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "----+-------------------------+---------"); - PrintAndLogEx(INFO, "blk | data | ascii"); - PrintAndLogEx(INFO, "----+-------------------------+---------"); - for (uint16_t i = 0; i < blocks; i++){ - PrintAndLogEx(INFO, "%03d | %s ", i, sprint_hex_ascii(dump + (i * 8) , 8) ); - } - PrintAndLogEx(INFO, "----+-------------------------+---------"); - PrintAndLogEx(NORMAL, ""); - */ free(dump); return PM3_SUCCESS; } - static int CmdHFiClassDecrypt(const char *Cmd) { bool errors = false; @@ -1421,7 +1273,6 @@ static int CmdHFiClassDecrypt(const char *Cmd) { saveFileEML(fptr, decrypted, decryptedlen, 8); saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen, NULL); - PrintAndLogEx(INFO, "Following output skips CSN / block0"); printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen); PrintAndLogEx(NORMAL, ""); @@ -1567,13 +1418,6 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { return PM3_SUCCESS; } -static void calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t *MAC) { - uint8_t wb[9]; - wb[0] = blockno; - memcpy(wb + 1, data, 8); - doMAC_N(wb, sizeof(wb), div_key, MAC); -} - static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); @@ -1611,47 +1455,6 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { return true; } -static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) { - - iclass_auth_req_t payload = { - .use_raw = rawkey, - .use_elite = elite, - .use_credit_key = use_credit_key - }; - memcpy(payload.key, KEY, 8); - - SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - clearCommandBuffer(); - if (WaitForResponseTimeout(CMD_HF_ICLASS_AUTH, &resp, 2000) == 0) { - if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); - return false; - } - - if (resp.status != PM3_SUCCESS) { - if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); - return false; - } - - iclass_readblock_resp_t *packet = (iclass_readblock_resp_t *)resp.data.asBytes; - - if (packet->isOK == 0) { - if (verbose) PrintAndLogEx(FAILED, "authentication error"); - return false; - } - - if (div_key) - memcpy(div_key, packet->div_key, sizeof(packet->div_key)); - - if (MAC) - memcpy(MAC, packet->mac, sizeof(packet->mac)); - - if (verbose) - PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); - - return true; -} - static int CmdHFiClassDump(const char *Cmd) { uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -1665,6 +1468,7 @@ static int CmdHFiClassDump(const char *Cmd) { bool have_credit_key = false; bool elite = false; bool rawkey = false; + bool use_replay = false; bool errors = false; bool auth = false; uint8_t cmdp = 0; @@ -1732,12 +1536,23 @@ static int CmdHFiClassDump(const char *Cmd) { rawkey = true; cmdp++; break; + case 'n': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode")); + use_replay = true; + cmdp++; + break; default: PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; } } + + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'"); + errors = true; + } + if (errors) return usage_hf_iclass_dump(); uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); @@ -1808,6 +1623,7 @@ static int CmdHFiClassDump(const char *Cmd) { .req.use_raw = rawkey, .req.use_elite = elite, .req.use_credit_key = false, + .req.use_replay = use_replay, .req.send_reply = true, .req.do_auth = auth, .end_block = app_limit1, @@ -1951,9 +1767,6 @@ write_dump: PrintAndLogEx(INFO, "Reading AA2 failed. dumping AA1 data to file"); // print the dump - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); - PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(tag_data, 8)); printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got); // use CSN as filename @@ -1974,49 +1787,13 @@ write_dump: return PM3_SUCCESS; } -static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool verbose) { - /* - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) { - return PM3_ESOFT; - } +static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose) { - calc_wb_mac(blockno, bldata, div_key, MAC); - - struct p { - uint8_t blockno; - uint8_t data[12]; - } PACKED payload; - payload.blockno = blockno; - - memcpy(payload.data, bldata, 8); - memcpy(payload.data + 8, MAC, 4); - - - // - typedef struct { - uint8_t key[8]; - bool use_raw; - bool use_elite; - bool use_credit_key; - bool send_reply; - bool do_auth; - uint8_t blockno; - } PACKED iclass_auth_req_t; - - // iCLASS write block request data structure - typedef struct { - iclass_auth_req_t req; - uint8_t data[8]; - } PACKED iclass_writeblock_req_t; - - - */ iclass_writeblock_req_t payload = { .req.use_raw = rawkey, .req.use_elite = elite, .req.use_credit_key = use_credit_key, + .req.use_replay = replay, .req.blockno = blockno, .req.send_reply = true, .req.do_auth = true, @@ -2035,9 +1812,8 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bo if (resp.status != PM3_SUCCESS) { if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); - return PM3_EWRONGANSWER; + return resp.status; } - return (resp.data.asBytes[0] == 1) ? PM3_SUCCESS : PM3_ESOFT; } @@ -2052,6 +1828,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { bool use_credit_key = false; bool elite = false; bool rawkey = false; + bool use_replay = false; bool errors = false; bool verbose = false; uint8_t cmdp = 0; @@ -2105,6 +1882,13 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { rawkey = true; cmdp++; break; + /* + case 'n': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode")); + use_replay = true; + cmdp++; + break; + */ case 'v': verbose = true; cmdp++; @@ -2118,21 +1902,29 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { if (got_blockno == false) errors = true; + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'"); + errors = true; + } + if (errors || cmdp < 6) return usage_hf_iclass_writeblock(); - int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, verbose); - if (isok == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno); - else - PrintAndLogEx(FAILED, "Writing failed"); + int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, use_replay, verbose); + switch (isok) { + case PM3_SUCCESS: + PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno); + break; + case PM3_ETEAROFF: + if (verbose) + PrintAndLogEx(INFO, "Writing tear off triggered"); + break; + default: + PrintAndLogEx(FAILED, "Writing failed"); + break; + } return isok; } -/* -static int CmdHFiClassClone(const char *Cmd) { - return PM3_SUCCESS; -} -*/ static int CmdHFiClassRestore(const char *Cmd) { char filename[FILE_PATH_SIZE] = { 0x00 }; char tempStr[50] = {0}; @@ -2184,7 +1976,7 @@ static int CmdHFiClassRestore(const char *Cmd) { } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp + 1); if (keyNbr < ICLASS_KEYS_MAX) { - PrintAndLogEx(SUCCESS, "Using key[%d] %s", keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8)); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8)); memcpy(KEY, iClass_Key_Table[keyNbr], 8); } else { PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); @@ -2221,14 +2013,19 @@ static int CmdHFiClassRestore(const char *Cmd) { if (errors || cmdp < 8) return usage_hf_iclass_restore(); + if (rawkey + elite > 1) { + PrintAndLogEx(FAILED, "Can not use both 'e', 'r'"); + return PM3_EINVARG; + } + if (startblock < 5) { PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4"); return PM3_EINVARG; } - int total_bytes = (((endblock - startblock) + 1) * 12); + uint32_t payload_size = sizeof(iclass_restore_req_t) + (sizeof(iclass_restore_item_t) * (endblock - startblock + 1)); - if (total_bytes > PM3_CMD_DATA_SIZE - 2) { + if (payload_size > PM3_CMD_DATA_SIZE) { PrintAndLogEx(NORMAL, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE / 8); return PM3_EINVARG; } @@ -2246,103 +2043,82 @@ static int CmdHFiClassRestore(const char *Cmd) { return PM3_EFILE; } - if (bytes_read < sizeof(iclass_block_t) * (endblock - startblock + 1)) { - PrintAndLogEx(ERR, "file wrong size"); + if (bytes_read < ((endblock - startblock + 1) * 8)) { + PrintAndLogEx(ERR, "file is smaller than your suggested block range ( " _RED_("0x%02x..0x%02x")" )", + startblock, endblock + ); free(dump); return PM3_EFILE; } + iclass_restore_req_t *payload = calloc(1, payload_size); + payload->req.use_raw = rawkey; + payload->req.use_elite = elite; + payload->req.use_credit_key = use_credit_key; + payload->req.use_replay = false; + payload->req.blockno = startblock; + payload->req.send_reply = true; + payload->req.do_auth = true; + memcpy(payload->req.key, KEY, 8); + + payload->item_cnt = (endblock - startblock + 1); + // read data from file from block 6 --- 19 // we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data // then copy to usbcommand->asbytes; // max is 32 - 6 = 28 block. 28 x 12 bytes gives 336 bytes - iclass_block_t tag_data[PM3_CMD_DATA_SIZE / 12]; - memcpy(tag_data, dump + startblock * 8, sizeof(iclass_block_t) * (endblock - startblock + 1)); + for (uint8_t i = 0; i < payload->item_cnt; i++) { + payload->blocks[i].blockno = startblock + i; + memcpy(payload->blocks[i].data, dump + (startblock * 8) + (i * 8), sizeof(payload->blocks[i].data)); + } free(dump); - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - int i; - int numberAuthRetries = ICLASS_AUTH_RETRY; - do { - if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) - break; - } while (numberAuthRetries--); - - if (numberAuthRetries <= 0) { - PrintAndLogEx(ERR, "failed to authenticate"); - DropField(); - return PM3_ESOFT; - } - - uint8_t data[total_bytes]; - - // calculate all mac for every the block we will write - for (i = startblock; i <= endblock; i++) { - - calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC); - // usb command d start pointer = d + (i - 6) * 12 - // memcpy(pointer,tag_data[i - 6],8) 8 bytes - // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes; - // next one - uint8_t *ptr = data + (i - startblock) * 12; - memcpy(ptr, &(tag_data[i - startblock].d[0]), 8); - memcpy(ptr + 8, MAC, 4); - } - if (verbose) { - PrintAndLogEx(INFO, "------+--------------------------+-------------"); - PrintAndLogEx(INFO, "block | data | mac"); - PrintAndLogEx(INFO, "------+--------------------------+-------------"); - uint8_t p[12]; - for (i = 0; i <= endblock - startblock; i++) { - memcpy(p, data + (i * 12), 12); - char *s = calloc(70, sizeof(uint8_t)); - snprintf(s, 70, "| %s ", sprint_hex(p, 8)); - snprintf(s + strlen(s), 70 - strlen(s), "| %s", sprint_hex(p + 8, 4)); - PrintAndLogEx(NORMAL, " %02X %s", i + startblock, s); - free(s); + PrintAndLogEx(INFO, "Preparing to restore block range 0x%02x..0x%02x", startblock, endblock); + + PrintAndLogEx(INFO, "------+----------------------"); + PrintAndLogEx(INFO, "block | data"); + PrintAndLogEx(INFO, "------+----------------------"); + + for (uint8_t i = 0; i < payload->item_cnt; i++) { + iclass_restore_item_t item = payload->blocks[i]; + PrintAndLogEx(INFO, " %02X | %s", item.blockno, sprint_hex_inrow(item.data, sizeof(item.data))); } } - struct p { - uint8_t startblock; - uint8_t endblock; - uint8_t data[PM3_CMD_DATA_SIZE - 2]; - } PACKED payload; - - payload.startblock = startblock; - payload.endblock = endblock; - memcpy(payload.data, data, total_bytes); + PrintAndLogEx(INFO, "restore started..."); PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_CLONE, (uint8_t *)&payload, total_bytes + 2); + SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size); - if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 2000) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) { PrintAndLogEx(WARNING, "command execute timeout"); DropField(); + free(payload); return PM3_ETIMEOUT; } if (resp.status == PM3_SUCCESS) { - if (resp.data.asBytes[0] == 1) - PrintAndLogEx(SUCCESS, "Restore successful"); - else - PrintAndLogEx(WARNING, "Restore failed"); + PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful")); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl ") "` to verify data on card"); + } else { + PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed")); } + + free(payload); return resp.status; } -static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth, uint8_t *out) { +static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool replay, bool verbose, bool auth, uint8_t *out) { iclass_auth_req_t payload = { .use_raw = rawkey, .use_elite = elite, .use_credit_key = (keyType == 0x18), + .use_replay = replay, .blockno = blockno, .send_reply = true, .do_auth = auth, @@ -2391,6 +2167,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { bool got_blockno = false; bool elite = false; bool rawkey = false; + bool use_replay = false; bool errors = false; bool auth = false; bool verbose = false; @@ -2439,6 +2216,11 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { rawkey = true; cmdp++; break; + case 'n': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode")); + use_replay = true; + cmdp++; + break; case 'v': verbose = true; cmdp++; @@ -2452,6 +2234,11 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { if (got_blockno == false) errors = true; + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'"); + errors = true; + } + if (errors) return usage_hf_iclass_readblock(); if (verbose) { @@ -2462,12 +2249,12 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { } if (auth == false && verbose) { - PrintAndLogEx(WARNING, "warning: no authentication used with read. Typical for cards configured toin `non-secure page`"); + PrintAndLogEx(WARNING, "warning: no authentication used with read. Typical for cards configured into `non-secure page`"); } uint8_t data[8] = {0}; - int res = iclass_read_block(KEY, blockno, keyType, elite, rawkey, verbose, auth, data); + int res = iclass_read_block(KEY, blockno, keyType, elite, rawkey, use_replay, verbose, auth, data); if (res != PM3_SUCCESS) return res; @@ -2608,9 +2395,20 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e , filemaxblock ); */ + uint8_t pagemap = get_pagemap(hdr); + + int i = startblock; - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, " blk| data | ascii |lck| info"); + PrintAndLogEx(INFO, "----+-------------------------+----------+---+--------------"); + PrintAndLogEx(INFO, "0x00| " _GREEN_("%s") " | | CSN ", sprint_hex_ascii(iclass_dump, 8)); + + if (i != 1) + PrintAndLogEx(INFO, "...."); + while (i <= endblock) { uint8_t *blk = iclass_dump + (i * 8); @@ -2650,10 +2448,28 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e bl_lock = true; } - PrintAndLogEx(INFO, " %c |0x%02X| %s", (bl_lock) ? 'x' : ' ', i, sprint_hex_ascii(blk, 8)); + const char *lockstr = (bl_lock) ? _RED_("x") : " "; + + if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { + const char *info_nonks[] = {"CSN", "Config", "AIA", "User"}; + const char *s = info_nonks[3]; + if (i < 3) { + s = info_nonks[i]; + } + + PrintAndLogEx(INFO, "0x%02X| %s | %s | %s ", i, sprint_hex_ascii(blk, 8), lockstr, s); + } else { + const char *info_ks[] = {"CSN", "Config", "E-purse", "Debit", "Credit", "AIA", "User"}; + const char *s = info_ks[6]; + if (i < 6) { + s = info_ks[i]; + } + PrintAndLogEx(INFO, "0x%02X| %s | %s | %s ", i, sprint_hex_ascii(blk, 8), lockstr, s); + } i++; } - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); + PrintAndLogEx(INFO, "----+-------------------------+----------+---+--------------"); + PrintAndLogEx(NORMAL, ""); } static int CmdHFiClassView(const char *Cmd) { @@ -2697,13 +2513,9 @@ static int CmdHFiClassView(const char *Cmd) { PrintAndLogEx(INFO, "start " _YELLOW_("0x%02x") " end " _YELLOW_("0x%02x"), (startblock == 0) ? 6 : startblock, endblock); } + PrintAndLogEx(NORMAL, ""); print_picopass_header((picopass_hdr *) dump); print_picopass_info((picopass_hdr *) dump); - - PrintAndLogEx(NORMAL, ""); - uint8_t *csn = dump; - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); - PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(csn, 8)); printIclassDumpContents(dump, startblock, endblock, bytes_read); free(dump); return PM3_SUCCESS; @@ -2879,12 +2691,15 @@ static int saveKeys(char *filename) { static int printKeys(void) { PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "idx| key"); + PrintAndLogEx(INFO, "---+------------------------"); for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++) { if (memcmp(iClass_Key_Table[i], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) - PrintAndLogEx(INFO, "%u: %s", i, sprint_hex(iClass_Key_Table[i], 8)); + PrintAndLogEx(INFO, " %u |", i); else - PrintAndLogEx(INFO, "%u: "_YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8)); + PrintAndLogEx(INFO, " %u | " _YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8)); } + PrintAndLogEx(INFO, "---+------------------------"); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -3002,105 +2817,15 @@ static void add_key(uint8_t *key) { } } -static int CmdHFiClassCheckKeys(const char *Cmd) { - // empty string - if (strlen(Cmd) == 0) return usage_hf_iclass_chk(); - - uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - // elite key, raw key, standard key - bool use_elite = false; - bool use_raw = false; - bool use_credit_key = false; - bool found_key = false; - //bool found_credit = false; - bool got_csn = false; - bool errors = false; - uint8_t cmdp = 0x00; - - char filename[FILE_PATH_SIZE] = {0}; - uint8_t fileNameLen = 0; - - uint64_t t1 = msclock(); - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_chk(); - case 'f': - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); - if (fileNameLen < 1) { - PrintAndLogEx(WARNING, _RED_("no filename found after f")); - errors = true; - } - cmdp += 2; - break; - case 'e': - use_elite = true; - cmdp++; - break; - case 'c': - use_credit_key = true; - cmdp++; - break; - case 'r': - use_raw = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - if (errors) return usage_hf_iclass_chk(); - - uint8_t *keyBlock = NULL; - uint32_t keycount = 0; - - // load keys - int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount); - if (res != PM3_SUCCESS || keycount == 0) { - free(keyBlock); - return res; - } +/* +static int iclass_chk_keys(uint8_t *keyBlock, uint32_t keycount) { iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t)); - if (!pre) { - free(keyBlock); + if (pre == NULL) { return PM3_EMALLOC; } - // Get CSN / UID and CCNR - PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR..."); - for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) { - got_csn = select_only(CSN, CCNR, false); - if (got_csn == false) - PrintAndLogEx(WARNING, "one more try"); - } - - if (got_csn == false) { - PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting..."); - free(keyBlock); - DropField(); - return PM3_ESOFT; - } - - PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN))); - PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR))); - - PrintAndLogEx(SUCCESS, "Generating diversified keys %s", (use_elite || use_raw) ? NOLF : ""); - if (use_elite) - PrintAndLogEx(NORMAL, "using " _YELLOW_("elite algo")); - if (use_raw) - PrintAndLogEx(NORMAL, "using " _YELLOW_("raw mode")); - - GenerateMacFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, pre); - - PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT"); - // max 42 keys inside USB_COMMAND. 512/4 = 103 mac uint32_t chunksize = keycount > (PM3_CMD_DATA_SIZE / 4) ? (PM3_CMD_DATA_SIZE / 4) : keycount; bool lastChunk = false; @@ -3184,7 +2909,195 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { break; } - } // end chunks of keys + } + return PM3_SUCCESS; +} +*/ + +static int CmdHFiClassCheckKeys(const char *Cmd) { + + // empty string + if (strlen(Cmd) == 0) return usage_hf_iclass_chk(); + + uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + // elite key, raw key, standard key + bool use_elite = false; + bool use_raw = false; + bool use_credit_key = false; + bool found_key = false; + //bool found_credit = false; + bool got_csn = false; + bool errors = false; + uint8_t cmdp = 0x00; + + char filename[FILE_PATH_SIZE] = {0}; + uint8_t fileNameLen = 0; + + uint64_t t1 = msclock(); + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_iclass_chk(); + case 'f': + fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); + if (fileNameLen < 1) { + PrintAndLogEx(WARNING, _RED_("no filename found after f")); + errors = true; + } + cmdp += 2; + break; + case 'e': + use_elite = true; + cmdp++; + break; + case 'c': + use_credit_key = true; + cmdp++; + break; + case 'r': + use_raw = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + if (errors) return usage_hf_iclass_chk(); + + uint8_t *keyBlock = NULL; + uint32_t keycount = 0; + + // load keys + int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount); + if (res != PM3_SUCCESS || keycount == 0) { + free(keyBlock); + return res; + } + + // Get CSN / UID and CCNR + PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR..."); + for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) { + got_csn = select_only(CSN, CCNR, false); + if (got_csn == false) + PrintAndLogEx(WARNING, "one more try"); + } + + if (got_csn == false) { + PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting..."); + free(keyBlock); + DropField(); + return PM3_ESOFT; + } + + iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t)); + if (pre == NULL) { + return PM3_EMALLOC; + } + + + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN))); + PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR))); + + PrintAndLogEx(SUCCESS, "Generating diversified keys %s", (use_elite || use_raw) ? NOLF : ""); + if (use_elite) + PrintAndLogEx(NORMAL, "using " _YELLOW_("elite algo")); + if (use_raw) + PrintAndLogEx(NORMAL, "using " _YELLOW_("raw mode")); + + GenerateMacFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, pre); + + PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT"); + + + // max 42 keys inside USB_COMMAND. 512/4 = 103 mac + uint32_t chunksize = keycount > (PM3_CMD_DATA_SIZE / 4) ? (PM3_CMD_DATA_SIZE / 4) : keycount; + bool lastChunk = false; + + // fast push mode + conn.block_after_ACK = true; + + // keep track of position of found key + uint8_t found_offset = 0; + uint32_t key_offset = 0; + // main keychunk loop + for (key_offset = 0; key_offset < keycount; key_offset += chunksize) { + + uint64_t t2 = msclock(); + uint8_t timeout = 0; + + if (kbd_enter_pressed()) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(WARNING, "Aborted via keyboard!"); + goto out; + } + + uint32_t keys = ((keycount - key_offset) > chunksize) ? chunksize : keycount - key_offset; + + // last chunk? + if (keys == keycount - key_offset) { + lastChunk = true; + // Disable fast mode on last command + conn.block_after_ACK = false; + } + uint32_t flags = lastChunk << 8; + // bit 16 + // - 1 indicates credit key + // - 0 indicates debit key (default) + flags |= (use_credit_key << 16); + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys); + PacketResponseNG resp; + + bool looped = false; + while (!WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000)) { + timeout++; + PrintAndLogEx(NORMAL, "." NOLF); + if (timeout > 120) { + PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); + goto out; + } + looped = true; + } + + if (looped) + PrintAndLogEx(NORMAL, ""); + + found_offset = resp.oldarg[1] & 0xFF; + uint8_t isOK = resp.oldarg[0] & 0xFF; + + t2 = msclock() - t2; + switch (isOK) { + case 1: { + found_key = true; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s") + , sprint_hex(keyBlock + (key_offset + found_offset) * 8, 8) + ); + break; + } + case 0: { + PrintAndLogEx(INPLACE, "Chunk [%d/%d]", key_offset, keycount); + break; + } + case 99: { + } + default: { + break; + } + } + + // both keys found. + if (found_key) { + break; + } + + } out: t1 = msclock() - t1; @@ -3485,7 +3398,6 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { uint8_t key[8] = {0}; uint8_t data[16] = {0}; - bool isReverse = false; int len = 0; CLIParserContext *ctx; @@ -3502,7 +3414,7 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - isReverse = arg_get_lit(ctx, 1); + bool isReverse = arg_get_lit(ctx, 1); CLIGetHexWithReturn(ctx, 2, data, &len); @@ -3524,6 +3436,28 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFiClassAutopwn(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass autopwn", + "Tries to check keys, if found, dump card and save file", + "hf iclass autopwn\n"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + // Check keys. + + // dump + + PrintAndLogEx(INFO, "to be implemented"); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, {"help", CmdHelp, AlwaysAvailable, "This help"}, @@ -3538,11 +3472,10 @@ static command_t CommandTable[] = { {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "[options..] Write Picopass / iCLASS block"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"}, - {"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"}, + {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "[options..] Automatic key recovery tool for iCLASS"}, + {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "[options..] Check keys"}, {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "[options..] Use loclass to perform bruteforce reader attack"}, {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[options..] Uses authentication trace to check for key in dictionary file"}, - {"replay", CmdHFiClassReader_Replay, IfPm3Iclass, " Read Picopass / iCLASS tag via replay attack"}, - {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"}, {"sim", CmdHFiClassSim, IfPm3Iclass, "[options..] Simulate iCLASS tag"}, {"eload", CmdHFiClassELoad, IfPm3Iclass, "[f ] Load Picopass / iCLASS dump file into emulator memory"}, @@ -3606,33 +3539,33 @@ int info_iclass(void) { picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)resp.data.asBytes; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " --------------------------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "--------------------- " _CYAN_("Tag Information") " ----------------------"); + PrintAndLogEx(INFO, "------------------------------------------------------------"); if (readStatus & FLAG_ICLASS_CSN) { - PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn))); + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); } if (readStatus & FLAG_ICLASS_CONF) { - PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); + PrintAndLogEx(SUCCESS, " Config: %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); } // page mapping. If fuse0|1 == 0x01, card is in non-secure mode, with CSN, CONF, AIA as top 3 blocks. // page9 in http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20iClass/DS%20Picopass%202KS%20V1-0.pdf uint8_t pagemap = get_pagemap(hdr); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area))); + PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area))); } else { if (readStatus & FLAG_ICLASS_CC) { - PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); + PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); } - PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); - PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); + PrintAndLogEx(SUCCESS, " Kd: %s debit key, hidden", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); + PrintAndLogEx(SUCCESS, " Kc: %s credit key, hidden", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); if (readStatus & FLAG_ICLASS_AIA) { - PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); + PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); } } @@ -3640,7 +3573,7 @@ int info_iclass(void) { print_picopass_info(hdr); } - PrintAndLogEx(INFO, "------ " _CYAN_("Fingerprint") " ------"); + PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------"); uint8_t aia[8]; if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) @@ -3655,18 +3588,17 @@ int info_iclass(void) { bool se_enabled = (memcmp(aia, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); if (isHidRange) { - PrintAndLogEx(SUCCESS, "CSN is in HID range"); + PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("HID range")); if (legacy) - PrintAndLogEx(SUCCESS, "Credential : " _GREEN_("iCLASS legacy")); + PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS legacy")); if (se_enabled) - PrintAndLogEx(SUCCESS, "Credential : " _GREEN_("iCLASS SE")); - + PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE")); } else { - PrintAndLogEx(SUCCESS, _YELLOW_("PicoPass")" (CSN is not in HID range)"); + PrintAndLogEx(SUCCESS, " CSN..-....... " _YELLOW_("outside HID range")); } uint8_t cardtype = get_mem_config(hdr); - PrintAndLogEx(SUCCESS, " Card type : " _GREEN_("%s"), card_types[cardtype]); + PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]); } DropField(); diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index dff2b6345..fb3cb3c97 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -419,7 +419,7 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool uint8_t key[8]; if (check_known_default(csn, epurse, rmac, tmac, key)) { - snprintf(exp, size, "( " _GREEN_("%s") ")", sprint_hex(key, 8)); + snprintf(exp, size, "( " _GREEN_("%s") " )", sprint_hex_inrow(key, 8)); } curr_state = PICO_NONE; } diff --git a/client/src/cmdhflto.c b/client/src/cmdhflto.c index 7313d23fb..a4b7d1f03 100644 --- a/client/src/cmdhflto.c +++ b/client/src/cmdhflto.c @@ -22,6 +22,15 @@ #include "protocols.h" #include "fileutils.h" //saveFile +/* + iceman notes + We can't dump LTO 5 or 6 tags yet since we don't have a datasheet. + If you have access to datasheet, le me know! + + LTO w Type info 00 01 has 101 blocks. + LTO w Type info 00 03 has 255 blocks. + LTO w Type info 00 xx has NN blocks. +*/ #define CM_MEM_MAX_SIZE 0x1FE0 // (32byte/block * 255block = 8160byte) static int CmdHelp(const char *Cmd); @@ -185,6 +194,17 @@ static int CmdHfLTOInfo(const char *Cmd) { return infoLTO(true); } +static const char* lto_print_size(uint8_t ti) { + switch(ti) { + case 1: + return "101 blocks / 3232 bytes"; + case 3: + return "255 blocks / 8160 bytes"; + default : + return ""; + } +} + int infoLTO(bool verbose) { clearCommandBuffer(); @@ -199,8 +219,9 @@ int infoLTO(bool verbose) { if (ret_val == PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "UID: " _YELLOW_("%s"), sprint_hex_inrow(serial_number, sizeof(serial_number))); - PrintAndLogEx(SUCCESS, "TYPE INFO: " _YELLOW_("%s"), sprint_hex_inrow(type_info, sizeof(type_info))); + PrintAndLogEx(SUCCESS, "UID......... " _YELLOW_("%s"), sprint_hex_inrow(serial_number, sizeof(serial_number))); + PrintAndLogEx(SUCCESS, "Type info... " _YELLOW_("%s"), sprint_hex_inrow(type_info, sizeof(type_info))); + PrintAndLogEx(SUCCESS, "Memory...... " _YELLOW_("%s"), lto_print_size(type_info[1])); } return ret_val; @@ -442,11 +463,18 @@ int dumpLTO(uint8_t *dump, bool verbose) { lto_switch_off_field(); return ret_val; } + // 0003 == 255 blocks x 32 = 8160 bytes + // 0001 == 101 blocks x 32 = 3232 bytes + uint8_t blocks = 0xFF; + if (type_info[1] == 0x01) { + blocks = 0x65; + } + PrintAndLogEx(SUCCESS, "Found LTO tag w " _YELLOW_("%s") " memory", lto_print_size(type_info[1])); uint8_t block_data_d00_d15[18]; uint8_t block_data_d16_d31[18]; - for (uint8_t i = 0; i < 255; i++) { + for (uint8_t i = 0; i < blocks; i++) { ret_val = lto_rdbl(i, block_data_d00_d15, block_data_d16_d31, verbose); @@ -458,6 +486,8 @@ int dumpLTO(uint8_t *dump, bool verbose) { lto_switch_off_field(); return ret_val; } + PrintAndLogEx(INPLACE, "...reading block %d", i); + fflush(stdout); } lto_switch_off_field(); @@ -502,6 +532,7 @@ static int CmdHfLTODump(const char *Cmd) { } int ret_val = dumpLTO(dump, true); + PrintAndLogEx(NORMAL, ""); if (ret_val != PM3_SUCCESS) { free(dump); return ret_val; diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index ead78d7e4..84b2a3620 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -627,6 +627,76 @@ static void decode_print_st(uint16_t blockno, uint8_t *data) { } } + +static uint16_t NumOfBlocks(char card) { + switch (card) { + case '0' : + return MIFARE_MINI_MAXBLOCK; + case '1' : + return MIFARE_1K_MAXBLOCK; + case '2' : + return MIFARE_2K_MAXBLOCK; + case '4' : + return MIFARE_4K_MAXBLOCK; + default : + return 0; + } +} + +static uint8_t NumOfSectors(char card) { + switch (card) { + case '0' : + return MIFARE_MINI_MAXSECTOR; + case '1' : + return MIFARE_1K_MAXSECTOR; + case '2' : + return MIFARE_2K_MAXSECTOR; + case '4' : + return MIFARE_4K_MAXSECTOR; + default : + return 0; + } +} + +static uint8_t FirstBlockOfSector(uint8_t sectorNo) { + if (sectorNo < 32) { + return sectorNo * 4; + } else { + return 32 * 4 + (sectorNo - 32) * 16; + } +} + +static uint8_t NumBlocksPerSector(uint8_t sectorNo) { + if (sectorNo < 32) { + return 4; + } else { + return 16; + } +} + +static uint8_t GetSectorFromBlockNo(uint8_t blockNo) { + if (blockNo < 128) + return blockNo / 4; + else + return 32 + ((128 - blockNo) / 16); +} + +static char GetFormatFromSector(uint8_t sectorNo) { + switch (sectorNo) { + case MIFARE_MINI_MAXSECTOR: + return '0'; + case MIFARE_1K_MAXSECTOR: + return '1'; + case MIFARE_2K_MAXSECTOR: + return '2'; + case MIFARE_4K_MAXSECTOR: + return '4'; + default : + return ' '; + } +} + + static int CmdHF14AMfDarkside(const char *Cmd) { uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA; uint64_t key = 0; @@ -825,12 +895,9 @@ static int CmdHF14AMfRdSc(const char *Cmd) { PrintAndLogEx(NORMAL, "isOk:%02x", isOK); if (isOK) { - uint8_t blocks = 4; - uint8_t start = sectorNo * 4; - if (sectorNo >= 32) { - blocks = 16; - start = 128 + (sectorNo - 32) * 16; - } + uint8_t blocks = NumBlocksPerSector(sectorNo); + uint8_t start = FirstBlockOfSector(sectorNo); + for (int i = 0; i < blocks; i++) { PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16)); } @@ -843,74 +910,6 @@ static int CmdHF14AMfRdSc(const char *Cmd) { return PM3_SUCCESS; } -static uint16_t NumOfBlocks(char card) { - switch (card) { - case '0' : - return MIFARE_MINI_MAXBLOCK; - case '1' : - return MIFARE_1K_MAXBLOCK; - case '2' : - return MIFARE_2K_MAXBLOCK; - case '4' : - return MIFARE_4K_MAXBLOCK; - default : - return 0; - } -} - -static uint8_t NumOfSectors(char card) { - switch (card) { - case '0' : - return MIFARE_MINI_MAXSECTOR; - case '1' : - return MIFARE_1K_MAXSECTOR; - case '2' : - return MIFARE_2K_MAXSECTOR; - case '4' : - return MIFARE_4K_MAXSECTOR; - default : - return 0; - } -} - -static uint8_t FirstBlockOfSector(uint8_t sectorNo) { - if (sectorNo < 32) { - return sectorNo * 4; - } else { - return 32 * 4 + (sectorNo - 32) * 16; - } -} - -static uint8_t NumBlocksPerSector(uint8_t sectorNo) { - if (sectorNo < 32) { - return 4; - } else { - return 16; - } -} - -static uint8_t GetSectorFromBlockNo(uint8_t blockNo) { - if (blockNo < 128) - return blockNo / 4; - else - return 32 + ((128 - blockNo) / 16); -} - -static char GetFormatFromSector(uint8_t sectorNo) { - switch (sectorNo) { - case MIFARE_MINI_MAXSECTOR: - return '0'; - case MIFARE_1K_MAXSECTOR: - return '1'; - case MIFARE_2K_MAXSECTOR: - return '2'; - case MIFARE_4K_MAXSECTOR: - return '4'; - default : - return ' '; - } -} - static int FastDumpWithEcFill(uint8_t numsectors) { PacketResponseNG resp; @@ -2963,7 +2962,7 @@ out: printKeyTable(sectorsCnt, e_sector); if (use_flashmemory && found_keys == (sectorsCnt << 1)) { - PrintAndLogEx(SUCCESS, "Card dumped aswell. run " _YELLOW_("`%s %c`"), + PrintAndLogEx(SUCCESS, "Card dumped as well. run " _YELLOW_("`%s %c`"), "hf mf esave", GetFormatFromSector(sectorsCnt) ); diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index e72799bc4..fd0f6c93a 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -233,6 +233,7 @@ static int plus_print_version(uint8_t *version) { PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), version[7 + 7 + 7 + 5], version[7 + 7 + 7 + 5 + 1]); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information")); + PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version, 7)); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0])); PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[1])); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]); @@ -241,6 +242,7 @@ static int plus_print_version(uint8_t *version) { PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6], true)); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); + PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version + 7, 6)); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[7])); PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[8])); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[9]); @@ -265,13 +267,21 @@ static int get_plus_version(uint8_t *version, int *version_len) { static int CmdHFMFPInfo(const char *Cmd) { - if (Cmd && strlen(Cmd) > 0) - PrintAndLogEx(WARNING, "command don't have any parameters.\n"); - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); + // Mifare Plus info + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 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 + + bool supportVersion = false; bool supportSignature = false; @@ -284,17 +294,11 @@ static int CmdHFMFPInfo(const char *Cmd) { } else { // info about 14a part infoHF14A(false, false, false); + + // Historical bytes. + } - // Mifare Plus info - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 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 // Signature originality check uint8_t signature[56] = {0}; diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 771ae0e41..55e03a848 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -21,6 +21,7 @@ #include "generator.h" #include "mifare/ndef.h" #include "cliparser.h" +#include "cmdmain.h" #define MAX_UL_BLOCKS 0x0F @@ -241,7 +242,7 @@ static int usage_hf_mfu_otp_tearoff(void) { PrintAndLogEx(NORMAL, " s