diff --git a/.vscode/launch.json b/.vscode/launch.json index d3d86ee80..f6a030c7c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,13 +18,21 @@ "text": "-enable-pretty-printing", "ignoreFailures": true } - ] + ], + "windows": { + "processId": "${input:ProcessIDWindows}", + "miDebuggerPath": "${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe", + "externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while + "environment": [{ + "name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin" + }] + } },{ "name": "(gdb) Build & Launch", "type": "cppdbg", "request": "launch", "program": "${cwd}/client/proxmark3", - "args": ["/dev/ttyACM0"], + "args": ["/dev/ttyACM0"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], @@ -38,7 +46,15 @@ } ], "preLaunchTask": "client: Debug: clean & make", - "miDebuggerPath": "/usr/bin/gdb" + "miDebuggerPath": "/usr/bin/gdb", + "windows": { + "args": ["COM5"], + "miDebuggerPath": "${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe", + "externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while + "environment": [{ + "name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin" + }] + } } ], "inputs": [ @@ -50,6 +66,15 @@ "args": { "command": "pgrep -n proxmark3", } + + },{ + "id": "ProcessIDWindows", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "${workspaceFolder}/../../runme64.bat -c \"cat /proc/$(pgrep -n proxmark3)/winpid\"", + } + } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 155aa80cd..7354a8a2d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,6 +7,18 @@ "label": "all: Make & run", "type": "shell", "command": "make -j && ./pm3", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, "problemMatcher": [ "$gcc" ], @@ -19,6 +31,18 @@ "label": "choose: Make", "type": "shell", "command": "make ${input:componentType} -j", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, "problemMatcher": [ "$gcc" ], @@ -28,6 +52,18 @@ "label": "client: Debug: make", "type": "shell", "command": "make client -j DEBUG=1", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, "problemMatcher": [ "$gcc" ], @@ -37,6 +73,18 @@ "label": "client: Debug: clean & make", "type": "shell", "command": "make client/clean && make client -j DEBUG=1", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, "problemMatcher": [ "$gcc" ], @@ -46,18 +94,54 @@ "label": "fullimage: Make & Flash", "type": "shell", "command": "make fullimage && ./pm3-flash-fullimage", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, "problemMatcher": [] }, { "label": "BOOTROM: Make & Flash", "type": "shell", "command": "make bootrom && ./pm3-flash-bootrom", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, "problemMatcher": [] }, { "label": "Run client", "type": "shell", "command": "./pm3", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, "problemMatcher": [] } ], diff --git a/CHANGELOG.md b/CHANGELOG.md index e9bb8d98f..c1bda4ff5 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] + - Added T55xx Guide to assist in learning how to use the T55xx chip (@mwalker33) - Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001) - Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...) - ... diff --git a/README.md b/README.md index 9717c30c7..bc7e88854 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ |[Donations](#Donations)|[Maintainers](/doc/md/Development/Maintainers.md)|[Command Cheat sheet](/doc/cheatsheet.md)| ||[Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)|[More cheat sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)| ||**[Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md)**|[Complete client command set](/doc/commands.md)| -||**[JTAG](/doc/jtag_notes.md)**|| +||**[JTAG](/doc/jtag_notes.md)**|[T55xx Guide](/doc/T5577_Guide.md)| ## Notes / helpful documents @@ -57,7 +57,7 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md). This repo compiles nicely on - Proxspace v3.x - - [latest release v3.7](https://github.com/Gator96100/ProxSpace/releases) + - [latest release v3.7.1](https://github.com/Gator96100/ProxSpace/releases) - Windows/mingw environment with Qt5.6.1 & GCC 4.9 - Ubuntu 16.04 -> 20.04 - ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian diff --git a/armsrc/appmain.c b/armsrc/appmain.c index f06f30278..2added25f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1037,10 +1037,11 @@ static void PacketReceived(PacketCommandNG *packet) { case CMD_LF_VIKING_CLONE: { struct p { bool Q5; + bool EM; uint8_t blocks[8]; } PACKED; struct p *payload = (struct p *)packet->data.asBytes; - CopyVikingtoT55xx(payload->blocks, payload->Q5); + CopyVikingtoT55xx(payload->blocks, payload->Q5, payload->EM); break; } case CMD_LF_COTAG_READ: { diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 803972e05..5cb5d71ae 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1853,7 +1853,7 @@ void iClass_WriteBlock(uint8_t *msg) { // new block data memcpy(write + 2, payload->data, 8); - + uint8_t pagemap = get_pagemap(&hdr); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { // Unsecured tags uses CRC16, but don't include the UPDATE operation code @@ -1999,10 +1999,10 @@ void iClass_Restore(iclass_restore_req_t *msg) { // data + mac if (iclass_writeblock_ext(item.blockno, item.data, mac, use_mac)) { - Dbprintf("Write block [%02x] " _GREEN_("successful"), item.blockno); + Dbprintf("Write block [%3d/0x%02X] " _GREEN_("successful"), item.blockno, item.blockno); written++; } else { - Dbprintf("Write block [%02x] " _RED_("failed"), item.blockno); + Dbprintf("Write block [%3d/0x%02X] " _RED_("failed"), item.blockno, item.blockno); } } diff --git a/armsrc/lfops.c b/armsrc/lfops.c index a6fbb7bba..0d578295f 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -2252,11 +2252,14 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) { } // clone viking tag to T55xx -void CopyVikingtoT55xx(uint8_t *blocks, uint8_t Q5) { +void CopyVikingtoT55xx(uint8_t *blocks, bool q5, bool em) { uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), 0, 0}; - if (Q5) + if (q5) { data[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT; + } else if (em) { + data[0] = (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(2)); + } data[1] = bytes_to_num(blocks, 4); data[2] = bytes_to_num(blocks + 4, 4); diff --git a/armsrc/lfops.h b/armsrc/lfops.h index 0ec050158..703d48b21 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -41,7 +41,7 @@ int lf_io_watch(int findone, uint32_t *high, uint32_t *low); void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an HID card to T5557/T5567 -void CopyVikingtoT55xx(uint8_t *blocks, uint8_t Q5); +void CopyVikingtoT55xx(uint8_t *blocks, bool q5, bool em); int copy_em410x_to_t55xx(uint8_t card, uint8_t clock, uint32_t id_hi, uint32_t id_lo); diff --git a/client/dictionaries/iclass_default_keys.dic b/client/dictionaries/iclass_default_keys.dic index 22e1ee653..9f03720c9 100644 --- a/client/dictionaries/iclass_default_keys.dic +++ b/client/dictionaries/iclass_default_keys.dic @@ -10,3 +10,5 @@ AEA684A6DAB23278 # AA1 F0E1D2C3B4A59687 # Kd from PicoPass 2k documentation 5CBCF1DA45D5FB4F # PicoPass Default Exchange Key 31ad7ebd2f282168 # From HID multiclassSE reader +6EFD46EFCBB3C875 # From pastebin: https://pastebin.com/uHqpjiuU +E033CA419AEE43F9 # From pastebin: https://pastebin.com/uHqpjiuU \ No newline at end of file diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index b3bf93312..38c6e2503 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -1275,4 +1275,7 @@ AABAFFCC7612 # gamefactory # ozdilek # -17D071403C20 \ No newline at end of file +17D071403C20 +# +534F4C415249 +534f4c303232 \ No newline at end of file diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 852aae3b8..c8d0a57eb 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -1178,11 +1178,11 @@ static int CmdHF14AAPDU(const char *Cmd) { } CLIParserFree(ctx); - PrintAndLogEx(SUCCESS, "( " _YELLOW_("%s%s%s")" )", - activateField ? "select" : "", - leaveSignalON ? ", keep" : "", - decodeTLV ? ", TLV" : "" - ); + PrintAndLogEx(SUCCESS, "( " _YELLOW_("%s%s%s")" )", + activateField ? "select" : "", + leaveSignalON ? ", keep" : "", + decodeTLV ? ", TLV" : "" + ); PrintAndLogEx(SUCCESS, ">>> %s", sprint_hex_inrow(data, datalen)); if (decodeAPDU) { @@ -1217,7 +1217,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) { "Sends an raw bytes over ISO14443a. With option to use TOPAZ 14a mode.", "hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'\n" "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -1344,13 +1344,13 @@ static int waitCmd(bool i_select, uint32_t timeout) { if (i_select == false && len >= 3) { bool crc = check_crc(CRC_14443_A, data, len); - + char s[16]; - sprintf(s, - (crc) ? _GREEN_("%02X %02X") : _RED_("%02X %02X"), - data[len - 2], - data[len - 1] - ); + sprintf(s, + (crc) ? _GREEN_("%02X %02X") : _RED_("%02X %02X"), + data[len - 2], + data[len - 1] + ); PrintAndLogEx(SUCCESS, "%s[ %s ]", sprint_hex(data, len - 2), s); } else { diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 593eaaece..3eebbce74 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -1725,7 +1725,7 @@ static int CmdHF15Write(const char *Cmd) { AddCrc15(req, reqlen); reqlen += 2; - PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum); + PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data [ %s ] ", pagenum, pagenum, sprint_hex(req, reqlen)); PacketResponseNG resp; clearCommandBuffer(); diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index eaf5b5406..49784c4f5 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -71,153 +71,6 @@ static int usage_hf_iclass_sim(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } - -static int usage_hf_iclass_esave(void) { - PrintAndLogEx(NORMAL, "Save emulator memory to file."); - PrintAndLogEx(NORMAL, "if not filename is supplied, CSN will be used."); - PrintAndLogEx(NORMAL, "Number of bytes to download defaults to 256. Other value is 2048\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass esave [h] [f ] [s ]\n"); - PrintAndLogEx(NORMAL, "Options"); - PrintAndLogEx(NORMAL, " h : Show this help"); - PrintAndLogEx(NORMAL, " f : filename of dump"); - PrintAndLogEx(NORMAL, " s : (256|2048) number of bytes to save (default 256)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass esave")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass esave f hf-iclass-dump.bin")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass esave s 2048 f hf-iclass-dump.bin")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_iclass_eview(void) { - PrintAndLogEx(NORMAL, "It displays emulator memory"); - PrintAndLogEx(NORMAL, "Number of bytes to download defaults to 256. Other value is 2048\n"); - PrintAndLogEx(NORMAL, " Usage: hf iclass eview [s ] "); - PrintAndLogEx(NORMAL, " s : (256|2048) number of bytes to save (default 256)"); - PrintAndLogEx(NORMAL, " v : verbose output"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf iclass eview")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf iclass eview s 2048 v")); - return PM3_SUCCESS; -} -static int usage_hf_iclass_decrypt(void) { - PrintAndLogEx(NORMAL, "3DES decrypt data\n"); - PrintAndLogEx(NORMAL, "This is naive implementation, it tries to decrypt every block after block 6."); - PrintAndLogEx(NORMAL, "Correct behaviour would be to decrypt only the application areas where the key is valid,"); - PrintAndLogEx(NORMAL, "which is defined by the configuration block."); - PrintAndLogEx(NORMAL, "OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside"); - PrintAndLogEx(NORMAL, "in the resources directory. The file should be 16 bytes binary data\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass decrypt d f k \n"); - PrintAndLogEx(NORMAL, "Options"); - PrintAndLogEx(NORMAL, " h : Show this help"); - PrintAndLogEx(NORMAL, " d : 16 bytes hex"); - PrintAndLogEx(NORMAL, " f : filename of dump"); - PrintAndLogEx(NORMAL, " k : 16 bytes hex"); - PrintAndLogEx(NORMAL, " v : verbose output"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass decrypt f hf-iclass-AA162D30F8FF12F1-dump.bin")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass decrypt f hf-iclass-AA162D30F8FF12F1-dump.bin k 000102030405060708090a0b0c0d0e0f")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass decrypt d 1122334455667788 k 000102030405060708090a0b0c0d0e0f")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_iclass_encrypt(void) { - PrintAndLogEx(NORMAL, "3DES encrypt data\n"); - PrintAndLogEx(NORMAL, "OBS! In order to use this function, the file " _YELLOW_("'iclass_decryptionkey.bin'") " must reside"); - PrintAndLogEx(NORMAL, "in the resources directory. The file should be 16 bytes binary data\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass encrypt d k \n"); - PrintAndLogEx(NORMAL, "Options"); - PrintAndLogEx(NORMAL, " h : Show this help"); - PrintAndLogEx(NORMAL, " d : 16 bytes hex"); - PrintAndLogEx(NORMAL, " k : 16 bytes hex"); - PrintAndLogEx(NORMAL, " v : verbose output"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass encrypt d 0102030405060708")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass encrypt d 0102030405060708 k 00112233445566778899AABBCCDDEEFF")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_iclass_dump(void) { - PrintAndLogEx(NORMAL, "Dump all memory from a iCLASS tag\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass dump f k c [e|r|v]\n"); - 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 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:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass dump k 001122334455667B")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass dump k AAAAAAAAAAAAAAAA e")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass dump k 0")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_iclass_restore(void) { - PrintAndLogEx(NORMAL, "Restore data from dumpfile onto a iCLASS tag\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass restore f b l k c e|r\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : Show this help"); - PrintAndLogEx(NORMAL, " f : specify a filename to restore"); - PrintAndLogEx(NORMAL, " b : The first block to restore as 2 hex symbols"); - PrintAndLogEx(NORMAL, " l : The last block to restore as 2 hex symbols"); - PrintAndLogEx(NORMAL, " k : Access key as 16 hex symbols or 1 hex to select key from memory"); - PrintAndLogEx(NORMAL, " c : If 'c' is specified, the key set is assumed to be the credit key\n"); - PrintAndLogEx(NORMAL, " e : If 'e' is specified, elite computations applied to key"); - PrintAndLogEx(NORMAL, " r : If 'r' is specified, no computations applied to key (raw)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass restore f hf-iclass-AA162D30F8FF12F1-dump.bin b 06 l 1A k 1122334455667788 e")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass restore f hf-iclass-AA162D30F8FF12F1-dump b 05 l 19 k 0")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass restore f hf-iclass-AA162D30F8FF12F1-dump b 06 l 19 k 0 e")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_iclass_writeblock(void) { - PrintAndLogEx(NORMAL, "Write data to a iCLASS tag\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass wrbl b d k [c|e|r|v]\n"); - PrintAndLogEx(NORMAL, "Options:"); - 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 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")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass wrbl b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass wrbl b 1B d AAAAAAAAAAAAAAAA k 0")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_iclass_readblock(void) { - PrintAndLogEx(NORMAL, "Read a iCLASS block from tag\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass rdbl b k [c|e|r|v]\n"); - 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 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")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass rdbl b 1B k 0011223344556677 c")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass rdbl b 0A k 0")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} static int usage_hf_iclass_calc_newkey(void) { PrintAndLogEx(NORMAL, "Calculate new key for updating\n"); PrintAndLogEx(NORMAL, "Usage: hf iclass calc_newkey o n s [csn] e\n"); @@ -779,7 +632,7 @@ static int CmdHFiClassSim(const char *Cmd) { SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 1, CSN, 8); if (sim_type == ICLASS_SIM_MODE_FULL) - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass esave h") "` to save the emulator memory to file"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass esave -h") "` to save the emulator memory to file"); break; } } @@ -961,47 +814,36 @@ static int CmdHFiClassELoad(const char *Cmd) { PrintAndLogEx(SUCCESS, "sent %d bytes of data to device emulator memory", bytes_sent); return PM3_SUCCESS; } - static int CmdHFiClassESave(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass esave", + "Save emulator memory to file.\n" + "if filename is not supplied, CSN will be used.", + "hf iclass esave\n" + "hf iclass esave -f hf-iclass-dump\n" + "hf iclass esave -s 2048 -f hf-iclass-dump"); + void *argtable[] = { + arg_param_begin, + arg_str0("f", "file", "", "filename of dumpfile"), + arg_int0("s", "size", "<256|2048>", "number of bytes to save (default 256)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); char *fnameptr = filename; - int len = 0; - uint16_t bytes = 256; - 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_esave(); - case 'f': - len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (len >= FILE_PATH_SIZE) { - PrintAndLogEx(FAILED, "Filename too long"); - errors = true; - break; - } - cmdp += 2; - break; - case 's': - bytes = param_get32ex(Cmd, cmdp + 1, 256, 10); - if (bytes > 4096) { - PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes); - bytes = 4096; - } - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + + uint16_t bytes = arg_get_int_def(ctx, 2, 256); + + if (bytes > 4096) { + PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes); + bytes = 4096; } - //Validations - if (errors) { - return usage_hf_iclass_esave(); - } + CLIParserFree(ctx); uint8_t *dump = calloc(bytes, sizeof(uint8_t)); if (dump == NULL) { @@ -1017,7 +859,7 @@ static int CmdHFiClassESave(const char *Cmd) { } // user supplied filename? - if (len < 1) { + if (fnlen < 1) { fnameptr += snprintf(fnameptr, sizeof(filename), "hf-iclass-"); FillFileNameByUID(fnameptr, dump, "-dump", 8); } @@ -1032,44 +874,37 @@ static int CmdHFiClassESave(const char *Cmd) { } static int CmdHFiClassEView(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass eview", + "Display emulator memory.\n" + "Number of bytes to download defaults to 256. Other value is 2048.", + "hf iclass eview\n" + "hf iclass eview -s 2048\n" + "hf iclass eview -s 2048 -v"); - uint16_t blocks = 32, bytes = 256; - bool errors = false, verbose = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_eview(); - case 's': - bytes = param_get32ex(Cmd, cmdp + 1, 256, 10); + void *argtable[] = { + arg_param_begin, + arg_int0("s", "size", "<256|2048>", "number of bytes to save (default 256)"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); - if (bytes > 4096) { - PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes); - bytes = 4096; - } + uint16_t blocks = 32; + uint16_t bytes = arg_get_int_def(ctx, 1, 256); + bool verbose = arg_get_lit(ctx, 2); + blocks = bytes / 8; - if (bytes % 8 != 0) { - bytes &= 0xFFF8; - PrintAndLogEx(WARNING, "Number not divided by 8, truncating to %u", bytes); - } + CLIParserFree(ctx); - blocks = bytes / 8; - cmdp += 2; - break; - case 'v': - verbose = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + if (bytes > 4096) { + PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes); + bytes = 4096; } - //Validations - if (errors || bytes == 0) { - return usage_hf_iclass_eview(); + if (bytes % 8 != 0) { + bytes &= 0xFFF8; + PrintAndLogEx(WARNING, "Number not divided by 8, truncating to %u", bytes); } uint8_t *dump = calloc(bytes, sizeof(uint8_t)); @@ -1096,74 +931,82 @@ static int CmdHFiClassEView(const char *Cmd) { free(dump); return PM3_SUCCESS; } - static int CmdHFiClassDecrypt(const char *Cmd) { + CLIParserContext *clictx; + CLIParserInit(&clictx, "hf iclass decrypt", + "3DES decrypt data\n" + "This is a naive implementation, it tries to decrypt every block after block 6.\n" + "Correct behaviour would be to decrypt only the application areas where the key is valid,\n" + "which is defined by the configuration block.\n" + "OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside\n" + "in the resources directory. The file should be 16 bytes binary data", + "hf iclass decrypt -f hf-iclass-AA162D30F8FF12F1-dump.bin\n" + "hf iclass decrypt -f hf-iclass-AA162D30F8FF12F1-dump.bin -k 000102030405060708090a0b0c0d0e0f\n" + "hf iclass decrypt -d 1122334455667788 -k 000102030405060708090a0b0c0d0e0f"); - bool errors = false; - bool have_key = false; - bool have_data = false; - bool have_file = false; - bool verbose = false; - uint8_t cmdp = 0; + void *argtable[] = { + arg_param_begin, + arg_str0("f", "file", "", "filename of dumpfile"), + arg_str0("d", "data", "", "3DES encrypted data"), + arg_str0("k", "key", "", "3DES transport key"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(clictx, Cmd, argtable, false); - uint8_t enc_data[8] = {0}; - uint8_t dec_data[8] = {0}; - - size_t keylen = 0; - uint8_t key[32] = {0}; - uint8_t *keyptr = NULL; + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(clictx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); size_t decryptedlen = 0; uint8_t *decrypted = NULL; - char filename[FILE_PATH_SIZE]; + bool have_file = false; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_decrypt(); - case 'd': - if (param_gethex(Cmd, cmdp + 1, enc_data, 16)) { - PrintAndLogEx(ERR, "Data must be 16 HEX symbols"); - errors = true; - break; - } - have_data = true; - cmdp += 2; - break; - case 'f': - if (param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)) == 0) { - PrintAndLogEx(WARNING, "No filename found after f"); - errors = true; - break; - } - - if (loadFile_safe(filename, "", (void **)&decrypted, &decryptedlen) != PM3_SUCCESS) { - errors = true; - break; - } - have_file = true; - cmdp += 2; - break; - case 'k': - if (param_gethex(Cmd, cmdp + 1, key, 32)) { - PrintAndLogEx(ERR, "Transport key must include 32 HEX symbols"); - errors = true; - } - have_key = true; - cmdp += 2; - break; - case 'v': - verbose = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; + if (fnlen > 0) { + if (loadFile_safe(filename, "", (void **)&decrypted, &decryptedlen) != PM3_SUCCESS) { + CLIParserFree(clictx); + return PM3_EINVARG; } + have_file = true; } - if (errors || cmdp < 1) return usage_hf_iclass_decrypt(); + int enc_data_len = 0; + uint8_t enc_data[8] = {0}; + bool have_data = false; + + CLIGetHexWithReturn(clictx, 2, enc_data, &enc_data_len); + + if (enc_data_len > 0) { + if (enc_data_len != 8) { + PrintAndLogEx(ERR, "Data must be 8 bytes (16 HEX characters)"); + CLIParserFree(clictx); + return PM3_EINVARG; + } + have_data = true; + } + + int key_len = 0; + uint8_t key[16] = {0}; + uint8_t *keyptr = NULL; + bool have_key = false; + + CLIGetHexWithReturn(clictx, 3, key, &key_len); + + if (key_len > 0) { + if (key_len != 16) { + PrintAndLogEx(ERR, "Transport key must be 16 bytes (32 HEX characters)"); + CLIParserFree(clictx); + return PM3_EINVARG; + } + have_key = true; + } + + bool verbose = arg_get_lit(clictx, 4); + + CLIParserFree(clictx); + + size_t keylen = 0; + uint8_t dec_data[8] = {0}; bool use_sc = IsCryptoHelperPresent(verbose); @@ -1330,45 +1173,53 @@ static void iclass_encrypt_block_data(uint8_t *blk_data, uint8_t *key) { } static int CmdHFiClassEncryptBlk(const char *Cmd) { - bool errors = false; - bool have_key = false; - bool verbose = false; - uint8_t blk_data[8] = {0}; - uint8_t key[16] = {0}; - uint8_t *keyptr = NULL; - uint8_t cmdp = 0; + CLIParserContext *clictx; + CLIParserInit(&clictx, "hf iclass encrypt", + "3DES encrypt data\n" + "OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside\n" + "in the resources directory. The file should be 16 bytes binary data", + "hf iclass encrypt -d 0102030405060708\n" + "hf iclass encrypt -d 0102030405060708 -k 00112233445566778899AABBCCDDEEFF"); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_encrypt(); - case 'd': - if (param_gethex(Cmd, cmdp + 1, blk_data, 16)) { - PrintAndLogEx(ERR, "Block data must include 16 HEX symbols"); - errors = true; - } - cmdp += 2; - break; - case 'k': - if (param_gethex(Cmd, cmdp + 1, key, 32)) { - PrintAndLogEx(ERR, "Transport key must include 32 HEX symbols"); - errors = true; - } - have_key = true; - cmdp += 2; - break; - case 'v': - verbose = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + void *argtable[] = { + arg_param_begin, + arg_str1("d", "data", "", "data to encrypt"), + arg_str0("k", "key", "", "3DES transport key"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(clictx, Cmd, argtable, false); + + int blk_data_len = 0; + uint8_t blk_data[8] = {0}; + + CLIGetHexWithReturn(clictx, 1, blk_data, &blk_data_len); + + if (blk_data_len != 8) { + PrintAndLogEx(ERR, "Block data must be 8 bytes (16 HEX characters)"); + CLIParserFree(clictx); + return PM3_EINVARG; } - if (errors || cmdp < 1) return usage_hf_iclass_encrypt(); + int key_len = 0; + uint8_t key[16] = {0}; + uint8_t *keyptr = NULL; + bool have_key = false; + + CLIGetHexWithReturn(clictx, 2, key, &key_len); + + if (key_len > 0) { + if (key_len != 16) { + PrintAndLogEx(ERR, "Transport key must be 16 bytes (32 HEX characters)"); + CLIParserFree(clictx); + return PM3_EINVARG; + } + have_key = true; + } + + bool verbose = arg_get_lit(clictx, 3); + + CLIParserFree(clictx); bool use_sc = IsCryptoHelperPresent(verbose); @@ -1429,104 +1280,117 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { } static int CmdHFiClassDump(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass dump", + "Dump all memory from a iCLASS tag", + "hf iclass dump -k 001122334455667B\n" + "hf iclass dump -k AAAAAAAAAAAAAAAA --credit 001122334455667B\n" + "hf iclass dump -k AAAAAAAAAAAAAAAA --elite\n" + "hf iclass dump --ki 0\n" + "hf iclass dump --ki 0 --ci 2"); - uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t CreditKEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t keyNbr = 0; - uint8_t dataLen = 0; - uint8_t app_limit1 = 0, app_limit2 = 0; - uint8_t fileNameLen = 0; + void *argtable[] = { + arg_param_begin, + arg_str0("f", "file", "", "filename to save dump to"), + arg_str0("k", "key", "", "debit key as 16 hex symbols OR NR/MAC for replay"), + arg_int0(NULL, "ki", "", "debit key index to select key from memory 'hf iclass managekeys'"), + arg_str0(NULL, "credit", "", "credit key as 16 hex symbols"), + arg_int0(NULL, "ci", "", "credit key index to select key from memory 'hf iclass managekeys'"), + arg_lit0(NULL, "elite", "elite computations applied to key"), + arg_lit0(NULL, "raw", "raw, the key is interpreted as raw block 3/4"), + arg_lit0(NULL, "nr", "replay of NR/MAC"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - char tempStr[50] = {0}; - 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; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_dump(); - case 'c': - auth = true; - have_credit_key = true; - dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { - errors = param_gethex(tempStr, 0, CreditKEY, dataLen); - } else if (dataLen == 1) { - keyNbr = param_get8(Cmd, cmdp + 1); - if (keyNbr < ICLASS_KEYS_MAX) { - memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8); - PrintAndLogEx(INFO, "AA2 (credit) index %u", keyNbr); - } else { - PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); - errors = true; - } - } else { - PrintAndLogEx(WARNING, "\nERROR: Credit Key is incorrect length\n"); - errors = true; - } - cmdp += 2; - break; - case 'e': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo")); - elite = true; - cmdp++; - break; - case 'f': - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); - if (fileNameLen < 1) { - PrintAndLogEx(WARNING, "no filename found after f"); - errors = true; - } - cmdp += 2; - break; - case 'k': - auth = true; - dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { - errors = param_gethex(tempStr, 0, KEY, dataLen); - } else if (dataLen == 1) { - keyNbr = param_get8(Cmd, cmdp + 1); - if (keyNbr < ICLASS_KEYS_MAX) { - memcpy(KEY, iClass_Key_Table[keyNbr], 8); - PrintAndLogEx(INFO, "AA1 (debit) index %u", keyNbr); - } else { - PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); - errors = true; - } - } else { - PrintAndLogEx(WARNING, "\nERROR: Credit Key is incorrect length\n"); - errors = true; - } - cmdp += 2; - break; - case 'r': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("raw mode")); - 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; + int key_len = 0; + uint8_t key[8] = {0}; + bool auth = false; + + CLIGetHexWithReturn(ctx, 2, key, &key_len); + + int deb_key_nr = arg_get_int_def(ctx, 3, -1); + + if (key_len > 0 && deb_key_nr >= 0) { + PrintAndLogEx(ERR, "Please specify debit key or index, not both"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + if (key_len > 0) { + auth = true; + if (key_len != 8) { + PrintAndLogEx(ERR, "Debit key is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; } } - if ((use_replay + rawkey + elite) > 1) { - PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'"); - errors = true; + if (deb_key_nr >= 0) { + if (deb_key_nr < ICLASS_KEYS_MAX) { + auth = true; + memcpy(key, iClass_Key_Table[deb_key_nr], 8); + PrintAndLogEx(SUCCESS, "Using AA1 (debit) key[%d] " _GREEN_("%s"), deb_key_nr, sprint_hex(iClass_Key_Table[deb_key_nr], 8)); + } else { + PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); + return PM3_EINVARG; + } } - if (errors) return usage_hf_iclass_dump(); + int credit_key_len = 0; + uint8_t credit_key[8] = {0}; + bool have_credit_key = false; + + CLIGetHexWithReturn(ctx, 4, credit_key, &credit_key_len); + + int credit_key_nr = arg_get_int_def(ctx, 5, -1); + + if (credit_key_len > 0 && credit_key_nr >= 0) { + PrintAndLogEx(ERR, "Please specify credit key or index, not both"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + if (credit_key_len > 0) { + auth = true; + have_credit_key = true; + if (key_len != 8) { + PrintAndLogEx(ERR, "Credit key is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + if (credit_key_nr >= 0) { + if (credit_key_nr < ICLASS_KEYS_MAX) { + auth = true; + have_credit_key = true; + memcpy(key, iClass_Key_Table[credit_key_nr], 8); + PrintAndLogEx(SUCCESS, "Using AA2 (credit) key[%d] " _GREEN_("%s"), credit_key_nr, sprint_hex(iClass_Key_Table[credit_key_nr], 8)); + } else { + PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + bool elite = arg_get_lit(ctx, 6); + bool rawkey = arg_get_lit(ctx, 7); + bool use_replay = arg_get_lit(ctx, 8); + + CLIParserFree(ctx); + + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'"); + return PM3_EINVARG; + } + + uint8_t app_limit1 = 0, app_limit2 = 0; uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); @@ -1601,7 +1465,7 @@ static int CmdHFiClassDump(const char *Cmd) { .req.do_auth = auth, .end_block = app_limit1, }; - memcpy(payload.req.key, KEY, 8); + memcpy(payload.req.key, key, 8); // tags configured for NON SECURE PAGE, acts different if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { @@ -1676,7 +1540,7 @@ static int CmdHFiClassDump(const char *Cmd) { if (have_credit_key && pagemap != 0x01) { // AA2 authenticate credit key - memcpy(payload.req.key, CreditKEY, 8); + memcpy(payload.req.key, credit_key, 8); payload.req.use_credit_key = true; payload.start_block = app_limit1 + 1; @@ -1791,103 +1655,91 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bo } static int CmdHFiClass_WriteBlock(const char *Cmd) { - uint8_t blockno = 0; - uint8_t bldata[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t keyNbr = 0; - uint8_t dataLen = 0; - char tempStr[50] = {0}; - bool got_blockno = false; - bool use_credit_key = false; - bool elite = false; - bool rawkey = false; - bool use_replay = false; - bool errors = false; - bool verbose = false; - bool use_secure_pagemode = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_writeblock(); - case 'b': - blockno = param_get8ex(Cmd, cmdp + 1, 07, 16); - got_blockno = true; - cmdp += 2; - break; - case 'c': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("CREDIT")); - use_credit_key = true; - cmdp++; - break; - case 'd': - if (param_gethex(Cmd, cmdp + 1, bldata, 16)) { - PrintAndLogEx(WARNING, "Data must include 16 HEX symbols\n"); - errors = true; - } - cmdp += 2; - break; - case 'e': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo")); - elite = true; - cmdp++; - break; - case 'k': - dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { - errors = param_gethex(tempStr, 0, KEY, dataLen); - } 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)); - memcpy(KEY, iClass_Key_Table[keyNbr], 8); - } else { - PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); - errors = true; - } - } else { - PrintAndLogEx(WARNING, "\nERROR: Credit Key is incorrect length\n"); - errors = true; - } - use_secure_pagemode = true; - cmdp += 2; - break; - case 'r': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("raw mode")); - rawkey = true; - cmdp++; - break; - /* - case 'n': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode")); - use_replay = true; - cmdp++; - break; - */ - case 'v': - verbose = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass wrbl", + "Write data to an iCLASS tag", + "hf iclass wrbl -b 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B\n" + "hf iclass wrbl -b 27 -d AAAAAAAAAAAAAAAA -k 001122334455667B --credit\n" + "hf iclass wrbl -b 11 -d AAAAAAAAAAAAAAAA --ki 0"); + + void *argtable[] = { + arg_param_begin, + arg_str0("k", "key", "", "Access key as 16 hex symbols"), + arg_int0(NULL, "ki", "", "Key index to select key from memory 'hf iclass managekeys'"), + arg_int1("b", "block", "", "The block number to read as an integer"), + arg_str1("d", "data", "", "data to write as 16 hex symbols"), + arg_lit0(NULL, "credit", "key is assumed to be the credit key"), + arg_lit0(NULL, "elite", "elite computations applied to key"), + arg_lit0(NULL, "raw", "no computations applied to key (raw)"), + arg_lit0(NULL, "nr", "replay of NR/MAC"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int key_len = 0; + uint8_t key[8] = {0}; + + CLIGetHexWithReturn(ctx, 1, key, &key_len); + + int key_nr = arg_get_int_def(ctx, 2, -1); + + if (key_len > 0 && key_nr >= 0) { + PrintAndLogEx(ERR, "Please specify key or index, not both"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + bool auth = false; + + if (key_len > 0) { + auth = true; + if (key_len != 8) { + PrintAndLogEx(ERR, "Key is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } else if (key_nr >= 0) { + if (key_nr < ICLASS_KEYS_MAX) { + auth = true; + memcpy(key, iClass_Key_Table[key_nr], 8); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8)); + } else { + PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); + return PM3_EINVARG; } } - 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; + int blockno = arg_get_int_def(ctx, 3, 0); + + int data_len = 0; + uint8_t data[8] = {0}; + CLIGetHexWithReturn(ctx, 4, data, &data_len); + + if (data_len != 8) { + PrintAndLogEx(ERR, "Data must be 8 bytes (16 hex characters)"); + CLIParserFree(ctx); + return PM3_EINVARG; } - if (errors || cmdp < 4) return usage_hf_iclass_writeblock(); + bool use_credit_key = arg_get_lit(ctx, 5); + bool elite = arg_get_lit(ctx, 6); + bool rawkey = arg_get_lit(ctx, 7); + bool use_replay = arg_get_lit(ctx, 8); + bool verbose = arg_get_lit(ctx, 9); - int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, use_replay, verbose, use_secure_pagemode); + CLIParserFree(ctx); + + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'"); + return PM3_EINVARG; + } + + int isok = iclass_write_block(blockno, data, key, use_credit_key, elite, rawkey, use_replay, verbose, auth); switch (isok) { case PM3_SUCCESS: - PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno); + PrintAndLogEx(SUCCESS, "Wrote block %3d/0x%02X successful", blockno, blockno); break; case PM3_ETEAROFF: if (verbose) @@ -1901,92 +1753,75 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { } static int CmdHFiClassRestore(const char *Cmd) { - char filename[FILE_PATH_SIZE] = { 0x00 }; - char tempStr[50] = {0}; - uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t keyNbr = 0; - uint8_t fileNameLen = 0; - uint8_t startblock = 0; - uint8_t endblock = 0; - uint8_t dataLen = 0; - bool got_startblk = false, got_endblk = false; - bool use_credit_key = false; - bool elite = false; - bool rawkey = false; - bool errors = false; - bool verbose = false; - uint8_t cmdp = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass restore", + "Restore data from dumpfile onto a iCLASS tag", + "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 06 --last 1A -k 1122334455667788 --elite\n" + "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 05 --last 19 --ki 0\n" + "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 06 --last 19 --ki 0 --elite"); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_restore(); - case 'b': - startblock = param_get8ex(Cmd, cmdp + 1, 07, 16); - got_startblk = true; - cmdp += 2; - break; - case 'c': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("CREDIT")); - use_credit_key = true; - cmdp++; - break; - case 'e': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo")); - elite = true; - cmdp++; - break; - case 'f': - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); - if (fileNameLen < 1) { - PrintAndLogEx(WARNING, "No filename found after f"); - errors = true; - } - cmdp += 2; - break; - case 'k': - dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { - errors = param_gethex(tempStr, 0, KEY, dataLen); - } else if (dataLen == 1) { - keyNbr = param_get8(Cmd, cmdp + 1); - if (keyNbr < ICLASS_KEYS_MAX) { - 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"); - errors = true; - } - } else { - PrintAndLogEx(WARNING, "\nERROR: Credit Key is incorrect length\n"); - errors = true; - } - cmdp += 2; - break; - case 'l': - endblock = param_get8ex(Cmd, cmdp + 1, 07, 16); - got_endblk = true; - cmdp += 2; - break; - case 'r': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("raw mode")); - rawkey = true; - cmdp++; - break; - case 'v': - verbose = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "specify a filename to restore"), + arg_str0("k", "key", "", "Access key as 16 hex symbols"), + arg_int0(NULL, "ki", "", "Key index to select key from memory 'hf iclass managekeys'"), + arg_int1(NULL, "first", "", "The first block number to restore as an integer"), + arg_int1(NULL, "last", "", "The last block number to restore as an integer"), + arg_lit0(NULL, "credit", "key is assumed to be the credit key"), + arg_lit0(NULL, "elite", "elite computations applied to key"), + arg_lit0(NULL, "raw", "no computations applied to key (raw)"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + int key_len = 0; + uint8_t key[8] = {0}; + + CLIGetHexWithReturn(ctx, 2, key, &key_len); + + int key_nr = arg_get_int_def(ctx, 3, -1); + + if (key_len > 0 && key_nr >= 0) { + PrintAndLogEx(ERR, "Please specify key or index, not both"); + CLIParserFree(ctx); + return PM3_EINVARG; } - if (got_endblk == false || got_startblk == false) - errors = true; - if (errors || cmdp < 8) return usage_hf_iclass_restore(); + if (key_len > 0) { + if (key_len != 8) { + PrintAndLogEx(ERR, "Key is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } else if (key_nr >= 0) { + if (key_nr < ICLASS_KEYS_MAX) { + memcpy(key, iClass_Key_Table[key_nr], 8); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8)); + } else { + PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } else { + PrintAndLogEx(ERR, "Please specify a key or key index"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + int startblock = arg_get_int_def(ctx, 4, 0); + int endblock = arg_get_int_def(ctx, 5, 0); + + bool use_credit_key = arg_get_lit(ctx, 6); + bool elite = arg_get_lit(ctx, 7); + bool rawkey = arg_get_lit(ctx, 8); + bool verbose = arg_get_lit(ctx, 9); + + CLIParserFree(ctx); if (rawkey + elite > 1) { PrintAndLogEx(FAILED, "Can not use both 'e', 'r'"); @@ -2034,7 +1869,7 @@ static int CmdHFiClassRestore(const char *Cmd) { payload->req.blockno = startblock; payload->req.send_reply = true; payload->req.do_auth = true; - memcpy(payload->req.key, KEY, 8); + memcpy(payload->req.key, key, 8); payload->item_cnt = (endblock - startblock + 1); @@ -2051,15 +1886,15 @@ static int CmdHFiClassRestore(const char *Cmd) { free(dump); if (verbose) { - PrintAndLogEx(INFO, "Preparing to restore block range 0x%02x..0x%02x", startblock, endblock); + PrintAndLogEx(INFO, "Preparing to restore block range %02d..%02d", startblock, endblock); - PrintAndLogEx(INFO, "------+----------------------"); - PrintAndLogEx(INFO, "block | data"); - PrintAndLogEx(INFO, "------+----------------------"); + 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))); + PrintAndLogEx(INFO, "%3d/0x%02X | %s", item.blockno, item.blockno, sprint_hex_inrow(item.data, sizeof(item.data))); } } @@ -2123,7 +1958,7 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, " block %02X : " _GREEN_("%s"), blockno, sprint_hex(packet->data, sizeof(packet->data))); + PrintAndLogEx(SUCCESS, " block %3d/0x%02X : " _GREEN_("%s"), blockno, blockno, sprint_hex(packet->data, sizeof(packet->data))); PrintAndLogEx(NORMAL, ""); if (out) @@ -2133,94 +1968,84 @@ static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, boo } static int CmdHFiClass_ReadBlock(const char *Cmd) { - uint8_t blockno = 0; - uint8_t keyType = 0x88; //debit key - uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t key_idx = 0; - uint8_t key_len = 0; - char tempStr[50] = {0}; - bool got_blockno = false; - bool elite = false; - bool rawkey = false; - bool use_replay = false; - bool errors = false; - bool auth = false; - bool verbose = false; - uint8_t cmdp = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass rdbl", + "Read a iCLASS block from tag", + "hf iclass rdbl -b 6 -k 0011223344556677\n" + "hf iclass rdbl -b 27 -k 0011223344556677 --credit\n" + "hf iclass rdbl -b 10 --ki 0"); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_readblock(); - case 'b': - blockno = param_get8ex(Cmd, cmdp + 1, 7, 16); - got_blockno = true; - cmdp += 2; - break; - case 'c': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("KC credit")); - keyType = 0x18; - cmdp++; - break; - case 'e': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo")); - elite = true; - cmdp++; - break; - case 'k': - auth = true; - key_len = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (key_len == 16) { - errors = param_gethex(tempStr, 0, KEY, key_len); - } else if (key_len == 1) { - key_idx = param_get8(Cmd, cmdp + 1); - if (key_idx < ICLASS_KEYS_MAX) { - memcpy(KEY, iClass_Key_Table[key_idx], 8); - } else { - PrintAndLogEx(WARNING, "\nERROR: key index is invalid\n"); - errors = true; - } - } else { - PrintAndLogEx(WARNING, "\nERROR: incorrect key length\n"); - errors = true; - } - cmdp += 2; - break; - case 'r': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("raw mode")); - rawkey = true; - cmdp++; - break; - case 'n': - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode")); - use_replay = true; - cmdp++; - break; - case 'v': - verbose = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; + void *argtable[] = { + arg_param_begin, + arg_str0("k", "key", "", "Access key as 16 hex symbols"), + arg_int0(NULL, "ki", "", "Key index to select key from memory 'hf iclass managekeys'"), + arg_int1("b", "block", "", "The block number to read as an integer"), + arg_lit0(NULL, "credit", "key is assumed to be the credit key"), + arg_lit0(NULL, "elite", "elite computations applied to key"), + arg_lit0(NULL, "raw", "no computations applied to key (raw)"), + arg_lit0(NULL, "nr", "replay of NR/MAC"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int key_len = 0; + uint8_t key[8] = {0}; + + CLIGetHexWithReturn(ctx, 1, key, &key_len); + + int key_nr = arg_get_int_def(ctx, 2, -1); + + if (key_len > 0 && key_nr >= 0) { + PrintAndLogEx(ERR, "Please specify key or index, not both"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + bool auth = false; + + if (key_len > 0) { + auth = true; + if (key_len != 8) { + PrintAndLogEx(ERR, "Key is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } else if (key_nr >= 0) { + if (key_nr < ICLASS_KEYS_MAX) { + auth = true; + memcpy(key, iClass_Key_Table[key_nr], 8); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8)); + } else { + PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); + return PM3_EINVARG; } } - 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; + int blockno = arg_get_int_def(ctx, 3, 0); + + uint8_t keyType = 0x88; //debit key + if (arg_get_lit(ctx, 4)) { + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key"); + keyType = 0x18; //credit key } - if (errors) return usage_hf_iclass_readblock(); + bool elite = arg_get_lit(ctx, 5); + bool rawkey = arg_get_lit(ctx, 6); + bool use_replay = arg_get_lit(ctx, 7); + bool verbose = arg_get_lit(ctx, 8); + + CLIParserFree(ctx); + + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(ERR, "Can not use a combo of 'e', 'r', 'n'"); + return PM3_EINVARG; + } if (verbose) { - if (key_len == 1) - PrintAndLogEx(SUCCESS, "Using key[%d] %s", key_idx, sprint_hex(KEY, 8)); - else - PrintAndLogEx(SUCCESS, "Using key %s", sprint_hex(KEY, 8)); + if (key_len > 0) + PrintAndLogEx(SUCCESS, "Using key %s", sprint_hex(key, 8)); } if (auth == false && verbose) { @@ -2229,7 +2054,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { } uint8_t data[8] = {0}; - int res = iclass_read_block(KEY, blockno, keyType, elite, rawkey, use_replay, verbose, auth, data); + int res = iclass_read_block(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, data); if (res != PM3_SUCCESS) return res; @@ -2393,9 +2218,9 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e int i = startblock; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, " blk| data | ascii |lck| info"); - PrintAndLogEx(INFO, "----+-------------------------+----------+---+--------------"); - PrintAndLogEx(INFO, "0x00| " _GREEN_("%s") " | | CSN ", sprint_hex_ascii(iclass_dump, 8)); + PrintAndLogEx(INFO, " block# | data | ascii |lck| info"); + PrintAndLogEx(INFO, "---------+-------------------------+----------+---+--------------"); + PrintAndLogEx(INFO, " 0/0x00 | " _GREEN_("%s") " | | CSN ", sprint_hex_ascii(iclass_dump, 8)); if (i != 1) PrintAndLogEx(INFO, "...."); @@ -2448,18 +2273,18 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e s = info_nonks[i]; } - PrintAndLogEx(INFO, "0x%02X| %s | %s | %s ", i, sprint_hex_ascii(blk, 8), lockstr, s); + PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s ", i, 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); + PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s ", i, i, sprint_hex_ascii(blk, 8), lockstr, s); } i++; } - PrintAndLogEx(INFO, "----+-------------------------+----------+---+--------------"); + PrintAndLogEx(INFO, "---------+-------------------------+----------+---+--------------"); PrintAndLogEx(NORMAL, ""); } @@ -2468,14 +2293,14 @@ static int CmdHFiClassView(const char *Cmd) { CLIParserInit(&ctx, "hf iclass view", "Print a iCLASS tag dump file", "hf iclass view -f hf-iclass-AA162D30F8FF12F1-dump.bin\n" - "hf iclass view --startblock 1 --file hf-iclass-AA162D30F8FF12F1-dump.bin\n"); + "hf iclass view --first 1 --file hf-iclass-AA162D30F8FF12F1-dump.bin\n"); void *argtable[] = { arg_param_begin, arg_str1("f", "file", "", "filename of dump"), - arg_int0("s", "startblock", "", "print from this block (default block6)"), - arg_int0("e", "endblock", "", "end printing at this block (default 0, ALL)"), - arg_lit0("v", "verbose", "verbose output"), + arg_int0(NULL, "first", "", "Begin printing from this block (default block6)"), + arg_int0(NULL, "last", "", "End printing at this block (default 0, ALL)"), + arg_lit0("v", "verbose", "verbose output"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -2500,8 +2325,7 @@ static int CmdHFiClassView(const char *Cmd) { if (verbose) { PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename); PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, (uint16_t)(bytes_read >> 3), (uint16_t)(bytes_read >> 3)); - PrintAndLogEx(INFO, "Printing blocks from"); - PrintAndLogEx(INFO, "start " _YELLOW_("0x%02x") " end " _YELLOW_("0x%02x"), (startblock == 0) ? 6 : startblock, endblock); + PrintAndLogEx(INFO, "Printing blocks from: " _YELLOW_("%02d") " to: " _YELLOW_("%02d"), (startblock == 0) ? 6 : startblock, endblock); } PrintAndLogEx(NORMAL, ""); @@ -3400,7 +3224,7 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_lit0("r", "reverse", "reverse permuted key"), - arg_str1(NULL, "key", "", "input key"), + arg_str1(NULL, "key", "", "input key"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3593,8 +3417,8 @@ int info_iclass(void) { uint8_t cardtype = get_mem_config(hdr); PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]); - - + + } DropField(); diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 82fc8a1c4..481a5ce14 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -5444,7 +5444,7 @@ static command_t CommandTable[] = { {"esave", CmdHF14AMfESave, IfPm3Iso14443a, "Save to file emul dump"}, {"eset", CmdHF14AMfESet, IfPm3Iso14443a, "Set simulator memory block"}, {"eview", CmdHF14AMfEView, IfPm3Iso14443a, "View emul memory"}, - {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic") " -----------------------"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen1") " -----------------------"}, {"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block"}, {"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector"}, {"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump"}, diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 4c4f713f7..f2282dbfd 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -395,9 +395,9 @@ static char *getCardSizeStr(uint8_t fsize) { // is LSB set? if (fsize & 1) - snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d - %d bytes") ")", fsize, usize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X ( " _GREEN_("%d - %d bytes") " )", fsize, usize, lsize); else - snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d bytes") ")", fsize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X ( " _GREEN_("%d bytes") " )", fsize, lsize); return buf; } @@ -407,14 +407,14 @@ static char *getProtocolStr(uint8_t id, bool hw) { char *retStr = buf; if (id == 0x04) { - snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") " )", id); } else if (id == 0x05) { if (hw) - snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-2, 14443-3") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") " )", id); else - snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-3, 14443-4") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") " )", id); } else { - snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("Unknown") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("Unknown") " )", id); } return buf; } @@ -425,19 +425,21 @@ static char *getVersionStr(uint8_t major, uint8_t minor) { char *retStr = buf; if (major == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire MF3ICD40") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire MF3ICD40") " )", major, minor); else if (major == 0x01 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV1") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV1") " )", major, minor); else if (major == 0x12 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV2") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV2") " )", major, minor); + else if (major == 0x42 && minor == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV2") " )", major, minor); else if (major == 0x33 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV3") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV3") " )", major, minor); else if (major == 0x30 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire Light") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire Light") " )", major, minor); else if (major == 0x10 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("NTAG413DNA") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("NTAG413DNA") " )", major, minor); else - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x ( " _YELLOW_("Unknown") " )", major, minor); return buf; //04 01 01 01 00 1A 05 @@ -1180,7 +1182,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n key 8b cpy 8b crc 2b - padding + padding */ // Variable length ciphered key data 24-42 bytes plus padding.. @@ -1188,11 +1190,11 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n sAPDU apdu = {0x90, MFDES_CHANGE_KEY, 0x00, 0x00, 0x01, data}; // 0xC4 size_t cmdcnt = 0; - + uint8_t new_key_length = 16; switch (new_algo) { case MFDES_ALGO_DES: - // double + // double memcpy(data + cmdcnt + 1, new_key, new_key_length); memcpy(data + cmdcnt + 1 + new_key_length, new_key, new_key_length); break; @@ -1381,15 +1383,43 @@ static int handler_desfire_signature(uint8_t *signature, size_t *signature_len) return res; } -// --- KEY SETTING -static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) { +// --- KEY VERSION +static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) { + PrintAndLogEx(SUCCESS, " Key [%u] Version : %d (0x%02x)", key_idx, key_version, key_version); + return PM3_SUCCESS; +} + +static int handler_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { + if (num_versions == NULL) { + PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL"); + return PM3_EINVARG; + } + sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64 + uint32_t recv_len = 0; + uint16_t sw = 0; + int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true); + + if (res != PM3_SUCCESS) + return res; + + if (sw != status(MFDES_S_OPERATION_OK)) + return PM3_ESOFT; + + return res; +} + +// --- KEY SETTING Application Master Key +static int desfire_print_amk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) { PrintAndLogEx(SUCCESS, " AID Key settings : 0x%02x", key_settings); // 2 MSB denotes const char *str = " Max key number and type : %d, " _YELLOW_("%s"); - if (algo == MFDES_ALGO_DES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES"); - else if (algo == MFDES_ALGO_AES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "AES"); - else if (algo == MFDES_ALGO_3K3DES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "3K3DES"); + if (algo == MFDES_ALGO_DES) + PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES"); + else if (algo == MFDES_ALGO_AES) + PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "AES"); + else if (algo == MFDES_ALGO_3K3DES) + PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "3K3DES"); //PrintAndLogEx(SUCCESS, " Max number of keys in AID : %d", num_keys & 0x3F); PrintAndLogEx(INFO, "-------------------------------------------------------------"); @@ -1408,14 +1438,69 @@ static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys, int PrintAndLogEx(SUCCESS, " -- All keys (except AMK,see Bit0) within this application are frozen"); break; default: - PrintAndLogEx(SUCCESS, " -- Authentication with the specified key is necessary to change any key.\nA change key and a PICC master key (CMK) can only be changed after authentication with the master key.\nFor keys other then the master or change key, an authentication with the same key is needed."); + PrintAndLogEx(SUCCESS, + " -- Authentication with the specified key is necessary to change any key.\n" + "A change key and a PICC master key (CMK) can only be changed after authentication with the master key.\n" + "For keys other then the master or change key, an authentication with the same key is needed." + ); break; } - PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO"); - PrintAndLogEx(SUCCESS, " [0x04] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, " [0x02] Directory list access with AMK : %s", (key_settings & (1 << 1)) ? "NO" : "YES"); - PrintAndLogEx(SUCCESS, " [0x01] AMK is changeable : %s", (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO"); + PrintAndLogEx(SUCCESS, " [1000] AMK Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); + PrintAndLogEx(SUCCESS, " [0100] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? "NO" : "YES"); + PrintAndLogEx(SUCCESS, " [0010] Directory list access with AMK : %s", (key_settings & (1 << 1)) ? "NO" : "YES"); + PrintAndLogEx(SUCCESS, " [0001] AMK is changeable : %s", (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); + return PM3_SUCCESS; +} + +// --- KEY SETTING PICC Master Key (CMK) +static int desfire_print_piccmk_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) { + //PrintAndLogEx(INFO, "--- " _CYAN_("PICC Master Key (CMK) settings")); + // number of Master keys (0x01) + PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F)); + const char *str = " Operation of PICC master key : " _YELLOW_("%s"); + + if (algo == MFDES_ALGO_DES) + PrintAndLogEx(SUCCESS, str, "(3)DES"); + else if (algo == MFDES_ALGO_AES) + PrintAndLogEx(SUCCESS, str, "AES"); + else if (algo == MFDES_ALGO_3K3DES) + PrintAndLogEx(SUCCESS, str, "3K3DES"); + + uint8_t cmk_num_versions = 0; + if (handler_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions); + } + + PrintAndLogEx(INFO, " ----------------------------------------------------------"); + + // Authentication tests + int res = test_desfire_authenticate(); + if (res == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); + + res = test_desfire_authenticate_iso(); + if (res == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); + + res = test_desfire_authenticate_aes(); + if (res == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); + + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, " Key setting: 0x%02X [%c%c%c%c]", + key_settings, + (key_settings & (1 << 3)) ? '1' : '0', + (key_settings & (1 << 2)) ? '1' : '0', + (key_settings & (1 << 1)) ? '1' : '0', + (key_settings & (1 << 0)) ? '1' : '0' + ); + + PrintAndLogEx(SUCCESS, " [1...] CMK Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)"); + PrintAndLogEx(SUCCESS, " [.1..] CMK required for create/delete : %s", (key_settings & (1 << 2)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, " [..1.] Directory list access with CMK : %s", (key_settings & (1 << 1)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, " [...1] CMK is changeable : %s", (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO (frozen)"); + return PM3_SUCCESS; } @@ -1445,31 +1530,6 @@ static int handler_desfire_getkeysettings(uint8_t *key_settings, uint8_t *num_ke return res; } -// --- KEY VERSION -static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) { - PrintAndLogEx(SUCCESS, " Key [%u] Version : %d (0x%02x)", key_idx, key_version, key_version); - return PM3_SUCCESS; -} - -static int handler_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) { - if (num_versions == NULL) { - PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL"); - return PM3_EINVARG; - } - sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64 - uint32_t recv_len = 0; - uint16_t sw = 0; - int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true); - - if (res != PM3_SUCCESS) - return res; - - if (sw != status(MFDES_S_OPERATION_OK)) - return PM3_ESOFT; - - return res; -} - static int handler_desfire_getuid(uint8_t *uid) { if (uid == NULL) { PrintAndLogEx(DEBUG, "UID=NULL"); @@ -1585,14 +1645,14 @@ static int handler_desfire_select_application(uint8_t *aid) { sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, aid}; //0x5a uint32_t recv_len = 0; uint16_t sw = 0; - + int res = send_desfire_cmd(&apdu, !tag->rf_field_on, NULL, &recv_len, &sw, sizeof(dfname_t), true); if (res != PM3_SUCCESS) { PrintAndLogEx(WARNING, - _RED_(" Can't select AID 0x%X -> %s"), - (aid[2] << 16) + (aid[1] << 8) + aid[0], - GetErrorString(res, &sw) - ); + _RED_(" Can't select AID 0x%X -> %s"), + (aid[2] << 16) + (aid[1] << 8) + aid[0], + GetErrorString(res, &sw) + ); DropFieldDesfire(); return res; } @@ -1672,17 +1732,17 @@ static int handler_desfire_createapp(aidhdr_t *aidhdr, bool usename, bool usefid apdu.Lc = apdu.Lc - sizeof(aidhdr->fid); } uint8_t *data = NULL; - + // skip over FID if not used. if (usefid == false && usename) { data = calloc(apdu.Lc, sizeof(uint8_t)); apdu.data = data; - + memcpy(data, aidhdr->aid, sizeof(aidhdr->aid)); data[3] = aidhdr->keysetting1; data[4] = aidhdr->keysetting2; memcpy(data + 5, aidhdr->name, sizeof(aidhdr->name)); - + PrintAndLogEx(INFO, "new data: %s", sprint_hex_inrow(data, apdu.Lc)); } @@ -2006,6 +2066,8 @@ static int handler_desfire_create_backup_file(mfdes_file_t *file) { static int getKeySettings(uint8_t *aid) { if (aid == NULL) return PM3_EINVARG; + uint8_t num_keys = 0; + uint8_t key_setting = 0; int res = 0; if (memcmp(aid, "\x00\x00\x00", 3) == 0) { @@ -2013,50 +2075,15 @@ static int getKeySettings(uint8_t *aid) { //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings")); // KEY Settings - AMK - uint8_t num_keys = 0; - uint8_t key_setting = 0; mifare_des_authalgo_t algo = MFDES_ALGO_DES; res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys); if (res == PM3_SUCCESS) { - // number of Master keys (0x01) - PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F)); - - PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO"); - PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO"); - PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO"); - PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO"); + desfire_print_piccmk_keysetting(key_setting, num_keys, algo); } else { - PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); + PrintAndLogEx(WARNING, _RED_(" Can't read PICC Master key settings")); } - const char *str = " Operation of PICC master key : " _YELLOW_("%s"); - - if (algo == MFDES_ALGO_DES) PrintAndLogEx(SUCCESS, str, "(3)DES"); - else if (algo == MFDES_ALGO_AES) PrintAndLogEx(SUCCESS, str, "AES"); - else if (algo == MFDES_ALGO_3K3DES) PrintAndLogEx(SUCCESS, str, "3K3DES"); - - uint8_t cmk_num_versions = 0; - if (handler_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions); - PrintAndLogEx(INFO, " ----------------------------------------------------------"); - } - - // Authentication tests - res = test_desfire_authenticate(); - if (res == PM3_ETIMEOUT) return res; - PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - res = test_desfire_authenticate_iso(); - if (res == PM3_ETIMEOUT) return res; - PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - res = test_desfire_authenticate_aes(); - if (res == PM3_ETIMEOUT) return res; - PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO"); - - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - } else { // AID - APPLICATION MASTER KEYS @@ -2065,12 +2092,10 @@ static int getKeySettings(uint8_t *aid) { if (res != PM3_SUCCESS) return res; // KEY Settings - AMK - uint8_t num_keys = 0; - uint8_t key_setting = 0; mifare_des_authalgo_t algo = MFDES_ALGO_DES; res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys); if (res == PM3_SUCCESS) { - desfire_print_keysetting(key_setting, num_keys, algo); + desfire_print_amk_keysetting(key_setting, num_keys, algo); } else { PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); } @@ -2393,7 +2418,7 @@ static int CmdHF14ADesCreateApp(const char *Cmd) { if (usefid) memcpy(aidhdr.fid, fid, sizeof(aidhdr.fid)); - if (usename) + if (usename) memcpy(aidhdr.name, name, sizeof(aidhdr.name)); PrintAndLogEx(INFO, "Creating AID using:"); @@ -2405,14 +2430,14 @@ static int CmdHF14ADesCreateApp(const char *Cmd) { if (usename) PrintAndLogEx(INFO, "DF Name %s", aidhdr.name); -/* - uint8_t rootaid[3] = {0x00, 0x00, 0x00}; - int res = handler_desfire_select_application(rootaid); - if (res != PM3_SUCCESS) { - DropFieldDesfire(); - return res; - } -*/ + /* + uint8_t rootaid[3] = {0x00, 0x00, 0x00}; + int res = handler_desfire_select_application(rootaid); + if (res != PM3_SUCCESS) { + DropFieldDesfire(); + return res; + } + */ int res = handler_desfire_createapp(&aidhdr, usename, usefid); DropFieldDesfire(); @@ -3436,6 +3461,8 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information")); + PrintAndLogEx(INFO, " raw: %s", sprint_hex_inrow(info.versionHW, sizeof(info.versionHW))); + PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionHW[0])); PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionHW[1]); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionHW[2]); @@ -3444,6 +3471,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(info.versionHW[6], true)); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); + PrintAndLogEx(INFO, " raw: %s", sprint_hex_inrow(info.versionSW, sizeof(info.versionSW))); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionSW[0])); PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionSW[1]); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionSW[2]); @@ -3670,7 +3698,7 @@ static int CmdHF14ADesDump(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); CLIParserFree(ctx); - + (void)Cmd; // Cmd is not used so far DropFieldDesfire(); diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index 9abc2862c..3b260ed2e 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -1882,7 +1882,7 @@ uint32_t static em4x05_Sniff_GetBlock(char *bits, bool fwd) { if (parity != (bits[35] - '0')) parityerror = true; - if (parityerror) + if (parityerror) PrintAndLogEx(ERR, "parity error : "); if (!fwd) { diff --git a/client/src/cmdlfkeri.c b/client/src/cmdlfkeri.c index c482a7941..93e8a2521 100644 --- a/client/src/cmdlfkeri.c +++ b/client/src/cmdlfkeri.c @@ -179,68 +179,56 @@ static int CmdKeriDemod(const char *Cmd) { return demodKeri(true); } -static int CmdKeriRead(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - lf_read(false, 10000); - return demodKeri(true); -} - -static int CmdKeriClone(const char *Cmd) { - - bool q5 = false, em = false; - - uint8_t keritype[2] = {'i'}; // default to internalid - int typeLen = 0; - uint32_t fc = 0; - uint32_t cid = 0; - uint32_t internalid = 0; - uint32_t blocks[3] = { - T55x7_TESTMODE_DISABLED | - T55x7_X_MODE | - T55x7_MODULATION_PSK1 | - T55x7_PSKCF_RF_2 | - 2 << T55x7_MAXBLOCK_SHIFT, - 0, - 0 - }; - - // dynamic bitrate used - blocks[0] |= 0xF << 18; - +static int CmdKeriReader(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "lf keri clone", - "clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag", - "lf keri clone -t i --id 12345\n" - "lf keri clone -t m --fc 6 --id 12345\n"); + CLIParserInit(&ctx, "lf keri reader", + "read a keri tag", + "lf keri reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 10000); + demodKeri(!cm); + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; +} + +static int CmdKeriClone(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf keri clone", + "clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag", + "lf keri clone -t i --cn 12345 -> Internal ID\n" + "lf keri clone -t m --fc 6 --cn 12345 -> MS ID\n"); void *argtable[] = { arg_param_begin, - arg_lit0("q", "q5", "specify writing to Q5/T5555 tag"), arg_str0("t", "type", "", "Type m - MS, i - Internal ID"), arg_int0(NULL, "fc", "", "Facility Code"), - arg_int1(NULL, "id", "", "Keri ID"), - arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"), + arg_int1(NULL, "cn", "", "KERI card ID"), + arg_lit0(NULL, "q5", "specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - char cardtype[16] = {"T55x7"}; - if (arg_get_lit(ctx, 1)) { - blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT; - snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); - q5 = true; - } - if (arg_get_lit(ctx, 5)) { - blocks[0] = EM4305_KERI_CONFIG_BLOCK; - snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); - em = true; - } + uint8_t keritype[2] = {'i'}; // default to internalid + int typeLen = sizeof(keritype); + CLIGetStrWithReturn(ctx, 1, keritype, &typeLen); - typeLen = sizeof(keritype); - CLIGetStrWithReturn(ctx, 2, keritype, &typeLen); - - fc = arg_get_int_def(ctx, 3, 0); - cid = arg_get_int_def(ctx, 4, 0); + uint32_t fc = arg_get_int_def(ctx, 2, 0); + uint32_t cid = arg_get_int_def(ctx, 3, 0); + bool q5 = arg_get_lit(ctx, 4); + bool em = arg_get_lit(ctx, 5); CLIParserFree(ctx); if (q5 && em) { @@ -249,6 +237,7 @@ static int CmdKeriClone(const char *Cmd) { } // Setup card data/build internal id + uint32_t internalid = 0; switch (keritype[0]) { case 'i' : // Internal ID // MSB is ONE @@ -262,6 +251,24 @@ static int CmdKeriClone(const char *Cmd) { return PM3_EINVARG; } + uint32_t blocks[3]; + blocks[0] = T55x7_TESTMODE_DISABLED | T55x7_X_MODE | T55x7_MODULATION_PSK1 | T55x7_PSKCF_RF_2 | 2 << T55x7_MAXBLOCK_SHIFT; + // dynamic bitrate used + blocks[0] |= 0xF << 18; + + char cardtype[16] = {"T55x7"}; + + if (q5) { + blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + if (em) { + blocks[0] = EM4305_KERI_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } + + // Prepare and write to card // 3 LSB is ONE uint64_t data = ((uint64_t)internalid << 3) + 7; @@ -288,19 +295,18 @@ static int CmdKeriSim(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf keri sim", - "Enables simulation of KERI card with card number.", - "lf keri sim --id 112233" + "Enables simulation of KERI card with internal ID.\n" + "You supply a KERI card id and it will converted to a KERI internal ID.", + "lf keri sim --cn 112233" ); void *argtable[] = { arg_param_begin, - arg_int1(NULL, "id", "", "KERI Internal ID"), + arg_u64_1(NULL, "id", "", "KERI card ID"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - - uint64_t internalid = arg_get_int_def(ctx, 1, 0); - + uint64_t internalid = arg_get_u64_def(ctx, 1, 0); CLIParserFree(ctx); internalid |= 0x80000000; @@ -314,7 +320,7 @@ static int CmdKeriSim(const char *Cmd) { bs[j++] = ((internalid >> i) & 1); } - PrintAndLogEx(SUCCESS, "Simulating KERI - Internal Id: %" PRIu64, internalid); + PrintAndLogEx(SUCCESS, "Simulating KERI - Internal Id " _YELLOW_("%" PRIu64), internalid); lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs)); payload->carrier = 2; @@ -322,8 +328,6 @@ static int CmdKeriSim(const char *Cmd) { payload->clock = 32; memcpy(payload->data, bs, sizeof(bs)); - PrintAndLogEx(INFO, "Simulating"); - clearCommandBuffer(); SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs)); free(payload); @@ -338,11 +342,11 @@ static int CmdKeriSim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"}, - {"read", CmdKeriRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, - {"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"}, - {"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"}, + {"reader", CmdKeriReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, + {"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"}, + {"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfmotorola.c b/client/src/cmdlfmotorola.c index 28b6bd39b..9f700c043 100644 --- a/client/src/cmdlfmotorola.c +++ b/client/src/cmdlfmotorola.c @@ -9,22 +9,20 @@ // PSK1, RF/32, 64 bits long, at 74 kHz //----------------------------------------------------------------------------- #include "cmdlfmotorola.h" - -#include //tolower - -#include "commonutil.h" // ARRAYLEN +#include // tolower +#include "commonutil.h" // ARRAYLEN #include "common.h" #include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" #include "cmddata.h" #include "cmdlf.h" -#include "lfdemod.h" // preamble test -#include "protocols.h" // t55xx defines -#include "cmdlft55xx.h" // clone.. -#include "cmdlf.h" // cmdlfconfig -#include "cliparser.h" // cli parse input - +#include "lfdemod.h" // preamble test +#include "protocols.h" // t55xx defines +#include "cmdlft55xx.h" // clone.. +#include "cmdlf.h" // cmdlfconfig +#include "cliparser.h" // cli parse input +#include "cmdlfem4x05.h" // EM defines static int CmdHelp(const char *Cmd); @@ -124,7 +122,22 @@ static int CmdMotorolaDemod(const char *Cmd) { return demodMotorola(true); } -static int CmdMotorolaRead(const char *Cmd) { +static int CmdMotorolaReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf motorola reader", + "read a Motorola tag", + "lf motorola reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + // Motorola Flexpass seem to work at 74 kHz // and take about 4400 samples to befor modulating sample_config sc = { @@ -138,61 +151,86 @@ static int CmdMotorolaRead(const char *Cmd) { }; lf_config(&sc); - // 64 * 32 * 2 * n-ish - lf_read(false, 5000); + do { + // 64 * 32 * 2 * n-ish + lf_read(false, 5000); + demodMotorola(!cm); + } while (cm && !kbd_enter_pressed()); // reset back to 125 kHz sc.divisor = LF_DIVISOR_125; sc.samples_to_skip = 0; lf_config(&sc); - return demodMotorola(true); + + return PM3_SUCCESS; } static int CmdMotorolaClone(const char *Cmd) { - - uint32_t blocks[3] = {0}; - uint8_t data[8]; - int datalen = 0; - CLIParserContext *ctx; CLIParserInit(&ctx, "lf motorola clone", - "clone Motorola UID to T55x7 or Q5/T5555 tag\n" + "clone Motorola UID to a T55x7, Q5/T5555 or EM4305/4469 tag.\n" "defaults to 64 bit format", - "lf motorola clone -r a0000000a0002021" + "lf motorola clone --raw a0000000a0002021\n" + "lf motorola clone --q5 --raw a0000000a0002021 -> encode for Q5/T5555 tag\n" + "lf motorola clone --em --raw a0000000a0002021 -> encode for EM4305/4469" ); void *argtable[] = { arg_param_begin, - arg_strx1("r", "raw", "", "raw bytes"), - arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"), + arg_strx1("r", "raw", "", "raw hex bytes. 8 bytes"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - CLIGetHexWithReturn(ctx, 1, data, &datalen); - bool is_t5555 = arg_get_lit(ctx, 2); + + int raw_len = 0; + uint8_t raw[8]; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + bool q5 = arg_get_lit(ctx, 2); + bool em = arg_get_lit(ctx, 3); CLIParserFree(ctx); - //TODO add selection of chip for Q5 or T55x7 + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; + } - PrintAndLogEx(INFO, "Target chip " _YELLOW_("%s"), (is_t5555) ? "Q5/T5555" : "T55x7"); + //TODO add selection of chip for Q5 or T55x7 + uint32_t blocks[3] = {0}; + + blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT); + char cardtype[16] = {"T55x7"}; + // Q5 + if (q5) { + blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + // EM4305 + if (em) { + blocks[0] = EM4305_MOTOROLA_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } + + blocks[1] = bytes_to_num(raw, 4); + blocks[2] = bytes_to_num(raw + 4, 4); // config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2) - PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag"); - PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen)); - - if (is_t5555) - blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT; - else - blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT); - - - blocks[1] = bytes_to_num(data, 4); - blocks[2] = bytes_to_num(data + 4, 4); - + PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit to " _YELLOW_("%s") " with raw " _GREEN_("%s") + , cardtype + , sprint_hex_inrow(raw, sizeof(raw)) + ); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + + int res; + if (em) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola reader`") " to verify"); return res; } @@ -205,11 +243,11 @@ static int CmdMotorolaSim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdMotorolaDemod, AlwaysAvailable, "Demodulate an MOTOROLA tag from the GraphBuffer"}, - {"read", CmdMotorolaRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, - {"clone", CmdMotorolaClone, IfPm3Lf, "clone MOTOROLA tag to T55x7"}, - {"sim", CmdMotorolaSim, IfPm3Lf, "simulate MOTOROLA tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdMotorolaDemod, AlwaysAvailable, "Demodulate an MOTOROLA tag from the GraphBuffer"}, + {"reader", CmdMotorolaReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, + {"clone", CmdMotorolaClone, IfPm3Lf, "clone MOTOROLA tag to T55x7"}, + {"sim", CmdMotorolaSim, IfPm3Lf, "simulate MOTOROLA tag"}, {NULL, NULL, NULL, NULL} }; @@ -266,5 +304,5 @@ int detectMotorola(uint8_t *dest, size_t *size) { } int readMotorolaUid(void) { - return (CmdMotorolaRead("") == PM3_SUCCESS); + return (CmdMotorolaReader("") == PM3_SUCCESS); } diff --git a/client/src/cmdlfnexwatch.c b/client/src/cmdlfnexwatch.c index 8eb44c39b..3224e94a7 100644 --- a/client/src/cmdlfnexwatch.c +++ b/client/src/cmdlfnexwatch.c @@ -9,20 +9,21 @@ //----------------------------------------------------------------------------- #include "cmdlfnexwatch.h" -#include // PRIu +#include // PRIu #include -#include // tolower -#include // free, alloc - -#include "commonutil.h" // ARRAYLEN -#include "cmdparser.h" // command_t +#include // tolower +#include // free, alloc +#include "commonutil.h" // ARRAYLEN +#include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" -#include "cmddata.h" // preamblesearch +#include "cmddata.h" // preamblesearch #include "cmdlf.h" #include "lfdemod.h" -#include "protocols.h" // t55xx defines -#include "cmdlft55xx.h" // clone.. +#include "protocols.h" // t55xx defines +#include "cmdlft55xx.h" // clone.. +#include "cmdlfem4x05.h" // +#include "cliparser.h" typedef enum { SCRAMBLE, @@ -31,49 +32,6 @@ typedef enum { static int CmdHelp(const char *Cmd); -static int usage_lf_nexwatch_clone(void) { - PrintAndLogEx(NORMAL, "clone a Nexwatch tag to a T55x7 tag."); - PrintAndLogEx(NORMAL, "You can use raw hex values or create a credential based on id, mode"); - PrintAndLogEx(NORMAL, "and type of credential (Nexkey/Quadrakey)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf nexwatch clone [h] [b ] [c ] [m ] [n|q]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " r : raw hex data. 12 bytes max"); - PrintAndLogEx(NORMAL, " c : card id (decimal)"); - PrintAndLogEx(NORMAL, " m : mode (decimal) (0-15, defaults to 1)"); - PrintAndLogEx(NORMAL, " n : Nexkey credential"); - PrintAndLogEx(NORMAL, " q : Quadrakey credential"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch clone r 5600000000213C9F8F150C")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch clone c 521512301 m 1 n") " -- Nexkey credential"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch clone c 521512301 m 1 q") " -- Quadrakey credential"); - return PM3_SUCCESS; -} - -static int usage_lf_nexwatch_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of Nexwatch card"); - PrintAndLogEx(NORMAL, "You can use raw hex values or create a credential based on id, mode"); - PrintAndLogEx(NORMAL, "and type of credential (Nexkey/Quadrakey)"); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf nexwatch sim [h] [c ] [m ] [n|q]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " r : raw hex data. 16 bytes max"); - PrintAndLogEx(NORMAL, " c : card id (decimal)"); - PrintAndLogEx(NORMAL, " m : mode (decimal) (0-15, defaults to 1)"); - PrintAndLogEx(NORMAL, " n : Nexkey credential"); - PrintAndLogEx(NORMAL, " q : Quadrakey credential"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch sim r 5600000000213C9F8F150C")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch sim c 521512301 m 1 n") " -- Nexkey credential"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf nexwatch sim c 521512301 m 1 q") " -- Quadrakey credential"); - return PM3_SUCCESS; -} - // scramble parity (1234) -> (4231) static uint8_t nexwatch_parity_swap(uint8_t parity) { uint8_t a = (((parity >> 3) & 1)); @@ -263,168 +221,230 @@ static int CmdNexWatchDemod(const char *Cmd) { return demodNexWatch(true); } -//by marshmellow -//see ASKDemod for what args are accepted -static int CmdNexWatchRead(const char *Cmd) { - (void)Cmd; - lf_read(false, 20000); - return demodNexWatch(true); +static int CmdNexWatchReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf nexwatch reader", + "read a nexwatch tag", + "lf nexwatch reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 20000); + demodNexWatch(!cm); + } while (cm && !kbd_enter_pressed()); + return PM3_SUCCESS; } static int CmdNexWatchClone(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf nexwatch clone", + "clone a Nexwatch tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n" + "You can use raw hex values or create a credential based on id, mode\n" + "and type of credential (Nexkey / Quadrakey)", + "lf nexwatch clone --raw 5600000000213C9F8F150C00\n" + "lf nexwatch clone --cn 521512301 -m 1 -n -> Nexkey credential\n" + "lf nexwatch clone --cn 521512301 -m 1 -q -> Quadrakey credential\n" + ); - // 56000000 00213C9F 8F150C00 - uint32_t blocks[4]; - bool use_raw = false; - bool errors = false; - uint8_t cmdp = 0; - int datalen = 0; - uint8_t magic = 0xBE; - uint32_t cn = 0; - uint8_t rawhex[12] = {0x56, 0}; + void *argtable[] = { + arg_param_begin, + arg_str0("r", "raw", "", "raw hex data. 12 bytes"), + arg_u64_0(NULL, "cn", "", "card id"), + arg_u64_0("m", "mode", "", "mode (decimal) (0-15, defaults to 1)"), + arg_lit0("n", NULL, "Nexkey credential"), + arg_lit0("q", NULL, "Quadrakey credential"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_nexwatch_clone(); - case 'r': { - int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen); - if (res != 0) - errors = true; + int raw_len = 0; + // skip first block, 3*4 = 12 bytes left + uint8_t raw[12] = {0x56, 0}; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); - use_raw = true; - cmdp += 2; - break; - } - case 'c': { - cn = param_get32ex(Cmd, cmdp + 1, 0, 10); - uint32_t scrambled; - nexwatch_scamble(SCRAMBLE, &cn, &scrambled); - num_to_bytes(scrambled, 4, rawhex + 5); - cmdp += 2; - break; - } - case 'm': { - uint8_t mode = param_get8ex(Cmd, cmdp + 1, 1, 10); - mode &= 0x0F; - rawhex[9] |= (mode << 4); - cmdp += 2; - break; - } - case 'n': { - magic = 0x88; - cmdp++; - break; - } - case 'q': { - magic = 0xBE; - cmdp++; - break; - } - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + uint32_t cn = arg_get_u32_def(ctx, 2, -1); + uint32_t mode = arg_get_u32_def(ctx, 3, -1); + bool use_nexkey = arg_get_lit(ctx, 4); + bool use_quadrakey = arg_get_lit(ctx, 5); + bool q5 = arg_get_lit(ctx, 6); + bool em = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + + if (use_nexkey && use_quadrakey) { + PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time"); + return PM3_EINVARG; } - if (errors || cmdp == 0) return usage_lf_nexwatch_clone(); + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; + } + + // 56000000 00213C9F 8F150C00 + bool use_raw = (raw_len != 0); + + if (use_raw && cn != -1) { + PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time"); + return PM3_EINVARG; + } + + if (cn != -1) { + uint32_t scrambled; + nexwatch_scamble(SCRAMBLE, &cn, &scrambled); + num_to_bytes(scrambled, 4, raw + 5); + } + + if (mode != -1) { + if (mode > 15) { + mode = 1; + } + mode &= 0x0F; + raw[9] |= (mode << 4); + } + + uint8_t magic = 0xBE; + if (use_nexkey) + magic = 0x88; + + if (use_quadrakey) + magic = 0xBE; + + uint32_t blocks[4]; //Nexwatch - compat mode, PSK, data rate 40, 3 data blocks blocks[0] = T55x7_MODULATION_PSK1 | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT; + char cardtype[16] = {"T55x7"}; + // Q5 + if (q5) { + blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + // EM4305 + if (em) { + blocks[0] = EM4305_NEXWATCH_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } if (use_raw == false) { - uint8_t parity = nexwatch_parity(rawhex + 5) & 0xF; - rawhex[9] |= parity; - rawhex[10] |= nexwatch_checksum(magic, cn, parity); + uint8_t parity = nexwatch_parity(raw + 5) & 0xF; + raw[9] |= parity; + raw[10] |= nexwatch_checksum(magic, cn, parity); } for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { - blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); + blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); } - PrintAndLogEx(INFO, "Preparing to clone NexWatch to T55x7 with raw hex"); + PrintAndLogEx(INFO, "Preparing to clone NexWatch to " _YELLOW_("%s") " raw " _YELLOW_("%s"), cardtype, sprint_hex_inrow(raw, sizeof(raw))); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res; + if (em) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch reader`") " to verify"); return res; } static int CmdNexWatchSim(const char *Cmd) { - uint8_t cmdp = 0; - bool errors = false; - bool use_raw = false; - uint8_t rawhex[12] = {0x56, 0}; - int rawlen = sizeof(rawhex); - uint8_t magic = 0xBE; - uint32_t cn = 0; - uint8_t bs[128]; - memset(bs, 0, sizeof(bs)); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf nexwatch sim", + "Enables simulation of secura card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.\n" + "You can use raw hex values or create a credential based on id, mode\n" + "and type of credential (Nexkey/Quadrakey)", + "lf nexwatch sim --raw 5600000000213C9F8F150C00\n" + "lf nexwatch sim --cn 521512301 -m 1 -n -> Nexkey credential\n" + "lf nexwatch sim --cn 521512301 -m 1 -q -> Quadrakey credential" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_nexwatch_clone(); - case 'r': { - int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &rawlen); - if (res != 0) - errors = true; + void *argtable[] = { + arg_param_begin, + arg_str0("r", "raw", "", "raw hex data. 12 bytes"), + arg_u64_0(NULL, "cn", "", "card id"), + arg_u64_0("m", "mode", "", "mode (decimal) (0-15, defaults to 1)"), + arg_lit0("n", NULL, "Nexkey credential"), + arg_lit0("q", NULL, "Quadrakey credential"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - use_raw = true; - cmdp += 2; - break; - } - case 'c': { - cn = param_get32ex(Cmd, cmdp + 1, 0, 10); - uint32_t scrambled; - nexwatch_scamble(SCRAMBLE, &cn, &scrambled); - num_to_bytes(scrambled, 4, rawhex + 5); - cmdp += 2; - break; - } - case 'm': { - uint8_t mode = param_get8ex(Cmd, cmdp + 1, 1, 10); - mode &= 0x0F; - rawhex[9] |= (mode << 4); - cmdp += 2; - break; - } - case 'n': { - magic = 0x88; - cmdp++; - break; - } - case 'q': { - magic = 0xBE; - cmdp++; - break; - } - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + int raw_len = 0; + // skip first block, 3*4 = 12 bytes left + uint8_t raw[12] = {0x56, 0}; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + + uint32_t cn = arg_get_u32_def(ctx, 2, -1); + uint32_t mode = arg_get_u32_def(ctx, 3, -1); + bool use_nexkey = arg_get_lit(ctx, 4); + bool use_quadrakey = arg_get_lit(ctx, 5); + CLIParserFree(ctx); + + if (use_nexkey && use_quadrakey) { + PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time"); + return PM3_EINVARG; } - if (errors || cmdp == 0) return usage_lf_nexwatch_sim(); + bool use_raw = (raw_len != 0); + + if (use_raw && cn != -1) { + PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time"); + return PM3_EINVARG; + } + + if (cn != -1) { + uint32_t scrambled; + nexwatch_scamble(SCRAMBLE, &cn, &scrambled); + num_to_bytes(scrambled, 4, raw + 5); + } + + if (mode != -1) { + if (mode > 15) { + mode = 1; + } + mode &= 0x0F; + raw[9] |= (mode << 4); + } + + uint8_t magic = 0xBE; + if (use_nexkey) + magic = 0x88; + + if (use_quadrakey) + magic = 0xBE; if (use_raw == false) { - uint8_t parity = nexwatch_parity(rawhex + 5) & 0xF; - rawhex[9] |= parity; - rawhex[10] |= nexwatch_checksum(magic, cn, parity); + uint8_t parity = nexwatch_parity(raw + 5) & 0xF; + raw[9] |= parity; + raw[10] |= nexwatch_checksum(magic, cn, parity); } - // hex to bits. - uint32_t rawblocks[3]; - for (size_t i = 0; i < ARRAYLEN(rawblocks); i++) { - rawblocks[i] = bytes_to_num(rawhex + (i * sizeof(uint32_t)), sizeof(uint32_t)); - num_to_bytebits(rawblocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8)); + uint8_t bs[96]; + memset(bs, 0, sizeof(bs)); + + // hex to bits. (3 * 32 == 96) + for (size_t i = 0; i < 3; i++) { + uint32_t tmp = bytes_to_num(raw + (i * sizeof(uint32_t)), sizeof(uint32_t)); + num_to_bytebits(tmp, sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8)); } - PrintAndLogEx(SUCCESS, "Simulating NexWatch - raw: %s", sprint_hex_inrow(rawhex, rawlen)); + PrintAndLogEx(SUCCESS, "Simulating NexWatch - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw))); lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs)); payload->carrier = 2; @@ -447,11 +467,11 @@ static int CmdNexWatchSim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdNexWatchDemod, AlwaysAvailable, "Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"}, - {"read", CmdNexWatchRead, IfPm3Lf, "Attempt to Read and Extract tag data from the antenna"}, - {"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"}, - {"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdNexWatchDemod, AlwaysAvailable, "Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"}, + {"reader", CmdNexWatchReader, IfPm3Lf, "Attempt to Read and Extract tag data from the antenna"}, + {"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"}, + {"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfnoralsy.c b/client/src/cmdlfnoralsy.c index de62f2236..a49093ec8 100644 --- a/client/src/cmdlfnoralsy.c +++ b/client/src/cmdlfnoralsy.c @@ -8,52 +8,23 @@ // ASK/Manchester, STT, RF/32, 96 bits long (some bits unknown) //----------------------------------------------------------------------------- #include "cmdlfnoralsy.h" - #include #include #include - -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" #include "cmddata.h" #include "cmdlf.h" -#include "protocols.h" // for T55xx config register definitions -#include "lfdemod.h" // parityTest -#include "cmdlft55xx.h" // verifywrite +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest +#include "cmdlft55xx.h" // verifywrite +#include "cmdlfem4x05.h" // +#include "cliparser.h" static int CmdHelp(const char *Cmd); -static int usage_lf_noralsy_clone(void) { - PrintAndLogEx(NORMAL, "clone a Noralsy tag to a T55x7 or Q5/T5555 tag."); - PrintAndLogEx(NORMAL, "Usage: lf noralsy clone [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : Noralsy card ID"); - PrintAndLogEx(NORMAL, " : Tag allocation year"); - PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf noralsy clone 112233")); - return PM3_SUCCESS; -} - -static int usage_lf_noralsy_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of Noralsy card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf noralsy sim [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : Noralsy card ID"); - PrintAndLogEx(NORMAL, " : Tag allocation year"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf noralsy sim 112233")); - return PM3_SUCCESS; -} - static uint8_t noralsy_chksum(uint8_t *bits, uint8_t len) { uint8_t sum = 0; for (uint8_t i = 0; i < len; i += 4) @@ -136,28 +107,72 @@ static int CmdNoralsyDemod(const char *Cmd) { return demodNoralsy(true); } -static int CmdNoralsyRead(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - lf_read(false, 8000); - return demodNoralsy(true); +static int CmdNoralsyReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf noralsy reader", + "read a noralsy tag", + "lf noralsy reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 8000); + demodNoralsy(!cm); + } while (cm && !kbd_enter_pressed()); + return PM3_SUCCESS; } static int CmdNoralsyClone(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf noralsy clone", + "clone a noralsy tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", + "lf noralsy clone --cn 112233\n" + "lf noralsy clone --cn 112233 --q5 -> encode for Q5/T5555 tag\n" + "lf noralsy clone --cn 112233 --em -> encode for EM4305/4469" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_1(NULL, "cn", "", "Noralsy card ID"), + arg_u64_0("y", "year", "", "tag allocation year"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + uint32_t id = arg_get_u32_def(ctx, 1, 0); + uint16_t year = arg_get_u32_def(ctx, 2, 2000); + bool q5 = arg_get_lit(ctx, 3); + bool em = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; + } - uint16_t year = 0; - uint32_t id = 0; uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0}; - - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_noralsy_clone(); - - id = param_get32ex(Cmd, 0, 0, 10); - year = param_get32ex(Cmd, 1, 2000, 10); - + char cardtype[16] = {"T55x7"}; //Q5 - bool q5 = tolower(param_getchar(Cmd, 2) == 'q'); - if (q5) + if (q5) { blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + // EM4305 + if (em) { + blocks[0] = EM4305_NORALSY_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } uint8_t *bits = calloc(96, sizeof(uint8_t)); if (getnoralsyBits(id, year, bits) != PM3_SUCCESS) { @@ -172,36 +187,50 @@ static int CmdNoralsyClone(const char *Cmd) { free(bits); - PrintAndLogEx(INFO, "Preparing to clone Noralsy to " _YELLOW_("%s") " with CardId: %u", (q5) ? "Q5/T5555" : "T55x7", id); + PrintAndLogEx(INFO, "Preparing to clone Noralsy to " _YELLOW_("%s") " with Card id: " _GREEN_("%u"), cardtype, id); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res; + if (em) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy reader`") " to verify"); return res; } static int CmdNoralsySim(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf noralsy sim", + "Enables simulation of Noralsy card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.\n", + "lf noralsy sim --cn 1337\n" + "lf noralsy sim --cn 1337 --year 2010" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_1(NULL, "cn", "", "Noralsy card ID"), + arg_u64_0("y", "year", "", "tag allocation year"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + uint32_t id = arg_get_u32_def(ctx, 1, 0); + uint16_t year = arg_get_u32_def(ctx, 2, 2000); + CLIParserFree(ctx); + uint8_t bs[96]; memset(bs, 0, sizeof(bs)); - uint16_t year = 0; - uint32_t id = 0; - - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') - return usage_lf_noralsy_sim(); - - id = param_get32ex(Cmd, 0, 0, 10); - year = param_get32ex(Cmd, 1, 2000, 10); - if (getnoralsyBits(id, year, bs) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Error with tag bitstream generation."); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: %u", id); + PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: " _YELLOW_("%u") " year " _YELLOW_("%u"), id, year); lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs)); payload->encoding = 1; @@ -225,11 +254,11 @@ static int CmdNoralsySim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"}, - {"read", CmdNoralsyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, - {"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"}, - {"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"}, + {"reader", CmdNoralsyReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, + {"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"}, + {"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"}, {NULL, NULL, NULL, NULL} }; @@ -272,7 +301,6 @@ int getnoralsyBits(uint32_t id, uint16_t year, uint8_t *bits) { return PM3_SUCCESS; } -// by iceman // find Noralsy preamble in already demoded data int detectNoralsy(uint8_t *dest, size_t *size) { if (*size < 96) return -1; //make sure buffer has data diff --git a/client/src/cmdlfpac.c b/client/src/cmdlfpac.c index 211ddbca0..fbc642850 100644 --- a/client/src/cmdlfpac.c +++ b/client/src/cmdlfpac.c @@ -25,40 +25,14 @@ #include "protocols.h" // t55xx defines #include "cmdlft55xx.h" // clone #include "parity.h" +#include "cmdlfem4x05.h" // +#include "cliparser.h" static int CmdHelp(const char *Cmd); -static int usage_lf_pac_clone(void) { - PrintAndLogEx(NORMAL, "clone a PAC/Stanley tag to a T55x7 tag."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf pac clone [h] [c ] [b ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " c : 8 byte card ID"); - PrintAndLogEx(NORMAL, " b : raw hex data. 16 bytes max"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf pac clone c CD4F5552 ")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf pac clone b FF2049906D8511C593155B56D5B2649F ")); - return PM3_SUCCESS; -} -static int usage_lf_pac_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of PAC/Stanley card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, "The card ID is 8 byte number. Larger values are truncated."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf pac sim "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " : 8 byte PAC/Stanley card id"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf pac sim 12345678")); - return PM3_SUCCESS; -} - // PAC_8byte format: preamble (8 mark/idle bits), ascii STX (02), ascii '2' (32), ascii '0' (30), ascii bytes 0..7 (cardid), then xor checksum of cardid bytes // all bytes following 8 bit preamble are one start bit (0), 7 data bits (lsb first), odd parity bit, and one stop bit (1) -static int demodbuf_to_pacid(uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_size) { +static int pac_buf_to_cardid(uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_size) { const size_t byteLength = 10; // start bit, 7 data bits, parity bit, stop bit const size_t startIndex = 8 + (3 * byteLength) + 1; // skip 8 bits preamble, STX, '2', '0', and first start bit const size_t dataLength = 9; @@ -93,35 +67,33 @@ static int demodbuf_to_pacid(uint8_t *src, const size_t src_size, uint8_t *dst, return PM3_SUCCESS; } -/* // convert a 16 byte array of raw demod data (FF204990XX...) to 8 bytes of PAC_8byte ID // performs no parity or checksum validation -static void pacRawToCardId(uint8_t* outCardId, const uint8_t* rawBytes) { +static void pac_raw_to_cardid(const uint8_t* src, uint8_t *dst) { for (int i = 4; i < 12; i++) { uint8_t shift = 7 - (i + 3) % 4 * 2; size_t index = i + (i - 1) / 4; - outCardId[i - 4] = reflect8((((rawBytes[index] << 8) | (rawBytes[index + 1])) >> shift) & 0xFE); + dst[i - 4] = reflect8((((src[index] << 8) | (src[index + 1])) >> shift) & 0xFE); } } -*/ // convert 8 bytes of PAC_8byte ID to 16 byte array of raw data (FF204990XX...) -static void pacCardIdToRaw(uint8_t *outRawBytes, const char *cardId) { +static void pac_cardid_to_raw(const char *src, uint8_t *dst) { uint8_t idbytes[10]; // prepend PAC_8byte card type "20" idbytes[0] = '2'; idbytes[1] = '0'; for (size_t i = 0; i < 8; i++) - idbytes[i + 2] = toupper(cardId[i]); + idbytes[i + 2] = toupper(src[i]); // initialise array with start and stop bits for (size_t i = 0; i < 16; i++) - outRawBytes[i] = 0x40 >> (i + 3) % 5 * 2; + dst[i] = 0x40 >> (i + 3) % 5 * 2; - outRawBytes[0] = 0xFF; // mark + stop - outRawBytes[1] = 0x20; // start + reflect8(STX) + dst[0] = 0xFF; // mark + stop + dst[1] = 0x20; // start + reflect8(STX) uint8_t checksum = 0; for (size_t i = 2; i < 13; i++) { @@ -138,8 +110,8 @@ static void pacCardIdToRaw(uint8_t *outRawBytes, const char *cardId) { } pattern <<= shift; - outRawBytes[index] |= pattern >> 8 & 0xFF; - outRawBytes[index + 1] |= pattern & 0xFF; + dst[index] |= pattern >> 8 & 0xFF; + dst[index + 1] |= pattern & 0xFF; } } @@ -176,7 +148,7 @@ int demodPac(bool verbose) { const size_t idLen = 9; // 8 bytes + null terminator uint8_t cardid[idLen]; - int retval = demodbuf_to_pacid(DemodBuffer, DemodBufferLen, cardid, sizeof(cardid)); + int retval = pac_buf_to_cardid(DemodBuffer, DemodBufferLen, cardid, sizeof(cardid)); if (retval == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "PAC/Stanley - Card: " _GREEN_("%s") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4); @@ -189,93 +161,183 @@ static int CmdPacDemod(const char *Cmd) { return demodPac(true); } -static int CmdPacRead(const char *Cmd) { - (void)Cmd; - lf_read(false, 4096 * 2 + 20); - return demodPac(true); +static int CmdPacReader(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf pac reader", + "read a pac tag", + "lf pac reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 4096 * 2 + 20); + demodPac(!cm); + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; } static int CmdPacClone(const char *Cmd) { - uint32_t blocks[5]; - bool errors = false; - uint8_t cmdp = 0; - int datalen = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf pac clone", + "clone a PAC/Stanley tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", + "lf pac clone --cn CD4F5552\n" + "lf pac clone --cn CD4F5552 --q5 -> encode for Q5/T5555 tag\n" + "lf pac clone --cn CD4F5552 --em -> encode for EM4305/4469\n" + "lf pac clone --raw FF2049906D8511C593155B56D5B2649F" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_pac_clone(); - case 'c': { - // skip first block, 4*4 = 16 bytes left - uint8_t rawhex[16] = {0}; - char cardid[9]; - int res = param_getstr(Cmd, cmdp + 1, cardid, sizeof(cardid)); - if (res < 8) - errors = true; + void *argtable[] = { + arg_param_begin, + arg_str0(NULL, "cn", "", "8 byte PAC/Stanley card ID"), + arg_str0("r", "raw", "", "raw hex data. 16 bytes max"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - pacCardIdToRaw(rawhex, cardid); - for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { - blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); - } - cmdp += 2; - break; - } - case 'b': { - // skip first block, 4*4 = 16 bytes left - uint8_t rawhex[16] = {0}; - int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen); - if (res != 0) - errors = true; + uint8_t cnstr[9]; + int cnlen = 9; + memset(cnstr, 0x00, sizeof(cnstr)); + CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen); - for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { - blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); - } - cmdp += 2; - break; - } - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + // skip first block, 4*4 = 16 bytes left + int raw_len = 0; + uint8_t raw[16] = {0}; + CLIGetHexWithReturn(ctx, 2, raw, &raw_len); + + bool q5 = arg_get_lit(ctx, 3); + bool em = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; + } + if (cnlen && raw_len) { + PrintAndLogEx(FAILED, "Can't specify both CardID and raw hex at the same time"); + return PM3_EINVARG; } - if (errors || cmdp == 0) return usage_lf_pac_clone(); + if (cnlen && cnlen < 8) { + PrintAndLogEx(FAILED, "Card ID must be 8 or 9 hex digits (%d)", cnlen); + return PM3_EINVARG; + } - //Pac - compat mode, NRZ, data rate 32, 3 data blocks + if (cnlen == 8 || cnlen == 9) { + pac_cardid_to_raw((char*)cnstr, raw); + } else { + pac_raw_to_cardid(raw, cnstr); + } + + uint32_t blocks[5]; + for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { + blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); + } + + // Pac - compat mode, NRZ, data rate 32, 3 data blocks blocks[0] = T55x7_MODULATION_DIRECT | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT; + char cardtype[16] = {"T55x7"}; + // Q5 + if (q5) { + blocks[0] = T5555_FIXED | T5555_MODULATION_DIRECT | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + // EM4305 + if (em) { + blocks[0] = EM4305_PAC_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } + + PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to " _YELLOW_("%s") " with ID " _GREEN_("%s") " raw " _GREEN_("%s") + , cardtype + , cnstr + , sprint_hex_inrow(raw, sizeof(raw)) + ); - PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to T55x7 with raw hex"); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res; + if (em) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac reader`") " to verify"); return res; } static int CmdPacSim(const char *Cmd) { - // NRZ sim. - char cardid[9] = { 0 }; - uint8_t rawBytes[16] = { 0 }; - uint32_t rawBlocks[4]; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pac_sim(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf pac sim", + "Enables simulation of PAC/Stanley card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.\n" + "The card ID is 8 byte number. Larger values are truncated.", + "lf pac sim --cn CD4F5552\n" + "lf pac sim --raw FF2049906D8511C593155B56D5B2649F" + ); - int res = param_getstr(Cmd, 0, cardid, sizeof(cardid)); - if (res < 8) return usage_lf_pac_sim(); + void *argtable[] = { + arg_param_begin, + arg_str0(NULL, "cn", "", "8 byte PAC/Stanley card ID"), + arg_str0("r", "raw", "", "raw hex data. 16 bytes max"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t bs[128]; - pacCardIdToRaw(rawBytes, cardid); - for (size_t i = 0; i < ARRAYLEN(rawBlocks); i++) { - rawBlocks[i] = bytes_to_num(rawBytes + (i * sizeof(uint32_t)), sizeof(uint32_t)); - num_to_bytebits(rawBlocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8)); + uint8_t cnstr[10]; + int cnlen = 9; + memset(cnstr, 0x00, sizeof(cnstr)); + CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen); + + // skip first block, 4*4 = 16 bytes left + int raw_len = 0; + uint8_t raw[16] = {0}; + CLIGetHexWithReturn(ctx, 2, raw, &raw_len); + CLIParserFree(ctx); + + if (cnlen && raw_len) { + PrintAndLogEx(FAILED, "Can't specify both CardID and raw hex at the same time"); + return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "Simulating PAC/Stanley - ID " _YELLOW_("%s")" raw "_YELLOW_("%08X%08X%08X%08X"), cardid, rawBlocks[0], rawBlocks[1], rawBlocks[2], rawBlocks[3]); + if (cnlen && cnlen < 8) { + PrintAndLogEx(FAILED, "Card ID must be 8 or 9 hex digits (%d)", cnlen); + return PM3_EINVARG; + } + if (cnlen == 8 || cnlen == 9) { + pac_cardid_to_raw((char*)cnstr, raw); + } else { + pac_raw_to_cardid(raw, cnstr); + } + + uint8_t bs[128]; + for (size_t i = 0; i < 4; i++) { + uint32_t tmp = bytes_to_num(raw + (i * sizeof(uint32_t)), sizeof(uint32_t)); + num_to_bytebits(tmp, sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8)); + } + + PrintAndLogEx(SUCCESS, "Simulating PAC/Stanley - ID " _YELLOW_("%s")" raw " _YELLOW_("%s") + , cnstr + , sprint_hex_inrow(raw, sizeof(raw)) + ); + + // NRZ sim. lf_nrzsim_t *payload = calloc(1, sizeof(lf_nrzsim_t) + sizeof(bs)); payload->invert = 0; payload->separator = 0; @@ -297,11 +359,11 @@ static int CmdPacSim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"}, - {"read", CmdPacRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, - {"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"}, - {"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"}, + {"reader", CmdPacReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, + {"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"}, + {"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfparadox.c b/client/src/cmdlfparadox.c index 1b0aae510..08b67de1c 100644 --- a/client/src/cmdlfparadox.c +++ b/client/src/cmdlfparadox.c @@ -1,4 +1,5 @@ //----------------------------------------------------------------------------- +// Marshmellow // // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -8,13 +9,11 @@ // FSK2a, rf/50, 96 bits (completely known) //----------------------------------------------------------------------------- #include "cmdlfparadox.h" - #include #include #include #include - -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" @@ -25,40 +24,11 @@ #include "protocols.h" // t55xx defines #include "cmdlft55xx.h" // clone.. #include "crc.h" // maxim +#include "cmdlfem4x05.h" // +#include "cliparser.h" static int CmdHelp(const char *Cmd); -static int usage_lf_paradox_clone(void) { - PrintAndLogEx(NORMAL, "clone a Paradox tag to a T55x7 tag."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf paradox clone [h] [b ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " b : raw hex data. 12 bytes max"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf paradox clone b 0f55555695596a6a9999a59a")); - return PM3_SUCCESS; -} - -/* -static int usage_lf_paradox_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of Paradox card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf paradox sim [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " : 8-bit value facility code"); - PrintAndLogEx(NORMAL, " : 16-bit value card number"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf paradox sim 123 11223")); - return PM3_SUCCESS; -} -*/ - const uint8_t paradox_lut[] = { 0xDB, 0xFC, 0x3F, 0xC5, 0x50, 0x14, 0x05, 0x47, 0x9F, 0xED, 0x7D, 0x59, 0x22, 0x84, 0x21, 0x4E, @@ -71,9 +41,9 @@ const uint8_t paradox_lut[] = { #define PARADOX_PREAMBLE_LEN 8 -//by marshmellow -//Paradox Prox demod - FSK2a RF/50 with preamble of 00001111 (then manchester encoded) -//print full Paradox Prox ID and some bit format details if found +// by marshmellow +// Paradox Prox demod - FSK2a RF/50 with preamble of 00001111 (then manchester encoded) +// print full Paradox Prox ID and some bit format details if found int demodParadox(bool verbose) { (void) verbose; // unused so far @@ -204,91 +174,141 @@ static int CmdParadoxDemod(const char *Cmd) { return demodParadox(true); } -//by marshmellow -//see ASKDemod for what args are accepted -static int CmdParadoxRead(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - lf_read(false, 10000); - return demodParadox(true); +static int CmdParadoxReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf paradox reader", + "read a Paradox tag", + "lf Paradox reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 10000); + demodParadox(!cm); + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; } static int CmdParadoxClone(const char *Cmd) { - uint32_t blocks[4]; - bool errors = false; - uint8_t cmdp = 0; - int datalen = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf paradox clone", + "clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", + "lf paradox clone --raw 0f55555695596a6a9999a59a\n" + "lf paradox clone -r 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag\n" + "lf paradox clone -r 0f55555695596a6a9999a59a --em -> encode for EM4305/4469" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_paradox_clone(); - case 'b': { - // skip first block, 3*4 =12 bytes left - uint8_t rawhex[12] = {0}; - int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen); - if (res != 0) - errors = true; + void *argtable[] = { + arg_param_begin, + arg_str0("r", "raw", "", "raw hex data. 12 bytes max"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { - blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); - } - cmdp += 2; - break; - } - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + int raw_len = 0; + // skip first block, 3*4 = 12 bytes left + uint8_t raw[12] = {0}; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + + bool q5 = arg_get_lit(ctx, 2); + bool em = arg_get_lit(ctx, 3); + CLIParserFree(ctx); + + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; } - if (errors || cmdp == 0) return usage_lf_paradox_clone(); + if (raw_len != 12) { + PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len); + return PM3_EINVARG; + } - //Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks + uint32_t blocks[4]; + for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { + blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); + } + + // Paradox - FSK2a, data rate 50, 3 data blocks blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT; + char cardtype[16] = {"T55x7"}; + // Q5 + if (q5) { + blocks[0] = T5555_FIXED | T5555_INVERT_OUTPUT | T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } - PrintAndLogEx(INFO, "Preparing to clone Paradox to T55x7 with raw hex"); + // EM4305 + if (em) { + blocks[0] = EM4305_PARADOX_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } + + PrintAndLogEx(INFO, "Preparing to clone Paradox to " _YELLOW_("%s") " with raw hex", cardtype); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res; + if (em) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf paradox read`") " to verify"); return res; } static int CmdParadoxSim(const char *Cmd) { - PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); - return PM3_SUCCESS; -} -/* - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_paradox_sim(); - uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf paradox sim", + "Enables simulation of paradox card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.", + "lf paradox sim --raw 0f55555695596a6a9999a59a" + ); - uint8_t bs[96]; - memset(bs, 0x00, sizeof(bs)); + void *argtable[] = { + arg_param_begin, + arg_str0("r", "raw", "", " raw hex data. 12 bytes"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int raw_len = 0; + // skip first block, 3*4 = 12 bytes left + uint8_t raw[12] = {0}; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + CLIParserFree(ctx); + + if (raw_len != 12) { + PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len); + return PM3_EINVARG; + } + + PrintAndLogEx(SUCCESS, "Simulating Paradox - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw))); + + uint8_t bs[sizeof(raw) * 8]; + bytes_to_bytebits(raw, sizeof(raw), bs); // Paradox uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 1 FSK2a - uint8_t clk = 50, invert = 1, high = 10, low = 8; - - if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_paradox_sim(); - - facilitycode = (fc & 0x000000FF); - cardnumber = (cn & 0x0000FFFF); - - // if ( GetParadoxBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) { - // PrintAndLogEx(ERR, "Error with tag bitstream generation."); - // return 1; - // } - - PrintAndLogEx(NORMAL, "Simulating Paradox - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber); + uint8_t clk = 50, high = 10, low = 8; lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs)); payload->fchigh = high; payload->fclow = low; - payload->separator = invert; + payload->separator = 0; payload->clock = clk; memcpy(payload->data, bs, sizeof(bs)); @@ -302,15 +322,29 @@ static int CmdParadoxSim(const char *Cmd) { PrintAndLogEx(INFO, "Done"); if (resp.status != PM3_EOPABORTED) return resp.status; - return PM3_SUCCESS; -} + + return PM3_SUCCESS;} +/* + + if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_paradox_sim(); + + facilitycode = (fc & 0x000000FF); + cardnumber = (cn & 0x0000FFFF); + + // if ( GetParadoxBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) { + // PrintAndLogEx(ERR, "Error with tag bitstream generation."); + // return 1; + // } + + PrintAndLogEx(NORMAL, "Simulating Paradox - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber); + */ static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdParadoxDemod, AlwaysAvailable, "Demodulate a Paradox FSK tag from the GraphBuffer"}, - {"read", CmdParadoxRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"}, - {"clone", CmdParadoxClone, IfPm3Lf, "clone paradox tag to T55x7"}, - {"sim", CmdParadoxSim, IfPm3Lf, "simulate paradox tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdParadoxDemod, AlwaysAvailable, "Demodulate a Paradox FSK tag from the GraphBuffer"}, + {"reader", CmdParadoxReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"}, + {"clone", CmdParadoxClone, IfPm3Lf, "clone paradox tag"}, + {"sim", CmdParadoxSim, IfPm3Lf, "simulate paradox tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfpresco.c b/client/src/cmdlfpresco.c index d8bca9c19..3857cdd83 100644 --- a/client/src/cmdlfpresco.c +++ b/client/src/cmdlfpresco.c @@ -8,51 +8,64 @@ //----------------------------------------------------------------------------- #include "cmdlfpresco.h" - #include #include #include #include - -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" #include "cmddata.h" #include "cmdlf.h" -#include "protocols.h" // for T55xx config register definitions -#include "lfdemod.h" // parityTest -#include "cmdlft55xx.h" // verifywrite +#include "protocols.h" // for T55xx config register definitions +#include "lfdemod.h" // parityTest +#include "cmdlft55xx.h" // verifywrite +#include "cmdlfem4x05.h" // +#include "cliparser.h" static int CmdHelp(const char *Cmd); -static int usage_lf_presco_clone(void) { - PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 or Q5/T5555 tag."); - PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d c "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " d : 9 digit presco card ID"); - PrintAndLogEx(NORMAL, " c : 8 digit hex card number"); - PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf presco clone d 123456789")); +// find presco preamble 0x10D in already demoded data +static int detectPresco(uint8_t *dest, size_t *size) { + if (*size < 128 * 2) return -1; //make sure buffer has data + size_t startIdx = 0; + uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) + return -2; //preamble not found + if (*size != 128) return -3; //wrong demoded size + //return start position + return (int)startIdx; +} + +// convert base 12 ID to sitecode & usercode & 8 bit other unknown code +static int getWiegandFromPrintedPresco(void *arr, uint32_t *fullcode) { + char *s = (char*)arr; + uint8_t val = 0; + for (int i = 0; i < strlen(s); ++i) { + // Get value from number string. + if (s[i] == '*') + val = 10; + if (s[i] == '#') + val = 11; + if (s[i] >= 0x30 && s[i] <= 0x39) + val = s[i] - 0x30; + + *fullcode += val; + + // last digit is only added, not multipled. + if (i < strlen(s) - 1) + *fullcode *= 12; + } return PM3_SUCCESS; } -static int usage_lf_presco_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of presco card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d or c "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " d : 9 digit presco card number"); - PrintAndLogEx(NORMAL, " c : 8 digit hex card number"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf presco sim d 123456789")); +// calc not certain - intended to get bitstream for programming / sim +static int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) { + num_to_bytebits(0x10D00000, 32, prescoBits); + num_to_bytebits(0x00000000, 32, prescoBits + 32); + num_to_bytebits(0x00000000, 32, prescoBits + 64); + num_to_bytebits(fullcode, 32, prescoBits + 96); return PM3_SUCCESS; } @@ -85,15 +98,16 @@ int demodPresco(bool verbose) { uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32); - uint32_t cardid = raw4; - PrintAndLogEx(SUCCESS, "Presco - Card: " _GREEN_("%08X") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4); + uint32_t fullcode = raw4; + uint32_t usercode = fullcode & 0x0000FFFF; + uint32_t sitecode = (fullcode >> 24) & 0x000000FF; - uint32_t sitecode = 0, usercode = 0, fullcode = 0; - bool Q5 = false; - char cmd[12] = {0}; - sprintf(cmd, "H %08X", cardid); - getWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5); - PrintAndLogEx(SUCCESS, "SiteCode: " _GREEN_("%u") " UserCode: " _GREEN_("%u") " FullCode: " _GREEN_("%08X"), sitecode, usercode, fullcode); + PrintAndLogEx(SUCCESS, "Presco Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08X") " Raw: " _YELLOW_("%08X%08X%08X%08X") + , sitecode + , usercode + , fullcode + , raw1, raw2, raw3, raw4 + ); return PM3_SUCCESS; } @@ -103,35 +117,108 @@ static int CmdPrescoDemod(const char *Cmd) { } //see ASKDemod for what args are accepted -static int CmdPrescoRead(const char *Cmd) { - // Presco Number: 123456789 --> Sitecode 30 | usercode 8665 - (void)Cmd; // Cmd is not used so far - lf_read(false, 12000); - return demodPresco(true); +static int CmdPrescoReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf presco reader", + "read a presco tag", + "lf presco reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 12000); + demodPresco(!cm); + } while (cm && !kbd_enter_pressed()); + return PM3_SUCCESS; } // takes base 12 ID converts to hex // Or takes 8 digit hex ID static int CmdPrescoClone(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf presco clone", + "clone a presco tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", + "lf presco clone -d 018363467\n" + "lf presco clone -d 018363467 --q5 -> encode for Q5/T5555 tag\n" + "lf presco clone -d 018363467 --em -> encode for EM4305/4469" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("c", NULL, "", "8 digit hex card number"), + arg_str0("d", NULL, "", "9 digit presco card ID"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int hex_len = 0; + uint8_t hex[4] = {0,0,0,0}; + CLIGetHexWithReturn(ctx, 1, hex, &hex_len); + + uint8_t idstr[11]; + int slen = 9; + memset(idstr, 0x00, sizeof(idstr)); + CLIGetStrWithReturn(ctx, 2, idstr, &slen); + + bool q5 = arg_get_lit(ctx, 3); + bool em = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; + } + + uint32_t fullcode = 0; + + if (hex_len) { + fullcode = bytes_to_num(hex, hex_len); + } else { + //param get string int param_getstr(const char *line, int paramnum, char * str) + if (slen < 2) { + PrintAndLogEx(ERR, "Must contain atleast 2 digits"); + return PM3_EINVARG; + } + + getWiegandFromPrintedPresco(idstr, &fullcode); + } + + uint32_t usercode = fullcode & 0x0000FFFF; //% 65566 + uint32_t sitecode = (fullcode >> 24) & 0x000000FF; // /= 16777216; - bool Q5 = false; - uint32_t sitecode = 0, usercode = 0, fullcode = 0; uint32_t blocks[5] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT | T55x7_ST_TERMINATOR, 0, 0, 0, 0}; - // get wiegand from printed number. - if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) return usage_lf_presco_clone(); - - if (Q5) + char cardtype[16] = {"T55x7"}; + // Q5 + if (q5) { blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + // EM4305 + if (em) { + blocks[0] = EM4305_PRESCO_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } if ((sitecode & 0xFF) != sitecode) { sitecode &= 0xFF; - PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (Presco): %u", sitecode); + PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode); } if ((usercode & 0xFFFF) != usercode) { usercode &= 0xFFFF; - PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (Presco): %u", usercode); + PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode); } blocks[1] = 0x10D00000; //preamble @@ -139,25 +226,84 @@ static int CmdPrescoClone(const char *Cmd) { blocks[3] = 0x00000000; blocks[4] = fullcode; - PrintAndLogEx(INFO, "Preparing to clone Presco to " _YELLOW_("%s") " with SiteCode: %u, UserCode: %u, FullCode: %08x", (Q5) ? "Q5/T5555" : "T55x7", sitecode, usercode, fullcode); + PrintAndLogEx(INFO, "Preparing to clone Presco to " _GREEN_("%s") " with Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08x") + , cardtype + , sitecode + , usercode + , fullcode + ); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res; + if (em) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco reader`") " to verify"); return res; } // takes base 12 ID converts to hex // Or takes 8 digit hex ID static int CmdPrescoSim(const char *Cmd) { - uint32_t sitecode = 0, usercode = 0, fullcode = 0; - bool Q5 = false; - // get wiegand from printed number. - if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) - return usage_lf_presco_sim(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf presco sim", + "Enables simulation of presco card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.\n" + "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.", + "lf presco sim -d 018363467" + ); - PrintAndLogEx(SUCCESS, "Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X", sitecode, usercode, fullcode); + void *argtable[] = { + arg_param_begin, + arg_str0("c", NULL, "", "8 digit hex card number"), + arg_str0("d", NULL, "", "9 digit presco card ID"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int hex_len = 0; + uint8_t hex[4] = {0,0,0,0}; + CLIGetHexWithReturn(ctx, 1, hex, &hex_len); + + uint8_t idstr[11]; + int slen = 9; + memset(idstr, 0x00, sizeof(idstr)); + CLIGetStrWithReturn(ctx, 2, idstr, &slen); + CLIParserFree(ctx); + + uint32_t fullcode = 0; + + if (hex_len) { + fullcode = bytes_to_num(hex, hex_len); + } else { + if (slen < 2) { + PrintAndLogEx(ERR, "Must contain atleast 2 digits"); + return PM3_EINVARG; + } + getWiegandFromPrintedPresco(idstr, &fullcode); + } + + uint32_t usercode = fullcode & 0x0000FFFF; + uint32_t sitecode = (fullcode >> 24) & 0x000000FF; + + if ((sitecode & 0xFF) != sitecode) { + sitecode &= 0xFF; + PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode); + } + + if ((usercode & 0xFFFF) != usercode) { + usercode &= 0xFFFF; + PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode); + } + + PrintAndLogEx(SUCCESS, "Simulating Presco - Site Code: " _GREEN_("%u") " User Code: " _GREEN_("%u") " Full Code: " _GREEN_("%08X") + , sitecode + , usercode + , fullcode) + ; uint8_t bs[128]; getPrescoBits(fullcode, bs); @@ -185,9 +331,9 @@ static int CmdPrescoSim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"}, - {"read", CmdPrescoRead, IfPm3Lf, "Attempt to read and Extract tag data"}, - {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"}, - {"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"}, + {"reader", CmdPrescoReader, IfPm3Lf, "Attempt to read and Extract tag data"}, + {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"}, + {"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"}, {NULL, NULL, NULL, NULL} }; @@ -201,86 +347,3 @@ int CmdLFPresco(const char *Cmd) { clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); } - -// find presco preamble 0x10D in already demoded data -int detectPresco(uint8_t *dest, size_t *size) { - if (*size < 128 * 2) return -1; //make sure buffer has data - size_t startIdx = 0; - uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) - return -2; //preamble not found - if (*size != 128) return -3; //wrong demoded size - //return start position - return (int)startIdx; -} - -// convert base 12 ID to sitecode & usercode & 8 bit other unknown code -int getWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5) { - - bool hex = false, errors = false; - uint8_t cmdp = 0; - char id[11]; - int stringlen = 0; - memset(id, 0x00, sizeof(id)); - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return PM3_EINVARG; - case 'c': - hex = true; - //get hex - *fullcode = param_get32ex(Cmd, cmdp + 1, 0, 16); - cmdp += 2; - break; - case 'd': - //param get string int param_getstr(const char *line, int paramnum, char * str) - stringlen = param_getstr(Cmd, cmdp + 1, id, sizeof(id)); - if (stringlen < 2) return PM3_EINVARG; - cmdp += 2; - break; - case 'q': - *Q5 = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = 1; - break; - } - } - //Validations - if (errors || cmdp == 0) return PM3_EINVARG; - - if (!hex) { - uint8_t val = 0; - for (int index = 0; index < strlen(id); ++index) { - // Get value from number string. - if (id[index] == '*') - val = 10; - if (id[index] == '#') - val = 11; - if (id[index] >= 0x30 && id[index] <= 0x39) - val = id[index] - 0x30; - - *fullcode += val; - - // last digit is only added, not multipled. - if (index < strlen(id) - 1) - *fullcode *= 12; - } - } - - *usercode = *fullcode & 0x0000FFFF; //% 65566 - *sitecode = (*fullcode >> 24) & 0x000000FF; // /= 16777216; - return PM3_SUCCESS; -} - -// calc not certain - intended to get bitstream for programming / sim -int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) { - num_to_bytebits(0x10D00000, 32, prescoBits); - num_to_bytebits(0x00000000, 32, prescoBits + 32); - num_to_bytebits(0x00000000, 32, prescoBits + 64); - num_to_bytebits(fullcode, 32, prescoBits + 96); - return PM3_SUCCESS; -} diff --git a/client/src/cmdlfpresco.h b/client/src/cmdlfpresco.h index d90d6c573..961830ab2 100644 --- a/client/src/cmdlfpresco.h +++ b/client/src/cmdlfpresco.h @@ -12,11 +12,6 @@ #include "common.h" int CmdLFPresco(const char *Cmd); - int demodPresco(bool verbose); -int detectPresco(uint8_t *dest, size_t *size); -int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits); -int getWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5); - #endif diff --git a/client/src/cmdlfpyramid.c b/client/src/cmdlfpyramid.c index aba305b5d..452f3f61e 100644 --- a/client/src/cmdlfpyramid.c +++ b/client/src/cmdlfpyramid.c @@ -15,7 +15,6 @@ #include #include #include - #include "commonutil.h" // ARRAYLEN #include "cmdparser.h" // command_t #include "comms.h" @@ -27,43 +26,11 @@ #include "lfdemod.h" // parityTest #include "crc.h" #include "cmdlft55xx.h" // verifywrite +#include "cliparser.h" +#include "cmdlfem4x05.h" // EM Defines static int CmdHelp(const char *Cmd); -static int usage_lf_pyramid_clone(void) { - PrintAndLogEx(NORMAL, "clone a Farpointe/Pyramid tag to a T55x7 or Q5/T5555 tag."); - PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. "); - PrintAndLogEx(NORMAL, "Currently only works on 26bit"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf pyramid clone [h] [Q5]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " : 8-bit value facility code"); - PrintAndLogEx(NORMAL, " : 16-bit value card number"); - PrintAndLogEx(NORMAL, " Q5 : optional - specify writing to Q5/T5555 tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf pyramid clone 123 11223")); - return PM3_SUCCESS; -} - -static int usage_lf_pyramid_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of Farpointe/Pyramid card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated."); - PrintAndLogEx(NORMAL, "Currently work only on 26bit"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf pyramid sim [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " : 8-bit value facility code"); - PrintAndLogEx(NORMAL, " : 16-bit value card number"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf pyramid sim 123 11223")); - return PM3_SUCCESS; -} - //Pyramid Prox demod - FSK RF/50 with preamble of 0000000000000001 (always a 128 bit data stream) //print full Farpointe Data/Pyramid Prox ID and some bit format details if found int demodPyramid(bool verbose) { @@ -215,26 +182,71 @@ static int CmdPyramidDemod(const char *Cmd) { return demodPyramid(true); } -static int CmdPyramidRead(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - lf_read(false, 15000); - return demodPyramid(true); +static int CmdPyramidReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf pyramid reader", + "read a Farpointe/Pyramid tag", + "lf pyramid reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 15000); + demodPyramid(true); + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; } static int CmdPyramidClone(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pyramid_clone(); - uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0; - if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_pyramid_clone(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf pyramid clone", + "clone a Farpointe/Pyramid tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n" + "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n" + "Currently only works on 26bit", + "lf pyramid clone --fc 123 --cn 11223\n" + "lf pyramid clone --fc 123 --cn 11223 --q5 -> encode for Q5/T5555 tag\n" + "lf pyramid clone --fc 123 --cn 11223 --em -> encode for EM4305/4469" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_1(NULL, "fc", "", "8-bit value facility code"), + arg_u64_1(NULL, "cn", "", "16-bit value card number"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + uint32_t fc = arg_get_u32_def(ctx, 1, 0); + uint32_t cn = arg_get_u32_def(ctx, 2, 0); + bool q5 = arg_get_lit(ctx, 3); + bool em = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; + } + uint32_t blocks[5]; uint8_t *bs = calloc(128, sizeof(uint8_t)); if (bs == NULL) { return PM3_EMALLOC; } - facilitycode = (fc & 0x000000FF); - cardnumber = (cn & 0x0000FFFF); + uint32_t facilitycode = (fc & 0x000000FF); + uint32_t cardnumber = (cn & 0x0000FFFF); if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Error with tag bitstream generation."); @@ -243,11 +255,18 @@ static int CmdPyramidClone(const char *Cmd) { //Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4 << T55x7_MAXBLOCK_SHIFT; + char cardtype[16] = {"T55x7"}; // Q5 - bool q5 = tolower(param_getchar(Cmd, 2)) == 'q'; - if (q5) + if (q5) { blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 4 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + // EM4305 + if (em) { + blocks[0] = EM4305_PYRAMID_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } blocks[1] = bytebits_to_byte(bs, 32); blocks[2] = bytebits_to_byte(bs + 32, 32); @@ -256,36 +275,53 @@ static int CmdPyramidClone(const char *Cmd) { free(bs); - PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", (q5) ? "Q5/T5555" : "T55x7", facilitycode, cardnumber); + PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", cardtype, facilitycode, cardnumber); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res; + if (em) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid reader`") " to verify"); return res; } static int CmdPyramidSim(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf pyramid sim", + "Enables simulation of Farpointe/Pyramid card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.\n" + "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n" + "Currently work only on 26bit", + "lf pyramid sim --fc 123 --cn 1337" + ); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pyramid_sim(); + void *argtable[] = { + arg_param_begin, + arg_u64_1(NULL, "fc", "", "8-bit value facility code"), + arg_u64_1(NULL, "cn", "", "16-bit value card number"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + uint32_t fc = arg_get_u32_def(ctx, 1, 0); + uint32_t cn = arg_get_u32_def(ctx, 2, 0); + CLIParserFree(ctx); + + uint32_t facilitycode = (fc & 0x000000FF); + uint32_t cardnumber = (cn & 0x0000FFFF); - uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0; uint8_t bs[128]; memset(bs, 0x00, sizeof(bs)); - - if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_pyramid_sim(); - - facilitycode = (fc & 0x000000FF); - cardnumber = (cn & 0x0000FFFF); - if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Error with tag bitstream generation."); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber); + PrintAndLogEx(SUCCESS, "Simulating Farpointe/Pyramid - Facility Code: " _YELLOW_("%u") ", CardNumber: " _YELLOW_("%u"), facilitycode, cardnumber); // Pyramid uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 0 lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs)); @@ -309,11 +345,11 @@ static int CmdPyramidSim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "this help"}, - {"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"}, - {"read", CmdPyramidRead, IfPm3Lf, "attempt to read and extract tag data"}, - {"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"}, - {"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"}, + {"help", CmdHelp, AlwaysAvailable, "this help"}, + {"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"}, + {"reader", CmdPyramidReader, IfPm3Lf, "attempt to read and extract tag data"}, + {"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"}, + {"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfsecurakey.c b/client/src/cmdlfsecurakey.c index b5aab5fa8..9e8158c82 100644 --- a/client/src/cmdlfsecurakey.c +++ b/client/src/cmdlfsecurakey.c @@ -8,10 +8,8 @@ // ASK/Manchester, RF/40, 96 bits long (unknown cs) //----------------------------------------------------------------------------- #include "cmdlfsecurakey.h" - #include // memcpy #include // tolower - #include "commonutil.h" // ARRAYLEN #include "cmdparser.h" // command_t #include "comms.h" @@ -22,22 +20,11 @@ #include "parity.h" // for wiegand parity test #include "protocols.h" // t55xx defines #include "cmdlft55xx.h" // clone.. +#include "cliparser.h" +#include "cmdlfem4x05.h" // EM defines static int CmdHelp(const char *Cmd); -static int usage_lf_securakey_clone(void) { - PrintAndLogEx(NORMAL, "clone a Securakey tag to a T55x7 tag."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf securakey clone [h] [b ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " b : raw hex data. 12 bytes max"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf securakey clone b 7FCB400001ADEA5344300000")); - return PM3_SUCCESS; -} - //see ASKDemod for what args are accepted int demodSecurakey(bool verbose) { (void) verbose; // unused so far @@ -118,9 +105,11 @@ int demodSecurakey(bool verbose) { if (bitLen <= 32) PrintAndLogEx(SUCCESS, "Wiegand: " _GREEN_("%08X") " parity (%s)", (lWiegand << (bitLen / 2)) | rWiegand, parity ? _GREEN_("ok") : _RED_("fail")); - PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown"); - PrintAndLogEx(INFO, "How the checksum is calculated is unknown"); - PrintAndLogEx(INFO, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members"); + if (verbose) { + PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown"); + PrintAndLogEx(INFO, "How the checksum is calculated is unknown"); + PrintAndLogEx(INFO, "Help the community identify this format further\nby sharing your tag on the pm3 forum or discord"); + } return PM3_SUCCESS; } @@ -129,68 +118,160 @@ static int CmdSecurakeyDemod(const char *Cmd) { return demodSecurakey(true); } -static int CmdSecurakeyRead(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - lf_read(false, 8000); - return demodSecurakey(true); +static int CmdSecurakeyReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf securakey reader", + "read a Securakey tag", + "lf securakey reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 8000); + demodSecurakey(!cm); + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; } static int CmdSecurakeyClone(const char *Cmd) { - uint32_t blocks[4]; - bool errors = false; - uint8_t cmdp = 0; - int datalen = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf securakey clone", + "clone a Securakey tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", + "lf securakey clone --raw 7FCB400001ADEA5344300000\n" + "lf securakey clone --q5 --raw 7FCB400001ADEA5344300000 -> encode for Q5/T5555 tag\n" + "lf securakey clone --em --raw 7FCB400001ADEA5344300000 -> encode for EM4305/4469" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_securakey_clone(); - case 'b': { - // skip first block, 3*4 = 12 bytes left - uint8_t rawhex[12] = {0}; - int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen); - if (res != 0) - errors = true; + void *argtable[] = { + arg_param_begin, + arg_str0("r", "raw", "", "raw hex data. 12 bytes"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { - blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); - } - cmdp += 2; - break; - } - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + int raw_len = 0; + // skip first block, 3*4 = 12 bytes left + uint8_t raw[12] = {0}; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + bool q5 = arg_get_lit(ctx, 2); + bool em = arg_get_lit(ctx, 3); + CLIParserFree(ctx); + + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; } - if (errors || cmdp == 0) return usage_lf_securakey_clone(); + if (raw_len != 12) { + PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len); + return PM3_EINVARG; + } + + uint32_t blocks[4]; + for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { + blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t)); + } //Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks blocks[0] = T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_40 | 3 << T55x7_MAXBLOCK_SHIFT; + char cardtype[16] = {"T55x7"}; + // Q5 + if (q5) { + blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(40) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } - PrintAndLogEx(INFO, "Preparing to clone Securakey to T55x7 with raw hex"); + // EM4305 + if (em) { + blocks[0] = EM4305_SECURAKEY_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } + + PrintAndLogEx(INFO, "Preparing to clone Securakey to " _YELLOW_("%s") " with raw hex", cardtype); print_blocks(blocks, ARRAYLEN(blocks)); - int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res; + if (em) { + res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); + } else { + res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey reader`") " to verify"); return res; } static int CmdSecurakeySim(const char *Cmd) { - PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf securakey sim", + "Enables simulation of secura card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.", + "lf securakey sim --raw 7FCB400001ADEA5344300000" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("r", "raw", "", " raw hex data. 12 bytes"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int raw_len = 0; + // skip first block, 3*4 = 12 bytes left + uint8_t raw[12] = {0}; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + CLIParserFree(ctx); + + if (raw_len != 12) { + PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len); + return PM3_EINVARG; + } + + PrintAndLogEx(SUCCESS, "Simulating SecuraKey - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw))); + + uint8_t bs[sizeof(raw) * 8]; + bytes_to_bytebits(raw, sizeof(raw), bs); + + lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs)); + payload->encoding = 1; + payload->invert = 0; + payload->separator = 0; + payload->clock = 40; + memcpy(payload->data, bs, sizeof(bs)); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs)); + free(payload); + + PacketResponseNG resp; + WaitForResponse(CMD_LF_ASK_SIMULATE, &resp); + + PrintAndLogEx(INFO, "Done"); + if (resp.status != PM3_EOPABORTED) + return resp.status; + return PM3_SUCCESS; } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdSecurakeyDemod, AlwaysAvailable, "Demodulate an Securakey tag from the GraphBuffer"}, - {"read", CmdSecurakeyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, - {"clone", CmdSecurakeyClone, IfPm3Lf, "clone Securakey tag to T55x7"}, - {"sim", CmdSecurakeySim, IfPm3Lf, "simulate Securakey tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdSecurakeyDemod, AlwaysAvailable, "Demodulate an Securakey tag from the GraphBuffer"}, + {"reader", CmdSecurakeyReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, + {"clone", CmdSecurakeyClone, IfPm3Lf, "clone Securakey tag to T55x7"}, + {"sim", CmdSecurakeySim, IfPm3Lf, "simulate Securakey tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index a3ccf2052..80c8eda4f 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -1027,7 +1027,7 @@ static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) { } // Define prototype to call from within detect. -static int CmdT55xxWakeUp (const char *Cmd); +static int CmdT55xxWakeUp(const char *Cmd); static int CmdT55xxDetect(const char *Cmd) { @@ -1054,7 +1054,7 @@ static int CmdT55xxDetect(const char *Cmd) { return usage_t55xx_detect(); case 'p': password = param_get32ex(Cmd, cmdp + 1, 0, 16); - sprintf (wakecmd,"p %08x q",(uint32_t)(password & 0xFFFFFFFF)); + sprintf(wakecmd, "p %08x q", (uint32_t)(password & 0xFFFFFFFF)); usepwd = true; cmdp += 2; break; @@ -1077,7 +1077,7 @@ static int CmdT55xxDetect(const char *Cmd) { } if (errors) return usage_t55xx_detect(); - + // detect called so clear data blocks T55x7_ClearAllBlockData(); @@ -1096,11 +1096,11 @@ static int CmdT55xxDetect(const char *Cmd) { if (usewake) { // call wake if (try_with_pwd) - CmdT55xxWakeUp (wakecmd); + CmdT55xxWakeUp(wakecmd); else - CmdT55xxWakeUp ("q"); + CmdT55xxWakeUp("q"); // sleep 90 ms - nanosleep (&sleepperiod, &sleepperiod); + nanosleep(&sleepperiod, &sleepperiod); } if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false) @@ -1117,11 +1117,11 @@ static int CmdT55xxDetect(const char *Cmd) { if (usewake) { // call wake if (try_with_pwd) - CmdT55xxWakeUp (wakecmd); + CmdT55xxWakeUp(wakecmd); else - CmdT55xxWakeUp ("q"); + CmdT55xxWakeUp("q"); // sleep 90 ms - nanosleep (&sleepperiod, &sleepperiod); + nanosleep(&sleepperiod, &sleepperiod); } if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) { diff --git a/client/src/cmdlfti.c b/client/src/cmdlfti.c index dc3aeddf1..e2d7716d2 100644 --- a/client/src/cmdlfti.c +++ b/client/src/cmdlfti.c @@ -8,10 +8,10 @@ // Low frequency TI commands //----------------------------------------------------------------------------- +#include "cmdlfti.h" #include #include #include - #include "cmdparser.h" // command_t #include "commonutil.h" #include "comms.h" @@ -19,7 +19,7 @@ #include "ui.h" #include "proxgui.h" #include "graph.h" -#include "cmdlfti.h" +#include "cliparser.h" static int CmdHelp(const char *Cmd); @@ -277,10 +277,27 @@ static int CmdTIDemod(const char *Cmd) { } // read a TI tag and return its ID -static int CmdTIRead(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - clearCommandBuffer(); - SendCommandNG(CMD_LF_TI_READ, NULL, 0); +static int CmdTIReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf ti reader", + "read a TI tag", + "lf ti reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + clearCommandBuffer(); + SendCommandNG(CMD_LF_TI_READ, NULL, 0); + } while (cm && !kbd_enter_pressed()); + return PM3_SUCCESS; } @@ -300,15 +317,15 @@ static int CmdTIWrite(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0); PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti reader`") " to verify"); return PM3_SUCCESS; } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI-type LF tag from the GraphBuffer"}, - {"read", CmdTIRead, IfPm3Lf, "Read and decode a TI 134 kHz tag"}, - {"write", CmdTIWrite, IfPm3Lf, "Write new data to a r/w TI 134 kHz tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI-type LF tag from the GraphBuffer"}, + {"reader", CmdTIReader, IfPm3Lf, "Read and decode a TI 134 kHz tag"}, + {"write", CmdTIWrite, IfPm3Lf, "Write new data to a r/w TI 134 kHz tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfviking.c b/client/src/cmdlfviking.c index 4a5f534ab..0da4bcbd5 100644 --- a/client/src/cmdlfviking.c +++ b/client/src/cmdlfviking.c @@ -9,13 +9,10 @@ // ASK/Manchester, RF/32, 64 bits (complete) //----------------------------------------------------------------------------- #include "cmdlfviking.h" - #include #include #include - #include "common.h" - #include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" @@ -23,36 +20,10 @@ #include "cmdlf.h" #include "lfdemod.h" #include "commonutil.h" // num_to_bytes +#include "cliparser.h" static int CmdHelp(const char *Cmd); -static int usage_lf_viking_clone(void) { - PrintAndLogEx(NORMAL, "clone a Viking AM tag to a T55x7 or Q5/T5555 tag."); - PrintAndLogEx(NORMAL, "Usage: lf viking clone "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " : 8 digit hex viking card number"); - PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf viking clone 1A337")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf viking clone 1A337 Q5") " - encode for Q5/T5555 tag"); - return PM3_SUCCESS; -} - -static int usage_lf_viking_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of viking card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, "Per viking format, the card number is 8 digit hex number. Larger values are truncated."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf viking sim "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " : 8 digit hex viking card number"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf viking sim 1A337")); - return PM3_SUCCESS; -} - //see ASKDemod for what args are accepted int demodViking(bool verbose) { (void) verbose; // unused so far @@ -88,40 +59,90 @@ static int CmdVikingDemod(const char *Cmd) { } //see ASKDemod for what args are accepted -static int CmdVikingRead(const char *Cmd) { - (void)Cmd; - lf_read(false, 10000); - return demodViking(true); +static int CmdVikingReader(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf viking reader", + "read a Viking AM tag", + "lf viking reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 10000); + demodViking(true); + } while (cm && !kbd_enter_pressed()); + + return PM3_SUCCESS; } static int CmdVikingClone(const char *Cmd) { - uint32_t id = 0; - uint64_t rawID = 0; - bool Q5 = false; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_viking_clone(); - id = param_get32ex(Cmd, 0, 0, 16); - if (id == 0) return usage_lf_viking_clone(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf viking clone", + "clone a Viking AM tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", + "lf viking clone --cn 01A337\n" + "lf viking clone --cn 01A337 --q5 -> encode for Q5/T5555 tag\n" + "lf viking clone --cn 112233 --em -> encode for EM4305/4469" + ); - cmdp = tolower(param_getchar(Cmd, 1)); - if (cmdp == 'q') - Q5 = true; + void *argtable[] = { + arg_param_begin, + arg_strx0(NULL, "cn", "", "8 digit hex viking card number"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - rawID = getVikingBits(id); + int raw_len = 0; + uint8_t raw[4] = {0}; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + bool q5 = arg_get_lit(ctx, 2); + bool em = arg_get_lit(ctx, 3); + CLIParserFree(ctx); + + uint32_t id = bytes_to_num(raw, raw_len); + if (id == 0) { + PrintAndLogEx(ERR, "Cardnumber can't be zero"); + return PM3_EINVARG; + } + + if (q5 && em) { + PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); + return PM3_EINVARG; + } + + uint64_t rawID = getVikingBits(id); struct p { bool Q5; + bool EM; uint8_t blocks[8]; } PACKED payload; - payload.Q5 = Q5; + payload.Q5 = q5; + payload.EM = em; num_to_bytes(rawID, 8, &payload.blocks[0]); + char cardtype[16] = {"T55x7"}; + if (q5) + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + else if (em) + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + PrintAndLogEx(INFO, "Preparing to clone Viking tag on " _YELLOW_("%s") " - ID " _YELLOW_("%08X")" raw " _YELLOW_("%s") - , (Q5) ? "Q5/T5555" : "T55x7" + , cardtype , id - , sprint_hex(payload.blocks, sizeof(payload.blocks)) + , sprint_hex(payload.blocks, sizeof(payload.blocks)) ); clearCommandBuffer(); @@ -133,20 +154,40 @@ static int CmdVikingClone(const char *Cmd) { return PM3_ETIMEOUT; } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking reader`") " to verify"); return resp.status; } static int CmdVikingSim(const char *Cmd) { - uint32_t id = 0; - uint64_t rawID = 0; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_viking_sim(); - id = param_get32ex(Cmd, 0, 0, 16); - if (id == 0) return usage_lf_viking_sim(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf viking sim", + "Enables simulation of viking card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.\n" + "Per viking format, the card number is 8 digit hex number. Larger values are truncated.", + "lf viking sim --cn 01A337" + ); - rawID = getVikingBits(id); + void *argtable[] = { + arg_param_begin, + arg_strx0(NULL, "cn", "", "8 digit hex viking card number"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int raw_len = 0; + uint8_t raw[4] = {0}; + CLIGetHexWithReturn(ctx, 1, raw, &raw_len); + + uint32_t id = bytes_to_num(raw, raw_len); + if (id == 0) { + PrintAndLogEx(ERR, "Cardnumber can't be zero"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + CLIParserFree(ctx); + + uint64_t rawID = getVikingBits(id); PrintAndLogEx(SUCCESS, "Simulating Viking - ID " _YELLOW_("%08X") " raw " _YELLOW_("%08X%08X"), id, (uint32_t)(rawID >> 32), (uint32_t)(rawID & 0xFFFFFFFF)); @@ -176,7 +217,7 @@ static int CmdVikingSim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdVikingDemod, AlwaysAvailable, "Demodulate a Viking tag from the GraphBuffer"}, - {"read", CmdVikingRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"}, + {"reader", CmdVikingReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"}, {"clone", CmdVikingClone, IfPm3Lf, "clone Viking tag to T55x7 or Q5/T5555"}, {"sim", CmdVikingSim, IfPm3Lf, "simulate Viking tag"}, {NULL, NULL, NULL, NULL} @@ -201,7 +242,7 @@ uint64_t getVikingBits(uint32_t id) { ret |= checksum; return ret; } -// by marshmellow + // find viking preamble 0xF200 in already demoded data int detectViking(uint8_t *src, size_t *size) { //make sure buffer has data diff --git a/client/src/cmdlfvisa2000.c b/client/src/cmdlfvisa2000.c index 7fc3f89a5..ee145e2b9 100644 --- a/client/src/cmdlfvisa2000.c +++ b/client/src/cmdlfvisa2000.c @@ -27,41 +27,14 @@ #include "lfdemod.h" // parityTest #include "cmdlft55xx.h" // write verify #include "cmdlfem4x05.h" // +#include "cliparser.h" -#define BL0CK1 0x56495332 +#ifndef VISA2k_BL0CK1 +#define VISA2k_BL0CK1 0x56495332 +#endif static int CmdHelp(const char *Cmd); -static int usage_lf_visa2k_clone(void) { - PrintAndLogEx(NORMAL, "clone a Visa2000 tag to a T55x7 or Q5/T5555 tag."); - PrintAndLogEx(NORMAL, "Usage: lf visa2000 clone [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : Visa2k card ID"); - PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); - PrintAndLogEx(NORMAL, " : specify writing to EM4305/4469 tag"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 q5") " -- encode for Q5/T5555"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 em4305") " -- encode for EM4305/4469"); - return PM3_SUCCESS; -} - -static int usage_lf_visa2k_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of visa2k card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf visa2000 sim [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : Visa2k card ID"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 sim 112233")); - return PM3_SUCCESS; -} - static uint8_t visa_chksum(uint32_t id) { uint8_t sum = 0; for (uint8_t i = 0; i < 32; i += 4) @@ -165,47 +138,76 @@ static int CmdVisa2kDemod(const char *Cmd) { } // 64*96*2=12288 samples just in case we just missed the first preamble we can still catch 2 of them -static int CmdVisa2kRead(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - lf_read(false, 20000); - return demodVisa2k(true); +static int CmdVisa2kReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf visa2000 reader", + "read a visa2000 tag", + "lf visa2000 reader -@ -> continuous reader mode" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + do { + lf_read(false, 20000); + demodVisa2k(!cm); + } while (cm && !kbd_enter_pressed()); + return PM3_SUCCESS; } static int CmdVisa2kClone(const char *Cmd) { - uint64_t id = 0; - uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, BL0CK1, 0}; + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf visa2000 clone", + "clone a Visa2000 tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", + "lf visa2000 clone --cn 112233\n" + "lf visa2000 clone --cn 112233 --q5 -> encode for Q5/T5555 tag\n" + "lf visa2000 clone --cn 112233 --em -> encode for EM4305/4469" + ); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') - return usage_lf_visa2k_clone(); + void *argtable[] = { + arg_param_begin, + arg_u64_1(NULL, "cn", "", "Visa2k card ID"), + arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), + arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - id = param_get32ex(Cmd, 0, 0, 10); - - char cardtype[16] = {"T55x7"}; - // Q5 - bool q5 = tolower(param_getchar(Cmd, 1)) == 'q'; - if (q5) { - blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; - snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); - } - - // EM4305 - bool em = tolower(param_getchar(Cmd, 1)) == 'e'; - if (em) { - blocks[0] = EM4305_VISA2000_CONFIG_BLOCK; - snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); - } + uint32_t id = arg_get_u32_def(ctx, 1, 0); + bool q5 = arg_get_lit(ctx, 2); + bool em = arg_get_lit(ctx, 3); + CLIParserFree(ctx); if (q5 && em) { PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); return PM3_EINVARG; } + uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, VISA2k_BL0CK1, 0}; + char cardtype[16] = {"T55x7"}; + // Q5 + if (q5) { + blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; + snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); + } + + // EM4305 + if (em) { + blocks[0] = EM4305_VISA2000_CONFIG_BLOCK; + snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); + } + blocks[2] = id; blocks[3] = (visa_parity(id) << 4) | visa_chksum(id); - PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, cardtype, id); + PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu32, cardtype, id); print_blocks(blocks, ARRAYLEN(blocks)); int res; @@ -215,22 +217,31 @@ static int CmdVisa2kClone(const char *Cmd) { res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); } PrintAndLogEx(SUCCESS, "Done"); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 read`") " to verify"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 reader`") " to verify"); return res; } static int CmdVisa2kSim(const char *Cmd) { - uint32_t id = 0; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') - return usage_lf_visa2k_sim(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf visa2000 sim", + "Enables simulation of visa2k card with specified card number.\n" + "Simulation runs until the button is pressed or another USB command is issued.\n", + "lf visa2000 sim --cn 1337" + ); - id = param_get32ex(Cmd, 0, 0, 10); + void *argtable[] = { + arg_param_begin, + arg_u64_1(NULL, "cn", "", "Visa2k card ID"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + uint32_t id = arg_get_u32_def(ctx, 1, 0); + CLIParserFree(ctx); - PrintAndLogEx(SUCCESS, "Simulating Visa2000 - CardId: %u", id); + PrintAndLogEx(SUCCESS, "Simulating Visa2000 - CardId:" _YELLOW_("%u"), id); - uint32_t blocks[3] = { BL0CK1, id, (visa_parity(id) << 4) | visa_chksum(id) }; + uint32_t blocks[3] = { VISA2k_BL0CK1, id, (visa_parity(id) << 4) | visa_chksum(id) }; uint8_t bs[96]; for (int i = 0; i < 3; ++i) @@ -257,11 +268,11 @@ static int CmdVisa2kSim(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"}, - {"read", CmdVisa2kRead, IfPm3Lf, "attempt to read and extract tag data from the antenna"}, - {"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"}, - {"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"}, + {"reader", CmdVisa2kReader, IfPm3Lf, "attempt to read and extract tag data from the antenna"}, + {"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"}, + {"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdmain.c b/client/src/cmdmain.c index 551f5ccf6..c55c7792e 100644 --- a/client/src/cmdmain.c +++ b/client/src/cmdmain.c @@ -120,7 +120,7 @@ static int lf_search_plus(const char *Cmd) { return retval; } -static int CmdAuto(const char *Cmd) { +static int CmdAuto(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "auto", "Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE", @@ -136,7 +136,7 @@ static int CmdAuto(const char *Cmd) { PrintAndLogEx(INFO, "lf search"); int ret = CmdLFfind(""); - if (ret == PM3_SUCCESS) + if (ret == PM3_SUCCESS) return ret; PrintAndLogEx(INFO, "hf search"); @@ -193,7 +193,7 @@ static int CmdHints(const char *Cmd) { PrintAndLogEx(ERR, "you can't turn off and on at the same time"); return PM3_EINVARG; } - + if (turn_off) { session.show_hints = false; } else if (turn_on) { diff --git a/client/src/crypto/asn1dump.c b/client/src/crypto/asn1dump.c index f1addb9e2..cae25c1b6 100644 --- a/client/src/crypto/asn1dump.c +++ b/client/src/crypto/asn1dump.c @@ -116,7 +116,7 @@ static void asn1_tag_dump_str_time(const struct tlv *tlv, const struct asn1_tag if (longyear == false) PrintAndLogEx(NORMAL, "20" NOLF); - PrintAndLogEx(NORMAL, "%s-" NOLF, sprint_hex(tlv->value, startindx) ); + PrintAndLogEx(NORMAL, "%s-" NOLF, sprint_hex(tlv->value, startindx)); if (len < startindx + 2) break; @@ -276,7 +276,7 @@ static void asn1_tag_dump_object_id(const struct tlv *tlv, const struct asn1_tag asn1_buf.p = (uint8_t *)tlv->value; char pstr[300]; mbedtls_oid_get_numeric_string(pstr, sizeof(pstr), &asn1_buf); - + PrintAndLogEx(INFO, "%*s %s" NOLF, (level * 4), " ", pstr); char *jsondesc = asn1_oid_description(pstr, true); diff --git a/client/src/emv/emv_tags.c b/client/src/emv/emv_tags.c index 661df0e5e..f86b88826 100644 --- a/client/src/emv/emv_tags.c +++ b/client/src/emv/emv_tags.c @@ -462,9 +462,9 @@ static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *ta if (val & 0x80) { PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " "); PrintAndLogEx(NORMAL, " %s - '%s'", - bitstrings[bit - 1], - (bits->bit == EMV_BIT(byte, bit)) ? bits->name : "Unknown" - ); + bitstrings[bit - 1], + (bits->bit == EMV_BIT(byte, bit)) ? bits->name : "Unknown" + ); } if (bits->bit == EMV_BIT(byte, bit)) bits ++; @@ -535,10 +535,10 @@ static void emv_tag_dump_numeric(const struct tlv *tlv, const struct emv_tag *ta static void emv_tag_dump_yymmdd(const struct tlv *tlv, const struct emv_tag *tag, int level) { PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " "); PrintAndLogEx(NORMAL, " Date: 20%02lu.%lu.%lu", - emv_value_numeric(tlv, 0, 2), - emv_value_numeric(tlv, 2, 4), - emv_value_numeric(tlv, 4, 6) - ); + emv_value_numeric(tlv, 0, 2), + emv_value_numeric(tlv, 2, 4), + emv_value_numeric(tlv, 4, 6) + ); } static uint32_t emv_get_binary(const unsigned char *S) { @@ -749,12 +749,12 @@ static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *t PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " "); PrintAndLogEx(NORMAL, " %02x %02x: '%s' '%s' and '%s' if this CVM is unsuccessful", - tlv->value[i], - tlv->value[i + 1], - method, - condition, - (tlv->value[i] & 0x40) ? "continue" : "fail" - ); + tlv->value[i], + tlv->value[i + 1], + method, + condition, + (tlv->value[i] & 0x40) ? "continue" : "fail" + ); } } diff --git a/client/src/emv/emvcore.c b/client/src/emv/emvcore.c index 913316725..7982ff711 100644 --- a/client/src/emv/emvcore.c +++ b/client/src/emv/emvcore.c @@ -778,7 +778,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { if (sdad_tlv) { PrintAndLogEx(INFO, "* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA..."); - const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true); + struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true); if (!atc_db) { PrintAndLogEx(ERR, "Error: Can't recover IDN (ICC Dynamic Number)"); emv_pk_free(pk); @@ -804,9 +804,10 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { emv_pk_free(pk); emv_pk_free(issuer_pk); emv_pk_free(icc_pk); - atc_db = NULL; + tlvdb_free(atc_db); return 9; } + } else { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { diff --git a/client/src/fido/fidocore.c b/client/src/fido/fidocore.c index abe3f28ce..fcebb2674 100644 --- a/client/src/fido/fidocore.c +++ b/client/src/fido/fidocore.c @@ -541,7 +541,7 @@ int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, b res = CborGetArrayBinStringValue(&mapsmt, der, sizeof(der), &derLen); cbor_check(res); if (verbose2) { - PrintAndLogEx(INFO, "DER certificate[%zu]:", derLen); + PrintAndLogEx(INFO, "DER certificate[%zu]:", derLen); PrintAndLogEx(INFO, "------------------DER-------------------"); PrintAndLogEx(INFO, "%s", sprint_hex(der, derLen)); PrintAndLogEx(INFO, "----------------DER---------------------"); diff --git a/client/src/loclass/elite_crack.c b/client/src/loclass/elite_crack.c index a559b4e7b..3defe5560 100644 --- a/client/src/loclass/elite_crack.c +++ b/client/src/loclass/elite_crack.c @@ -468,9 +468,9 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]) { mbedtls_des_setkey_enc(&ctx_e, key64_stdformat); mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result); - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "-- High security custom key (Kcus) --"); - PrintAndLogEx(SUCCESS, "Standard format %s", sprint_hex(key64_stdformat, 8)); + PrintAndLogEx(SUCCESS, "Standard format " _GREEN_("%s"), sprint_hex(key64_stdformat, 8)); PrintAndLogEx(SUCCESS, "iClass format %s", sprint_hex(key64, 8)); if (master_key != NULL) diff --git a/client/src/util.c b/client/src/util.c index 2e1cfb0bd..e9fd171e2 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -212,23 +212,23 @@ void print_buffer(const uint8_t *data, const size_t len, int level) { // (16 * 3) + (16) + + 1 memset(buf, 0, sizeof(buf)); sprintf(buf, "%*s%02x: ", (level * 4), " ", i); - - hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, 16, (sizeof(buf) - strlen(buf) - 1), 0, 1, true); + + hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, 16, (sizeof(buf) - strlen(buf) - 1), 0, 1, true); snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, 16)); PrintAndLogEx(INFO, "%s", buf); } - + // the last odd bytes uint8_t mod = len % 16; - + if (mod) { memset(buf, 0, sizeof(buf)); sprintf(buf, "%*s%02x: ", (level * 4), " ", i); hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, mod, (sizeof(buf) - strlen(buf) - 1), 0, 1, true); - + // add the spaces... - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%*s", ((16 - mod) * 3) , " "); - + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%*s", ((16 - mod) * 3), " "); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, mod)); PrintAndLogEx(INFO, "%s", buf); } @@ -446,6 +446,25 @@ void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) { } } +void bytes_to_bytebits(void* src, size_t srclen, void* dest) { + + uint8_t *s = (uint8_t*)src; + uint8_t *d = (uint8_t*)dest; + + uint32_t i = srclen * 8; + while (srclen--) { + uint8_t b = s[srclen]; + d[--i] = (b >> 0) & 1; + d[--i] = (b >> 1) & 1; + d[--i] = (b >> 2) & 1; + d[--i] = (b >> 3) & 1; + d[--i] = (b >> 4) & 1; + d[--i] = (b >> 5) & 1; + d[--i] = (b >> 6) & 1; + d[--i] = (b >> 7) & 1; + } +} + // aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp // to // hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii diff --git a/client/src/util.h b/client/src/util.h index 51100731e..28ca74917 100644 --- a/client/src/util.h +++ b/client/src/util.h @@ -56,6 +56,7 @@ void print_blocks(uint32_t *data, size_t len); int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen); void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest); void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest); +void bytes_to_bytebits(void* src, size_t srclen, void* dest); // Swap endian on arrays up to 64bytes. uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); diff --git a/doc/T5577_Guide.md b/doc/T5577_Guide.md new file mode 100644 index 000000000..cdffadd20 --- /dev/null +++ b/doc/T5577_Guide.md @@ -0,0 +1,694 @@ +# T5577 Introduction Guide + +### Based on RRG proxmark3 fork. + +### Ver.1 8 Sep 2019 + +| Contents | +| ----------------------------------------------------------------------------------- | +| [Part 1](#part-1) | +| [Introduction](#introduction) | +| [T5577 Overview](#t5577-overview) | +| [What data is on my T5577](#what-data-is-on-my-t5577) | +| [Read and Write Blocks of Data](#read-and-write-blocks-of-data) | +| [Exercise 1](#exercise-1) | +| [How do I use a password](#how-do-i-use-a-password) | +| | +| [Part 2 – Configuration Blocks](#part-2-configuration-blocks) | +| [The configuration Block – Block 0 Page 0](#the-configuration-block-block-0-page-0) | +| [Exercise 2](#exercise-2) | +| [The configuration Block – Block 3 Page 1](#the-configuration-block-block-3-page-1) | + +# Part 1 + +## Introduction + +The T5577 is a generic LF (Low Frequency) RFID card the is used in the +125 Khz frequency space. It is a good card to use to learn about RFID and +learn how to use the proxmark3. + +It is highly recommend that when learning about RFID that learning how +to read the data sheets be near the top of the list. It can be very hard +as the data sheet will hold the information you need, but you don’t yet +know what it means. As such, I will attempt to point to sections of the +data sheet and would highly advise that you look at the data sheet as +you go. Overtime the data sheet may change, as a result things may not +always be reference correctly. + +As at writing this guide, the data sheet can be found at : + + + +This guide is not a how do I clone document. It is meant to help people +learn how to use the T5577 and in the process learn about rfid and the +proxmark3. + +Throughout this guide I will give examples. It is recommended that you +try these as we go. To do so, have a blank T5577 card that you can use +for this purpose. + +## T5577 Overview + +The T5577 is a chip that can hold data and a configuration (Section +4.12). + +In the diagram below, all white blocks can hold data. Some can be used +for a second purpose, such as the ‘password’ and ‘traceability data’. +The ‘Configuration Data’ and ‘Analog front end option setup’ will tell +the chip how to behave. + +![](./t55xx_mem_map.png) + + + +## What data is on my T5577 + +Let’s have a look and see what a card might look in the proxmark3 +software. Since we can change the configuration of how the T5577 will +output data, the proxmark3 software need to work out how to interpreted +the data it receives, we do this with the following command. + +It should be noted that the T5577 has many clones. As such the default +setup of each card may be different. If the tractability data is +present, then this will vary based on the batch of cards. + +Always run this command when you place a t5577 on the proxmark3. In all +examples shown, it will be assumed you have run the detect command. +``` +[usb] pm3 --> lf t55xx detect +``` +You should see a results simular to the following: +``` + Chip Type : T55x7 + Modulation : ASK + Bit Rate : 2 - RF/32 + Inverted : No + Offset : 32 + Seq. Term. : Yes + Block0 : 0x000880E0 + Downlink Mode : default/fixed bit length +``` +Now that the proxmark3 has detected a T55x7 chip, and found some +information about it, we should be able to see all the data on the chip. +``` +[usb] pm3 --> lf t55xx dump +``` +Your results should look similar to the following: +``` +[+] Reading Page 0: +[+] blk | hex data | binary | ascii +[+] ----+----------+----------------------------------+------- +[+] 00 | 000880E0 | 00000000000010001000000011100000 | .... +[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] Reading Page 1: +[+] blk | hex data | binary | ascii +[+] ----+----------+----------------------------------+------- +[+] 00 | 000880E0 | 00000000000010001000000011100000 | .... +[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H +[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#. +[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | .... +``` +I will cover the meaning of this data as we go, but for now, lets keep +it simple. + +## Read and Write Blocks of Data + +The basic function of using the proxmark3 with rfid cards is to read and +write data. This reading and writing must be done in the correct way +needed for the chip (and its configuration). Lucky for us, the +developers have done a great job and gave us commands. What we need to +know is that with the T5577 data is read/written one complete block at a +time. Each block holds 32 bits of data (hence the binary output shown) + +Since we know that the card has data and configuration blocks, lets say +away from those while we learn how to read and write. I suggest you +follow along and perform each command and check the results as we go. + +We can store our own data in blocks 1-7 (remember that block 7 will be +needed if we want to set a password). + +(Don’t forget to run the detect command: lf t55xx detect, and ensure you +can see the card) + +1) Check what is stored in block 1. The following command can be read + as, run a low frequency (lf) command for the T55xx chip (t55xx) and + read block (b) number 1. + ``` + [usb] pm3 --> lf t55xx read b 1 + ``` + result: + ``` + [+] Reading Page 0: + [+] blk | hex data | binary | ascii + [+] ----+----------+----------------------------------+------- + [+] 01 | FFFFFFFF | 11111111111111111111111111111111 | .... + ``` + Note: Depending on the history of your card your data may vary, but + should match the dump data. + +2) Write some new data into block 1 on the card. + + We use the d option to supply the data ‘12345678’ + ``` + [usb] pm3 --> lf t55xx write b 1 d 12345678 + ``` + result: + ``` + [=] Writing page 0 block: 01 data: 0x12345678 + ``` +3) Now, lets check if the data was written. + ``` + [usb] pm3 --> lf t55xx read b 1 + ``` + result: + ``` + [+] Reading Page 0: + [+] blk | hex data | binary | ascii + [+] ----+----------+----------------------------------+------- + [+] 01 | 12345678 | 00010010001101000101011001111000 | .4Vx + ``` +4) The data is written in Hexadecimal. A single hex digit holds 4 bits + of data. So to store 32 bits in a block we need to supply 8 hex + digits (8 \* 4 = 32). If you are familiar with hex and binary do a + little bit of home work to learn. The following is a quick start. + + | Hex | Binary | Decimal | + |:---:|:------:|:-------:| + | 0 | 0000 | 0 | + | 1 | 0001 | 1 | + | 2 | 0010 | 2 | + | 3 | 0011 | 3 | + | 4 | 0100 | 4 | + | 5 | 0101 | 5 | + | 6 | 0110 | 6 | + | 7 | 0111 | 7 | + | 8 | 1000 | 8 | + | 9 | 1001 | 9 | + | A | 1010 | 10 | + | B | 1011 | 11 | + | C | 1100 | 12 | + | D | 1101 | 13 | + | E | 1110 | 14 | + | F | 1111 | 15 | + + To use all the bits we supply the data in Hex format and it will + always be 8 hex digits. + + Lets try and write 89ABCDEF + ``` + [usb] pm3 --> lf t55xx write b 1 d 89abcdef + ``` + result: + ``` + [=] Writing page 0 block: 01 data: 0x89ABCDEF + ``` + and check + ``` + [usb] pm3 --> lf t55xx read b 1 + ``` + result: + ``` + [+] Reading Page 0: + [+] blk | hex data | binary | ascii + [+] ----+----------+----------------------------------+------- + [+] 01 | 89ABCDEF | 10001001101010111100110111101111 | .... + ``` + +### Exercise 1 + +Using the read and write commands you have learnt see if you can make +the lf t55 dump command show the following data for blocks 1-7 (Page 0). +Do not write to block 0 or try and change the data on page 1. +``` +[usb] pm3 --> lf t55 dump +``` +result: +``` +[+] Reading Page 0: +[+] blk | hex data | binary | ascii +[+] ----+----------+----------------------------------+------- +[+] 00 | 000880E0 | 00000000000010001000000011100000 | .... +[+] 01 | 89ABCDEF | 10001001101010111100110111101111 | .... +[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | .... +[+] Reading Page 1: +[+] blk | hex data | binary | ascii +[+] ----+----------+----------------------------------+------- +[+] 00 | 000880E0 | 00000000000010001000000011100000 | .... +[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H +[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#. +[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | .... +``` + +Practice reading and writing to blocks 1 to 7 until you are happy you +can do it and get the results you wanted (i.e. the data you want stored +is written to the block you want it stored in). + +## How do I use a password + +This can be a little tricky for beginners. +***If you forget your password you will lose access to your card***. + +To tell the T5577 to use a password we have to change the data in the +configuration block (0). To help learn this and make it as simple as I +can, please read and follow exactly. If your results DON’T match 100% as +required, please do not proceed. + +1) Lets start with a known card state and wipe the card. This will set + a default configuration to block 0 and set all the data in blocks + 1-7 to a default. + ``` + [usb] pm3 --> lf t55xx wipe + ``` + Result: + ``` + [=] Begin wiping T55x7 tag + + [=] Default configation block 000880E0 + [=] Writing page 0 block: 00 data: 0x000880E0 + [=] Writing page 0 block: 01 data: 0x00000000 + [=] Writing page 0 block: 02 data: 0x00000000 + [=] Writing page 0 block: 03 data: 0x00000000 + [=] Writing page 0 block: 04 data: 0x00000000 + [=] Writing page 0 block: 05 data: 0x00000000 + [=] Writing page 0 block: 06 data: 0x00000000 + [=] Writing page 0 block: 07 data: 0x00000000 + ``` + +2) Check that the card is in the desired state. + ``` + [usb] pm3 --> lf t55xx detect + ``` + result: + ``` + Chip Type : T55x7 + Modulation : ASK + Bit Rate : 2 - RF/32 + Inverted : No + Offset : 32 + Seq. Term. : Yes + Block0 : 0x000880E0 + Downlink Mode : default/fixed bit length + ``` + + If block 0 does not hold the hex data **0x00088040 resolve this + first before proceeding.** + +3) Set the password we want to use. For this example lets use the + password : ***12345678*** + + The password is saved in block 7 of page 0. + ``` + [usb] pm3 --> lf t55xx write b 7 d 12345678 + ``` + result: + ``` + [=] Writing page 0 block: 07 data: 0x12345678 + ``` + +4) Lets verify both block 0 and block 7 + ``` + [usb] pm3 --> lf t55xx dump + ``` + result: + ``` + [+] Reading Page 0: + [+] blk | hex data | binary | ascii + [+] ----+----------+----------------------------------+------- + [+] 00 | 000880E0 | 00000000000010001000000011100000 | .... + [+] 01 | FFFFFFFF | 11111111111111111111111111111111 | .... + [+] 02 | FFFFFFFF | 11111111111111111111111111111111 | .... + [+] 03 | FFFFFFFF | 11111111111111111111111111111111 | .... + [+] 04 | FFFFFFFF | 11111111111111111111111111111111 | .... + [+] 05 | FFFFFFFF | 11111111111111111111111111111111 | .... + [+] 06 | FFFFFFFF | 11111111111111111111111111111111 | .... + [+] 07 | 12345678 | 00010010001101000101011001111000 | .4Vx + [+] Reading Page 1: + [+] blk | hex data | binary | ascii + [+] ----+----------+----------------------------------+------- + [+] 00 | 000880E0 | 00000000000010001000000011100000 | .... + [+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H + [+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#. + [+] 03 | FFFFFFFF | 11111111111111111111111111111111 | .... + ``` + ***Important : If block 0 and block 7 don’t match exactly, do not continue.*** + +5) Now we have a known configuration block and a known password of + 12345678, we are ready to tell the card to use the password. + + To do this the datasheet tells us we need to set the 28th + bit “PWD”. Check your datasheet and see the entire table (remember + the data sheet is your friend). + + ![](./t55xx_block0.png) + + We will cover other things in the configuration later. But the key + note here is we ONLY want to change bit 28 and nothing else. + + Current Block 0 : ***00088040*** + New Block 0 : ***00088050*** + + To understand what happened to get from 00088040 to 00088050 we need + to look at the binary data. + + While this can be confusing it is important to understand this as we + do more advanced things. + + Bit Location (28) + 000000000011111111112222222 ***2*** 2233 + 123456789012345678901234567 ***8*** 9012 + + | Hex Data | Binary Data | + |:--------:|:---------------------------------------| + | 00088040 | 000000000000100010000000010***0***0000 | + | 00088050 | 000000000000100010000000010***1***0000 | + + + + See how in the above we change the bit in location 28 from a 0 to 1 + 0 = No Password, 1 = Use Password + + Note how we did NOT change any other part of the configuration, only bit 28. + + To re-cap. + We put the card into a known configuration Block 0 : 00088040 + We set the a known password Block 7 : 12345678 + We altered the config data to tell the T5577 to use the password. + New Block 0 : 00088050 + + If you have completed all steps and have the exact same results, we are + ready to apply the new configuration. + ``` + [usb] pm3 --> lf t55xx write b 0 d 00088050 + ``` + result: + ``` + [=] Writing page 0 block: 00 data: 0x00088050 + ``` + +6) Lets check what happens when the password is set. + ``` + [usb] pm3 --> lf t55 detect + ``` + result: + ``` + [!] Could not detect modulation automatically. Try setting it manually with 'lf t55xx config' + ``` + Note how the lf t55 detect no longer seems to work\! + + In this case, this is due to needing a password to read/write to the + card. + + Lets try again, but this time supply the password. We use the option + p followed by the password. + ``` + [usb] pm3 --> lf t55 detect p 12345678 + ``` + result: + ``` + Chip Type : T55x7 + Modulation : ASK + Bit Rate : 2 - RF/32 + Inverted : No + Offset : 32 + Seq. Term. : Yes + Block0 : 0x00088050 + Downlink Mode : default/fixed bit length + ``` + +7) Write a block of data with a password + ``` + [usb] pm3 --> lf t55xx write b 1 d 1234abcd p 12345678 + ``` + result: + ``` + [=] Writing page 0 block: 01 data: 0x1234ABCD pwd: 0x12345678 + ``` + +8) Read a block of data with a password + + ***\*\*\*\* Important \*\*\*\**** + + ***Reading a T5577 block with a password when a password is not + enabled can result in locking the card. Please only use read with a + password when it is known that a password is in use.*** + + The proxmark3 has a safety check\! + ``` + [usb] pm3 --> lf t55xx read b 1 p 12345678 + ``` + result: + ``` + [+] Reading Page 0: + [+] blk | hex data | binary | ascii + [+] ----+----------+----------------------------------+------- + [!] Safety check: Could not detect if PWD bit is set in config block. Exits. + ``` + + Note that the proxmark3 did not read the block, the safty kicked in + and wants us to confirm by supply the override option ‘o’. + + Lets try again with the ‘o’ option as we know the password is set. + ``` + [usb] pm3 --> lf t55xx read b 1 p 12345678 o + ``` + result: + ``` + [+] Reading Page 0: + [+] blk | hex data | binary | ascii + [+] ----+----------+----------------------------------+------- + [=] Safety check overridden - proceeding despite risk + [+] 01 | 1234ABCD | 00010010001101001010101111001101 | .4.. + ``` + This time, we can see the data we wrote to block 1 is found with the + read command. + +9) Remove the need to supply the password. + + To do this we need to clear Bit 28 (set to 0) in the config. We have + this from above. + + Remember if we don’t know the config and write this config to the + card, it will over write all other settings. This can recoved the + card, but will lose any settings you may want. So it’s a good idea + to read the config, and set bit 28 to 0, rather than just overwrite + the config and change the way the card works. + + In our examples we know what it should be : 00088040 + ``` + [usb] pm3 --> lf t55xx write b 0 d 00088040 p 12345678 + ``` + result: + ``` + [=] Writing page 0 block: 00 data: 0x00088040 pwd: 0x12345678 + ``` + Now check if we can detect without a password + ``` + [usb] pm3 --> lf t55 detect + ``` + result: + ``` + Chip Type : T55x7 + Modulation : ASK + Bit Rate : 2 - RF/32 + Inverted : No + Offset : 32 + Seq. Term. : Yes + Block0 : 0x00088040 + Downlink Mode : default/fixed bit length + ``` + Yes we can and we can see Block 0 is the correct config 00088040 + +# Part 2 – Configuration Blocks + +One of the things a lot of people have trouble with or miss, is that the +T5577 has two different and separate communications protocols, each with +their own sub-protocols. + + - Card to Reader + - Reader to Card + +In Card to Reader, the T5577 will encode its data using the settings +from Block 0 in Page 0. It will use this in both default read mode +(where is sends out the blocks from 1 to x on power up), as well as when +it responds to commands. + +In the Read To Card, the T5577 will encode the data using the settings +from Block 3 Page 1. If the command is not encoded correctly it will +ignore the command and revert back to default read mode. + +## The configuration Block – Block 0 Page 0 + +For this configuration the settings chosen will be for the purpose of +the card when used in production. E.G. If you want the card to act like +an EM4100, then we need to choose the settings that work like the +EM4100; same goes for others like HID. I am not going to cover these +here, rather use an example. Others have collect these and posted on the +forum. + +To get started lets look back at the tech sheet. + +![](./t55xx_clock0_cfg.png) + +The non-password protect EM4100 could have a block 0 config of 00148040, +so what does it mean. + +To decode this config, we need to look at it in binary +00000000000101001000000001000000. Note that it had 32 bits and the +config block 0 is 32 bits. Now we can break it down. + +| Bits | Purpose | Value | +| ------- | ---------------------- | ----------- | +| 0000 | Master Key | Nothing Set | +| 0000000 | Not used in Basic Mode | | +| 101 | Data Bit Rate | RF/64 | +| 0 | Not used in Basic Mode | | +| 01000 | Modulation | Manchester | +| 00 | PSKCF | RF/2 | +| 0 | AOR | Not Set | +| 0 | Not used in Basic Mode | | +| 010 | Max Block | 2 | +| 0 | Password | Not Set | +| 0 | ST Sequence Terminator | Not Set | +| 00 | Not used in Basic Mode | | +| 0 | Init Delay | Not Set | + +To get more detail on each item, read through the data sheet. + +Lets see how the proxmark3 can help us learn. We will assume the T5577 +is in the same state from Part 1, where we can write to the card with no +password set (if not, review and get you card back to this state). + +1) Lets turn you T5577 into an EM4100 with ID 1122334455 + ``` + [usb] pm3 --> lf em 410x_write 1122334455 1 + ``` + result: + ``` + [+] Writing T55x7 tag with UID 0x1122334455 (clock rate: 64) + #db# Started writing T55x7 tag ... + #db# Clock rate: 64 + #db# Tag T55x7 written with 0xff8c65298c94a940 + ``` + +2) Check this has work. + ``` + [usb] pm3 --> lf search + ``` + result: + ``` + [=] NOTE: some demods output possible binary + [=] if it finds something that looks like a tag + [=] False Positives ARE possible + [=] + [=] Checking for known tags... + + [+] EM410x pattern found + + EM TAG ID : 1122334455 + + Possible de-scramble patterns + + Unique TAG ID : 8844CC22AA + HoneyWell IdentKey { + DEZ 8 : 03359829 + DEZ 10 : 0573785173 + DEZ 5.5 : 08755.17493 + DEZ 3.5A : 017.17493 + DEZ 3.5B : 034.17493 + DEZ 3.5C : 051.17493 + DEZ 14/IK2 : 00073588229205 + DEZ 15/IK3 : 000585269781162 + DEZ 20/ZK : 08080404121202021010 + } + Other : 17493_051_03359829 + Pattern Paxton : 289899093 [0x11478255] + Pattern 1 : 5931804 [0x5A831C] + Pattern Sebury : 17493 51 3359829 [0x4455 0x33 0x334455] + + [+] Valid EM410x ID found! + + + [+] Chipset detection : T55xx found + + [+] Try `lf t55xx` commands + ``` + Looks good. + +3) Now lest see what the T5577 detect and info shows + ``` + [usb] pm3 --> lf t55 detect + ``` + result: + ``` + [usb] pm3 --> lf t55 detect + Chip Type : T55x7 + Modulation : ASK + Bit Rate : 5 - RF/64 + Inverted : No + Offset : 32 + Seq. Term. : Yes + Block0 : 0x00148040 + Downlink Mode : default/fixed bit length + ``` + ``` + [usb] pm3 --> lf t55xx info + ``` + result: + ``` + + -- T55x7 Configuration & Tag Information -------------------- + ------------------------------------------------------------- + Safer key : 0 + reserved : 0 + Data bit rate : 5 - RF/64 + eXtended mode : No + Modulation : 8 - Manchester + PSK clock frequency : 0 - RF/2 + AOR - Answer on Request : No + OTP - One Time Pad : No + Max block : 2 + Password mode : No + Sequence Terminator : No + Fast Write : No + Inverse data : No + POR-Delay : No + ------------------------------------------------------------- + Raw Data - Page 0 + Block 0 : 0x00148040 00000000000101001000000001000000 + + Config block match : EM unique, Paxton + ------------------------------------------------------------- + ``` + We can see that the info gave us more information and confirmed what + we decoded by hand. But remember, the detect is still needed so the + proxmark3 software will know how to decode the info block. + + We can see that for the EM4100 emulation we have two blocks of data + (Max Block = 2). On the T5577 these will be Blocks 1 and 2. + +## Exercise 2 + +Using the skills form part 1, see if you can view the data in blocks 1 and 2. + +Note: the EM4100 ID of 1122334455 is encoded, so don’t expect to see + those bytes as such. To learn how to do that, you guessed it, find the + datasheet and review. + +At this point we have an EM4100 card. If we wanted to password protect +it, we can follow the password section and update the config from +00148040 to 00148050. + +***Important : Don’t forget to set a valid password in block 7 and remember it.*** + +## The configuration Block – Block 3 Page 1 diff --git a/doc/cheatsheet.md b/doc/cheatsheet.md index a3ea9c579..e725d8d25 100644 --- a/doc/cheatsheet.md +++ b/doc/cheatsheet.md @@ -62,30 +62,47 @@ Dump iCLASS card contents ``` Options --- -k : *Access Key as 16 hex symbols or 1 hex to select key from memory +-f, --file filename to save dump to +-k, --key debit key as 16 hex symbols OR NR/MAC for replay + --ki debit key index to select key from memory 'hf iclass managekeys' + --credit credit key as 16 hex symbols + --ci credit key index to select key from memory 'hf iclass managekeys' + --elite elite computations applied to key + --raw raw, the key is interpreted as raw block 3/4 + --nr replay of NR/MAC -m3 --> hf iclass dump k 0 +pm3 --> hf iclass dump --ki 0 ``` Read iCLASS Block ``` Options --- -b : The block number as 2 hex symbols -k : Access Key as 16 hex symbols or 1 hex to select key from memory +-k, --key Access key as 16 hex symbols +-b, --block The block number to read as an integer + --ki Key index to select key from memory 'hf iclass managekeys' + --credit key is assumed to be the credit key + --elite elite computations applied to key + --raw no computations applied to key (raw) + --nr replay of NR/MAC -pm3 --> hf iclass rdbl b 7 k 0 +pm3 --> hf iclass rdbl -b 7 --ki 0 ``` Write to iCLASS Block ``` Options --- -b : The block number as 2 hex symbols -d : Set the Data to write as 16 hex symbols -k : Access Key as 16 hex symbols or 1 hex to select key from memory +-k, --key Access key as 16 hex symbols +-b, --block The block number to read as an integer +-d, --data data to write as 16 hex symbols + --ki Key index to select key from memory 'hf iclass managekeys' + --credit key is assumed to be the credit key + --elite elite computations applied to key + --raw no computations applied to key (raw) + --nr replay of NR/MAC -pm3 --> hf iclass wrbl b 07 d 6ce099fe7e614fd0 k 0 +pm3 --> hf iclass wrbl -b 7 -d 6ce099fe7e614fd0 --ki 0 ``` Print keystore @@ -111,22 +128,24 @@ Encrypt iCLASS Block ``` Options --- -d : 16 bytes hex -k : 16 bytes hex +-d, --data data to encrypt +-k, --key 3DES transport key +-v, --verbose verbose output -pm3 --> hf iclass encrypt d 0000000f2aa3dba8 +pm3 --> hf iclass encrypt -d 0000000f2aa3dba8 ``` Decrypt iCLASS Block / file ``` Options --- -d : 16 bytes hex -f : filename of dump -k : 16 bytes hex +-f, --file filename of dumpfile +-d, --data 3DES encrypted data +-k, --key 3DES transport key +-v, --verbose verbose output -pm3 --> hf iclass decrypt d 2AD4C8211F996871 -pm3 --> hf iclass decrypt f hf-iclass-db883702f8ff12e0.bin +pm3 --> hf iclass decrypt -d 2AD4C8211F996871 +pm3 --> hf iclass decrypt -f hf-iclass-db883702f8ff12e0.bin ``` Load iCLASS dump into memory for simulation @@ -140,8 +159,8 @@ pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin Clone iCLASS Legacy Sequence ``` -pm3 --> hf iclass rdbl b 7 k 0 -pm3 --> hf iclass wrbl b 7 d 6ce099fe7e614fd0 k 0 +pm3 --> hf iclass rdbl -b 7 --ki 0 +pm3 --> hf iclass wrbl -b 7 -d 6ce099fe7e614fd0 --ki 0 ``` Simulate iCLASS @@ -159,7 +178,7 @@ pm3 --> hf iclass sim 3 Simulate iCLASS Sequence ``` -pm3 --> hf iclass dump k 0 +pm3 --> hf iclass dump --ki 0 pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin pm3 --> hf iclass sim 3 ``` @@ -175,7 +194,7 @@ e : If 'e' is specified, elite computations applied to key pm3 --> hf iclass sim 2 pm3 --> hf iclass loclass -f iclass_mac_attack.bin pm3 --> hf iclass managekeys n 7 k -pm3 --> hf iclass dump k 7 e +pm3 --> hf iclass dump --ki 7 --elite ``` Verify custom iCLASS key diff --git a/doc/commands.md b/doc/commands.md index e52c2361d..bc0855668 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -11,7 +11,7 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`auto `|N |`Automated detection process for unknown tags` -|`clear `|Y |`clear screen` +|`clear `|Y |`Clear screen` |`help `|Y |`This help. Use ' help' for details of a particular command.` |`hints `|Y |`Turn hints on / off` |`msleep `|Y |`Add a pause in milliseconds` @@ -38,6 +38,7 @@ Check column "offline" for their availability. |`analyse nuid `|Y |`create NUID from 7byte UID` |`analyse demodbuff `|Y |`Load binary string to demodbuffer` |`analyse freq `|Y |`Calc wave lengths` +|`analyse foo `|Y |`muxer` ### data @@ -256,7 +257,6 @@ Check column "offline" for their availability. |`hf iclass restore `|N |`[options..] Restore a dump file onto a Picopass / iCLASS tag` |`hf iclass sniff `|N |` Eavesdrop Picopass / iCLASS communication` |`hf iclass wrbl `|N |`[options..] Write Picopass / iCLASS block` -|`hf iclass autopwn `|N |`[options..] Automatic key recovery tool for iCLASS` |`hf iclass chk `|N |`[options..] Check keys` |`hf iclass loclass `|Y |`[options..] Use loclass to perform bruteforce reader attack` |`hf iclass lookup `|Y |`[options..] Uses authentication trace to check for key in dictionary file` @@ -773,7 +773,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf nexwatch help `|Y |`This help` |`lf nexwatch demod `|Y |`Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer` -|`lf nexwatch read `|N |`Attempt to Read and Extract tag data from the antenna` +|`lf nexwatch reader `|N |`Attempt to Read and Extract tag data from the antenna` |`lf nexwatch clone `|N |`clone NexWatch tag to T55x7` |`lf nexwatch sim `|N |`simulate NexWatch tag` @@ -786,7 +786,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf noralsy help `|Y |`This help` |`lf noralsy demod `|Y |`Demodulate an Noralsy tag from the GraphBuffer` -|`lf noralsy read `|N |`Attempt to read and extract tag data from the antenna` +|`lf noralsy reader `|N |`Attempt to read and extract tag data from the antenna` |`lf noralsy clone `|N |`clone Noralsy tag to T55x7 or Q5/T5555` |`lf noralsy sim `|N |`simulate Noralsy tag` @@ -799,7 +799,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf pac help `|Y |`This help` |`lf pac demod `|Y |`Demodulate a PAC tag from the GraphBuffer` -|`lf pac read `|N |`Attempt to read and extract tag data from the antenna` +|`lf pac reader `|N |`Attempt to read and extract tag data from the antenna` |`lf pac clone `|N |`clone PAC tag to T55x7` |`lf pac sim `|N |`simulate PAC tag` @@ -812,8 +812,8 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf paradox help `|Y |`This help` |`lf paradox demod `|Y |`Demodulate a Paradox FSK tag from the GraphBuffer` -|`lf paradox read `|N |`Attempt to read and Extract tag data from the antenna` -|`lf paradox clone `|N |`clone paradox tag to T55x7` +|`lf paradox reader `|N |`Attempt to read and Extract tag data from the antenna` +|`lf paradox clone `|N |`clone paradox tag` |`lf paradox sim `|N |`simulate paradox tag` @@ -837,7 +837,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf presco help `|Y |`This help` |`lf presco demod `|Y |`demodulate Presco tag from the GraphBuffer` -|`lf presco read `|N |`Attempt to read and Extract tag data` +|`lf presco reader `|N |`Attempt to read and Extract tag data` |`lf presco clone `|N |`clone presco tag to T55x7 or Q5/T5555` |`lf presco sim `|N |`simulate presco tag` @@ -850,7 +850,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf pyramid help `|Y |`this help` |`lf pyramid demod `|Y |`demodulate a Pyramid FSK tag from the GraphBuffer` -|`lf pyramid read `|N |`attempt to read and extract tag data` +|`lf pyramid reader `|N |`attempt to read and extract tag data` |`lf pyramid clone `|N |`clone pyramid tag to T55x7 or Q5/T5555` |`lf pyramid sim `|N |`simulate pyramid tag` @@ -863,7 +863,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf securakey help `|Y |`This help` |`lf securakey demod `|Y |`Demodulate an Securakey tag from the GraphBuffer` -|`lf securakey read `|N |`Attempt to read and extract tag data from the antenna` +|`lf securakey reader `|N |`Attempt to read and extract tag data from the antenna` |`lf securakey clone `|N |`clone Securakey tag to T55x7` |`lf securakey sim `|N |`simulate Securakey tag` @@ -876,7 +876,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf ti help `|Y |`This help` |`lf ti demod `|Y |`Demodulate raw bits for TI-type LF tag from the GraphBuffer` -|`lf ti read `|N |`Read and decode a TI 134 kHz tag` +|`lf ti reader `|N |`Read and decode a TI 134 kHz tag` |`lf ti write `|N |`Write new data to a r/w TI 134 kHz tag` @@ -918,7 +918,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf viking help `|Y |`This help` |`lf viking demod `|Y |`Demodulate a Viking tag from the GraphBuffer` -|`lf viking read `|N |`Attempt to read and Extract tag data from the antenna` +|`lf viking reader `|N |`Attempt to read and Extract tag data from the antenna` |`lf viking clone `|N |`clone Viking tag to T55x7 or Q5/T5555` |`lf viking sim `|N |`simulate Viking tag` @@ -931,14 +931,14 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf visa2000 help `|Y |`This help` |`lf visa2000 demod `|Y |`demodulate an VISA2000 tag from the GraphBuffer` -|`lf visa2000 read `|N |`attempt to read and extract tag data from the antenna` +|`lf visa2000 reader `|N |`attempt to read and extract tag data from the antenna` |`lf visa2000 clone `|N |`clone Visa2000 tag to T55x7 or Q5/T5555` |`lf visa2000 sim `|N |`simulate Visa2000 tag` ### mem - { Flash Memory manipulation... } + { Flash memory manipulation... } |command |offline |description |------- |------- |----------- @@ -953,7 +953,7 @@ Check column "offline" for their availability. ### reveng - { CRC calculations from RevEng software } + { CRC calculations from RevEng software... } [=] reveng: no mode switch specified. Use reveng -h for help. @@ -975,7 +975,7 @@ Check column "offline" for their availability. ### script - { Scripting commands } + { Scripting commands... } |command |offline |description |------- |------- |----------- diff --git a/doc/t55xx_block0.png b/doc/t55xx_block0.png new file mode 100644 index 000000000..2220adf3f Binary files /dev/null and b/doc/t55xx_block0.png differ diff --git a/doc/t55xx_clock0_cfg.png b/doc/t55xx_clock0_cfg.png new file mode 100644 index 000000000..394e7078d Binary files /dev/null and b/doc/t55xx_clock0_cfg.png differ diff --git a/doc/t55xx_mem_map.png b/doc/t55xx_mem_map.png new file mode 100644 index 000000000..7a985275b Binary files /dev/null and b/doc/t55xx_mem_map.png differ