Merge branch 'master' into allin

update 201127
This commit is contained in:
tharexde 2020-11-27 21:24:33 +01:00
commit b18ded915a
44 changed files with 3012 additions and 1877 deletions

29
.vscode/launch.json vendored
View file

@ -18,7 +18,15 @@
"text": "-enable-pretty-printing", "text": "-enable-pretty-printing",
"ignoreFailures": true "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", "name": "(gdb) Build & Launch",
"type": "cppdbg", "type": "cppdbg",
@ -38,7 +46,15 @@
} }
], ],
"preLaunchTask": "client: Debug: clean & make", "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": [ "inputs": [
@ -50,6 +66,15 @@
"args": { "args": {
"command": "pgrep -n proxmark3", "command": "pgrep -n proxmark3",
} }
},{
"id": "ProcessIDWindows",
"type": "command",
"command": "shellCommand.execute",
"args": {
"command": "${workspaceFolder}/../../runme64.bat -c \"cat /proc/$(pgrep -n proxmark3)/winpid\"",
}
} }
] ]
} }

84
.vscode/tasks.json vendored
View file

@ -7,6 +7,18 @@
"label": "all: Make & run", "label": "all: Make & run",
"type": "shell", "type": "shell",
"command": "make -j && ./pm3", "command": "make -j && ./pm3",
"windows": {
"options": {
"cwd": "${workspaceFolder}/../..",
"shell": {
"executable": "${workspaceFolder}/../../runme64.bat",
"args": [
"-c \"cd ${workspaceFolderBasename} &&"
],
}
}
},
"problemMatcher": [ "problemMatcher": [
"$gcc" "$gcc"
], ],
@ -19,6 +31,18 @@
"label": "choose: Make", "label": "choose: Make",
"type": "shell", "type": "shell",
"command": "make ${input:componentType} -j", "command": "make ${input:componentType} -j",
"windows": {
"options": {
"cwd": "${workspaceFolder}/../..",
"shell": {
"executable": "${workspaceFolder}/../../runme64.bat",
"args": [
"-c \"cd ${workspaceFolderBasename} &&"
],
}
}
},
"problemMatcher": [ "problemMatcher": [
"$gcc" "$gcc"
], ],
@ -28,6 +52,18 @@
"label": "client: Debug: make", "label": "client: Debug: make",
"type": "shell", "type": "shell",
"command": "make client -j DEBUG=1", "command": "make client -j DEBUG=1",
"windows": {
"options": {
"cwd": "${workspaceFolder}/../..",
"shell": {
"executable": "${workspaceFolder}/../../runme64.bat",
"args": [
"-c \"cd ${workspaceFolderBasename} &&"
],
}
}
},
"problemMatcher": [ "problemMatcher": [
"$gcc" "$gcc"
], ],
@ -37,6 +73,18 @@
"label": "client: Debug: clean & make", "label": "client: Debug: clean & make",
"type": "shell", "type": "shell",
"command": "make client/clean && make client -j DEBUG=1", "command": "make client/clean && make client -j DEBUG=1",
"windows": {
"options": {
"cwd": "${workspaceFolder}/../..",
"shell": {
"executable": "${workspaceFolder}/../../runme64.bat",
"args": [
"-c \"cd ${workspaceFolderBasename} &&"
],
}
}
},
"problemMatcher": [ "problemMatcher": [
"$gcc" "$gcc"
], ],
@ -46,18 +94,54 @@
"label": "fullimage: Make & Flash", "label": "fullimage: Make & Flash",
"type": "shell", "type": "shell",
"command": "make fullimage && ./pm3-flash-fullimage", "command": "make fullimage && ./pm3-flash-fullimage",
"windows": {
"options": {
"cwd": "${workspaceFolder}/../..",
"shell": {
"executable": "${workspaceFolder}/../../runme64.bat",
"args": [
"-c \"cd ${workspaceFolderBasename} &&"
],
}
}
},
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "BOOTROM: Make & Flash", "label": "BOOTROM: Make & Flash",
"type": "shell", "type": "shell",
"command": "make bootrom && ./pm3-flash-bootrom", "command": "make bootrom && ./pm3-flash-bootrom",
"windows": {
"options": {
"cwd": "${workspaceFolder}/../..",
"shell": {
"executable": "${workspaceFolder}/../../runme64.bat",
"args": [
"-c \"cd ${workspaceFolderBasename} &&"
],
}
}
},
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "Run client", "label": "Run client",
"type": "shell", "type": "shell",
"command": "./pm3", "command": "./pm3",
"windows": {
"options": {
"cwd": "${workspaceFolder}/../..",
"shell": {
"executable": "${workspaceFolder}/../../runme64.bat",
"args": [
"-c \"cd ${workspaceFolderBasename} &&"
],
}
}
},
"problemMatcher": [] "problemMatcher": []
} }
], ],

View file

@ -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... 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] ## [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) - Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001)
- Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...) - Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...)
- ... - ...

View file

@ -21,7 +21,7 @@
|[Donations](#Donations)|[Maintainers](/doc/md/Development/Maintainers.md)|[Command Cheat sheet](/doc/cheatsheet.md)| |[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)| ||[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)| ||**[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 ## 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 This repo compiles nicely on
- Proxspace v3.x - 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 - Windows/mingw environment with Qt5.6.1 & GCC 4.9
- Ubuntu 16.04 -> 20.04 - Ubuntu 16.04 -> 20.04
- ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian - ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian

View file

@ -1037,10 +1037,11 @@ static void PacketReceived(PacketCommandNG *packet) {
case CMD_LF_VIKING_CLONE: { case CMD_LF_VIKING_CLONE: {
struct p { struct p {
bool Q5; bool Q5;
bool EM;
uint8_t blocks[8]; uint8_t blocks[8];
} PACKED; } PACKED;
struct p *payload = (struct p *)packet->data.asBytes; struct p *payload = (struct p *)packet->data.asBytes;
CopyVikingtoT55xx(payload->blocks, payload->Q5); CopyVikingtoT55xx(payload->blocks, payload->Q5, payload->EM);
break; break;
} }
case CMD_LF_COTAG_READ: { case CMD_LF_COTAG_READ: {

View file

@ -1999,10 +1999,10 @@ void iClass_Restore(iclass_restore_req_t *msg) {
// data + mac // data + mac
if (iclass_writeblock_ext(item.blockno, item.data, mac, use_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++; written++;
} else { } else {
Dbprintf("Write block [%02x] " _RED_("failed"), item.blockno); Dbprintf("Write block [%3d/0x%02X] " _RED_("failed"), item.blockno, item.blockno);
} }
} }

View file

@ -2252,11 +2252,14 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) {
} }
// clone viking tag to T55xx // 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}; 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; 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[1] = bytes_to_num(blocks, 4);
data[2] = bytes_to_num(blocks + 4, 4); data[2] = bytes_to_num(blocks + 4, 4);

View file

@ -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 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); int copy_em410x_to_t55xx(uint8_t card, uint8_t clock, uint32_t id_hi, uint32_t id_lo);

View file

@ -10,3 +10,5 @@ AEA684A6DAB23278 # AA1
F0E1D2C3B4A59687 # Kd from PicoPass 2k documentation F0E1D2C3B4A59687 # Kd from PicoPass 2k documentation
5CBCF1DA45D5FB4F # PicoPass Default Exchange Key 5CBCF1DA45D5FB4F # PicoPass Default Exchange Key
31ad7ebd2f282168 # From HID multiclassSE reader 31ad7ebd2f282168 # From HID multiclassSE reader
6EFD46EFCBB3C875 # From pastebin: https://pastebin.com/uHqpjiuU
E033CA419AEE43F9 # From pastebin: https://pastebin.com/uHqpjiuU

View file

@ -1276,3 +1276,6 @@ AABAFFCC7612
# ozdilek # ozdilek
# #
17D071403C20 17D071403C20
#
534F4C415249
534f4c303232

View file

@ -1179,10 +1179,10 @@ static int CmdHF14AAPDU(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
PrintAndLogEx(SUCCESS, "( " _YELLOW_("%s%s%s")" )", PrintAndLogEx(SUCCESS, "( " _YELLOW_("%s%s%s")" )",
activateField ? "select" : "", activateField ? "select" : "",
leaveSignalON ? ", keep" : "", leaveSignalON ? ", keep" : "",
decodeTLV ? ", TLV" : "" decodeTLV ? ", TLV" : ""
); );
PrintAndLogEx(SUCCESS, ">>> %s", sprint_hex_inrow(data, datalen)); PrintAndLogEx(SUCCESS, ">>> %s", sprint_hex_inrow(data, datalen));
if (decodeAPDU) { 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.", "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 -sc 3000 -> select, crc, where 3000 == 'read block 00'\n"
"hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40\n" "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
@ -1347,10 +1347,10 @@ static int waitCmd(bool i_select, uint32_t timeout) {
char s[16]; char s[16];
sprintf(s, sprintf(s,
(crc) ? _GREEN_("%02X %02X") : _RED_("%02X %02X"), (crc) ? _GREEN_("%02X %02X") : _RED_("%02X %02X"),
data[len - 2], data[len - 2],
data[len - 1] data[len - 1]
); );
PrintAndLogEx(SUCCESS, "%s[ %s ]", sprint_hex(data, len - 2), s); PrintAndLogEx(SUCCESS, "%s[ %s ]", sprint_hex(data, len - 2), s);
} else { } else {

View file

@ -1725,7 +1725,7 @@ static int CmdHF15Write(const char *Cmd) {
AddCrc15(req, reqlen); AddCrc15(req, reqlen);
reqlen += 2; 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; PacketResponseNG resp;
clearCommandBuffer(); clearCommandBuffer();

File diff suppressed because it is too large Load diff

View file

@ -5444,7 +5444,7 @@ static command_t CommandTable[] = {
{"esave", CmdHF14AMfESave, IfPm3Iso14443a, "Save to file emul dump"}, {"esave", CmdHF14AMfESave, IfPm3Iso14443a, "Save to file emul dump"},
{"eset", CmdHF14AMfESet, IfPm3Iso14443a, "Set simulator memory block"}, {"eset", CmdHF14AMfESet, IfPm3Iso14443a, "Set simulator memory block"},
{"eview", CmdHF14AMfEView, IfPm3Iso14443a, "View emul memory"}, {"eview", CmdHF14AMfEView, IfPm3Iso14443a, "View emul memory"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic") " -----------------------"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen1") " -----------------------"},
{"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block"}, {"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block"},
{"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector"}, {"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector"},
{"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump"}, {"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump"},

View file

@ -395,9 +395,9 @@ static char *getCardSizeStr(uint8_t fsize) {
// is LSB set? // is LSB set?
if (fsize & 1) 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 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; return buf;
} }
@ -407,14 +407,14 @@ static char *getProtocolStr(uint8_t id, bool hw) {
char *retStr = buf; char *retStr = buf;
if (id == 0x04) { 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) { } else if (id == 0x05) {
if (hw) 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 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 { } else {
snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("Unknown") ")", id); snprintf(retStr, sizeof(buf), "0x%02X ( " _YELLOW_("Unknown") " )", id);
} }
return buf; return buf;
} }
@ -425,19 +425,21 @@ static char *getVersionStr(uint8_t major, uint8_t minor) {
char *retStr = buf; char *retStr = buf;
if (major == 0x00) 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) 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) 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) 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) 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) 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 else
snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor); snprintf(retStr, sizeof(buf), "%x.%x ( " _YELLOW_("Unknown") " )", major, minor);
return buf; return buf;
//04 01 01 01 00 1A 05 //04 01 01 01 00 1A 05
@ -1381,15 +1383,43 @@ static int handler_desfire_signature(uint8_t *signature, size_t *signature_len)
return res; return res;
} }
// --- KEY SETTING // --- KEY VERSION
static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys, int algo) { 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); PrintAndLogEx(SUCCESS, " AID Key settings : 0x%02x", key_settings);
// 2 MSB denotes // 2 MSB denotes
const char *str = " Max key number and type : %d, " _YELLOW_("%s"); const char *str = " Max key number and type : %d, " _YELLOW_("%s");
if (algo == MFDES_ALGO_DES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES"); if (algo == MFDES_ALGO_DES)
else if (algo == MFDES_ALGO_AES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "AES"); PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "(3)DES");
else if (algo == MFDES_ALGO_3K3DES) PrintAndLogEx(SUCCESS, str, num_keys & 0x3F, "3K3DES"); 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(SUCCESS, " Max number of keys in AID : %d", num_keys & 0x3F);
PrintAndLogEx(INFO, "-------------------------------------------------------------"); 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"); PrintAndLogEx(SUCCESS, " -- All keys (except AMK,see Bit0) within this application are frozen");
break; break;
default: 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; break;
} }
PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO"); PrintAndLogEx(SUCCESS, " [1000] AMK Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO (frozen)");
PrintAndLogEx(SUCCESS, " [0x04] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? "NO" : "YES"); PrintAndLogEx(SUCCESS, " [0100] 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, " [0010] 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, " [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; return PM3_SUCCESS;
} }
@ -1445,31 +1530,6 @@ static int handler_desfire_getkeysettings(uint8_t *key_settings, uint8_t *num_ke
return res; 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) { static int handler_desfire_getuid(uint8_t *uid) {
if (uid == NULL) { if (uid == NULL) {
PrintAndLogEx(DEBUG, "UID=NULL"); PrintAndLogEx(DEBUG, "UID=NULL");
@ -1589,10 +1649,10 @@ static int handler_desfire_select_application(uint8_t *aid) {
int res = send_desfire_cmd(&apdu, !tag->rf_field_on, NULL, &recv_len, &sw, sizeof(dfname_t), true); int res = send_desfire_cmd(&apdu, !tag->rf_field_on, NULL, &recv_len, &sw, sizeof(dfname_t), true);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, PrintAndLogEx(WARNING,
_RED_(" Can't select AID 0x%X -> %s"), _RED_(" Can't select AID 0x%X -> %s"),
(aid[2] << 16) + (aid[1] << 8) + aid[0], (aid[2] << 16) + (aid[1] << 8) + aid[0],
GetErrorString(res, &sw) GetErrorString(res, &sw)
); );
DropFieldDesfire(); DropFieldDesfire();
return res; return res;
} }
@ -2006,6 +2066,8 @@ static int handler_desfire_create_backup_file(mfdes_file_t *file) {
static int getKeySettings(uint8_t *aid) { static int getKeySettings(uint8_t *aid) {
if (aid == NULL) return PM3_EINVARG; if (aid == NULL) return PM3_EINVARG;
uint8_t num_keys = 0;
uint8_t key_setting = 0;
int res = 0; int res = 0;
if (memcmp(aid, "\x00\x00\x00", 3) == 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")); //PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
// KEY Settings - AMK // KEY Settings - AMK
uint8_t num_keys = 0;
uint8_t key_setting = 0;
mifare_des_authalgo_t algo = MFDES_ALGO_DES; mifare_des_authalgo_t algo = MFDES_ALGO_DES;
res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys); res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
// number of Master keys (0x01) desfire_print_piccmk_keysetting(key_setting, num_keys, algo);
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");
} else { } 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 { } else {
// AID - APPLICATION MASTER KEYS // AID - APPLICATION MASTER KEYS
@ -2065,12 +2092,10 @@ static int getKeySettings(uint8_t *aid) {
if (res != PM3_SUCCESS) return res; if (res != PM3_SUCCESS) return res;
// KEY Settings - AMK // KEY Settings - AMK
uint8_t num_keys = 0;
uint8_t key_setting = 0;
mifare_des_authalgo_t algo = MFDES_ALGO_DES; mifare_des_authalgo_t algo = MFDES_ALGO_DES;
res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys); res = key_setting_to_algo(aid, &key_setting, &algo, &num_keys);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
desfire_print_keysetting(key_setting, num_keys, algo); desfire_print_amk_keysetting(key_setting, num_keys, algo);
} else { } else {
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings")); PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
} }
@ -2405,14 +2430,14 @@ static int CmdHF14ADesCreateApp(const char *Cmd) {
if (usename) if (usename)
PrintAndLogEx(INFO, "DF Name %s", aidhdr.name); PrintAndLogEx(INFO, "DF Name %s", aidhdr.name);
/* /*
uint8_t rootaid[3] = {0x00, 0x00, 0x00}; uint8_t rootaid[3] = {0x00, 0x00, 0x00};
int res = handler_desfire_select_application(rootaid); int res = handler_desfire_select_application(rootaid);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
DropFieldDesfire(); DropFieldDesfire();
return res; return res;
} }
*/ */
int res = handler_desfire_createapp(&aidhdr, usename, usefid); int res = handler_desfire_createapp(&aidhdr, usename, usefid);
DropFieldDesfire(); 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(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]);
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information")); 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, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionHW[0]));
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionHW[1]); PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionHW[1]);
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionHW[2]); 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(INFO, " Protocol: %s", getProtocolStr(info.versionHW[6], true));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); 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, " Vendor Id: " _YELLOW_("%s"), getTagInfo(info.versionSW[0]));
PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionSW[1]); PrintAndLogEx(INFO, " Type: " _YELLOW_("0x%02X"), info.versionSW[1]);
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionSW[2]); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), info.versionSW[2]);

View file

@ -179,68 +179,56 @@ static int CmdKeriDemod(const char *Cmd) {
return demodKeri(true); return demodKeri(true);
} }
static int CmdKeriRead(const char *Cmd) { static int CmdKeriReader(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;
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf keri clone", CLIParserInit(&ctx, "lf keri reader",
"clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag", "read a keri tag",
"lf keri clone -t i --id 12345\n" "lf keri reader -@ -> continuous reader mode"
"lf keri clone -t m --fc 6 --id 12345\n"); );
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[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("q", "q5", "specify writing to Q5/T5555 tag"),
arg_str0("t", "type", "<m|i>", "Type m - MS, i - Internal ID"), arg_str0("t", "type", "<m|i>", "Type m - MS, i - Internal ID"),
arg_int0(NULL, "fc", "<dec>", "Facility Code"), arg_int0(NULL, "fc", "<dec>", "Facility Code"),
arg_int1(NULL, "id", "<dec>", "Keri ID"), arg_int1(NULL, "cn", "<dec>", "KERI card ID"),
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"), arg_lit0(NULL, "q5", "specify writing to Q5/T5555 tag"),
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
char cardtype[16] = {"T55x7"}; uint8_t keritype[2] = {'i'}; // default to internalid
if (arg_get_lit(ctx, 1)) { int typeLen = sizeof(keritype);
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT; CLIGetStrWithReturn(ctx, 1, keritype, &typeLen);
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;
}
typeLen = sizeof(keritype); uint32_t fc = arg_get_int_def(ctx, 2, 0);
CLIGetStrWithReturn(ctx, 2, keritype, &typeLen); uint32_t cid = arg_get_int_def(ctx, 3, 0);
bool q5 = arg_get_lit(ctx, 4);
fc = arg_get_int_def(ctx, 3, 0); bool em = arg_get_lit(ctx, 5);
cid = arg_get_int_def(ctx, 4, 0);
CLIParserFree(ctx); CLIParserFree(ctx);
if (q5 && em) { if (q5 && em) {
@ -249,6 +237,7 @@ static int CmdKeriClone(const char *Cmd) {
} }
// Setup card data/build internal id // Setup card data/build internal id
uint32_t internalid = 0;
switch (keritype[0]) { switch (keritype[0]) {
case 'i' : // Internal ID case 'i' : // Internal ID
// MSB is ONE // MSB is ONE
@ -262,6 +251,24 @@ static int CmdKeriClone(const char *Cmd) {
return PM3_EINVARG; 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 // Prepare and write to card
// 3 LSB is ONE // 3 LSB is ONE
uint64_t data = ((uint64_t)internalid << 3) + 7; uint64_t data = ((uint64_t)internalid << 3) + 7;
@ -288,19 +295,18 @@ static int CmdKeriSim(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf keri sim", CLIParserInit(&ctx, "lf keri sim",
"Enables simulation of KERI card with card number.", "Enables simulation of KERI card with internal ID.\n"
"lf keri sim --id 112233" "You supply a KERI card id and it will converted to a KERI internal ID.",
"lf keri sim --cn 112233"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_int1(NULL, "id", "<dec>", "KERI Internal ID"), arg_u64_1(NULL, "id", "<dec>", "KERI card ID"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
uint64_t internalid = arg_get_u64_def(ctx, 1, 0);
uint64_t internalid = arg_get_int_def(ctx, 1, 0);
CLIParserFree(ctx); CLIParserFree(ctx);
internalid |= 0x80000000; internalid |= 0x80000000;
@ -314,7 +320,7 @@ static int CmdKeriSim(const char *Cmd) {
bs[j++] = ((internalid >> i) & 1); 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)); lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs));
payload->carrier = 2; payload->carrier = 2;
@ -322,8 +328,6 @@ static int CmdKeriSim(const char *Cmd) {
payload->clock = 32; payload->clock = 32;
memcpy(payload->data, bs, sizeof(bs)); memcpy(payload->data, bs, sizeof(bs));
PrintAndLogEx(INFO, "Simulating");
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs)); SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs));
free(payload); free(payload);
@ -338,11 +342,11 @@ static int CmdKeriSim(const char *Cmd) {
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"}, {"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"},
{"read", CmdKeriRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, {"reader", CmdKeriReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"}, {"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"},
{"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"}, {"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -9,22 +9,20 @@
// PSK1, RF/32, 64 bits long, at 74 kHz // PSK1, RF/32, 64 bits long, at 74 kHz
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfmotorola.h" #include "cmdlfmotorola.h"
#include <ctype.h> // tolower
#include <ctype.h> //tolower #include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "common.h" #include "common.h"
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
#include "cmddata.h" #include "cmddata.h"
#include "cmdlf.h" #include "cmdlf.h"
#include "lfdemod.h" // preamble test #include "lfdemod.h" // preamble test
#include "protocols.h" // t55xx defines #include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone.. #include "cmdlft55xx.h" // clone..
#include "cmdlf.h" // cmdlfconfig #include "cmdlf.h" // cmdlfconfig
#include "cliparser.h" // cli parse input #include "cliparser.h" // cli parse input
#include "cmdlfem4x05.h" // EM defines
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -124,7 +122,22 @@ static int CmdMotorolaDemod(const char *Cmd) {
return demodMotorola(true); 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 // Motorola Flexpass seem to work at 74 kHz
// and take about 4400 samples to befor modulating // and take about 4400 samples to befor modulating
sample_config sc = { sample_config sc = {
@ -138,61 +151,86 @@ static int CmdMotorolaRead(const char *Cmd) {
}; };
lf_config(&sc); lf_config(&sc);
// 64 * 32 * 2 * n-ish do {
lf_read(false, 5000); // 64 * 32 * 2 * n-ish
lf_read(false, 5000);
demodMotorola(!cm);
} while (cm && !kbd_enter_pressed());
// reset back to 125 kHz // reset back to 125 kHz
sc.divisor = LF_DIVISOR_125; sc.divisor = LF_DIVISOR_125;
sc.samples_to_skip = 0; sc.samples_to_skip = 0;
lf_config(&sc); lf_config(&sc);
return demodMotorola(true);
return PM3_SUCCESS;
} }
static int CmdMotorolaClone(const char *Cmd) { static int CmdMotorolaClone(const char *Cmd) {
uint32_t blocks[3] = {0};
uint8_t data[8];
int datalen = 0;
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf motorola clone", 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", "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[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_strx1("r", "raw", "<hex>", "raw bytes"), arg_strx1("r", "raw", "<hex>", "raw hex bytes. 8 bytes"),
arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"), 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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); 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); 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) // config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2)
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag"); PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit to " _YELLOW_("%s") " with raw " _GREEN_("%s")
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen)); , cardtype
, sprint_hex_inrow(raw, sizeof(raw))
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);
print_blocks(blocks, ARRAYLEN(blocks)); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola reader`") " to verify");
return res; return res;
} }
@ -205,11 +243,11 @@ static int CmdMotorolaSim(const char *Cmd) {
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdMotorolaDemod, AlwaysAvailable, "Demodulate an MOTOROLA tag from the GraphBuffer"}, {"demod", CmdMotorolaDemod, AlwaysAvailable, "Demodulate an MOTOROLA tag from the GraphBuffer"},
{"read", CmdMotorolaRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, {"reader", CmdMotorolaReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdMotorolaClone, IfPm3Lf, "clone MOTOROLA tag to T55x7"}, {"clone", CmdMotorolaClone, IfPm3Lf, "clone MOTOROLA tag to T55x7"},
{"sim", CmdMotorolaSim, IfPm3Lf, "simulate MOTOROLA tag"}, {"sim", CmdMotorolaSim, IfPm3Lf, "simulate MOTOROLA tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@ -266,5 +304,5 @@ int detectMotorola(uint8_t *dest, size_t *size) {
} }
int readMotorolaUid(void) { int readMotorolaUid(void) {
return (CmdMotorolaRead("") == PM3_SUCCESS); return (CmdMotorolaReader("") == PM3_SUCCESS);
} }

View file

@ -9,20 +9,21 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfnexwatch.h" #include "cmdlfnexwatch.h"
#include <inttypes.h> // PRIu #include <inttypes.h> // PRIu
#include <string.h> #include <string.h>
#include <ctype.h> // tolower #include <ctype.h> // tolower
#include <stdlib.h> // free, alloc #include <stdlib.h> // free, alloc
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN #include "cmdparser.h" // command_t
#include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
#include "cmddata.h" // preamblesearch #include "cmddata.h" // preamblesearch
#include "cmdlf.h" #include "cmdlf.h"
#include "lfdemod.h" #include "lfdemod.h"
#include "protocols.h" // t55xx defines #include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone.. #include "cmdlft55xx.h" // clone..
#include "cmdlfem4x05.h" //
#include "cliparser.h"
typedef enum { typedef enum {
SCRAMBLE, SCRAMBLE,
@ -31,49 +32,6 @@ typedef enum {
static int CmdHelp(const char *Cmd); 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 <raw hex>] [c <id>] [m <mode>] [n|q]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " r <raw hex> : raw hex data. 12 bytes max");
PrintAndLogEx(NORMAL, " c <id> : card id (decimal)");
PrintAndLogEx(NORMAL, " m <mode> : 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] <r raw hex> [c <id>] [m <mode>] [n|q]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " r <raw hex> : raw hex data. 16 bytes max");
PrintAndLogEx(NORMAL, " c <id> : card id (decimal)");
PrintAndLogEx(NORMAL, " m <mode> : 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) // scramble parity (1234) -> (4231)
static uint8_t nexwatch_parity_swap(uint8_t parity) { static uint8_t nexwatch_parity_swap(uint8_t parity) {
uint8_t a = (((parity >> 3) & 1)); uint8_t a = (((parity >> 3) & 1));
@ -263,168 +221,230 @@ static int CmdNexWatchDemod(const char *Cmd) {
return demodNexWatch(true); return demodNexWatch(true);
} }
//by marshmellow static int CmdNexWatchReader(const char *Cmd) {
//see ASKDemod for what args are accepted CLIParserContext *ctx;
static int CmdNexWatchRead(const char *Cmd) { CLIParserInit(&ctx, "lf nexwatch reader",
(void)Cmd; "read a nexwatch tag",
lf_read(false, 20000); "lf nexwatch reader -@ -> continuous reader mode"
return demodNexWatch(true); );
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) { 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 void *argtable[] = {
uint32_t blocks[4]; arg_param_begin,
bool use_raw = false; arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
bool errors = false; arg_u64_0(NULL, "cn", "<dec>", "card id"),
uint8_t cmdp = 0; arg_u64_0("m", "mode", "<dec>", "mode (decimal) (0-15, defaults to 1)"),
int datalen = 0; arg_lit0("n", NULL, "Nexkey credential"),
uint8_t magic = 0xBE; arg_lit0("q", NULL, "Quadrakey credential"),
uint32_t cn = 0; arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
uint8_t rawhex[12] = {0x56, 0}; 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) { int raw_len = 0;
switch (tolower(param_getchar(Cmd, cmdp))) { // skip first block, 3*4 = 12 bytes left
case 'h': uint8_t raw[12] = {0x56, 0};
return usage_lf_nexwatch_clone(); CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
case 'r': {
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
if (res != 0)
errors = true;
use_raw = true; uint32_t cn = arg_get_u32_def(ctx, 2, -1);
cmdp += 2; uint32_t mode = arg_get_u32_def(ctx, 3, -1);
break; bool use_nexkey = arg_get_lit(ctx, 4);
} bool use_quadrakey = arg_get_lit(ctx, 5);
case 'c': { bool q5 = arg_get_lit(ctx, 6);
cn = param_get32ex(Cmd, cmdp + 1, 0, 10); bool em = arg_get_lit(ctx, 7);
uint32_t scrambled; CLIParserFree(ctx);
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
num_to_bytes(scrambled, 4, rawhex + 5); if (use_nexkey && use_quadrakey) {
cmdp += 2; PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time");
break; return PM3_EINVARG;
}
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;
}
} }
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 //Nexwatch - compat mode, PSK, data rate 40, 3 data blocks
blocks[0] = T55x7_MODULATION_PSK1 | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT; 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) { if (use_raw == false) {
uint8_t parity = nexwatch_parity(rawhex + 5) & 0xF; uint8_t parity = nexwatch_parity(raw + 5) & 0xF;
rawhex[9] |= parity; raw[9] |= parity;
rawhex[10] |= nexwatch_checksum(magic, cn, parity); raw[10] |= nexwatch_checksum(magic, cn, parity);
} }
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { 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)); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch reader`") " to verify");
return res; return res;
} }
static int CmdNexWatchSim(const char *Cmd) { static int CmdNexWatchSim(const char *Cmd) {
uint8_t cmdp = 0; CLIParserContext *ctx;
bool errors = false; CLIParserInit(&ctx, "lf nexwatch sim",
bool use_raw = false; "Enables simulation of secura card with specified card number.\n"
uint8_t rawhex[12] = {0x56, 0}; "Simulation runs until the button is pressed or another USB command is issued.\n"
int rawlen = sizeof(rawhex); "You can use raw hex values or create a credential based on id, mode\n"
uint8_t magic = 0xBE; "and type of credential (Nexkey/Quadrakey)",
uint32_t cn = 0; "lf nexwatch sim --raw 5600000000213C9F8F150C00\n"
uint8_t bs[128]; "lf nexwatch sim --cn 521512301 -m 1 -n -> Nexkey credential\n"
memset(bs, 0, sizeof(bs)); "lf nexwatch sim --cn 521512301 -m 1 -q -> Quadrakey credential"
);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { void *argtable[] = {
switch (tolower(param_getchar(Cmd, cmdp))) { arg_param_begin,
case 'h': arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
return usage_lf_nexwatch_clone(); arg_u64_0(NULL, "cn", "<dec>", "card id"),
case 'r': { arg_u64_0("m", "mode", "<dec>", "mode (decimal) (0-15, defaults to 1)"),
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &rawlen); arg_lit0("n", NULL, "Nexkey credential"),
if (res != 0) arg_lit0("q", NULL, "Quadrakey credential"),
errors = true; arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
use_raw = true; int raw_len = 0;
cmdp += 2; // skip first block, 3*4 = 12 bytes left
break; uint8_t raw[12] = {0x56, 0};
} CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
case 'c': {
cn = param_get32ex(Cmd, cmdp + 1, 0, 10); uint32_t cn = arg_get_u32_def(ctx, 2, -1);
uint32_t scrambled; uint32_t mode = arg_get_u32_def(ctx, 3, -1);
nexwatch_scamble(SCRAMBLE, &cn, &scrambled); bool use_nexkey = arg_get_lit(ctx, 4);
num_to_bytes(scrambled, 4, rawhex + 5); bool use_quadrakey = arg_get_lit(ctx, 5);
cmdp += 2; CLIParserFree(ctx);
break;
} if (use_nexkey && use_quadrakey) {
case 'm': { PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time");
uint8_t mode = param_get8ex(Cmd, cmdp + 1, 1, 10); return PM3_EINVARG;
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;
}
} }
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) { if (use_raw == false) {
uint8_t parity = nexwatch_parity(rawhex + 5) & 0xF; uint8_t parity = nexwatch_parity(raw + 5) & 0xF;
rawhex[9] |= parity; raw[9] |= parity;
rawhex[10] |= nexwatch_checksum(magic, cn, parity); raw[10] |= nexwatch_checksum(magic, cn, parity);
} }
// hex to bits. uint8_t bs[96];
uint32_t rawblocks[3]; memset(bs, 0, sizeof(bs));
for (size_t i = 0; i < ARRAYLEN(rawblocks); i++) {
rawblocks[i] = bytes_to_num(rawhex + (i * sizeof(uint32_t)), sizeof(uint32_t)); // hex to bits. (3 * 32 == 96)
num_to_bytebits(rawblocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8)); 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)); lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs));
payload->carrier = 2; payload->carrier = 2;
@ -447,11 +467,11 @@ static int CmdNexWatchSim(const char *Cmd) {
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdNexWatchDemod, AlwaysAvailable, "Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"}, {"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"}, {"reader", CmdNexWatchReader, IfPm3Lf, "Attempt to Read and Extract tag data from the antenna"},
{"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"}, {"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"},
{"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"}, {"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -8,52 +8,23 @@
// ASK/Manchester, STT, RF/32, 96 bits long (some bits unknown) // ASK/Manchester, STT, RF/32, 96 bits long (some bits unknown)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfnoralsy.h" #include "cmdlfnoralsy.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
#include "cmddata.h" #include "cmddata.h"
#include "cmdlf.h" #include "cmdlf.h"
#include "protocols.h" // for T55xx config register definitions #include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest #include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite #include "cmdlft55xx.h" // verifywrite
#include "cmdlfem4x05.h" //
#include "cliparser.h"
static int CmdHelp(const char *Cmd); 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] <card id> <year> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <card id> : Noralsy card ID");
PrintAndLogEx(NORMAL, " <year> : Tag allocation year");
PrintAndLogEx(NORMAL, " <Q5> : 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] <card id> <year>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <card id> : Noralsy card ID");
PrintAndLogEx(NORMAL, " <year> : 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) { static uint8_t noralsy_chksum(uint8_t *bits, uint8_t len) {
uint8_t sum = 0; uint8_t sum = 0;
for (uint8_t i = 0; i < len; i += 4) for (uint8_t i = 0; i < len; i += 4)
@ -136,28 +107,72 @@ static int CmdNoralsyDemod(const char *Cmd) {
return demodNoralsy(true); return demodNoralsy(true);
} }
static int CmdNoralsyRead(const char *Cmd) { static int CmdNoralsyReader(const char *Cmd) {
(void)Cmd; // Cmd is not used so far CLIParserContext *ctx;
lf_read(false, 8000); CLIParserInit(&ctx, "lf noralsy reader",
return demodNoralsy(true); "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) { 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", "<dec>", "Noralsy card ID"),
arg_u64_0("y", "year", "<dec>", "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}; uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0};
char cardtype[16] = {"T55x7"};
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);
//Q5 //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; 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)); uint8_t *bits = calloc(96, sizeof(uint8_t));
if (getnoralsyBits(id, year, bits) != PM3_SUCCESS) { if (getnoralsyBits(id, year, bits) != PM3_SUCCESS) {
@ -172,36 +187,50 @@ static int CmdNoralsyClone(const char *Cmd) {
free(bits); 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)); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy reader`") " to verify");
return res; return res;
} }
static int CmdNoralsySim(const char *Cmd) { 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", "<dec>", "Noralsy card ID"),
arg_u64_0("y", "year", "<dec>", "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]; uint8_t bs[96];
memset(bs, 0, sizeof(bs)); 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) { if (getnoralsyBits(id, year, bs) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation."); PrintAndLogEx(ERR, "Error with tag bitstream generation.");
return PM3_ESOFT; 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)); lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
payload->encoding = 1; payload->encoding = 1;
@ -225,11 +254,11 @@ static int CmdNoralsySim(const char *Cmd) {
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"}, {"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"},
{"read", CmdNoralsyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, {"reader", CmdNoralsyReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"}, {"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"},
{"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"}, {"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@ -272,7 +301,6 @@ int getnoralsyBits(uint32_t id, uint16_t year, uint8_t *bits) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// by iceman
// find Noralsy preamble in already demoded data // find Noralsy preamble in already demoded data
int detectNoralsy(uint8_t *dest, size_t *size) { int detectNoralsy(uint8_t *dest, size_t *size) {
if (*size < 96) return -1; //make sure buffer has data if (*size < 96) return -1; //make sure buffer has data

View file

@ -25,40 +25,14 @@
#include "protocols.h" // t55xx defines #include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone #include "cmdlft55xx.h" // clone
#include "parity.h" #include "parity.h"
#include "cmdlfem4x05.h" //
#include "cliparser.h"
static int CmdHelp(const char *Cmd); 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 <card id>] [b <raw hex>]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " c <card id> : 8 byte card ID");
PrintAndLogEx(NORMAL, " b <raw hex> : 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 <Card-ID>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " <Card ID> : 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 // 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) // 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 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 startIndex = 8 + (3 * byteLength) + 1; // skip 8 bits preamble, STX, '2', '0', and first start bit
const size_t dataLength = 9; 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; return PM3_SUCCESS;
} }
/*
// convert a 16 byte array of raw demod data (FF204990XX...) to 8 bytes of PAC_8byte ID // convert a 16 byte array of raw demod data (FF204990XX...) to 8 bytes of PAC_8byte ID
// performs no parity or checksum validation // 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++) { for (int i = 4; i < 12; i++) {
uint8_t shift = 7 - (i + 3) % 4 * 2; uint8_t shift = 7 - (i + 3) % 4 * 2;
size_t index = i + (i - 1) / 4; 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...) // 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]; uint8_t idbytes[10];
// prepend PAC_8byte card type "20" // prepend PAC_8byte card type "20"
idbytes[0] = '2'; idbytes[0] = '2';
idbytes[1] = '0'; idbytes[1] = '0';
for (size_t i = 0; i < 8; i++) 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 // initialise array with start and stop bits
for (size_t i = 0; i < 16; i++) 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 dst[0] = 0xFF; // mark + stop
outRawBytes[1] = 0x20; // start + reflect8(STX) dst[1] = 0x20; // start + reflect8(STX)
uint8_t checksum = 0; uint8_t checksum = 0;
for (size_t i = 2; i < 13; i++) { for (size_t i = 2; i < 13; i++) {
@ -138,8 +110,8 @@ static void pacCardIdToRaw(uint8_t *outRawBytes, const char *cardId) {
} }
pattern <<= shift; pattern <<= shift;
outRawBytes[index] |= pattern >> 8 & 0xFF; dst[index] |= pattern >> 8 & 0xFF;
outRawBytes[index + 1] |= pattern & 0xFF; dst[index + 1] |= pattern & 0xFF;
} }
} }
@ -176,7 +148,7 @@ int demodPac(bool verbose) {
const size_t idLen = 9; // 8 bytes + null terminator const size_t idLen = 9; // 8 bytes + null terminator
uint8_t cardid[idLen]; 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) if (retval == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "PAC/Stanley - Card: " _GREEN_("%s") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4); 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); return demodPac(true);
} }
static int CmdPacRead(const char *Cmd) { static int CmdPacReader(const char *Cmd) {
(void)Cmd;
lf_read(false, 4096 * 2 + 20); CLIParserContext *ctx;
return demodPac(true); 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) { static int CmdPacClone(const char *Cmd) {
uint32_t blocks[5]; CLIParserContext *ctx;
bool errors = false; CLIParserInit(&ctx, "lf pac clone",
uint8_t cmdp = 0; "clone a PAC/Stanley tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
int datalen = 0; "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) { void *argtable[] = {
switch (tolower(param_getchar(Cmd, cmdp))) { arg_param_begin,
case 'h': arg_str0(NULL, "cn", "<dec>", "8 byte PAC/Stanley card ID"),
return usage_lf_pac_clone(); arg_str0("r", "raw", "<hex>", "raw hex data. 16 bytes max"),
case 'c': { arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
// skip first block, 4*4 = 16 bytes left arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
uint8_t rawhex[16] = {0}; arg_param_end
char cardid[9]; };
int res = param_getstr(Cmd, cmdp + 1, cardid, sizeof(cardid)); CLIExecWithReturn(ctx, Cmd, argtable, false);
if (res < 8)
errors = true;
pacCardIdToRaw(rawhex, cardid); uint8_t cnstr[9];
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { int cnlen = 9;
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); memset(cnstr, 0x00, sizeof(cnstr));
} CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen);
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;
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { // skip first block, 4*4 = 16 bytes left
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); int raw_len = 0;
} uint8_t raw[16] = {0};
cmdp += 2; CLIGetHexWithReturn(ctx, 2, raw, &raw_len);
break;
} bool q5 = arg_get_lit(ctx, 3);
default: bool em = arg_get_lit(ctx, 4);
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); CLIParserFree(ctx);
errors = true;
break; 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; 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)); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac reader`") " to verify");
return res; return res;
} }
static int CmdPacSim(const char *Cmd) { static int CmdPacSim(const char *Cmd) {
// NRZ sim. CLIParserContext *ctx;
char cardid[9] = { 0 }; CLIParserInit(&ctx, "lf pac sim",
uint8_t rawBytes[16] = { 0 }; "Enables simulation of PAC/Stanley card with specified card number.\n"
uint32_t rawBlocks[4]; "Simulation runs until the button is pressed or another USB command is issued.\n"
char cmdp = tolower(param_getchar(Cmd, 0)); "The card ID is 8 byte number. Larger values are truncated.",
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pac_sim(); "lf pac sim --cn CD4F5552\n"
"lf pac sim --raw FF2049906D8511C593155B56D5B2649F"
);
int res = param_getstr(Cmd, 0, cardid, sizeof(cardid)); void *argtable[] = {
if (res < 8) return usage_lf_pac_sim(); arg_param_begin,
arg_str0(NULL, "cn", "<dec>", "8 byte PAC/Stanley card ID"),
arg_str0("r", "raw", "<hex>", "raw hex data. 16 bytes max"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t bs[128]; uint8_t cnstr[10];
pacCardIdToRaw(rawBytes, cardid); int cnlen = 9;
for (size_t i = 0; i < ARRAYLEN(rawBlocks); i++) { memset(cnstr, 0x00, sizeof(cnstr));
rawBlocks[i] = bytes_to_num(rawBytes + (i * sizeof(uint32_t)), sizeof(uint32_t)); CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen);
num_to_bytebits(rawBlocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
// 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)); lf_nrzsim_t *payload = calloc(1, sizeof(lf_nrzsim_t) + sizeof(bs));
payload->invert = 0; payload->invert = 0;
payload->separator = 0; payload->separator = 0;
@ -297,11 +359,11 @@ static int CmdPacSim(const char *Cmd) {
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"}, {"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"},
{"read", CmdPacRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, {"reader", CmdPacReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"}, {"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"},
{"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"}, {"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -1,4 +1,5 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Marshmellow
// //
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // 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 // 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) // FSK2a, rf/50, 96 bits (completely known)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfparadox.h" #include "cmdlfparadox.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
@ -25,40 +24,11 @@
#include "protocols.h" // t55xx defines #include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone.. #include "cmdlft55xx.h" // clone..
#include "crc.h" // maxim #include "crc.h" // maxim
#include "cmdlfem4x05.h" //
#include "cliparser.h"
static int CmdHelp(const char *Cmd); 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 <raw hex>]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " b <raw hex> : 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] <Facility-Code> <Card-Number>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
PrintAndLogEx(NORMAL, " <Card Number> : 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[] = { const uint8_t paradox_lut[] = {
0xDB, 0xFC, 0x3F, 0xC5, 0x50, 0x14, 0x05, 0x47, 0xDB, 0xFC, 0x3F, 0xC5, 0x50, 0x14, 0x05, 0x47,
0x9F, 0xED, 0x7D, 0x59, 0x22, 0x84, 0x21, 0x4E, 0x9F, 0xED, 0x7D, 0x59, 0x22, 0x84, 0x21, 0x4E,
@ -71,9 +41,9 @@ const uint8_t paradox_lut[] = {
#define PARADOX_PREAMBLE_LEN 8 #define PARADOX_PREAMBLE_LEN 8
//by marshmellow // by marshmellow
//Paradox Prox demod - FSK2a RF/50 with preamble of 00001111 (then manchester encoded) // 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 // print full Paradox Prox ID and some bit format details if found
int demodParadox(bool verbose) { int demodParadox(bool verbose) {
(void) verbose; // unused so far (void) verbose; // unused so far
@ -204,91 +174,141 @@ static int CmdParadoxDemod(const char *Cmd) {
return demodParadox(true); return demodParadox(true);
} }
//by marshmellow static int CmdParadoxReader(const char *Cmd) {
//see ASKDemod for what args are accepted CLIParserContext *ctx;
static int CmdParadoxRead(const char *Cmd) { CLIParserInit(&ctx, "lf paradox reader",
(void)Cmd; // Cmd is not used so far "read a Paradox tag",
lf_read(false, 10000); "lf Paradox reader -@ -> continuous reader mode"
return demodParadox(true); );
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) { static int CmdParadoxClone(const char *Cmd) {
uint32_t blocks[4]; CLIParserContext *ctx;
bool errors = false; CLIParserInit(&ctx, "lf paradox clone",
uint8_t cmdp = 0; "clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
int datalen = 0; "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) { void *argtable[] = {
switch (tolower(param_getchar(Cmd, cmdp))) { arg_param_begin,
case 'h': arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
return usage_lf_paradox_clone(); arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
case 'b': { arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
// skip first block, 3*4 =12 bytes left arg_param_end
uint8_t rawhex[12] = {0}; };
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen); CLIExecWithReturn(ctx, Cmd, argtable, false);
if (res != 0)
errors = true;
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { int raw_len = 0;
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); // skip first block, 3*4 = 12 bytes left
} uint8_t raw[12] = {0};
cmdp += 2; CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
break;
} bool q5 = arg_get_lit(ctx, 2);
default: bool em = arg_get_lit(ctx, 3);
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); CLIParserFree(ctx);
errors = true;
break; 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; 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)); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf paradox read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf paradox read`") " to verify");
return res; return res;
} }
static int CmdParadoxSim(const char *Cmd) { 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]; void *argtable[] = {
memset(bs, 0x00, sizeof(bs)); arg_param_begin,
arg_str0("r", "raw", "<hex>", " 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 // Paradox uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 1 FSK2a
uint8_t clk = 50, invert = 1, high = 10, low = 8; uint8_t clk = 50, 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);
lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs)); lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs));
payload->fchigh = high; payload->fchigh = high;
payload->fclow = low; payload->fclow = low;
payload->separator = invert; payload->separator = 0;
payload->clock = clk; payload->clock = clk;
memcpy(payload->data, bs, sizeof(bs)); memcpy(payload->data, bs, sizeof(bs));
@ -302,15 +322,29 @@ static int CmdParadoxSim(const char *Cmd) {
PrintAndLogEx(INFO, "Done"); PrintAndLogEx(INFO, "Done");
if (resp.status != PM3_EOPABORTED) if (resp.status != PM3_EOPABORTED)
return resp.status; 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdParadoxDemod, AlwaysAvailable, "Demodulate a Paradox FSK tag from the GraphBuffer"}, {"demod", CmdParadoxDemod, AlwaysAvailable, "Demodulate a Paradox FSK tag from the GraphBuffer"},
{"read", CmdParadoxRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"}, {"reader", CmdParadoxReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
{"clone", CmdParadoxClone, IfPm3Lf, "clone paradox tag to T55x7"}, {"clone", CmdParadoxClone, IfPm3Lf, "clone paradox tag"},
{"sim", CmdParadoxSim, IfPm3Lf, "simulate paradox tag"}, {"sim", CmdParadoxSim, IfPm3Lf, "simulate paradox tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -8,51 +8,64 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfpresco.h" #include "cmdlfpresco.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include "commonutil.h" // ARRAYLEN
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
#include "cmddata.h" #include "cmddata.h"
#include "cmdlf.h" #include "cmdlf.h"
#include "protocols.h" // for T55xx config register definitions #include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest #include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite #include "cmdlft55xx.h" // verifywrite
#include "cmdlfem4x05.h" //
#include "cliparser.h"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int usage_lf_presco_clone(void) { // find presco preamble 0x10D in already demoded data
PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 or Q5/T5555 tag."); static int detectPresco(uint8_t *dest, size_t *size) {
PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d <Card-ID> c <hex-ID> <Q5>"); if (*size < 128 * 2) return -1; //make sure buffer has data
PrintAndLogEx(NORMAL, "Options:"); size_t startIdx = 0;
PrintAndLogEx(NORMAL, " h : this help"); 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};
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card ID"); if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number"); return -2; //preamble not found
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag"); if (*size != 128) return -3; //wrong demoded size
PrintAndLogEx(NORMAL, ""); //return start position
PrintAndLogEx(NORMAL, "Examples:"); return (int)startIdx;
PrintAndLogEx(NORMAL, _YELLOW_(" lf presco clone d 123456789")); }
// 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; return PM3_SUCCESS;
} }
static int usage_lf_presco_sim(void) { // calc not certain - intended to get bitstream for programming / sim
PrintAndLogEx(NORMAL, "Enables simulation of presco card with specified card number."); static int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) {
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); num_to_bytebits(0x10D00000, 32, prescoBits);
PrintAndLogEx(NORMAL, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated."); num_to_bytebits(0x00000000, 32, prescoBits + 32);
PrintAndLogEx(NORMAL, ""); num_to_bytebits(0x00000000, 32, prescoBits + 64);
PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d <Card-ID> or c <hex-ID>"); num_to_bytebits(fullcode, 32, prescoBits + 96);
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card number");
PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf presco sim d 123456789"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -85,15 +98,16 @@ int demodPresco(bool verbose) {
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32); uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32); uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32);
uint32_t cardid = raw4; uint32_t fullcode = raw4;
PrintAndLogEx(SUCCESS, "Presco - Card: " _GREEN_("%08X") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4); uint32_t usercode = fullcode & 0x0000FFFF;
uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
uint32_t sitecode = 0, usercode = 0, fullcode = 0; PrintAndLogEx(SUCCESS, "Presco Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08X") " Raw: " _YELLOW_("%08X%08X%08X%08X")
bool Q5 = false; , sitecode
char cmd[12] = {0}; , usercode
sprintf(cmd, "H %08X", cardid); , fullcode
getWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5); , raw1, raw2, raw3, raw4
PrintAndLogEx(SUCCESS, "SiteCode: " _GREEN_("%u") " UserCode: " _GREEN_("%u") " FullCode: " _GREEN_("%08X"), sitecode, usercode, fullcode); );
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -103,35 +117,108 @@ static int CmdPrescoDemod(const char *Cmd) {
} }
//see ASKDemod for what args are accepted //see ASKDemod for what args are accepted
static int CmdPrescoRead(const char *Cmd) { static int CmdPrescoReader(const char *Cmd) {
// Presco Number: 123456789 --> Sitecode 30 | usercode 8665 CLIParserContext *ctx;
(void)Cmd; // Cmd is not used so far CLIParserInit(&ctx, "lf presco reader",
lf_read(false, 12000); "read a presco tag",
return demodPresco(true); "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 // takes base 12 ID converts to hex
// Or takes 8 digit hex ID // Or takes 8 digit hex ID
static int CmdPrescoClone(const char *Cmd) { 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, "<hex>", "8 digit hex card number"),
arg_str0("d", NULL, "<digits>", "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}; 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. char cardtype[16] = {"T55x7"};
if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) return usage_lf_presco_clone(); // Q5
if (q5) {
if (Q5)
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR; 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) { if ((sitecode & 0xFF) != sitecode) {
sitecode &= 0xFF; 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) { if ((usercode & 0xFFFF) != usercode) {
usercode &= 0xFFFF; 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 blocks[1] = 0x10D00000; //preamble
@ -139,25 +226,84 @@ static int CmdPrescoClone(const char *Cmd) {
blocks[3] = 0x00000000; blocks[3] = 0x00000000;
blocks[4] = fullcode; 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)); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco reader`") " to verify");
return res; return res;
} }
// takes base 12 ID converts to hex // takes base 12 ID converts to hex
// Or takes 8 digit hex ID // Or takes 8 digit hex ID
static int CmdPrescoSim(const char *Cmd) { static int CmdPrescoSim(const char *Cmd) {
uint32_t sitecode = 0, usercode = 0, fullcode = 0; CLIParserContext *ctx;
bool Q5 = false; CLIParserInit(&ctx, "lf presco sim",
// get wiegand from printed number. "Enables simulation of presco card with specified card number.\n"
if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) "Simulation runs until the button is pressed or another USB command is issued.\n"
return usage_lf_presco_sim(); "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, "<hex>", "8 digit hex card number"),
arg_str0("d", NULL, "<digits>", "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]; uint8_t bs[128];
getPrescoBits(fullcode, bs); getPrescoBits(fullcode, bs);
@ -185,9 +331,9 @@ static int CmdPrescoSim(const char *Cmd) {
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"}, {"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"},
{"read", CmdPrescoRead, IfPm3Lf, "Attempt to read and Extract tag data"}, {"reader", CmdPrescoReader, IfPm3Lf, "Attempt to read and Extract tag data"},
{"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"}, {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"},
{"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"}, {"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@ -201,86 +347,3 @@ int CmdLFPresco(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
return CmdsParse(CommandTable, Cmd); 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;
}

View file

@ -12,11 +12,6 @@
#include "common.h" #include "common.h"
int CmdLFPresco(const char *Cmd); int CmdLFPresco(const char *Cmd);
int demodPresco(bool verbose); 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 #endif

View file

@ -15,7 +15,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
@ -27,43 +26,11 @@
#include "lfdemod.h" // parityTest #include "lfdemod.h" // parityTest
#include "crc.h" #include "crc.h"
#include "cmdlft55xx.h" // verifywrite #include "cmdlft55xx.h" // verifywrite
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM Defines
static int CmdHelp(const char *Cmd); 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] <Facility-Code> <Card-Number> [Q5]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
PrintAndLogEx(NORMAL, " <Card Number> : 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] <Facility-Code> <Card-Number>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
PrintAndLogEx(NORMAL, " <Card Number> : 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) //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 //print full Farpointe Data/Pyramid Prox ID and some bit format details if found
int demodPyramid(bool verbose) { int demodPyramid(bool verbose) {
@ -215,26 +182,71 @@ static int CmdPyramidDemod(const char *Cmd) {
return demodPyramid(true); return demodPyramid(true);
} }
static int CmdPyramidRead(const char *Cmd) { static int CmdPyramidReader(const char *Cmd) {
(void)Cmd; // Cmd is not used so far CLIParserContext *ctx;
lf_read(false, 15000); CLIParserInit(&ctx, "lf pyramid reader",
return demodPyramid(true); "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) { static int CmdPyramidClone(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pyramid_clone(); CLIParserInit(&ctx, "lf pyramid clone",
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0; "clone a Farpointe/Pyramid tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_pyramid_clone(); "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", "<dec>", "8-bit value facility code"),
arg_u64_1(NULL, "cn", "<dec>", "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]; uint32_t blocks[5];
uint8_t *bs = calloc(128, sizeof(uint8_t)); uint8_t *bs = calloc(128, sizeof(uint8_t));
if (bs == NULL) { if (bs == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
facilitycode = (fc & 0x000000FF); uint32_t facilitycode = (fc & 0x000000FF);
cardnumber = (cn & 0x0000FFFF); uint32_t cardnumber = (cn & 0x0000FFFF);
if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) { if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation."); 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 //Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks
blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4 << T55x7_MAXBLOCK_SHIFT; blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4 << T55x7_MAXBLOCK_SHIFT;
char cardtype[16] = {"T55x7"};
// Q5 // 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; 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[1] = bytebits_to_byte(bs, 32);
blocks[2] = bytebits_to_byte(bs + 32, 32); blocks[2] = bytebits_to_byte(bs + 32, 32);
@ -256,36 +275,53 @@ static int CmdPyramidClone(const char *Cmd) {
free(bs); 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)); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid reader`") " to verify");
return res; return res;
} }
static int CmdPyramidSim(const char *Cmd) { 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)); void *argtable[] = {
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pyramid_sim(); arg_param_begin,
arg_u64_1(NULL, "fc", "<dec>", "8-bit value facility code"),
arg_u64_1(NULL, "cn", "<dec>", "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]; uint8_t bs[128];
memset(bs, 0x00, sizeof(bs)); 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) { if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation."); PrintAndLogEx(ERR, "Error with tag bitstream generation.");
return PM3_ESOFT; 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 // Pyramid uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 0
lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs)); 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"}, {"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"}, {"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"},
{"read", CmdPyramidRead, IfPm3Lf, "attempt to read and extract tag data"}, {"reader", CmdPyramidReader, IfPm3Lf, "attempt to read and extract tag data"},
{"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"}, {"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"},
{"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"}, {"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -8,10 +8,8 @@
// ASK/Manchester, RF/40, 96 bits long (unknown cs) // ASK/Manchester, RF/40, 96 bits long (unknown cs)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfsecurakey.h" #include "cmdlfsecurakey.h"
#include <string.h> // memcpy #include <string.h> // memcpy
#include <ctype.h> // tolower #include <ctype.h> // tolower
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
@ -22,22 +20,11 @@
#include "parity.h" // for wiegand parity test #include "parity.h" // for wiegand parity test
#include "protocols.h" // t55xx defines #include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone.. #include "cmdlft55xx.h" // clone..
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
static int CmdHelp(const char *Cmd); 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 <raw hex>]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " b <raw hex> : 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 //see ASKDemod for what args are accepted
int demodSecurakey(bool verbose) { int demodSecurakey(bool verbose) {
(void) verbose; // unused so far (void) verbose; // unused so far
@ -118,9 +105,11 @@ int demodSecurakey(bool verbose) {
if (bitLen <= 32) if (bitLen <= 32)
PrintAndLogEx(SUCCESS, "Wiegand: " _GREEN_("%08X") " parity (%s)", (lWiegand << (bitLen / 2)) | rWiegand, parity ? _GREEN_("ok") : _RED_("fail")); 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"); if (verbose) {
PrintAndLogEx(INFO, "How the checksum is calculated is unknown"); PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown");
PrintAndLogEx(INFO, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members"); 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; return PM3_SUCCESS;
} }
@ -129,68 +118,160 @@ static int CmdSecurakeyDemod(const char *Cmd) {
return demodSecurakey(true); return demodSecurakey(true);
} }
static int CmdSecurakeyRead(const char *Cmd) { static int CmdSecurakeyReader(const char *Cmd) {
(void)Cmd; // Cmd is not used so far CLIParserContext *ctx;
lf_read(false, 8000); CLIParserInit(&ctx, "lf securakey reader",
return demodSecurakey(true); "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) { static int CmdSecurakeyClone(const char *Cmd) {
uint32_t blocks[4]; CLIParserContext *ctx;
bool errors = false; CLIParserInit(&ctx, "lf securakey clone",
uint8_t cmdp = 0; "clone a Securakey tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
int datalen = 0; "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) { void *argtable[] = {
switch (tolower(param_getchar(Cmd, cmdp))) { arg_param_begin,
case 'h': arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
return usage_lf_securakey_clone(); arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
case 'b': { arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
// skip first block, 3*4 = 12 bytes left arg_param_end
uint8_t rawhex[12] = {0}; };
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen); CLIExecWithReturn(ctx, Cmd, argtable, false);
if (res != 0)
errors = true;
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { int raw_len = 0;
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); // skip first block, 3*4 = 12 bytes left
} uint8_t raw[12] = {0};
cmdp += 2; CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
break; bool q5 = arg_get_lit(ctx, 2);
} bool em = arg_get_lit(ctx, 3);
default: CLIParserFree(ctx);
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true; if (q5 && em) {
break; 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 //Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks
blocks[0] = T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_40 | 3 << T55x7_MAXBLOCK_SHIFT; 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)); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey reader`") " to verify");
return res; return res;
} }
static int CmdSecurakeySim(const char *Cmd) { 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", "<hex>", " 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; return PM3_SUCCESS;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdSecurakeyDemod, AlwaysAvailable, "Demodulate an Securakey tag from the GraphBuffer"}, {"demod", CmdSecurakeyDemod, AlwaysAvailable, "Demodulate an Securakey tag from the GraphBuffer"},
{"read", CmdSecurakeyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, {"reader", CmdSecurakeyReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdSecurakeyClone, IfPm3Lf, "clone Securakey tag to T55x7"}, {"clone", CmdSecurakeyClone, IfPm3Lf, "clone Securakey tag to T55x7"},
{"sim", CmdSecurakeySim, IfPm3Lf, "simulate Securakey tag"}, {"sim", CmdSecurakeySim, IfPm3Lf, "simulate Securakey tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -1027,7 +1027,7 @@ static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
} }
// Define prototype to call from within detect. // 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) { static int CmdT55xxDetect(const char *Cmd) {
@ -1054,7 +1054,7 @@ static int CmdT55xxDetect(const char *Cmd) {
return usage_t55xx_detect(); return usage_t55xx_detect();
case 'p': case 'p':
password = param_get32ex(Cmd, cmdp + 1, 0, 16); 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; usepwd = true;
cmdp += 2; cmdp += 2;
break; break;
@ -1096,11 +1096,11 @@ static int CmdT55xxDetect(const char *Cmd) {
if (usewake) { if (usewake) {
// call wake // call wake
if (try_with_pwd) if (try_with_pwd)
CmdT55xxWakeUp (wakecmd); CmdT55xxWakeUp(wakecmd);
else else
CmdT55xxWakeUp ("q"); CmdT55xxWakeUp("q");
// sleep 90 ms // sleep 90 ms
nanosleep (&sleepperiod, &sleepperiod); nanosleep(&sleepperiod, &sleepperiod);
} }
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false) 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) { if (usewake) {
// call wake // call wake
if (try_with_pwd) if (try_with_pwd)
CmdT55xxWakeUp (wakecmd); CmdT55xxWakeUp(wakecmd);
else else
CmdT55xxWakeUp ("q"); CmdT55xxWakeUp("q");
// sleep 90 ms // sleep 90 ms
nanosleep (&sleepperiod, &sleepperiod); nanosleep(&sleepperiod, &sleepperiod);
} }
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) { if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {

View file

@ -8,10 +8,10 @@
// Low frequency TI commands // Low frequency TI commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfti.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h> #include <inttypes.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "commonutil.h" #include "commonutil.h"
#include "comms.h" #include "comms.h"
@ -19,7 +19,7 @@
#include "ui.h" #include "ui.h"
#include "proxgui.h" #include "proxgui.h"
#include "graph.h" #include "graph.h"
#include "cmdlfti.h" #include "cliparser.h"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -277,10 +277,27 @@ static int CmdTIDemod(const char *Cmd) {
} }
// read a TI tag and return its ID // read a TI tag and return its ID
static int CmdTIRead(const char *Cmd) { static int CmdTIReader(const char *Cmd) {
(void)Cmd; // Cmd is not used so far CLIParserContext *ctx;
clearCommandBuffer(); CLIParserInit(&ctx, "lf ti reader",
SendCommandNG(CMD_LF_TI_READ, NULL, 0); "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; return PM3_SUCCESS;
} }
@ -300,15 +317,15 @@ static int CmdTIWrite(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0); SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0);
PrintAndLogEx(SUCCESS, "Done"); 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; return PM3_SUCCESS;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI-type LF tag from the GraphBuffer"}, {"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"}, {"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"}, {"write", CmdTIWrite, IfPm3Lf, "Write new data to a r/w TI 134 kHz tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -9,13 +9,10 @@
// ASK/Manchester, RF/32, 64 bits (complete) // ASK/Manchester, RF/32, 64 bits (complete)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfviking.h" #include "cmdlfviking.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include "common.h" #include "common.h"
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
@ -23,36 +20,10 @@
#include "cmdlf.h" #include "cmdlf.h"
#include "lfdemod.h" #include "lfdemod.h"
#include "commonutil.h" // num_to_bytes #include "commonutil.h" // num_to_bytes
#include "cliparser.h"
static int CmdHelp(const char *Cmd); 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 <Card ID - 8 hex digits> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " <Card Number> : 8 digit hex viking card number");
PrintAndLogEx(NORMAL, " <Q5> : 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 <Card-Number>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " <Card Number> : 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 //see ASKDemod for what args are accepted
int demodViking(bool verbose) { int demodViking(bool verbose) {
(void) verbose; // unused so far (void) verbose; // unused so far
@ -88,40 +59,90 @@ static int CmdVikingDemod(const char *Cmd) {
} }
//see ASKDemod for what args are accepted //see ASKDemod for what args are accepted
static int CmdVikingRead(const char *Cmd) { static int CmdVikingReader(const char *Cmd) {
(void)Cmd;
lf_read(false, 10000); CLIParserContext *ctx;
return demodViking(true); 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) { 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); CLIParserContext *ctx;
if (id == 0) return usage_lf_viking_clone(); 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)); void *argtable[] = {
if (cmdp == 'q') arg_param_begin,
Q5 = true; arg_strx0(NULL, "cn", "<hex>", "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 { struct p {
bool Q5; bool Q5;
bool EM;
uint8_t blocks[8]; uint8_t blocks[8];
} PACKED payload; } PACKED payload;
payload.Q5 = Q5; payload.Q5 = q5;
payload.EM = em;
num_to_bytes(rawID, 8, &payload.blocks[0]); 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") PrintAndLogEx(INFO, "Preparing to clone Viking tag on " _YELLOW_("%s") " - ID " _YELLOW_("%08X")" raw " _YELLOW_("%s")
, (Q5) ? "Q5/T5555" : "T55x7" , cardtype
, id , id
, sprint_hex(payload.blocks, sizeof(payload.blocks)) , sprint_hex(payload.blocks, sizeof(payload.blocks))
); );
clearCommandBuffer(); clearCommandBuffer();
@ -133,20 +154,40 @@ static int CmdVikingClone(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
PrintAndLogEx(SUCCESS, "Done"); 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; return resp.status;
} }
static int CmdVikingSim(const char *Cmd) { 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); CLIParserContext *ctx;
if (id == 0) return usage_lf_viking_sim(); 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", "<hex>", "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)); 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdVikingDemod, AlwaysAvailable, "Demodulate a Viking tag from the GraphBuffer"}, {"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"}, {"clone", CmdVikingClone, IfPm3Lf, "clone Viking tag to T55x7 or Q5/T5555"},
{"sim", CmdVikingSim, IfPm3Lf, "simulate Viking tag"}, {"sim", CmdVikingSim, IfPm3Lf, "simulate Viking tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
@ -201,7 +242,7 @@ uint64_t getVikingBits(uint32_t id) {
ret |= checksum; ret |= checksum;
return ret; return ret;
} }
// by marshmellow
// find viking preamble 0xF200 in already demoded data // find viking preamble 0xF200 in already demoded data
int detectViking(uint8_t *src, size_t *size) { int detectViking(uint8_t *src, size_t *size) {
//make sure buffer has data //make sure buffer has data

View file

@ -27,41 +27,14 @@
#include "lfdemod.h" // parityTest #include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // write verify #include "cmdlft55xx.h" // write verify
#include "cmdlfem4x05.h" // #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 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] <card ID> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <card ID> : Visa2k card ID");
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, " <em4305> : 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] <card ID>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <card ID> : 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) { static uint8_t visa_chksum(uint32_t id) {
uint8_t sum = 0; uint8_t sum = 0;
for (uint8_t i = 0; i < 32; i += 4) 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 // 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) { static int CmdVisa2kReader(const char *Cmd) {
(void)Cmd; // Cmd is not used so far CLIParserContext *ctx;
lf_read(false, 20000); CLIParserInit(&ctx, "lf visa2000 reader",
return demodVisa2k(true); "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) { static int CmdVisa2kClone(const char *Cmd) {
uint64_t id = 0; CLIParserContext *ctx;
uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, BL0CK1, 0}; 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)); void *argtable[] = {
if (strlen(Cmd) == 0 || cmdp == 'h') arg_param_begin,
return usage_lf_visa2k_clone(); arg_u64_1(NULL, "cn", "<dec>", "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); uint32_t id = arg_get_u32_def(ctx, 1, 0);
bool q5 = arg_get_lit(ctx, 2);
char cardtype[16] = {"T55x7"}; bool em = arg_get_lit(ctx, 3);
// Q5 CLIParserFree(ctx);
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");
}
if (q5 && em) { if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time"); PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG; 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[2] = id;
blocks[3] = (visa_parity(id) << 4) | visa_chksum(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)); print_blocks(blocks, ARRAYLEN(blocks));
int res; int res;
@ -215,22 +217,31 @@ static int CmdVisa2kClone(const char *Cmd) {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
} }
PrintAndLogEx(SUCCESS, "Done"); 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; return res;
} }
static int CmdVisa2kSim(const char *Cmd) { static int CmdVisa2kSim(const char *Cmd) {
uint32_t id = 0; CLIParserContext *ctx;
char cmdp = tolower(param_getchar(Cmd, 0)); CLIParserInit(&ctx, "lf visa2000 sim",
if (strlen(Cmd) == 0 || cmdp == 'h') "Enables simulation of visa2k card with specified card number.\n"
return usage_lf_visa2k_sim(); "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", "<dec>", "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]; uint8_t bs[96];
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
@ -257,11 +268,11 @@ static int CmdVisa2kSim(const char *Cmd) {
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"}, {"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"},
{"read", CmdVisa2kRead, IfPm3Lf, "attempt to read and extract tag data from the antenna"}, {"reader", CmdVisa2kReader, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
{"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"}, {"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"},
{"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"}, {"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -116,7 +116,7 @@ static void asn1_tag_dump_str_time(const struct tlv *tlv, const struct asn1_tag
if (longyear == false) if (longyear == false)
PrintAndLogEx(NORMAL, "20" NOLF); 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) if (len < startindx + 2)
break; break;

View file

@ -462,9 +462,9 @@ static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *ta
if (val & 0x80) { if (val & 0x80) {
PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " "); PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " ");
PrintAndLogEx(NORMAL, " %s - '%s'", PrintAndLogEx(NORMAL, " %s - '%s'",
bitstrings[bit - 1], bitstrings[bit - 1],
(bits->bit == EMV_BIT(byte, bit)) ? bits->name : "Unknown" (bits->bit == EMV_BIT(byte, bit)) ? bits->name : "Unknown"
); );
} }
if (bits->bit == EMV_BIT(byte, bit)) if (bits->bit == EMV_BIT(byte, bit))
bits ++; 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) { static void emv_tag_dump_yymmdd(const struct tlv *tlv, const struct emv_tag *tag, int level) {
PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " "); PrintAndLogEx(INFO, "%*s" NOLF, (level * 4), " ");
PrintAndLogEx(NORMAL, " Date: 20%02lu.%lu.%lu", PrintAndLogEx(NORMAL, " Date: 20%02lu.%lu.%lu",
emv_value_numeric(tlv, 0, 2), emv_value_numeric(tlv, 0, 2),
emv_value_numeric(tlv, 2, 4), emv_value_numeric(tlv, 2, 4),
emv_value_numeric(tlv, 4, 6) emv_value_numeric(tlv, 4, 6)
); );
} }
static uint32_t emv_get_binary(const unsigned char *S) { 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(INFO, "%*s" NOLF, (level * 4), " ");
PrintAndLogEx(NORMAL, " %02x %02x: '%s' '%s' and '%s' if this CVM is unsuccessful", PrintAndLogEx(NORMAL, " %02x %02x: '%s' '%s' and '%s' if this CVM is unsuccessful",
tlv->value[i], tlv->value[i],
tlv->value[i + 1], tlv->value[i + 1],
method, method,
condition, condition,
(tlv->value[i] & 0x40) ? "continue" : "fail" (tlv->value[i] & 0x40) ? "continue" : "fail"
); );
} }
} }

View file

@ -778,7 +778,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
if (sdad_tlv) { if (sdad_tlv) {
PrintAndLogEx(INFO, "* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA..."); 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) { if (!atc_db) {
PrintAndLogEx(ERR, "Error: Can't recover IDN (ICC Dynamic Number)"); PrintAndLogEx(ERR, "Error: Can't recover IDN (ICC Dynamic Number)");
emv_pk_free(pk); emv_pk_free(pk);
@ -804,9 +804,10 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
emv_pk_free(pk); emv_pk_free(pk);
emv_pk_free(issuer_pk); emv_pk_free(issuer_pk);
emv_pk_free(icc_pk); emv_pk_free(icc_pk);
atc_db = NULL; tlvdb_free(atc_db);
return 9; return 9;
} }
} else { } else {
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
if (dac_db) { if (dac_db) {

View file

@ -468,9 +468,9 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]) {
mbedtls_des_setkey_enc(&ctx_e, key64_stdformat); mbedtls_des_setkey_enc(&ctx_e, key64_stdformat);
mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result); mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result);
PrintAndLogEx(NORMAL, "\n"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "-- High security custom key (Kcus) --"); 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)); PrintAndLogEx(SUCCESS, "iClass format %s", sprint_hex(key64, 8));
if (master_key != NULL) if (master_key != NULL)

View file

@ -227,7 +227,7 @@ void print_buffer(const uint8_t *data, const size_t len, int level) {
hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, mod, (sizeof(buf) - strlen(buf) - 1), 0, 1, true); hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, mod, (sizeof(buf) - strlen(buf) - 1), 0, 1, true);
// add the spaces... // 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)); snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, mod));
PrintAndLogEx(INFO, "%s", buf); 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 // aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp
// to // to
// hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii // hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii

View file

@ -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); 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_bytebits(uint64_t n, size_t len, uint8_t *dest);
void num_to_bytebitsLSBF(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. // Swap endian on arrays up to 64bytes.
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);

694
doc/T5577_Guide.md Normal file
View file

@ -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 dont 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 :
<http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-9187-RFID-ATA5577C_Datasheet.pdf>
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
Lets 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).
(Dont 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 DONT 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 dont 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 28<sup>th</sup>
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 dont 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 its 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 dont 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 : Dont forget to set a valid password in block 7 and remember it.***
## The configuration Block Block 3 Page 1

View file

@ -62,30 +62,47 @@ Dump iCLASS card contents
``` ```
Options Options
--- ---
k <key> : *Access Key as 16 hex symbols or 1 hex to select key from memory -f, --file <filename> filename to save dump to
-k, --key <hex> debit key as 16 hex symbols OR NR/MAC for replay
--ki <dec> debit key index to select key from memory 'hf iclass managekeys'
--credit <hex> credit key as 16 hex symbols
--ci <dec> 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 Read iCLASS Block
``` ```
Options Options
--- ---
b <block> : The block number as 2 hex symbols -k, --key <hex> Access key as 16 hex symbols
k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory -b, --block <dec> The block number to read as an integer
--ki <dec> 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 Write to iCLASS Block
``` ```
Options Options
--- ---
b <block> : The block number as 2 hex symbols -k, --key <hex> Access key as 16 hex symbols
d <data> : Set the Data to write as 16 hex symbols -b, --block <dec> The block number to read as an integer
k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory -d, --data <hex> data to write as 16 hex symbols
--ki <dec> 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 Print keystore
@ -111,22 +128,24 @@ Encrypt iCLASS Block
``` ```
Options Options
--- ---
d <block data> : 16 bytes hex -d, --data <hex> data to encrypt
k <transport key> : 16 bytes hex -k, --key <hex> 3DES transport key
-v, --verbose verbose output
pm3 --> hf iclass encrypt d 0000000f2aa3dba8 pm3 --> hf iclass encrypt -d 0000000f2aa3dba8
``` ```
Decrypt iCLASS Block / file Decrypt iCLASS Block / file
``` ```
Options Options
--- ---
d <encrypted blk> : 16 bytes hex -f, --file <filename> filename of dumpfile
f <filename> : filename of dump -d, --data <hex> 3DES encrypted data
k <transport key> : 16 bytes hex -k, --key <hex> 3DES transport key
-v, --verbose verbose output
pm3 --> hf iclass decrypt d 2AD4C8211F996871 pm3 --> hf iclass decrypt -d 2AD4C8211F996871
pm3 --> hf iclass decrypt f hf-iclass-db883702f8ff12e0.bin pm3 --> hf iclass decrypt -f hf-iclass-db883702f8ff12e0.bin
``` ```
Load iCLASS dump into memory for simulation Load iCLASS dump into memory for simulation
@ -140,8 +159,8 @@ pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin
Clone iCLASS Legacy Sequence Clone iCLASS Legacy Sequence
``` ```
pm3 --> hf iclass rdbl b 7 k 0 pm3 --> hf iclass rdbl -b 7 --ki 0
pm3 --> hf iclass wrbl b 7 d 6ce099fe7e614fd0 k 0 pm3 --> hf iclass wrbl -b 7 -d 6ce099fe7e614fd0 --ki 0
``` ```
Simulate iCLASS Simulate iCLASS
@ -159,7 +178,7 @@ pm3 --> hf iclass sim 3
Simulate iCLASS Sequence 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 eload -f hf-iclass-db883702f8ff12e0.bin
pm3 --> hf iclass sim 3 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 sim 2
pm3 --> hf iclass loclass -f iclass_mac_attack.bin pm3 --> hf iclass loclass -f iclass_mac_attack.bin
pm3 --> hf iclass managekeys n 7 k <Kcus> pm3 --> hf iclass managekeys n 7 k <Kcus>
pm3 --> hf iclass dump k 7 e pm3 --> hf iclass dump --ki 7 --elite
``` ```
Verify custom iCLASS key Verify custom iCLASS key

View file

@ -11,7 +11,7 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`auto `|N |`Automated detection process for unknown tags` |`auto `|N |`Automated detection process for unknown tags`
|`clear `|Y |`clear screen` |`clear `|Y |`Clear screen`
|`help `|Y |`This help. Use '<command> help' for details of a particular command.` |`help `|Y |`This help. Use '<command> help' for details of a particular command.`
|`hints `|Y |`Turn hints on / off` |`hints `|Y |`Turn hints on / off`
|`msleep `|Y |`Add a pause in milliseconds` |`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 nuid `|Y |`create NUID from 7byte UID`
|`analyse demodbuff `|Y |`Load binary string to demodbuffer` |`analyse demodbuff `|Y |`Load binary string to demodbuffer`
|`analyse freq `|Y |`Calc wave lengths` |`analyse freq `|Y |`Calc wave lengths`
|`analyse foo `|Y |`muxer`
### data ### 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 restore `|N |`[options..] Restore a dump file onto a Picopass / iCLASS tag`
|`hf iclass sniff `|N |` Eavesdrop Picopass / iCLASS communication` |`hf iclass sniff `|N |` Eavesdrop Picopass / iCLASS communication`
|`hf iclass wrbl `|N |`[options..] Write Picopass / iCLASS block` |`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 chk `|N |`[options..] Check keys`
|`hf iclass loclass `|Y |`[options..] Use loclass to perform bruteforce reader attack` |`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` |`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 help `|Y |`This help`
|`lf nexwatch demod `|Y |`Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer` |`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 clone `|N |`clone NexWatch tag to T55x7`
|`lf nexwatch sim `|N |`simulate NexWatch tag` |`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 help `|Y |`This help`
|`lf noralsy demod `|Y |`Demodulate an Noralsy tag from the GraphBuffer` |`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 clone `|N |`clone Noralsy tag to T55x7 or Q5/T5555`
|`lf noralsy sim `|N |`simulate Noralsy tag` |`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 help `|Y |`This help`
|`lf pac demod `|Y |`Demodulate a PAC tag from the GraphBuffer` |`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 clone `|N |`clone PAC tag to T55x7`
|`lf pac sim `|N |`simulate PAC tag` |`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 help `|Y |`This help`
|`lf paradox demod `|Y |`Demodulate a Paradox FSK tag from the GraphBuffer` |`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 reader `|N |`Attempt to read and Extract tag data from the antenna`
|`lf paradox clone `|N |`clone paradox tag to T55x7` |`lf paradox clone `|N |`clone paradox tag`
|`lf paradox sim `|N |`simulate 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 help `|Y |`This help`
|`lf presco demod `|Y |`demodulate Presco tag from the GraphBuffer` |`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 clone `|N |`clone presco tag to T55x7 or Q5/T5555`
|`lf presco sim `|N |`simulate presco tag` |`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 help `|Y |`this help`
|`lf pyramid demod `|Y |`demodulate a Pyramid FSK tag from the GraphBuffer` |`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 clone `|N |`clone pyramid tag to T55x7 or Q5/T5555`
|`lf pyramid sim `|N |`simulate pyramid tag` |`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 help `|Y |`This help`
|`lf securakey demod `|Y |`Demodulate an Securakey tag from the GraphBuffer` |`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 clone `|N |`clone Securakey tag to T55x7`
|`lf securakey sim `|N |`simulate Securakey tag` |`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 help `|Y |`This help`
|`lf ti demod `|Y |`Demodulate raw bits for TI-type LF tag from the GraphBuffer` |`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` |`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 help `|Y |`This help`
|`lf viking demod `|Y |`Demodulate a Viking tag from the GraphBuffer` |`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 clone `|N |`clone Viking tag to T55x7 or Q5/T5555`
|`lf viking sim `|N |`simulate Viking tag` |`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 help `|Y |`This help`
|`lf visa2000 demod `|Y |`demodulate an VISA2000 tag from the GraphBuffer` |`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 clone `|N |`clone Visa2000 tag to T55x7 or Q5/T5555`
|`lf visa2000 sim `|N |`simulate Visa2000 tag` |`lf visa2000 sim `|N |`simulate Visa2000 tag`
### mem ### mem
{ Flash Memory manipulation... } { Flash memory manipulation... }
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
@ -953,7 +953,7 @@ Check column "offline" for their availability.
### reveng ### reveng
{ CRC calculations from RevEng software } { CRC calculations from RevEng software... }
[=] reveng: no mode switch specified. Use reveng -h for help. [=] reveng: no mode switch specified. Use reveng -h for help.
@ -975,7 +975,7 @@ Check column "offline" for their availability.
### script ### script
{ Scripting commands } { Scripting commands... }
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------

BIN
doc/t55xx_block0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
doc/t55xx_clock0_cfg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
doc/t55xx_mem_map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB