mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
Merge branch 'master' into allin
update 201127
This commit is contained in:
commit
b18ded915a
44 changed files with 3012 additions and 1877 deletions
29
.vscode/launch.json
vendored
29
.vscode/launch.json
vendored
|
@ -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
84
.vscode/tasks.json
vendored
|
@ -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": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -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,...)
|
||||||
- ...
|
- ...
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -1276,3 +1276,6 @@ AABAFFCC7612
|
||||||
# ozdilek
|
# ozdilek
|
||||||
#
|
#
|
||||||
17D071403C20
|
17D071403C20
|
||||||
|
#
|
||||||
|
534F4C415249
|
||||||
|
534f4c303232
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
@ -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"},
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
694
doc/T5577_Guide.md
Normal 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 don’t yet
|
||||||
|
know what it means. As such, I will attempt to point to sections of the
|
||||||
|
data sheet and would highly advise that you look at the data sheet as
|
||||||
|
you go. Overtime the data sheet may change, as a result things may not
|
||||||
|
always be reference correctly.
|
||||||
|
|
||||||
|
As at writing this guide, the data sheet can be found at :
|
||||||
|
|
||||||
|
<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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## What data is on my T5577
|
||||||
|
|
||||||
|
Let’s have a look and see what a card might look in the proxmark3
|
||||||
|
software. Since we can change the configuration of how the T5577 will
|
||||||
|
output data, the proxmark3 software need to work out how to interpreted
|
||||||
|
the data it receives, we do this with the following command.
|
||||||
|
|
||||||
|
It should be noted that the T5577 has many clones. As such the default
|
||||||
|
setup of each card may be different. If the tractability data is
|
||||||
|
present, then this will vary based on the batch of cards.
|
||||||
|
|
||||||
|
Always run this command when you place a t5577 on the proxmark3. In all
|
||||||
|
examples shown, it will be assumed you have run the detect command.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx detect
|
||||||
|
```
|
||||||
|
You should see a results simular to the following:
|
||||||
|
```
|
||||||
|
Chip Type : T55x7
|
||||||
|
Modulation : ASK
|
||||||
|
Bit Rate : 2 - RF/32
|
||||||
|
Inverted : No
|
||||||
|
Offset : 32
|
||||||
|
Seq. Term. : Yes
|
||||||
|
Block0 : 0x000880E0
|
||||||
|
Downlink Mode : default/fixed bit length
|
||||||
|
```
|
||||||
|
Now that the proxmark3 has detected a T55x7 chip, and found some
|
||||||
|
information about it, we should be able to see all the data on the chip.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx dump
|
||||||
|
```
|
||||||
|
Your results should look similar to the following:
|
||||||
|
```
|
||||||
|
[+] Reading Page 0:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||||
|
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] Reading Page 1:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||||
|
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
|
||||||
|
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
|
||||||
|
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
```
|
||||||
|
I will cover the meaning of this data as we go, but for now, lets keep
|
||||||
|
it simple.
|
||||||
|
|
||||||
|
## Read and Write Blocks of Data
|
||||||
|
|
||||||
|
The basic function of using the proxmark3 with rfid cards is to read and
|
||||||
|
write data. This reading and writing must be done in the correct way
|
||||||
|
needed for the chip (and its configuration). Lucky for us, the
|
||||||
|
developers have done a great job and gave us commands. What we need to
|
||||||
|
know is that with the T5577 data is read/written one complete block at a
|
||||||
|
time. Each block holds 32 bits of data (hence the binary output shown)
|
||||||
|
|
||||||
|
Since we know that the card has data and configuration blocks, lets say
|
||||||
|
away from those while we learn how to read and write. I suggest you
|
||||||
|
follow along and perform each command and check the results as we go.
|
||||||
|
|
||||||
|
We can store our own data in blocks 1-7 (remember that block 7 will be
|
||||||
|
needed if we want to set a password).
|
||||||
|
|
||||||
|
(Don’t forget to run the detect command: lf t55xx detect, and ensure you
|
||||||
|
can see the card)
|
||||||
|
|
||||||
|
1) Check what is stored in block 1. The following command can be read
|
||||||
|
as, run a low frequency (lf) command for the T55xx chip (t55xx) and
|
||||||
|
read block (b) number 1.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx read b 1
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[+] Reading Page 0:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
```
|
||||||
|
Note: Depending on the history of your card your data may vary, but
|
||||||
|
should match the dump data.
|
||||||
|
|
||||||
|
2) Write some new data into block 1 on the card.
|
||||||
|
|
||||||
|
We use the d option to supply the data ‘12345678’
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx write b 1 d 12345678
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[=] Writing page 0 block: 01 data: 0x12345678
|
||||||
|
```
|
||||||
|
3) Now, lets check if the data was written.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx read b 1
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[+] Reading Page 0:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 01 | 12345678 | 00010010001101000101011001111000 | .4Vx
|
||||||
|
```
|
||||||
|
4) The data is written in Hexadecimal. A single hex digit holds 4 bits
|
||||||
|
of data. So to store 32 bits in a block we need to supply 8 hex
|
||||||
|
digits (8 \* 4 = 32). If you are familiar with hex and binary do a
|
||||||
|
little bit of home work to learn. The following is a quick start.
|
||||||
|
|
||||||
|
| Hex | Binary | Decimal |
|
||||||
|
|:---:|:------:|:-------:|
|
||||||
|
| 0 | 0000 | 0 |
|
||||||
|
| 1 | 0001 | 1 |
|
||||||
|
| 2 | 0010 | 2 |
|
||||||
|
| 3 | 0011 | 3 |
|
||||||
|
| 4 | 0100 | 4 |
|
||||||
|
| 5 | 0101 | 5 |
|
||||||
|
| 6 | 0110 | 6 |
|
||||||
|
| 7 | 0111 | 7 |
|
||||||
|
| 8 | 1000 | 8 |
|
||||||
|
| 9 | 1001 | 9 |
|
||||||
|
| A | 1010 | 10 |
|
||||||
|
| B | 1011 | 11 |
|
||||||
|
| C | 1100 | 12 |
|
||||||
|
| D | 1101 | 13 |
|
||||||
|
| E | 1110 | 14 |
|
||||||
|
| F | 1111 | 15 |
|
||||||
|
|
||||||
|
To use all the bits we supply the data in Hex format and it will
|
||||||
|
always be 8 hex digits.
|
||||||
|
|
||||||
|
Lets try and write 89ABCDEF
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx write b 1 d 89abcdef
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[=] Writing page 0 block: 01 data: 0x89ABCDEF
|
||||||
|
```
|
||||||
|
and check
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx read b 1
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[+] Reading Page 0:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 01 | 89ABCDEF | 10001001101010111100110111101111 | ....
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exercise 1
|
||||||
|
|
||||||
|
Using the read and write commands you have learnt see if you can make
|
||||||
|
the lf t55 dump command show the following data for blocks 1-7 (Page 0).
|
||||||
|
Do not write to block 0 or try and change the data on page 1.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55 dump
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[+] Reading Page 0:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||||
|
[+] 01 | 89ABCDEF | 10001001101010111100110111101111 | ....
|
||||||
|
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] Reading Page 1:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||||
|
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
|
||||||
|
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
|
||||||
|
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
```
|
||||||
|
|
||||||
|
Practice reading and writing to blocks 1 to 7 until you are happy you
|
||||||
|
can do it and get the results you wanted (i.e. the data you want stored
|
||||||
|
is written to the block you want it stored in).
|
||||||
|
|
||||||
|
## How do I use a password
|
||||||
|
|
||||||
|
This can be a little tricky for beginners.
|
||||||
|
***If you forget your password you will lose access to your card***.
|
||||||
|
|
||||||
|
To tell the T5577 to use a password we have to change the data in the
|
||||||
|
configuration block (0). To help learn this and make it as simple as I
|
||||||
|
can, please read and follow exactly. If your results DON’T match 100% as
|
||||||
|
required, please do not proceed.
|
||||||
|
|
||||||
|
1) Lets start with a known card state and wipe the card. This will set
|
||||||
|
a default configuration to block 0 and set all the data in blocks
|
||||||
|
1-7 to a default.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx wipe
|
||||||
|
```
|
||||||
|
Result:
|
||||||
|
```
|
||||||
|
[=] Begin wiping T55x7 tag
|
||||||
|
|
||||||
|
[=] Default configation block 000880E0
|
||||||
|
[=] Writing page 0 block: 00 data: 0x000880E0
|
||||||
|
[=] Writing page 0 block: 01 data: 0x00000000
|
||||||
|
[=] Writing page 0 block: 02 data: 0x00000000
|
||||||
|
[=] Writing page 0 block: 03 data: 0x00000000
|
||||||
|
[=] Writing page 0 block: 04 data: 0x00000000
|
||||||
|
[=] Writing page 0 block: 05 data: 0x00000000
|
||||||
|
[=] Writing page 0 block: 06 data: 0x00000000
|
||||||
|
[=] Writing page 0 block: 07 data: 0x00000000
|
||||||
|
```
|
||||||
|
|
||||||
|
2) Check that the card is in the desired state.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx detect
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
Chip Type : T55x7
|
||||||
|
Modulation : ASK
|
||||||
|
Bit Rate : 2 - RF/32
|
||||||
|
Inverted : No
|
||||||
|
Offset : 32
|
||||||
|
Seq. Term. : Yes
|
||||||
|
Block0 : 0x000880E0
|
||||||
|
Downlink Mode : default/fixed bit length
|
||||||
|
```
|
||||||
|
|
||||||
|
If block 0 does not hold the hex data **0x00088040 resolve this
|
||||||
|
first before proceeding.**
|
||||||
|
|
||||||
|
3) Set the password we want to use. For this example lets use the
|
||||||
|
password : ***12345678***
|
||||||
|
|
||||||
|
The password is saved in block 7 of page 0.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx write b 7 d 12345678
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[=] Writing page 0 block: 07 data: 0x12345678
|
||||||
|
```
|
||||||
|
|
||||||
|
4) Lets verify both block 0 and block 7
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx dump
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[+] Reading Page 0:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||||
|
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
[+] 07 | 12345678 | 00010010001101000101011001111000 | .4Vx
|
||||||
|
[+] Reading Page 1:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||||
|
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
|
||||||
|
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
|
||||||
|
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||||
|
```
|
||||||
|
***Important : If block 0 and block 7 don’t match exactly, do not continue.***
|
||||||
|
|
||||||
|
5) Now we have a known configuration block and a known password of
|
||||||
|
12345678, we are ready to tell the card to use the password.
|
||||||
|
|
||||||
|
To do this the datasheet tells us we need to set the 28<sup>th</sup>
|
||||||
|
bit “PWD”. Check your datasheet and see the entire table (remember
|
||||||
|
the data sheet is your friend).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
We will cover other things in the configuration later. But the key
|
||||||
|
note here is we ONLY want to change bit 28 and nothing else.
|
||||||
|
|
||||||
|
Current Block 0 : ***00088040***
|
||||||
|
New Block 0 : ***00088050***
|
||||||
|
|
||||||
|
To understand what happened to get from 00088040 to 00088050 we need
|
||||||
|
to look at the binary data.
|
||||||
|
|
||||||
|
While this can be confusing it is important to understand this as we
|
||||||
|
do more advanced things.
|
||||||
|
|
||||||
|
Bit Location (28)
|
||||||
|
000000000011111111112222222 ***2*** 2233
|
||||||
|
123456789012345678901234567 ***8*** 9012
|
||||||
|
|
||||||
|
| Hex Data | Binary Data |
|
||||||
|
|:--------:|:---------------------------------------|
|
||||||
|
| 00088040 | 000000000000100010000000010***0***0000 |
|
||||||
|
| 00088050 | 000000000000100010000000010***1***0000 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
See how in the above we change the bit in location 28 from a 0 to 1
|
||||||
|
0 = No Password, 1 = Use Password
|
||||||
|
|
||||||
|
Note how we did NOT change any other part of the configuration, only bit 28.
|
||||||
|
|
||||||
|
To re-cap.
|
||||||
|
We put the card into a known configuration Block 0 : 00088040
|
||||||
|
We set the a known password Block 7 : 12345678
|
||||||
|
We altered the config data to tell the T5577 to use the password.
|
||||||
|
New Block 0 : 00088050
|
||||||
|
|
||||||
|
If you have completed all steps and have the exact same results, we are
|
||||||
|
ready to apply the new configuration.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx write b 0 d 00088050
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[=] Writing page 0 block: 00 data: 0x00088050
|
||||||
|
```
|
||||||
|
|
||||||
|
6) Lets check what happens when the password is set.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55 detect
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[!] Could not detect modulation automatically. Try setting it manually with 'lf t55xx config'
|
||||||
|
```
|
||||||
|
Note how the lf t55 detect no longer seems to work\!
|
||||||
|
|
||||||
|
In this case, this is due to needing a password to read/write to the
|
||||||
|
card.
|
||||||
|
|
||||||
|
Lets try again, but this time supply the password. We use the option
|
||||||
|
p followed by the password.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55 detect p 12345678
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
Chip Type : T55x7
|
||||||
|
Modulation : ASK
|
||||||
|
Bit Rate : 2 - RF/32
|
||||||
|
Inverted : No
|
||||||
|
Offset : 32
|
||||||
|
Seq. Term. : Yes
|
||||||
|
Block0 : 0x00088050
|
||||||
|
Downlink Mode : default/fixed bit length
|
||||||
|
```
|
||||||
|
|
||||||
|
7) Write a block of data with a password
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx write b 1 d 1234abcd p 12345678
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[=] Writing page 0 block: 01 data: 0x1234ABCD pwd: 0x12345678
|
||||||
|
```
|
||||||
|
|
||||||
|
8) Read a block of data with a password
|
||||||
|
|
||||||
|
***\*\*\*\* Important \*\*\*\****
|
||||||
|
|
||||||
|
***Reading a T5577 block with a password when a password is not
|
||||||
|
enabled can result in locking the card. Please only use read with a
|
||||||
|
password when it is known that a password is in use.***
|
||||||
|
|
||||||
|
The proxmark3 has a safety check\!
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx read b 1 p 12345678
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[+] Reading Page 0:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[!] Safety check: Could not detect if PWD bit is set in config block. Exits.
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the proxmark3 did not read the block, the safty kicked in
|
||||||
|
and wants us to confirm by supply the override option ‘o’.
|
||||||
|
|
||||||
|
Lets try again with the ‘o’ option as we know the password is set.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx read b 1 p 12345678 o
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[+] Reading Page 0:
|
||||||
|
[+] blk | hex data | binary | ascii
|
||||||
|
[+] ----+----------+----------------------------------+-------
|
||||||
|
[=] Safety check overridden - proceeding despite risk
|
||||||
|
[+] 01 | 1234ABCD | 00010010001101001010101111001101 | .4..
|
||||||
|
```
|
||||||
|
This time, we can see the data we wrote to block 1 is found with the
|
||||||
|
read command.
|
||||||
|
|
||||||
|
9) Remove the need to supply the password.
|
||||||
|
|
||||||
|
To do this we need to clear Bit 28 (set to 0) in the config. We have
|
||||||
|
this from above.
|
||||||
|
|
||||||
|
Remember if we don’t know the config and write this config to the
|
||||||
|
card, it will over write all other settings. This can recoved the
|
||||||
|
card, but will lose any settings you may want. So it’s a good idea
|
||||||
|
to read the config, and set bit 28 to 0, rather than just overwrite
|
||||||
|
the config and change the way the card works.
|
||||||
|
|
||||||
|
In our examples we know what it should be : 00088040
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx write b 0 d 00088040 p 12345678
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[=] Writing page 0 block: 00 data: 0x00088040 pwd: 0x12345678
|
||||||
|
```
|
||||||
|
Now check if we can detect without a password
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55 detect
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
Chip Type : T55x7
|
||||||
|
Modulation : ASK
|
||||||
|
Bit Rate : 2 - RF/32
|
||||||
|
Inverted : No
|
||||||
|
Offset : 32
|
||||||
|
Seq. Term. : Yes
|
||||||
|
Block0 : 0x00088040
|
||||||
|
Downlink Mode : default/fixed bit length
|
||||||
|
```
|
||||||
|
Yes we can and we can see Block 0 is the correct config 00088040
|
||||||
|
|
||||||
|
# Part 2 – Configuration Blocks
|
||||||
|
|
||||||
|
One of the things a lot of people have trouble with or miss, is that the
|
||||||
|
T5577 has two different and separate communications protocols, each with
|
||||||
|
their own sub-protocols.
|
||||||
|
|
||||||
|
- Card to Reader
|
||||||
|
- Reader to Card
|
||||||
|
|
||||||
|
In Card to Reader, the T5577 will encode its data using the settings
|
||||||
|
from Block 0 in Page 0. It will use this in both default read mode
|
||||||
|
(where is sends out the blocks from 1 to x on power up), as well as when
|
||||||
|
it responds to commands.
|
||||||
|
|
||||||
|
In the Read To Card, the T5577 will encode the data using the settings
|
||||||
|
from Block 3 Page 1. If the command is not encoded correctly it will
|
||||||
|
ignore the command and revert back to default read mode.
|
||||||
|
|
||||||
|
## The configuration Block – Block 0 Page 0
|
||||||
|
|
||||||
|
For this configuration the settings chosen will be for the purpose of
|
||||||
|
the card when used in production. E.G. If you want the card to act like
|
||||||
|
an EM4100, then we need to choose the settings that work like the
|
||||||
|
EM4100; same goes for others like HID. I am not going to cover these
|
||||||
|
here, rather use an example. Others have collect these and posted on the
|
||||||
|
forum.
|
||||||
|
|
||||||
|
To get started lets look back at the tech sheet.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The non-password protect EM4100 could have a block 0 config of 00148040,
|
||||||
|
so what does it mean.
|
||||||
|
|
||||||
|
To decode this config, we need to look at it in binary
|
||||||
|
00000000000101001000000001000000. Note that it had 32 bits and the
|
||||||
|
config block 0 is 32 bits. Now we can break it down.
|
||||||
|
|
||||||
|
| Bits | Purpose | Value |
|
||||||
|
| ------- | ---------------------- | ----------- |
|
||||||
|
| 0000 | Master Key | Nothing Set |
|
||||||
|
| 0000000 | Not used in Basic Mode | |
|
||||||
|
| 101 | Data Bit Rate | RF/64 |
|
||||||
|
| 0 | Not used in Basic Mode | |
|
||||||
|
| 01000 | Modulation | Manchester |
|
||||||
|
| 00 | PSKCF | RF/2 |
|
||||||
|
| 0 | AOR | Not Set |
|
||||||
|
| 0 | Not used in Basic Mode | |
|
||||||
|
| 010 | Max Block | 2 |
|
||||||
|
| 0 | Password | Not Set |
|
||||||
|
| 0 | ST Sequence Terminator | Not Set |
|
||||||
|
| 00 | Not used in Basic Mode | |
|
||||||
|
| 0 | Init Delay | Not Set |
|
||||||
|
|
||||||
|
To get more detail on each item, read through the data sheet.
|
||||||
|
|
||||||
|
Lets see how the proxmark3 can help us learn. We will assume the T5577
|
||||||
|
is in the same state from Part 1, where we can write to the card with no
|
||||||
|
password set (if not, review and get you card back to this state).
|
||||||
|
|
||||||
|
1) Lets turn you T5577 into an EM4100 with ID 1122334455
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf em 410x_write 1122334455 1
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[+] Writing T55x7 tag with UID 0x1122334455 (clock rate: 64)
|
||||||
|
#db# Started writing T55x7 tag ...
|
||||||
|
#db# Clock rate: 64
|
||||||
|
#db# Tag T55x7 written with 0xff8c65298c94a940
|
||||||
|
```
|
||||||
|
|
||||||
|
2) Check this has work.
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf search
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[=] NOTE: some demods output possible binary
|
||||||
|
[=] if it finds something that looks like a tag
|
||||||
|
[=] False Positives ARE possible
|
||||||
|
[=]
|
||||||
|
[=] Checking for known tags...
|
||||||
|
|
||||||
|
[+] EM410x pattern found
|
||||||
|
|
||||||
|
EM TAG ID : 1122334455
|
||||||
|
|
||||||
|
Possible de-scramble patterns
|
||||||
|
|
||||||
|
Unique TAG ID : 8844CC22AA
|
||||||
|
HoneyWell IdentKey {
|
||||||
|
DEZ 8 : 03359829
|
||||||
|
DEZ 10 : 0573785173
|
||||||
|
DEZ 5.5 : 08755.17493
|
||||||
|
DEZ 3.5A : 017.17493
|
||||||
|
DEZ 3.5B : 034.17493
|
||||||
|
DEZ 3.5C : 051.17493
|
||||||
|
DEZ 14/IK2 : 00073588229205
|
||||||
|
DEZ 15/IK3 : 000585269781162
|
||||||
|
DEZ 20/ZK : 08080404121202021010
|
||||||
|
}
|
||||||
|
Other : 17493_051_03359829
|
||||||
|
Pattern Paxton : 289899093 [0x11478255]
|
||||||
|
Pattern 1 : 5931804 [0x5A831C]
|
||||||
|
Pattern Sebury : 17493 51 3359829 [0x4455 0x33 0x334455]
|
||||||
|
|
||||||
|
[+] Valid EM410x ID found!
|
||||||
|
|
||||||
|
|
||||||
|
[+] Chipset detection : T55xx found
|
||||||
|
|
||||||
|
[+] Try `lf t55xx` commands
|
||||||
|
```
|
||||||
|
Looks good.
|
||||||
|
|
||||||
|
3) Now lest see what the T5577 detect and info shows
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55 detect
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55 detect
|
||||||
|
Chip Type : T55x7
|
||||||
|
Modulation : ASK
|
||||||
|
Bit Rate : 5 - RF/64
|
||||||
|
Inverted : No
|
||||||
|
Offset : 32
|
||||||
|
Seq. Term. : Yes
|
||||||
|
Block0 : 0x00148040
|
||||||
|
Downlink Mode : default/fixed bit length
|
||||||
|
```
|
||||||
|
```
|
||||||
|
[usb] pm3 --> lf t55xx info
|
||||||
|
```
|
||||||
|
result:
|
||||||
|
```
|
||||||
|
|
||||||
|
-- T55x7 Configuration & Tag Information --------------------
|
||||||
|
-------------------------------------------------------------
|
||||||
|
Safer key : 0
|
||||||
|
reserved : 0
|
||||||
|
Data bit rate : 5 - RF/64
|
||||||
|
eXtended mode : No
|
||||||
|
Modulation : 8 - Manchester
|
||||||
|
PSK clock frequency : 0 - RF/2
|
||||||
|
AOR - Answer on Request : No
|
||||||
|
OTP - One Time Pad : No
|
||||||
|
Max block : 2
|
||||||
|
Password mode : No
|
||||||
|
Sequence Terminator : No
|
||||||
|
Fast Write : No
|
||||||
|
Inverse data : No
|
||||||
|
POR-Delay : No
|
||||||
|
-------------------------------------------------------------
|
||||||
|
Raw Data - Page 0
|
||||||
|
Block 0 : 0x00148040 00000000000101001000000001000000
|
||||||
|
|
||||||
|
Config block match : EM unique, Paxton
|
||||||
|
-------------------------------------------------------------
|
||||||
|
```
|
||||||
|
We can see that the info gave us more information and confirmed what
|
||||||
|
we decoded by hand. But remember, the detect is still needed so the
|
||||||
|
proxmark3 software will know how to decode the info block.
|
||||||
|
|
||||||
|
We can see that for the EM4100 emulation we have two blocks of data
|
||||||
|
(Max Block = 2). On the T5577 these will be Blocks 1 and 2.
|
||||||
|
|
||||||
|
## Exercise 2
|
||||||
|
|
||||||
|
Using the skills form part 1, see if you can view the data in blocks 1 and 2.
|
||||||
|
|
||||||
|
Note: the EM4100 ID of 1122334455 is encoded, so don’t expect to see
|
||||||
|
those bytes as such. To learn how to do that, you guessed it, find the
|
||||||
|
datasheet and review.
|
||||||
|
|
||||||
|
At this point we have an EM4100 card. If we wanted to password protect
|
||||||
|
it, we can follow the password section and update the config from
|
||||||
|
00148040 to 00148050.
|
||||||
|
|
||||||
|
***Important : Don’t forget to set a valid password in block 7 and remember it.***
|
||||||
|
|
||||||
|
## The configuration Block – Block 3 Page 1
|
|
@ -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
|
||||||
|
|
|
@ -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
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
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
BIN
doc/t55xx_mem_map.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
Loading…
Add table
Add a link
Reference in a new issue