mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-09-30 20:26:14 +08:00
commit
a7d145c9d8
|
@ -3,9 +3,14 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Fix `hf 15 sim` - Added basic response to GET_SYSTEM_INFO and READBLOCK requests in order to fix iso15693 tag sim
|
||||
- Added `mf mfu sim t 7 n <numreads>` - MFU emulation now supports automatic exit after <num> blocks read. (@cyberpunk-re)
|
||||
- Added T55xx Guide to assist in learning how to use the T55xx chip (@mwalker33)
|
||||
- Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001)
|
||||
- Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...)
|
||||
- ...
|
||||
- Change `hf iclass chk/lookup/loclass` speedups (@iceman1001)
|
||||
- Change - ongoing convertion to cliparser (@tcprst, @iceman1001)
|
||||
- Added compilation options for 256k Proxmark versions, see doc (@doegox)
|
||||
- Added support for 10b UID in `hf 14a sim` (@doegox)
|
||||
- Added `HF_TCPRST` standalone mode which read and emulate IKEA Rothult cards (@tcprst)
|
||||
|
|
9
Makefile
9
Makefile
|
@ -169,6 +169,7 @@ help:
|
|||
@echo "+ fpga_compress - Make tools/fpga_compress"
|
||||
@echo
|
||||
@echo "+ style - Apply some automated source code formatting rules"
|
||||
@echo "+ cliparser - Generate cliparser TODO
|
||||
@echo "+ check - Run offline tests. Set CHECKARGS to pass arguments to the test script"
|
||||
@echo "+ .../check - Run offline tests against specific target. See above."
|
||||
@echo "+ miscchecks - Detect various encoding issues in source code"
|
||||
|
@ -248,6 +249,14 @@ endif
|
|||
# easy printing of MAKE VARIABLES
|
||||
print-%: ; @echo $* = $($*)
|
||||
|
||||
cliparser:
|
||||
# Get list of all commands
|
||||
cat doc/commands.md | grep -e ^\|\` | cut -f 2 -d "\`" | grep -v 'help\|list\|mem spiffs\|quit\|exit' | awk '{$$1=$$1};1' > cliparser_all_commands.tmp
|
||||
# Get list of cliparserized commands
|
||||
grep -r CLIParserInit ./client/src/ | cut -f 2 -d "\"" | awk '{$$1=$$1};1' > cliparser_done.tmp
|
||||
# Determine commands that still need cliparser conversion
|
||||
grep -xvf cliparser_done.tmp cliparser_all_commands.tmp > ./doc/cliparser_todo.txt
|
||||
|
||||
style:
|
||||
# Make sure astyle is installed
|
||||
@which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 )
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|[Donations](#Donations)|[Maintainers](/doc/md/Development/Maintainers.md)|[Command Cheat sheet](/doc/cheatsheet.md)|
|
||||
||[Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)|[More cheat sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)|
|
||||
||**[Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md)**|[Complete client command set](/doc/commands.md)|
|
||||
||**[JTAG](/doc/jtag_notes.md)**||
|
||||
||**[JTAG](/doc/jtag_notes.md)**|[T55xx Guide](/doc/T5577_Guide.md)|
|
||||
|
||||
|
||||
## Notes / helpful documents
|
||||
|
|
|
@ -243,7 +243,7 @@ void RunMod(void) {
|
|||
uint8_t flags = FLAG_7B_UID_IN_DATA;
|
||||
|
||||
Dbprintf("Starting simulation, press pm3-button to stop and go back to search state.");
|
||||
SimulateIso14443aTag(7, flags, card.uid);
|
||||
SimulateIso14443aTag(7, flags, card.uid, 0);
|
||||
|
||||
// Go back to search state if user presses pm3-button
|
||||
state = STATE_SEARCH;
|
||||
|
|
|
@ -244,22 +244,22 @@ void RunMod(void) {
|
|||
|
||||
if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 1k");
|
||||
SimulateIso14443aTag(1, flags, data);
|
||||
SimulateIso14443aTag(1, flags, data, 0);
|
||||
} else if (uids[selected].sak == 0x18 && uids[selected].atqa[0] == 0x02 && uids[selected].atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 4k (4b uid)");
|
||||
SimulateIso14443aTag(8, flags, data);
|
||||
SimulateIso14443aTag(8, flags, data, 0);
|
||||
} else if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 4k (7b uid)");
|
||||
SimulateIso14443aTag(8, flags, data);
|
||||
SimulateIso14443aTag(8, flags, data, 0);
|
||||
} else if (uids[selected].sak == 0x00 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) {
|
||||
DbpString("Mifare Ultralight");
|
||||
SimulateIso14443aTag(2, flags, data);
|
||||
SimulateIso14443aTag(2, flags, data, 0);
|
||||
} else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0x03) {
|
||||
DbpString("Mifare DESFire");
|
||||
SimulateIso14443aTag(3, flags, data);
|
||||
SimulateIso14443aTag(3, flags, data, 0);
|
||||
} else {
|
||||
Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
|
||||
SimulateIso14443aTag(1, flags, data);
|
||||
SimulateIso14443aTag(1, flags, data, 0);
|
||||
}
|
||||
|
||||
} else if (button_pressed == BUTTON_SINGLE_CLICK) {
|
||||
|
|
|
@ -95,7 +95,7 @@ void RunMod(void) {
|
|||
|
||||
WAIT_BUTTON_RELEASED();
|
||||
|
||||
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
|
||||
CopyHIDtoT55x7(0, high[selected], low[selected], 0, false, false);
|
||||
Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]);
|
||||
|
||||
LEDsoff();
|
||||
|
|
|
@ -121,7 +121,7 @@ void RunMod(void) {
|
|||
Dbprintf("[=] cloning %x | %x%08x", selected, high[selected], low[selected]);
|
||||
|
||||
// high2, high, low, no longFMT
|
||||
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
|
||||
CopyHIDtoT55x7(0, high[selected], low[selected], 0, false, false);
|
||||
|
||||
DbpString("[=] cloned done");
|
||||
|
||||
|
|
|
@ -874,7 +874,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_LF_HID_CLONE: {
|
||||
lf_hidsim_t *payload = (lf_hidsim_t *)packet->data.asBytes;
|
||||
CopyHIDtoT55x7(payload->hi2, payload->hi, payload->lo, payload->longFMT);
|
||||
CopyHIDtoT55x7(payload->hi2, payload->hi, payload->lo, payload->longFMT, payload->Q5, payload->EM);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_IO_WATCH: {
|
||||
|
@ -907,7 +907,13 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_LF_TI_WRITE: {
|
||||
WriteTItag(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]);
|
||||
struct p {
|
||||
uint32_t high;
|
||||
uint32_t low;
|
||||
uint16_t crc;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
WriteTItag(payload->high, payload->low, packet->crc);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SIMULATE: {
|
||||
|
@ -1037,10 +1043,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
case CMD_LF_VIKING_CLONE: {
|
||||
struct p {
|
||||
bool Q5;
|
||||
bool EM;
|
||||
uint8_t blocks[8];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
CopyVikingtoT55xx(payload->blocks, payload->Q5);
|
||||
CopyVikingtoT55xx(payload->blocks, payload->Q5, payload->EM);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_COTAG_READ: {
|
||||
|
@ -1267,9 +1274,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t tagtype;
|
||||
uint8_t flags;
|
||||
uint8_t uid[10];
|
||||
uint8_t exitAfter;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
SimulateIso14443aTag(payload->tagtype, payload->flags, payload->uid); // ## Simulate iso14443a tag - pass tag type & UID
|
||||
SimulateIso14443aTag(payload->tagtype, payload->flags, payload->uid, payload->exitAfter); // ## Simulate iso14443a tag - pass tag type & UID
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443A_ANTIFUZZ: {
|
||||
|
|
|
@ -620,7 +620,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
|
|||
set_tracelen(numbts);
|
||||
set_tracelen(BigBuf_max_traceLen());
|
||||
|
||||
Dbprintf("Felica sniffing done, tracelen: %i, use hf list felica for annotations", BigBuf_get_traceLen());
|
||||
Dbprintf("Felica sniffing done, tracelen: %i, use " _YELLOW_("`hf felica list`") " for annotations", BigBuf_get_traceLen());
|
||||
reply_mix(CMD_ACK, 1, numbts, 0, 0, 0);
|
||||
LED_D_OFF();
|
||||
}
|
||||
|
|
|
@ -1999,10 +1999,10 @@ void iClass_Restore(iclass_restore_req_t *msg) {
|
|||
|
||||
// data + mac
|
||||
if (iclass_writeblock_ext(item.blockno, item.data, mac, use_mac)) {
|
||||
Dbprintf("Write block [%02x] " _GREEN_("successful"), item.blockno);
|
||||
Dbprintf("Write block [%3d/0x%02X] " _GREEN_("successful"), item.blockno, item.blockno);
|
||||
written++;
|
||||
} else {
|
||||
Dbprintf("Write block [%02x] " _RED_("failed"), item.blockno);
|
||||
Dbprintf("Write block [%3d/0x%02X] " _RED_("failed"), item.blockno, item.blockno);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ticks.h"
|
||||
#include "dbprint.h"
|
||||
#include "util.h"
|
||||
#include "util.h"
|
||||
#include "parity.h"
|
||||
#include "mifareutil.h"
|
||||
#include "commonutil.h"
|
||||
|
@ -1251,7 +1252,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
// response to send, and send it.
|
||||
// 'hf 14a sim'
|
||||
//-----------------------------------------------------------------------------
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data, uint8_t exitAfterNReads) {
|
||||
|
||||
#define ATTACK_KEY_COUNT 8 // keep same as define in cmdhfmf.c -> readerAttack()
|
||||
|
||||
|
@ -1327,6 +1328,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
int happened = 0;
|
||||
int happened2 = 0;
|
||||
int cmdsRecvd = 0;
|
||||
uint32_t numReads = 0; //Counts numer of times reader reads a block
|
||||
|
||||
// compatible write block number
|
||||
uint8_t wrblock = 0;
|
||||
|
@ -1338,7 +1340,10 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
LED_A_ON();
|
||||
|
||||
// main loop
|
||||
for (;;) {
|
||||
//for (;;) {
|
||||
bool finished = false;
|
||||
bool button_pushed = BUTTON_PRESS();
|
||||
while (!button_pushed && !finished) {
|
||||
WDT_HIT();
|
||||
|
||||
tag_response_info_t *p_response = NULL;
|
||||
|
@ -1467,6 +1472,12 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
emlGetMemBt(emdata, start, 16);
|
||||
AddCrc14A(emdata, 16);
|
||||
EmSendCmd(emdata, sizeof(emdata));
|
||||
numReads++; // Increment number of times reader requested a block
|
||||
|
||||
if (exitAfterNReads > 0 && numReads == exitAfterNReads) {
|
||||
Dbprintf("[MFUEMUL_WORK] %d reads done, exiting", numReads);
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
|
||||
p_response = NULL;
|
||||
|
@ -1979,9 +1990,11 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
|
|||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
if (check == 2000) {
|
||||
if (BUTTON_PRESS())
|
||||
if (check == 1000) {
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
Dbprintf("----------- " _GREEN_("BREAKING") " ----------");
|
||||
return 1;
|
||||
}
|
||||
check = 0;
|
||||
}
|
||||
++check;
|
||||
|
|
|
@ -129,7 +129,7 @@ RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time);
|
|||
RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time);
|
||||
|
||||
void RAMFUNC SniffIso14443a(uint8_t param);
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data);
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data, uint8_t numReads);
|
||||
bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_info_t **responses, uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages);
|
||||
bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len);
|
||||
void iso14443a_antifuzz(uint32_t flags);
|
||||
|
|
|
@ -104,10 +104,12 @@
|
|||
#define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet
|
||||
|
||||
// 32 + 2 crc + 1
|
||||
#define ISO15_MAX_FRAME 35
|
||||
#define CMD_ID_RESP 5
|
||||
#define CMD_READ_RESP 13
|
||||
#define CMD_INV_RESP 12
|
||||
#define ISO15_MAX_FRAME 35
|
||||
#define CMD_ID_RESP 5
|
||||
#define CMD_READ_RESP 13
|
||||
#define CMD_INV_RESP 12
|
||||
#define CMD_SYSINFO_RESP 17
|
||||
#define CMD_READBLOCK_RESP 7
|
||||
|
||||
//#define Crc(data, len) Crc(CRC_15693, (data), (len))
|
||||
#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
|
||||
|
@ -1679,27 +1681,7 @@ void SimTagIso15693(uint8_t *uid) {
|
|||
|
||||
LED_C_ON();
|
||||
|
||||
// Build INVENTORY command
|
||||
uint8_t resp_inv[CMD_INV_RESP] = {0};
|
||||
|
||||
resp_inv[0] = 0; // No error, no protocol format extension
|
||||
resp_inv[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported
|
||||
|
||||
// 64-bit UID
|
||||
resp_inv[2] = uid[7];
|
||||
resp_inv[3] = uid[6];
|
||||
resp_inv[4] = uid[5];
|
||||
resp_inv[5] = uid[4];
|
||||
resp_inv[6] = uid[3];
|
||||
resp_inv[7] = uid[2];
|
||||
resp_inv[8] = uid[1];
|
||||
resp_inv[9] = uid[0];
|
||||
|
||||
// CRC
|
||||
AddCrc15(resp_inv, 10);
|
||||
CodeIso15693AsTag(resp_inv, CMD_INV_RESP);
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
enum { NO_FIELD, IDLE, ACTIVATED, SELECTED, HALTED } chip_state = NO_FIELD;
|
||||
|
||||
|
@ -1745,11 +1727,96 @@ void SimTagIso15693(uint8_t *uid) {
|
|||
if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) {
|
||||
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
|
||||
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
||||
|
||||
// Build INVENTORY command
|
||||
uint8_t resp_inv[CMD_INV_RESP] = {0};
|
||||
|
||||
resp_inv[0] = 0; // No error, no protocol format extension
|
||||
resp_inv[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported
|
||||
|
||||
// 64-bit UID
|
||||
resp_inv[2] = uid[7];
|
||||
resp_inv[3] = uid[6];
|
||||
resp_inv[4] = uid[5];
|
||||
resp_inv[5] = uid[4];
|
||||
resp_inv[6] = uid[3];
|
||||
resp_inv[7] = uid[2];
|
||||
resp_inv[8] = uid[1];
|
||||
resp_inv[9] = uid[0];
|
||||
|
||||
// CRC
|
||||
AddCrc15(resp_inv, 10);
|
||||
CodeIso15693AsTag(resp_inv, CMD_INV_RESP);
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
|
||||
LogTrace_ISO15693(resp_inv, CMD_INV_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
|
||||
|
||||
chip_state = SELECTED;
|
||||
}
|
||||
|
||||
// GET_SYSTEM_INFO
|
||||
if ((cmd[1] == ISO15_CMD_SYSINFO)) {
|
||||
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
|
||||
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
||||
|
||||
// Build GET_SYSTEM_INFO command
|
||||
uint8_t resp_sysinfo[CMD_SYSINFO_RESP] = {0};
|
||||
|
||||
resp_sysinfo[0] = 0; // Response flags.
|
||||
resp_sysinfo[1] = 0x0F; // Information flags (0x0F - DSFID, AFI, Mem size, IC)
|
||||
|
||||
// 64-bit UID
|
||||
resp_sysinfo[2] = uid[7];
|
||||
resp_sysinfo[3] = uid[6];
|
||||
resp_sysinfo[4] = uid[5];
|
||||
resp_sysinfo[5] = uid[4];
|
||||
resp_sysinfo[6] = uid[3];
|
||||
resp_sysinfo[7] = uid[2];
|
||||
resp_sysinfo[8] = uid[1];
|
||||
resp_sysinfo[9] = uid[0];
|
||||
|
||||
resp_sysinfo[10] = 0; // DSFID
|
||||
resp_sysinfo[11] = 0; // AFI
|
||||
|
||||
resp_sysinfo[12] = 0x1B; // Memory size.
|
||||
resp_sysinfo[13] = 0x03; // Memory size.
|
||||
resp_sysinfo[14] = 0x01; // IC reference.
|
||||
|
||||
// CRC
|
||||
AddCrc15(resp_sysinfo, 15);
|
||||
CodeIso15693AsTag(resp_sysinfo, CMD_SYSINFO_RESP);
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
|
||||
LogTrace_ISO15693(resp_sysinfo, CMD_SYSINFO_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
|
||||
}
|
||||
|
||||
// READ_BLOCK
|
||||
if ((cmd[1] == ISO15_CMD_READ)) {
|
||||
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
|
||||
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
||||
|
||||
// Build GET_SYSTEM_INFO command
|
||||
uint8_t resp_readblock[CMD_READBLOCK_RESP] = {0};
|
||||
|
||||
resp_readblock[0] = 0; // Response flags.
|
||||
resp_readblock[1] = 0; // Block data.
|
||||
resp_readblock[2] = 0; // Block data.
|
||||
resp_readblock[3] = 0; // Block data.
|
||||
resp_readblock[4] = 0; // Block data.
|
||||
|
||||
// CRC
|
||||
AddCrc15(resp_readblock, 5);
|
||||
CodeIso15693AsTag(resp_readblock, CMD_READBLOCK_RESP);
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
|
||||
LogTrace_ISO15693(resp_readblock, CMD_READBLOCK_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
|
||||
}
|
||||
}
|
||||
|
||||
switch_off();
|
||||
|
|
|
@ -803,7 +803,7 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) {
|
|||
AcquireTiType();
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
DbpString("Now use `lf ti read` to check");
|
||||
DbpString("Now use `lf ti reader` to check");
|
||||
StopTicks();
|
||||
}
|
||||
|
||||
|
@ -2190,10 +2190,8 @@ void T55xxWakeUp(uint32_t pwd, uint8_t flags) {
|
|||
reply_ng(CMD_LF_T55XX_WAKEUP, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/*-------------- Cloning routines -----------*/
|
||||
static void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) {
|
||||
|
||||
t55xx_write_block_t cmd;
|
||||
cmd.pwd = 0;
|
||||
cmd.flags = 0;
|
||||
|
@ -2203,11 +2201,18 @@ static void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblock
|
|||
cmd.blockno = i - 1;
|
||||
T55xxWriteBlock((uint8_t *)&cmd);
|
||||
}
|
||||
|
||||
}
|
||||
/* disabled until verified.
|
||||
static void WriteEM4x05(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) {
|
||||
for (uint8_t i = numblocks + startblock; i > startblock; i--) {
|
||||
EM4xWriteWord(i - 1, blockdata[i - 1], 0, false);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// Copy HID id to card and setup block 0 config
|
||||
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) {
|
||||
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool q5, bool em) {
|
||||
uint32_t data[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t last_block = 0;
|
||||
|
||||
|
@ -2244,25 +2249,43 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) {
|
|||
data[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2a | last_block << T55x7_MAXBLOCK_SHIFT;
|
||||
|
||||
//TODO add selection of chip for Q5 or T55x7
|
||||
// data[0] = T5555_SET_BITRATE(50) | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | last_block << T5555_MAXBLOCK_SHIFT;
|
||||
if (q5) {
|
||||
data[0] = T5555_SET_BITRATE(50) | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | last_block << T5555_MAXBLOCK_SHIFT;
|
||||
} else if (em) {
|
||||
data[0] = (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_INVERT | EM4x05_SET_NUM_BLOCKS(last_block));
|
||||
}
|
||||
|
||||
LED_D_ON();
|
||||
WriteT55xx(data, 0, last_block + 1);
|
||||
if (em) {
|
||||
Dbprintf("Clone HID Prox to EM4x05 is untested and disabled until verified");
|
||||
//WriteEM4x05(data, 0, last_block + 1);
|
||||
} else {
|
||||
WriteT55xx(data, 0, last_block + 1);
|
||||
}
|
||||
LED_D_OFF();
|
||||
reply_ng(CMD_LF_HID_CLONE, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
|
||||
// clone viking tag to T55xx
|
||||
void CopyVikingtoT55xx(uint8_t *blocks, uint8_t Q5) {
|
||||
void CopyVikingtoT55xx(uint8_t *blocks, bool q5, bool em) {
|
||||
|
||||
uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), 0, 0};
|
||||
if (Q5)
|
||||
if (q5) {
|
||||
data[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
} else if (em) {
|
||||
data[0] = (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(2));
|
||||
}
|
||||
|
||||
data[1] = bytes_to_num(blocks, 4);
|
||||
data[2] = bytes_to_num(blocks + 4, 4);
|
||||
|
||||
// Program the data blocks for supplied ID and the block 0 config
|
||||
WriteT55xx(data, 0, 3);
|
||||
if (em) {
|
||||
Dbprintf("Clone Viking to EM4x05 is untested and disabled until verified");
|
||||
//WriteEM4x05(data, 0, 3);
|
||||
} else {
|
||||
WriteT55xx(data, 0, 3);
|
||||
}
|
||||
LED_D_OFF();
|
||||
reply_ng(CMD_LF_VIKING_CLONE, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
|
|
|
@ -39,9 +39,8 @@ int lf_awid_watch(int findone, uint32_t *high, uint32_t *low); // Realtime demod
|
|||
int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low);
|
||||
int lf_io_watch(int findone, uint32_t *high, uint32_t *low);
|
||||
|
||||
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an HID card to T5557/T5567
|
||||
|
||||
void CopyVikingtoT55xx(uint8_t *blocks, uint8_t Q5);
|
||||
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool q5, bool em); // Clone an HID card to T5557/T5567
|
||||
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);
|
||||
|
||||
|
|
|
@ -509,11 +509,22 @@ void doCotagAcquisition(void) {
|
|||
bool firsthigh = false, firstlow = false;
|
||||
uint16_t i = 0, noise_counter = 0;
|
||||
|
||||
uint16_t checker = 0;
|
||||
|
||||
while ((i < bufsize - 1) && (noise_counter < COTAG_T1 << 1)) {
|
||||
|
||||
if (BUTTON_PRESS())
|
||||
break;
|
||||
|
||||
if (checker == 4000) {
|
||||
if (data_available())
|
||||
break;
|
||||
else
|
||||
checker = 0;
|
||||
} else {
|
||||
++checker;
|
||||
}
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
|
@ -567,12 +578,22 @@ uint16_t doCotagAcquisitionManchester(uint8_t *dest, uint16_t destlen) {
|
|||
bool firsthigh = false, firstlow = false;
|
||||
uint8_t curr = 0, prev = 0;
|
||||
uint16_t i = 0;
|
||||
uint16_t period = 0;
|
||||
uint16_t period = 0, checker = 0;
|
||||
|
||||
while ((i < destlen) && BUTTON_PRESS() == false) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (checker == 4000) {
|
||||
if (data_available())
|
||||
break;
|
||||
else
|
||||
checker = 0;
|
||||
} else {
|
||||
++checker;
|
||||
}
|
||||
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
|
|
|
@ -535,8 +535,9 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
|
||||
WDT_HIT();
|
||||
|
||||
if (counter == 2000) {
|
||||
if (counter == 1000) {
|
||||
if (data_available()) {
|
||||
Dbprintf("----------- " _GREEN_("BREAKING") " ----------");
|
||||
break;
|
||||
}
|
||||
counter = 0;
|
||||
|
|
|
@ -248,7 +248,8 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||
${PM3_ROOT}/client/src/cmdlfdestron.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem.c
|
||||
${PM3_ROOT}/client/src/cmdlfem410x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x05.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||
|
|
|
@ -489,7 +489,8 @@ SRCS = aiddesfire.c \
|
|||
cmdlfawid.c \
|
||||
cmdlfcotag.c \
|
||||
cmdlfdestron.c \
|
||||
cmdlfem4x.c \
|
||||
cmdlfem.c \
|
||||
cmdlfem410x.c \
|
||||
cmdlfem4x05.c \
|
||||
cmdlfem4x50.c \
|
||||
cmdlffdxb.c \
|
||||
|
|
|
@ -10,3 +10,5 @@ AEA684A6DAB23278 # AA1
|
|||
F0E1D2C3B4A59687 # Kd from PicoPass 2k documentation
|
||||
5CBCF1DA45D5FB4F # PicoPass Default Exchange Key
|
||||
31ad7ebd2f282168 # From HID multiclassSE reader
|
||||
6EFD46EFCBB3C875 # From pastebin: https://pastebin.com/uHqpjiuU
|
||||
E033CA419AEE43F9 # From pastebin: https://pastebin.com/uHqpjiuU
|
|
@ -105,6 +105,11 @@ c934fe34d934
|
|||
cccccccccccc
|
||||
dddddddddddd
|
||||
eeeeeeeeeeee
|
||||
#
|
||||
# elevator
|
||||
# data from forum
|
||||
FFFFFF545846
|
||||
#
|
||||
f1a97341a9fc
|
||||
44ab09010845 # hotel system
|
||||
85fed980ea5a # hotel system
|
||||
|
@ -1276,3 +1281,6 @@ AABAFFCC7612
|
|||
# ozdilek
|
||||
#
|
||||
17D071403C20
|
||||
#
|
||||
534F4C415249
|
||||
534f4c303232
|
|
@ -3,7 +3,14 @@
|
|||
51243648
|
||||
000D8787
|
||||
19920427
|
||||
65857569 //chinese "handheld RFID writer" blue cloner from circa 2013 (also sold by xfpga.com)
|
||||
# ZX-copy3 T55xx / EM4305
|
||||
# ref. http://www.proxmark.org/forum/viewtopic.php?pid=40662#p40662
|
||||
# default PROX
|
||||
50524F58
|
||||
# blue gun EM4305
|
||||
F9DCEBA0
|
||||
# chinese "handheld RFID writer" blue cloner from circa 2013 (also sold by xfpga.com)
|
||||
65857569
|
||||
# ref. http://kazus.ru/forums/showpost.php?p=1045937&postcount=77
|
||||
05D73B9F
|
||||
# ref. http://www.proxmark.org/forum/viewtopic.php?=
|
||||
|
@ -24,10 +31,6 @@ A5B4C3D2
|
|||
575F4F4B
|
||||
#
|
||||
50520901
|
||||
# default PROX
|
||||
50524F58
|
||||
# blue gun EM4305
|
||||
F9DCEBA0
|
||||
# Default pwd, simple:
|
||||
00000000
|
||||
11111111
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
typedef struct pm3_device pm3;
|
||||
|
||||
pm3 *pm3_open(char *port);
|
||||
int pm3_console(pm3* dev, char *cmd);
|
||||
const char *pm3_name_get(pm3* dev);
|
||||
void pm3_close(pm3* dev);
|
||||
int pm3_console(pm3 *dev, char *cmd);
|
||||
const char *pm3_name_get(pm3 *dev);
|
||||
void pm3_close(pm3 *dev);
|
||||
pm3 *pm3_get_current_dev(void);
|
||||
#endif // LIBPM3_H
|
||||
|
|
82
client/luascripts/mfc_hammerlite.lua
Normal file
82
client/luascripts/mfc_hammerlite.lua
Normal file
|
@ -0,0 +1,82 @@
|
|||
local getopt = require('getopt')
|
||||
local lib14a = require('read14a')
|
||||
local cmds = require('commands')
|
||||
local ansicolors = require('ansicolors')
|
||||
|
||||
copyright = 'Copyright 2020 A. Ozkal, released under GPLv2+.'
|
||||
author = 'Ave'
|
||||
version = 'v0.1.1'
|
||||
desc = [[
|
||||
This script writes a bunch of random blocks to a Mifare Classic card
|
||||
]]
|
||||
example = [[
|
||||
script run mfc_hammerlite -w 1000 -k FFFFFFFFFFFF
|
||||
]]
|
||||
usage = [[
|
||||
script run mfc_hammerlite [-h] [-w <writecount>] [-k <key>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : This help
|
||||
-w <writeroundcount> : Amount of write rounds to be done to each block (optional, default: 100)
|
||||
-k <key> : A key for the sectors
|
||||
]]
|
||||
|
||||
local function help()
|
||||
print(author)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ansicolors.cyan..'Usage'..ansicolors.reset)
|
||||
print(usage)
|
||||
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
|
||||
print(arguments)
|
||||
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
|
||||
print(example)
|
||||
end
|
||||
|
||||
function randhex(len)
|
||||
result = ""
|
||||
for i = 1,len,1
|
||||
do
|
||||
-- 48-57 numbers, 65-70 a-f
|
||||
hex = math.random(0, 15)
|
||||
if hex >= 10 then
|
||||
hex = hex + 7
|
||||
end
|
||||
result = result..string.char(48 + hex)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
---
|
||||
-- The main entry point
|
||||
function main(args)
|
||||
-- param defaults
|
||||
loopcount = 100
|
||||
verifyevery = 10
|
||||
key = "FFFFFFFFFFFF"
|
||||
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'hw:k:') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'w' then loopcount = tonumber(a) end
|
||||
if o == 'k' then key = a end
|
||||
end
|
||||
|
||||
starttime = os.time()
|
||||
|
||||
for i = 1,loopcount,1
|
||||
do
|
||||
for a = 1,63,1
|
||||
do
|
||||
if ((a + 1) % 4 ~= 0) and a ~= 0 then -- :)
|
||||
data = randhex(32)
|
||||
-- core.console('hf mf rdbl '..a..' A FFFFFFFFFFFF')
|
||||
core.console('hf mf wrbl '..a..' A '..key..' '..data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print("Hammering complete.")
|
||||
end
|
||||
|
||||
main(args)
|
189
client/luascripts/ntag_hammertime.lua
Normal file
189
client/luascripts/ntag_hammertime.lua
Normal file
|
@ -0,0 +1,189 @@
|
|||
local getopt = require('getopt')
|
||||
local lib14a = require('read14a')
|
||||
local cmds = require('commands')
|
||||
local ansicolors = require('ansicolors')
|
||||
|
||||
copyright = 'Copyright 2020 A. Ozkal, released under GPLv2+.'
|
||||
author = 'Ave'
|
||||
version = 'v2.1.3'
|
||||
desc = [[
|
||||
This script writes a bunch of random blocks to a NTAG or MFUL card to test its actual write limits
|
||||
]]
|
||||
example = [[
|
||||
script run ntag_hammertime -w 1000 -r 50 -z 50 -f 5 -s 4 -e 129
|
||||
]]
|
||||
usage = [[
|
||||
script run ntag_hammertime [-h] [-w <writecount>] [-r <readevery>] [-z <reselectevery>] [-f <maximumfails>] [-s <writestartblock>] [-e <writeendblock>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : This help
|
||||
-w <writeroundcount> : Amount of write rounds to be done to each block (optional, default: 100)
|
||||
-r <readevery> : Verify frequency (reads and checks written values every x rounds, optional, default: 10)
|
||||
-z <reselectevery> : Reselect frequency (reselects card once every x rounds, optional, default: 10)
|
||||
-f <maximumfails> : Maximum consequent fails (read/write) that will trigger a fail state (optional, default: 3)
|
||||
-s <writestartblock> : Block number for writes to be started to (optional, inclusive, decimal, default: 4)
|
||||
-e <writeendblock> : Block number for writes to be ended on (optional, inclusive, decimal, default: 129)
|
||||
]]
|
||||
|
||||
local function help()
|
||||
print(author)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ansicolors.cyan..'Usage'..ansicolors.reset)
|
||||
print(usage)
|
||||
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
|
||||
print(arguments)
|
||||
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
|
||||
print(example)
|
||||
end
|
||||
|
||||
function randhex(len)
|
||||
result = ""
|
||||
for i = 1,len,1
|
||||
do
|
||||
-- 48-57 numbers, 65-70 a-f
|
||||
hex = math.random(0, 15)
|
||||
if hex >= 10 then
|
||||
hex = hex + 7
|
||||
end
|
||||
result = result..string.char(48 + hex)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Used to send raw data to the firmware to subsequently forward the data to the card.
|
||||
-- from mifareplus.lua
|
||||
local function sendRaw(rawdata, crc, power)
|
||||
-- print(("<sent>: %s"):format(rawdata))
|
||||
|
||||
local flags = lib14a.ISO14A_COMMAND.ISO14A_RAW
|
||||
if crc then
|
||||
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC
|
||||
end
|
||||
if power then
|
||||
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT
|
||||
end
|
||||
|
||||
local command = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER,
|
||||
arg1 = flags, -- Send raw
|
||||
arg2 = string.len(rawdata) / 2, -- arg2 contains the length, which is half the length of the ASCII-string rawdata
|
||||
data = rawdata
|
||||
}
|
||||
local ignore_response = false
|
||||
local result, err = command:sendMIX(ignore_response)
|
||||
if result then
|
||||
--unpack the first 4 parts of the result as longs, and the last as an extremely long string to later be cut down based on arg1, the number of bytes returned
|
||||
local count,cmd,arg1,arg2,arg3,data = bin.unpack('LLLLH512',result)
|
||||
|
||||
returned_bytes = string.sub(data, 1, arg1 * 2)
|
||||
if #returned_bytes > 0 then
|
||||
-- print(("<recvd>: %s"):format(returned_bytes)) -- need to multiply by 2 because the hex digits are actually two bytes when they are strings
|
||||
return returned_bytes
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
print("Error sending the card raw data.")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function selectCard(keepField, arg2, attemptCount)
|
||||
for i = 1,attemptCount,1
|
||||
do
|
||||
if lib14a.read(keepField, arg2) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---
|
||||
-- The main entry point
|
||||
function main(args)
|
||||
failcounter = 0
|
||||
|
||||
-- param defaults
|
||||
loopcount = 100
|
||||
verifyevery = 10
|
||||
reselectevery = 10
|
||||
failmax = 3
|
||||
blockstart = 4
|
||||
blockend = 129
|
||||
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'hw:r:z:f:s:e:') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'w' then loopcount = tonumber(a) end
|
||||
if o == 'r' then verifyevery = tonumber(a) end
|
||||
if o == 'z' then reselectevery = tonumber(a) end
|
||||
if o == 'f' then failmax = tonumber(a) end
|
||||
if o == 's' then blockstart = tonumber(a) end
|
||||
if o == 'e' then blockend = tonumber(a) end
|
||||
end
|
||||
|
||||
starttime = os.time()
|
||||
|
||||
if selectCard(true, false, 3) ~= true then
|
||||
return print("Select failed.")
|
||||
end
|
||||
for i = 1,loopcount,1
|
||||
do
|
||||
for block = blockstart,blockend,1
|
||||
do
|
||||
data = randhex(8)
|
||||
print(i..": Writing "..data.." to block "..block..".")
|
||||
blockhex = string.format("%02x", block)
|
||||
result = sendRaw("A2"..blockhex..data, true, true)
|
||||
if result then -- if false/nil, that's a fail right there
|
||||
print(ansicolors.green.."Got "..result.."."..ansicolors.reset) -- We want this to be 0A
|
||||
failcounter = 0
|
||||
else
|
||||
print(ansicolors.red.."Write FAILED."..ansicolors.reset)
|
||||
failcounter = failcounter + 1
|
||||
goto continue
|
||||
end
|
||||
|
||||
if i % verifyevery == 0 then
|
||||
result = sendRaw("30"..blockhex, true, true)
|
||||
if result then -- if false, that's a fail right there
|
||||
result = string.sub(result, 0, 8)
|
||||
if result ~= data then
|
||||
print(ansicolors.red.."Read IMPROPER, supposed to be "..data..", got "..result.."."..ansicolors.reset)
|
||||
failcounter = failcounter + 1
|
||||
goto continue
|
||||
else
|
||||
print(ansicolors.green.."Read matches the write."..ansicolors.reset)
|
||||
failcounter = 0
|
||||
end
|
||||
else
|
||||
print(ansicolors.red.."Read FAILED."..ansicolors.reset)
|
||||
failcounter = failcounter + 1
|
||||
goto continue
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
|
||||
if failcounter >= failmax then
|
||||
-- close field
|
||||
lib14a.read(false, false)
|
||||
return print(ansicolors.red.."Test failed after "..(os.time() - starttime).." seconds, "..(i*(blockend-blockstart)).." writes and "..math.floor((i*(blockend-blockstart))/verifyevery).." reads."..ansicolors.reset)
|
||||
end
|
||||
end
|
||||
|
||||
if i % reselectevery == 0 then
|
||||
-- reselect
|
||||
sendRaw("", false, false)
|
||||
if selectCard(true, false, 3) ~= true then
|
||||
return print("Reselect failed.")
|
||||
end
|
||||
print("Reselected card, current rate: "..(i*(blockend-blockstart))/(os.time() - starttime).." writes/s.")
|
||||
end
|
||||
end
|
||||
|
||||
-- close field
|
||||
lib14a.read(false, false)
|
||||
print("Successfully completed test in "..(os.time() - starttime).." seconds, did "..(loopcount*(blockend-blockstart)).." writes and "..math.floor((loopcount*(blockend-blockstart))/verifyevery).." reads.")
|
||||
end
|
||||
|
||||
main(args)
|
|
@ -23,7 +23,7 @@
|
|||
#include "comms.h"
|
||||
#include "lfdemod.h" // for demod code
|
||||
#include "loclass/cipherutils.h" // for decimating samples in getsamples
|
||||
#include "cmdlfem4x.h" // askem410xdecode
|
||||
#include "cmdlfem410x.h" // askem410xdecode
|
||||
#include "fileutils.h" // searchFile
|
||||
#include "mifare/ndef.h"
|
||||
#include "cliparser.h"
|
||||
|
@ -1702,9 +1702,11 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
if (package->peak_v > NON_VOLTAGE && package->peak_f > 0)
|
||||
PrintAndLogEx(SUCCESS, "LF optimal: %5.2f V - %6.2f kHz", (package->peak_v * ANTENNA_ERROR) / 1000.0, LF_DIV2FREQ(package->peak_f));
|
||||
|
||||
// Empirical measures in mV
|
||||
const double vdd_rdv4 = 9000;
|
||||
const double vdd_other = 5400; // Empirical measures in mV
|
||||
const double vdd_other = 5400;
|
||||
double vdd = IfPm3Rdv4Fw() ? vdd_rdv4 : vdd_other;
|
||||
|
||||
if (package->peak_v > NON_VOLTAGE && package->peak_f > 0) {
|
||||
|
||||
// Q measure with Q=f/delta_f
|
||||
|
@ -1737,9 +1739,15 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
// cross-check results
|
||||
if (lfq1 > 3) {
|
||||
double approx_vdd = (double)package->peak_v * 3.14 / 2 / lfq1;
|
||||
if ((approx_vdd > (vdd_rdv4 + vdd_other) / 2) && (! IfPm3Rdv4Fw()))
|
||||
// Got 8858 on a RDV4 with large antenna 134/14
|
||||
// Got 8761 on a non-RDV4
|
||||
const double approx_vdd_other_max = 8840;
|
||||
|
||||
// 1% over threshold and supposedly non-RDV4
|
||||
if ((approx_vdd > approx_vdd_other_max * 1.01) && (! IfPm3Rdv4Fw()))
|
||||
PrintAndLogEx(WARNING, "Contradicting measures seem to indicate you're running a " _YELLOW_("PM3_OTHER firmware on a RDV4") ", please check your setup");
|
||||
if ((approx_vdd < (vdd_rdv4 + vdd_other) / 2) && (IfPm3Rdv4Fw()))
|
||||
// 1% below threshold and supposedly RDV4
|
||||
if ((approx_vdd < approx_vdd_other_max * 0.99) && (IfPm3Rdv4Fw()))
|
||||
PrintAndLogEx(WARNING, "Contradicting measures seem to indicate you're running a " _YELLOW_("PM3_RDV4 firmware on a non-RDV4") ", please check your setup");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ static int usage_hf_14a_config(void) {
|
|||
|
||||
static int usage_hf_14a_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t <type> u <uid> [x] [e] [v]");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t <type> u <uid> [n <numreads>] [x] [e] [v]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " t : 1 = MIFARE Classic 1k");
|
||||
|
@ -225,6 +225,7 @@ static int usage_hf_14a_sim(void) {
|
|||
PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro");
|
||||
PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult");
|
||||
PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID");
|
||||
PrintAndLogEx(NORMAL, " n : (Optional) Exit simulation after <numreads> blocks have been read by reader. 0 = infinite");
|
||||
PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader");
|
||||
PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys");
|
||||
PrintAndLogEx(NORMAL, " v : (Optional) Verbose");
|
||||
|
@ -657,6 +658,7 @@ int CmdHF14ASim(const char *Cmd) {
|
|||
bool errors = false;
|
||||
sector_t *k_sector = NULL;
|
||||
uint8_t k_sectorsCount = 40;
|
||||
uint8_t exitAfterNReads = 0;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
|
@ -693,6 +695,10 @@ int CmdHF14ASim(const char *Cmd) {
|
|||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'n':
|
||||
exitAfterNReads = param_get8(Cmd, cmdp + 1);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
|
@ -722,10 +728,12 @@ int CmdHF14ASim(const char *Cmd) {
|
|||
uint8_t tagtype;
|
||||
uint8_t flags;
|
||||
uint8_t uid[10];
|
||||
uint8_t exitAfter;
|
||||
} PACKED payload;
|
||||
|
||||
payload.tagtype = tagtype;
|
||||
payload.flags = flags;
|
||||
payload.exitAfter = exitAfterNReads;
|
||||
memcpy(payload.uid, uid, uidlen);
|
||||
|
||||
clearCommandBuffer();
|
||||
|
|
|
@ -1725,7 +1725,7 @@ static int CmdHF15Write(const char *Cmd) {
|
|||
AddCrc15(req, reqlen);
|
||||
reqlen += 2;
|
||||
|
||||
PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum);
|
||||
PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data [ %s ] ", pagenum, pagenum, sprint_hex(req, reqlen));
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
|
|
|
@ -49,7 +49,7 @@ static int usage_hf_felica_sim(void) {
|
|||
|
||||
static int usage_hf_felica_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, "\nInfo: It get data from the field and saves it into command buffer. ");
|
||||
PrintAndLogEx(NORMAL, " Buffer accessible from command 'hf list felica'");
|
||||
PrintAndLogEx(NORMAL, " Buffer accessible from command 'hf felica list'");
|
||||
PrintAndLogEx(NORMAL, "\nUsage: hf felica sniff [-h] [-s] [-t]");
|
||||
PrintAndLogEx(NORMAL, " -h this help");
|
||||
PrintAndLogEx(NORMAL, " -s samples to skip (decimal) max 9999");
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,7 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include "cliparser.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "cmdtrace.h"
|
||||
|
@ -36,62 +37,6 @@
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lto_info(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf lto info [h]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto info"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lto_rdbl(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf lto rdbl [h] s <start block> e <end block>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " s start block in decimal >= 0");
|
||||
PrintAndLogEx(NORMAL, " e end block in decimal <= 254");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto rdbl s 0 e 254") " - Read data block from 0 to 254");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lto_wrbl(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf lto wrbl [h] b <block> d <data>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " b block address (decimal, 0 - 254) ");
|
||||
PrintAndLogEx(NORMAL, " d 32 bytes of data to write (64 hex characters, no space)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto wrbl b 128 d 0001020304050607080910111213141516171819202122232425262728293031") " - write 00..31 to block address 128");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lto_dump(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf lto dump [h|p] f <filename>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " f file name");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto dump f myfile"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lto_restore(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf lto restore [h] f <filename>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " f file name [.bin|.eml]");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf lto restore f hf_lto_92C7842CFF.bin|.eml"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void lto_switch_off_field(void) {
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, 0, 0, 0, NULL, 0);
|
||||
}
|
||||
|
@ -173,25 +118,17 @@ static int lto_select(uint8_t *id_response, uint8_t id_len, uint8_t *type_respon
|
|||
}
|
||||
|
||||
static int CmdHfLTOInfo(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf lto info",
|
||||
"Get info from LTO tags",
|
||||
"hf lto info");
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lto_info();
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors) {
|
||||
return usage_lto_info();
|
||||
}
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return infoLTO(true);
|
||||
}
|
||||
|
||||
|
@ -304,48 +241,31 @@ int rdblLTO(uint8_t st_blk, uint8_t end_blk, bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdHfLTOReadBlock(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf lto rdbl",
|
||||
"Reead blocks from LTO tag",
|
||||
"hf lto rdbl --first 0 --last 254");
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
uint8_t st_blk = 0;
|
||||
uint8_t end_blk = 254;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0(NULL, "first", "<dec>", "The first block number to read as an integer"),
|
||||
arg_int0(NULL, "last", "<dec>", "The last block number to read as an integer"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lto_rdbl();
|
||||
case 's':
|
||||
st_blk = param_get8(Cmd, cmdp + 1);
|
||||
if (end_blk < st_blk) {
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
int startblock = arg_get_int_def(ctx, 1, 0);
|
||||
int endblock = arg_get_int_def(ctx, 2, 254);
|
||||
|
||||
case 'e':
|
||||
end_blk = param_get8(Cmd, cmdp + 1);
|
||||
if (end_blk < st_blk) {
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
//Validations
|
||||
if (errors) {
|
||||
usage_lto_rdbl();
|
||||
if (endblock < startblock) {
|
||||
PrintAndLogEx(ERR, "First block must be less than last block");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
return rdblLTO(st_blk, end_blk, true);
|
||||
return rdblLTO(startblock, endblock, true);
|
||||
}
|
||||
|
||||
static int lto_wrbl(uint8_t blk, uint8_t *data, bool verbose) {
|
||||
|
@ -407,46 +327,33 @@ int wrblLTO(uint8_t blk, uint8_t *data, bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdHfLTOWriteBlock(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf lto wrbl",
|
||||
"Write data to block on LTO tag",
|
||||
"hf lto wrbl --block 128 -d 0001020304050607080910111213141516171819202122232425262728293031");
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
bool b_opt_selected = false;
|
||||
bool d_opt_selected = false;
|
||||
uint8_t blk = 128;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("d", "data", "<hex>", "32 bytes of data to write (64 hex symbols, no spaces)"),
|
||||
arg_int1(NULL, "block", "<dec>", "The block number to write to as an integer"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int block_data_len = 0;
|
||||
uint8_t block_data[32] = {0};
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lto_wrbl();
|
||||
case 'b':
|
||||
blk = param_get8(Cmd, cmdp + 1);
|
||||
b_opt_selected = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
if (param_gethex(Cmd, cmdp + 1, block_data, 64)) {
|
||||
PrintAndLogEx(WARNING, "block data must include 64 HEX symbols");
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
d_opt_selected = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
CLIGetHexWithReturn(ctx, 1, block_data, &block_data_len);
|
||||
|
||||
if (block_data_len != 32) {
|
||||
PrintAndLogEx(ERR, "Block data is incorrect length");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors) {
|
||||
return usage_lto_wrbl();
|
||||
} else if (b_opt_selected == false || d_opt_selected == false) {
|
||||
PrintAndLogEx(WARNING, "Need to specify block address and data.");
|
||||
return usage_lto_wrbl();
|
||||
}
|
||||
int blk = arg_get_int_def(ctx, 2, 0);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
int res = wrblLTO(blk, block_data, true);
|
||||
if (res == PM3_SUCCESS)
|
||||
|
@ -504,35 +411,25 @@ int dumpLTO(uint8_t *dump, bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdHfLTODump(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf lto dump",
|
||||
"Dump data from LTO tag",
|
||||
"hf lto dump -f myfile");
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
uint32_t dump_len = CM_MEM_MAX_SIZE;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("f", "file", "<filename>", "specify a filename for dumpfile"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lto_dump();
|
||||
case 'f':
|
||||
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) {
|
||||
PrintAndLogEx(FAILED, "filename too long");
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (errors) {
|
||||
usage_lto_dump();
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
uint32_t dump_len = CM_MEM_MAX_SIZE;
|
||||
|
||||
uint8_t *dump = calloc(dump_len, sizeof(uint8_t));
|
||||
if (!dump) {
|
||||
|
@ -596,32 +493,23 @@ int restoreLTO(uint8_t *dump, bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdHfLTRestore(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf lto restore",
|
||||
"Restore data from dumpfile to LTO tag",
|
||||
"hf lto restore -f hf-lto-92C7842CFF.bin|.eml");
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("f", "file", "<filename>", "specify a filename for dumpfile"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lto_restore();
|
||||
case 'f':
|
||||
param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
||||
if (strlen(filename) < 5)
|
||||
errors = true;
|
||||
|
||||
cmdp += 2;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors || strlen(Cmd) == 0) {
|
||||
return usage_lto_restore();
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
size_t dump_len = 0;
|
||||
char *lowstr = str_dup(filename);
|
||||
|
|
|
@ -266,6 +266,16 @@ static int get_plus_version(uint8_t *version, int *version_len) {
|
|||
}
|
||||
|
||||
static int CmdHFMFPInfo(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp info",
|
||||
"Get info from MIFARE Plus tags",
|
||||
"hf mfp info");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||
|
|
|
@ -155,15 +155,17 @@ static int usage_hf_mfu_eload(void) {
|
|||
static int usage_hf_mfu_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "\nEmulating Ultralight tag from emulator memory\n");
|
||||
PrintAndLogEx(NORMAL, "\nBe sure to load the emulator memory first!\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mfu sim t 7 u <uid>");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mfu sim t 7 u <uid> [n <num>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " t 7 : 7 = NTAG or Ultralight sim (required)");
|
||||
PrintAndLogEx(NORMAL, " n <num> : exit simulation after <num> blocks have been read by reader. 0 = infinite (optional)");
|
||||
PrintAndLogEx(NORMAL, " u <uid> : 4 or 7 byte UID (optional)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7 u 1122344556677"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7 u 1122344556677 n 5"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -12,24 +12,23 @@
|
|||
// Low frequency commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlf.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "lfdemod.h" // device/client demods of LF signals
|
||||
#include "ui.h" // for show graph controls
|
||||
#include "proxgui.h"
|
||||
#include "cliparser.h" // args parsing
|
||||
#include "graph.h" // for graph data
|
||||
#include "cmddata.h" // for `lf search`
|
||||
#include "cmdlfawid.h" // for awid menu
|
||||
#include "cmdlfem4x.h" // for em4x menu
|
||||
#include "cmdlfem.h" // for em menu
|
||||
#include "cmdlfem410x.h" // for em4x menu
|
||||
#include "cmdlfem4x05.h" // for em4x05 / 4x69
|
||||
#include "cmdlfem4x50.h" // for em4x50
|
||||
#include "cmdlfhid.h" // for hid menu
|
||||
|
@ -1434,8 +1433,8 @@ int CmdLFfind(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INPLACE, "Searching for COTAG tag...");
|
||||
if (readCOTAGUid()) {
|
||||
PrintAndLogEx(INPLACE, "Searching for COTAG tag...");
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("COTAG ID") " found!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1530,7 +1529,7 @@ static command_t CommandTable[] = {
|
|||
{"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
|
||||
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
|
||||
{"destron", CmdLFDestron, AlwaysAvailable, "{ FDX-A Destron RFIDs... }"},
|
||||
{"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"},
|
||||
{"em", CmdLFEM, AlwaysAvailable, "{ EM CHIPs & RFIDs... }"},
|
||||
{"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"},
|
||||
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
|
||||
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},
|
||||
|
|
|
@ -10,97 +10,28 @@
|
|||
// Low frequency AWID26/50 commands
|
||||
// FSK2a, RF/50, 96 bits (complete)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfawid.h" // AWID function declarations
|
||||
|
||||
#include "cmdlfawid.h" // AWID function declarations
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "graph.h"
|
||||
#include "cmddata.h"
|
||||
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlf.h" // lf read
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlf.h" // lf read
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "util_posix.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 usage_lf_awid_watch(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables AWID compatible reader mode printing details of scanned AWID26 or AWID50 tags.");
|
||||
PrintAndLogEx(NORMAL, "By default, values are printed and logged until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf awid watch");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid watch"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_awid_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of AWID card with specified facility-code and card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf awid sim [h] <format> <facility-code> <card-number>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <format> : format length 26|34|37|50");
|
||||
PrintAndLogEx(NORMAL, " <facility-code> : 8|16bit value facility code");
|
||||
PrintAndLogEx(NORMAL, " <card number> : 16|32-bit value card number");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid sim 26 224 1337"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid sim 50 2001 13371337"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_awid_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables cloning of AWID card with specified facility-code and card number onto T55x7 or Q5/T5555.");
|
||||
PrintAndLogEx(NORMAL, "The T55x7 must be on the antenna when issuing this command. T55x7 blocks are calculated and printed in the process.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf awid clone [h] <format> <facility-code> <card-number> [Q5]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <format> : format length 26|34|37|50");
|
||||
PrintAndLogEx(NORMAL, " <facility-code> : 8|16bit value facility code");
|
||||
PrintAndLogEx(NORMAL, " <card number> : 16|32-bit value card number");
|
||||
PrintAndLogEx(NORMAL, " Q5 : optional - specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid clone 26 224 1337"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid clone 50 2001 13371337"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_awid_brute(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables bruteforce of AWID reader with specified facility-code.");
|
||||
PrintAndLogEx(NORMAL, "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step");
|
||||
PrintAndLogEx(NORMAL, "if cardnumber is not given, it starts with 1 and goes up to 65535");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf awid brute [h] [v] a <format> f <facility-code> c <cardnumber> d <delay>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " a <format> : format length 26|50");
|
||||
PrintAndLogEx(NORMAL, " f <facility-code> : 8|16bit value facility code");
|
||||
PrintAndLogEx(NORMAL, " c <cardnumber> : (optional) cardnumber to start with, max 65535");
|
||||
PrintAndLogEx(NORMAL, " d <delay> : delay betweens attempts in ms. Default 1000ms");
|
||||
PrintAndLogEx(NORMAL, " v : verbose logging, show all tries");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid brute a 26 f 224"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid brute a 50 f 2001 d 2000"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf awid brute v a 50 f 2001 c 200 d 2000"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int sendPing(void) {
|
||||
SendCommandNG(CMD_PING, NULL, 0);
|
||||
SendCommandNG(CMD_PING, NULL, 0);
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
SendCommandNG(CMD_PING, NULL, 0);
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
|
@ -112,7 +43,7 @@ static int sendPing(void) {
|
|||
static int sendTry(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint32_t delay, uint8_t *bits, size_t bs_len, bool verbose) {
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "Trying FC: %u; CN: %u", fc, cn);
|
||||
PrintAndLogEx(INFO, "Trying FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fc, cn);
|
||||
|
||||
if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
|
@ -180,8 +111,19 @@ static void verify_values(uint8_t *fmtlen, uint32_t *fc, uint32_t *cn) {
|
|||
// this read loops on device side.
|
||||
// uses the demod in lfops.c
|
||||
static int CmdAWIDWatch(const char *Cmd) {
|
||||
uint8_t c = tolower(param_getchar(Cmd, 0));
|
||||
if (c == 'h') return usage_lf_awid_watch();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf awid watch",
|
||||
"Enables AWID compatible reader mode printing details of scanned AWID26 or AWID50 tags.\n"
|
||||
"Run until the button is pressed or another USB command is issued.",
|
||||
"lf awid watch"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Watching for AWID cards - place tag on antenna");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
||||
|
@ -339,31 +281,156 @@ int demodAWID(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdAWIDDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf awid demod",
|
||||
"Try to find AWID Prox preamble, if found decode / descramble data",
|
||||
"lf awid demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodAWID(true);
|
||||
}
|
||||
|
||||
// this read is the "normal" read, which download lf signal and tries to demod here.
|
||||
static int CmdAWIDRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 12000);
|
||||
return demodAWID(true);
|
||||
static int CmdAWIDReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf awid reader",
|
||||
"read a AWID Prox tag",
|
||||
"lf awid 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 12000);
|
||||
demodAWID(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdAWIDClone(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf awid clone",
|
||||
"clone a AWID Prox tag to a T55x7, Q5/T5555 or EM4305/4469 tag",
|
||||
"lf awid clone --fmt 26 --fc 123 --cn 1337\n"
|
||||
"lf awid clone --fmt 50 --fc 2001 --cn 13371337\n"
|
||||
"lf awid clone --q5 --fmt 26 --fc 123 --cn 1337 -> encode for Q5/T5555 tag\n"
|
||||
"lf awid clone --em --fmt 26 --fc 123 --cn 1337 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|34|37|50"),
|
||||
arg_u64_1(NULL, "fc", "<dec>", "8|16bit value facility code"),
|
||||
arg_u64_1(NULL, "cn", "<dec>", "16|32-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);
|
||||
|
||||
uint8_t fmtlen = arg_get_u32_def(ctx, 1, 0);
|
||||
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
|
||||
bool q5 = arg_get_lit(ctx, 4);
|
||||
bool em = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
//t5555 (Q5) BITRATE = (RF-2)/2 (iceman)
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_AWID_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
verify_values(&fmtlen, &fc, &cn);
|
||||
|
||||
uint8_t *bits = calloc(96, sizeof(uint8_t));
|
||||
|
||||
if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
blocks[1] = bytebits_to_byte(bits, 32);
|
||||
blocks[2] = bytebits_to_byte(bits + 32, 32);
|
||||
blocks[3] = bytebits_to_byte(bits + 64, 32);
|
||||
|
||||
free(bits);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone AWID %u to " _YELLOW_("%s") " with FC: " _GREEN_("%u") " CN: " _GREEN_("%u"), fmtlen, cardtype, fc, cn);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf awid reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdAWIDSim(const char *Cmd) {
|
||||
uint32_t fc = 0, cn = 0;
|
||||
uint8_t fmtlen = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf awid sim",
|
||||
"Enables simulation of AWID card with specified facility-code and card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf awid sim --fmt 26 --fc 123 --cn 1337\n"
|
||||
"lf awid sim --fmt 50 --fc 2001 --cn 13371337"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|32|36|40"),
|
||||
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);
|
||||
|
||||
uint8_t fmtlen = arg_get_u32_def(ctx, 1, 0);
|
||||
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t bs[96];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_awid_sim();
|
||||
|
||||
fmtlen = param_get8(Cmd, 0);
|
||||
fc = param_get32ex(Cmd, 1, 0, 10);
|
||||
cn = param_get32ex(Cmd, 2, 0, 10);
|
||||
if (!fc || !cn) return usage_lf_awid_sim();
|
||||
|
||||
verify_values(&fmtlen, &fc, &cn);
|
||||
|
||||
if (getAWIDBits(fmtlen, fc, cn, bs) != PM3_SUCCESS) {
|
||||
|
@ -371,7 +438,7 @@ static int CmdAWIDSim(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: %u; CN: %u\n", fmtlen, fc, cn);
|
||||
PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fmtlen, fc, cn);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
|
||||
|
||||
// AWID uses: FSK2a fcHigh: 10, fcLow: 8, clk: 50, invert: 1
|
||||
|
@ -398,97 +465,34 @@ static int CmdAWIDSim(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdAWIDClone(const char *Cmd) {
|
||||
uint32_t fc = 0, cn = 0;
|
||||
uint8_t fmtlen = 0;
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_awid_clone();
|
||||
|
||||
fmtlen = param_get8(Cmd, 0);
|
||||
fc = param_get32ex(Cmd, 1, 0, 10);
|
||||
cn = param_get32ex(Cmd, 2, 0, 10);
|
||||
|
||||
if (!fc || !cn) return usage_lf_awid_clone();
|
||||
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
|
||||
|
||||
bool q5 = tolower(param_getchar(Cmd, 3)) == 'q';
|
||||
if (q5)
|
||||
//t5555 (Q5) BITRATE = (RF-2)/2 (iceman)
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
|
||||
verify_values(&fmtlen, &fc, &cn);
|
||||
|
||||
uint8_t *bits = calloc(96, sizeof(uint8_t));
|
||||
|
||||
if (getAWIDBits(fmtlen, fc, cn, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
blocks[1] = bytebits_to_byte(bits, 32);
|
||||
blocks[2] = bytebits_to_byte(bits + 32, 32);
|
||||
blocks[3] = bytebits_to_byte(bits + 64, 32);
|
||||
|
||||
free(bits);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone AWID %u to " _YELLOW_("%s") " with FC: %u, CN: %u", fmtlen, (q5) ? "Q5/T5555" : "T55x7", fc, cn);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf awid read`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdAWIDBrute(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf awid brute",
|
||||
"Enables bruteforce of AWID reader with specified facility-code.\n"
|
||||
"This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step\n"
|
||||
"if cardnumber is not given, it starts with 1 and goes up to 65535",
|
||||
"lf awid brute --fmt 26 --fc 224\n"
|
||||
"lf awid brute --fmt 50 --fc 2001 --delay 2000\n"
|
||||
"lf awid brute --fmt 50 --fc 2001 --cn 200 --delay 2000 -v"
|
||||
);
|
||||
|
||||
bool errors = false, verbose = false;
|
||||
uint32_t fc = 0, cn = 0, delay = 1000;
|
||||
uint8_t fmtlen = 0;
|
||||
uint8_t bits[96];
|
||||
size_t size = sizeof(bits);
|
||||
memset(bits, 0x00, size);
|
||||
uint8_t cmdp = 0;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|50"),
|
||||
arg_u64_1(NULL, "fc", "<dec>", "8|16bit value facility code"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "optional - card number to start with, max 65535"),
|
||||
arg_u64_0(NULL, "delay", "<dec>", "optional - delay betweens attempts in ms. Default 1000ms"),
|
||||
arg_lit0("v", "verbose", "verbose logging, show all tries"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_awid_brute();
|
||||
case 'f':
|
||||
fc = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
if (!fc)
|
||||
errors = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
// delay between attemps, defaults to 1000ms.
|
||||
delay = param_get32ex(Cmd, cmdp + 1, 1000, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'c':
|
||||
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
// truncate cardnumber.
|
||||
cn &= 0xFFFF;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'a':
|
||||
fmtlen = param_get8(Cmd, cmdp + 1);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fc == 0) errors = true;
|
||||
if (errors) return usage_lf_awid_brute();
|
||||
uint8_t fmtlen = arg_get_u32_def(ctx, 1, 0);
|
||||
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
|
||||
uint32_t delay = arg_get_u32_def(ctx, 4, 1000);
|
||||
bool verbose = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// limit fc according to selected format
|
||||
switch (fmtlen) {
|
||||
|
@ -506,12 +510,23 @@ static int CmdAWIDBrute(const char *Cmd) {
|
|||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Bruteforceing AWID %d Reader", fmtlen);
|
||||
|
||||
// truncate card number
|
||||
if ((cn & 0xFFFF) != cn) {
|
||||
cn &= 0xFFFF;
|
||||
PrintAndLogEx(INFO, "Card number truncated to 16-bits : %u", cn);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Bruteforceing AWID %d reader", fmtlen);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or press Enter");
|
||||
|
||||
uint16_t up = cn;
|
||||
uint16_t down = cn;
|
||||
|
||||
uint8_t bits[96];
|
||||
size_t size = sizeof(bits);
|
||||
memset(bits, 0x00, size);
|
||||
|
||||
// main loop
|
||||
for (;;) {
|
||||
|
||||
|
@ -525,13 +540,20 @@ static int CmdAWIDBrute(const char *Cmd) {
|
|||
}
|
||||
|
||||
// Do one up
|
||||
if (up < 0xFFFF)
|
||||
if (sendTry(fmtlen, fc, up++, delay, bits, size, verbose) != PM3_SUCCESS) return PM3_ESOFT;
|
||||
if (up < 0xFFFF) {
|
||||
if (sendTry(fmtlen, fc, up++, delay, bits, size, verbose) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
// Do one down (if cardnumber is given)
|
||||
if (cn > 1)
|
||||
if (down > 1)
|
||||
if (sendTry(fmtlen, fc, --down, delay, bits, size, verbose) != PM3_SUCCESS) return PM3_ESOFT;
|
||||
if (cn > 1) {
|
||||
if (down > 1) {
|
||||
if (sendTry(fmtlen, fc, --down, delay, bits, size, verbose) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -539,7 +561,7 @@ static int CmdAWIDBrute(const char *Cmd) {
|
|||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdAWIDDemod, AlwaysAvailable, "demodulate an AWID FSK tag from the GraphBuffer"},
|
||||
{"read", CmdAWIDRead, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"reader", CmdAWIDReader, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdAWIDClone, IfPm3Lf, "clone AWID tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdAWIDSim, IfPm3Lf, "simulate AWID tag"},
|
||||
{"brute", CmdAWIDBrute, IfPm3Lf, "Bruteforce card number against reader"},
|
||||
|
|
|
@ -8,33 +8,18 @@
|
|||
// Low frequency COTAG commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfcotag.h" // COTAG function declarations
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "lfdemod.h"
|
||||
#include "cmddata.h" // getSamples
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "ctype.h" // tolower
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_cotag_read(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: lf COTAG read [h] <signaldata>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <0|1|2> : 0 - HIGH/LOW signal; maxlength bigbuff");
|
||||
PrintAndLogEx(NORMAL, " : 1 - translation of HI/LO into bytes with manchester 0,1");
|
||||
PrintAndLogEx(NORMAL, " : 2 - raw signal; maxlength bigbuff");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, " lf cotag read 0");
|
||||
PrintAndLogEx(NORMAL, " lf cotag read 1");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// COTAG demod should be able to use GraphBuffer,
|
||||
// when data load samples
|
||||
int demodCOTAG(bool verbose) {
|
||||
|
@ -74,37 +59,85 @@ int demodCOTAG(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdCOTAGDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf cotag demod",
|
||||
"Try to find COTAG preamble, if found decode / descramble data",
|
||||
"lf cotag demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodCOTAG(true);
|
||||
}
|
||||
|
||||
// When reading a COTAG.
|
||||
// 0 = HIGH/LOW signal - maxlength bigbuff
|
||||
// 1 = translation for HI/LO into bytes with manchester 0,1 - length 300
|
||||
// 2 = raw signal - maxlength bigbuff
|
||||
static int CmdCOTAGRead(const char *Cmd) {
|
||||
static int CmdCOTAGReader(const char *Cmd) {
|
||||
|
||||
if (tolower(Cmd[0]) == 'h')
|
||||
return usage_lf_cotag_read();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf cotag reader",
|
||||
"read a COTAG tag, the current support for COTAG is limited. ",
|
||||
"lf cotag reader -2"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("1", NULL, "HIGH/LOW signal; maxlength bigbuff"),
|
||||
arg_lit0("2", NULL, "translation of HIGH/LOW into bytes with manchester 0,1"),
|
||||
arg_lit0("3", NULL, "raw signal; maxlength bigbuff"),
|
||||
arg_param_end
|
||||
};
|
||||
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
bool mode0 = arg_get_lit(ctx, 1);
|
||||
bool mode1 = arg_get_lit(ctx, 2);
|
||||
bool mode2 = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ((mode0 + mode1 + mode2) > 1) {
|
||||
PrintAndLogEx(ERR, "You can only use one option at a time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
uint8_t mode = 0xFF;
|
||||
if (mode0)
|
||||
mode = 0;
|
||||
if (mode1)
|
||||
mode = 1;
|
||||
if (mode2)
|
||||
mode = 2;
|
||||
|
||||
struct p {
|
||||
uint8_t mode;
|
||||
} PACKED payload;
|
||||
payload.mode = param_get8ex(Cmd, 0, 1, 10);
|
||||
payload.mode = mode;
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_COTAG_READ, (uint8_t *)&payload, sizeof(payload));
|
||||
|
||||
uint8_t timeout = 3;
|
||||
while (!WaitForResponseTimeout(CMD_LF_COTAG_READ, &resp, 2000)) {
|
||||
int res = PM3_SUCCESS;
|
||||
while (!WaitForResponseTimeout(CMD_LF_COTAG_READ, &resp, 1000)) {
|
||||
timeout--;
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
if (timeout == 0) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
res = PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (timeout != 3)
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
|
@ -126,12 +159,11 @@ static int CmdCOTAGRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdCOTAGDemod, AlwaysAvailable, "Tries to decode a COTAG signal"},
|
||||
{"read", CmdCOTAGRead, IfPm3Lf, "Attempt to read and extract tag data"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdCOTAGDemod, AlwaysAvailable, "Tries to decode a COTAG signal"},
|
||||
{"reader", CmdCOTAGReader, IfPm3Lf, "Attempt to read and extract tag data"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
|
@ -144,5 +176,5 @@ int CmdLFCOTAG(const char *Cmd) {
|
|||
}
|
||||
|
||||
int readCOTAGUid(void) {
|
||||
return (CmdCOTAGRead("") == PM3_SUCCESS);
|
||||
return (CmdCOTAGReader("-2") == PM3_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
// Low frequency FDX-A FECAVA Destron tag commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfdestron.h"
|
||||
|
||||
#include <ctype.h> //tolower
|
||||
#include <string.h> // memcpy
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include <ctype.h> // tolower
|
||||
#include <string.h> // memcpy
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "common.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cmdlf.h" // cmdlfconfig
|
||||
#include "cliparser.h" // cli parse input
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cmdlf.h" // cmdlfconfig
|
||||
#include "parity.h"
|
||||
#include "cliparser.h" // cli parse input
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
#define DESTRON_FRAME_SIZE 96
|
||||
#define DESTRON_PREAMBLE_SIZE 16
|
||||
|
@ -36,6 +36,7 @@ int demodDestron(bool verbose) {
|
|||
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: FSK Demod failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
size_t size = DemodBufferLen;
|
||||
int ans = detectDestron(DemodBuffer, &size);
|
||||
if (ans < 0) {
|
||||
|
@ -50,12 +51,13 @@ int demodDestron(bool verbose) {
|
|||
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
setDemodBuff(DemodBuffer, DESTRON_FRAME_SIZE, ans);
|
||||
setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
|
||||
|
||||
uint8_t bits[DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE] = {0};
|
||||
size_t bitlen = DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE;
|
||||
memcpy(bits, DemodBuffer + 16, DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE);
|
||||
memcpy(bits, DemodBuffer + DESTRON_PREAMBLE_SIZE, DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE);
|
||||
|
||||
uint8_t alignPos = 0;
|
||||
uint16_t errCnt = manrawdecode(bits, &bitlen, 0, &alignPos);
|
||||
|
@ -75,75 +77,159 @@ int demodDestron(bool verbose) {
|
|||
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: parity errors: %d", parity_err);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "FDX-A FECAVA Destron: " _GREEN_("%02X%02X%02X%02X%02X"), data[0], data[1], data[2], data[3], data[4]);
|
||||
PrintAndLogEx(SUCCESS, "FDX-A FECAVA Destron: " _GREEN_("%s"), sprint_hex_inrow(data, 5));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdDestronDemod(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
return demodDestron(true);
|
||||
}
|
||||
|
||||
static int CmdDestronRead(const char *Cmd) {
|
||||
lf_read(false, 16000);
|
||||
return demodDestron(true);
|
||||
}
|
||||
|
||||
static int CmdDestronClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[4] = {0};
|
||||
uint8_t data[8];
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf destron clone",
|
||||
"Enables cloning of Destron card with specified uid onto T55x7",
|
||||
"lf destron clone 1A2B3C4D5E"
|
||||
CLIParserInit(&ctx, "lf destron demod",
|
||||
"Try to find Destron preamble, if found decode / descramble data",
|
||||
"lf destron demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx1(NULL, NULL, "<uid (hex)>", NULL),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodDestron(true);
|
||||
}
|
||||
|
||||
static int CmdDestronReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf destron reader",
|
||||
"read a Destron tag",
|
||||
"lf destron 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 16000);
|
||||
demodDestron(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdDestronClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf destron clone",
|
||||
"clone a Destron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf destron clone --uid 1A2B3C4D5E\n"
|
||||
"lf destron clone --q5 --uid 1A2B3C4D5E -> encode for Q5/T5555 tag\n"
|
||||
"lf destron clone --em --uid 1A2B3C4D5E -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx1("u", "uid", "<hex>", "5 bytes max"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
|
||||
//TODO add selection of chip for Q5 or T55x7
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t data[8];
|
||||
int datalen = 0;
|
||||
CLIGetHexWithReturn(ctx, 1, data, &datalen);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (datalen > 5) {
|
||||
PrintAndLogEx(FAILED, "Uid is max 5 bytes. (got %u)", datalen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[4] = {0};
|
||||
blocks[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_DESTRON_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
uint8_t data_ex[12 + 24] = {0}; // ManchesterEncode need extra room
|
||||
for (int i = 0; i < datalen; i++) {
|
||||
data_ex[i + 1] = ~data [i] | (evenparity8(data[i]) << 7);
|
||||
data_ex[i + 1] = ~(data [i] | (oddparity8(data[i]) << 7));
|
||||
}
|
||||
|
||||
// manchester encode it
|
||||
for (int i = 0; i < 3; i++) {
|
||||
blocks[i + 1] = manchesterEncode2Bytes((data_ex[i * 2] << 8) + data_ex[i * 2 + 1]);
|
||||
}
|
||||
// inject preamble
|
||||
blocks[1] = (blocks[1] & 0xFFFF) | 0xAAE20000;
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Destron tag with ID: %s", sprint_hex(data, datalen));
|
||||
blocks[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
PrintAndLogEx(INFO, "Preparing to clone Destron tag to " _YELLOW_("%s") " with ID: " _YELLOW_("%s")
|
||||
, cardtype
|
||||
, sprint_hex_inrow(data, datalen)
|
||||
);
|
||||
|
||||
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf Destron read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf destron reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdDestronSim(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf destron sim",
|
||||
"Try to find Destron preamble, if found decode / descramble data",
|
||||
"lf destron sim"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdDestronDemod, AlwaysAvailable, "Demodulate an Destron tag from the GraphBuffer"},
|
||||
{"read", CmdDestronRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdDestronClone, IfPm3Lf, "Clone Destron tag to T55x7"},
|
||||
{"sim", CmdDestronSim, IfPm3Lf, "Simulate Destron tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdDestronDemod, AlwaysAvailable, "Demodulate an Destron tag from the GraphBuffer"},
|
||||
{"reader", CmdDestronReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdDestronClone, IfPm3Lf, "Clone Destron tag to T55x7"},
|
||||
{"sim", CmdDestronSim, IfPm3Lf, "Simulate Destron tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -185,5 +271,5 @@ int detectDestron(uint8_t *dest, size_t *size) {
|
|||
}
|
||||
|
||||
int readDestronUid(void) {
|
||||
return (CmdDestronRead("") == PM3_SUCCESS);
|
||||
return (CmdDestronReader("") == PM3_SUCCESS);
|
||||
}
|
||||
|
|
40
client/src/cmdlfem.c
Normal file
40
client/src/cmdlfem.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2020 iceman <iceman at icesql.net>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Low frequency EM4x commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfem.h"
|
||||
#include "cmdlfem410x.h"
|
||||
#include "cmdlfem4x05.h"
|
||||
#include "cmdlfem4x50.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h" // clearCommandBuffer
|
||||
#include "cmdlf.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"410x", CmdLFEM410X, AlwaysAvailable, "EM 4102 commands..."},
|
||||
{"4x05", CmdLFEM4X05, AlwaysAvailable, "EM 4205 / 4305 / 4369 / 4469 commands..."},
|
||||
{"4x50", CmdLFEM4X50, AlwaysAvailable, "EM 4350 / 4450 commands..."},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFEM(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
17
client/src/cmdlfem.h
Normal file
17
client/src/cmdlfem.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2020 iceman <iceman at icesql.net>
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Low frequency EM commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDLFEM4X_H__
|
||||
#define CMDLFEM4X_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int CmdLFEM(const char *Cmd);
|
||||
|
||||
#endif
|
|
@ -8,8 +8,7 @@
|
|||
// Low frequency EM4x commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfem4x.h"
|
||||
#include "cmdlfem4x05.h"
|
||||
#include "cmdlfem410x.h"
|
||||
#include "cmdlfem4x50.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -631,33 +630,14 @@ static int CmdEM410xClone(const char *Cmd) {
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 410x") " -----------------------"},
|
||||
//{"410x_demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"},
|
||||
{"410x_demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"},
|
||||
{"410x_read", CmdEM410xRead, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"410x_sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"},
|
||||
{"410x_brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"},
|
||||
{"410x_watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
|
||||
{"410x_spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
|
||||
{"410x_clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"},
|
||||
{"----------", CmdHelp, AlwaysAvailable, "-------------------- " _CYAN_("EM 4x05 / 4x69") " -------------------"},
|
||||
{"4x05_chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords from dictionary"},
|
||||
{"4x05_demod", CmdEM4x05Demod, AlwaysAvailable, "demodulate a EM4x05/EM4x69 tag from the GraphBuffer"},
|
||||
{"4x05_dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"},
|
||||
{"4x05_wipe", CmdEM4x05Wipe, IfPm3Lf, "wipe EM4x05/EM4x69 tag"},
|
||||
{"4x05_info", CmdEM4x05Info, IfPm3Lf, "tag information EM4x05/EM4x69"},
|
||||
{"4x05_read", CmdEM4x05Read, IfPm3Lf, "read word data from EM4x05/EM4x69"},
|
||||
{"4x05_write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"},
|
||||
{"4x05_unlock", CmdEM4x05Unlock, IfPm3Lf, "execute tear off against EM4x05/EM4x69"},
|
||||
{"4x05_sniff", CmdEM4x05Sniff, AlwaysAvailable, "Attempt to recover em4x05 commands from sample buffer"},
|
||||
{"4x05_brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"},
|
||||
{"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 4x50") " -----------------------"},
|
||||
{"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"},
|
||||
{"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"},
|
||||
{"4x50_write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"},
|
||||
{"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change password of EM4x50 tag"},
|
||||
{"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"},
|
||||
{"4x50_wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"},
|
||||
//{"demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"},
|
||||
{"demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"},
|
||||
{"read", CmdEM410xRead, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"},
|
||||
{"brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"},
|
||||
{"watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
|
||||
{"spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
|
||||
{"clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -667,7 +647,7 @@ static int CmdHelp(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFEM4X(const char *Cmd) {
|
||||
int CmdLFEM410X(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
|
@ -5,15 +5,15 @@
|
|||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Low frequency EM4x commands
|
||||
// Low frequency EM 410x commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDLFEM4X_H__
|
||||
#define CMDLFEM4X_H__
|
||||
#ifndef CMDLFEM410X_H__
|
||||
#define CMDLFEM410X_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int CmdLFEM4X(const char *Cmd);
|
||||
int CmdLFEM410X(const char *Cmd);
|
||||
|
||||
int demodEM410x(bool verbose);
|
||||
void printEM410x(uint32_t hi, uint64_t id);
|
|
@ -38,59 +38,7 @@
|
|||
|
||||
#define EM_PREAMBLE_LEN 8
|
||||
|
||||
static int usage_lf_em4x05_wipe(void) {
|
||||
PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_wipe [h] <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " c - chip type : 0 em4205");
|
||||
PrintAndLogEx(NORMAL, " 1 em4305 (default)");
|
||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_wipe");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_wipe 11223344");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_em4x05_read(void) {
|
||||
PrintAndLogEx(NORMAL, "Read EM4x05/EM4x69. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_read [h] <address> <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " address - memory address to read. (0-15)");
|
||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_read 1");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_read 1 11223344");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_em4x05_write(void) {
|
||||
PrintAndLogEx(NORMAL, "Write EM4x05/4x69. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_write [h] <address> <data> <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " address - memory address to write to. (0-13, 99 for Protection Words)");
|
||||
PrintAndLogEx(NORMAL, " data - data to write (hex)");
|
||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_write 1 deadc0de");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_write 1 deadc0de 11223344");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_em4x05_info(void) {
|
||||
PrintAndLogEx(NORMAL, "Tag information EM4205/4305/4469//4569 tags. Tag must be on antenna.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_info [h] <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_info");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x05_info deadc0de");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
// 1 = EM4x69
|
||||
// 2 = EM4x05
|
||||
|
@ -140,7 +88,6 @@ static bool em4x05_col_parity_test(uint8_t *bs, size_t size, uint8_t rows, uint8
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
// download samples from device and copy to Graphbuffer
|
||||
static bool em4x05_download_samples(void) {
|
||||
|
||||
|
@ -387,6 +334,7 @@ static bool em4x05_verify_write(uint8_t addr, uint32_t pwd, bool use_pwd, uint32
|
|||
uint32_t r = 0;
|
||||
int res = em4x05_read_word_ext(addr, pwd, use_pwd, &r);
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "%08x == %08x", r, data);
|
||||
return (r == data);
|
||||
}
|
||||
return false;
|
||||
|
@ -506,7 +454,40 @@ int em4x05_write_word_ext(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t dat
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int em4x05_protect(uint32_t pwd, bool use_pwd, uint32_t data) {
|
||||
struct {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t usepwd;
|
||||
} PACKED payload;
|
||||
|
||||
payload.password = pwd;
|
||||
payload.data = data;
|
||||
payload.usepwd = use_pwd;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_PROTECTWORD, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_PROTECTWORD, &resp, 2000)) {
|
||||
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdEM4x05Demod(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05 demod",
|
||||
"Try to find EM 4x05 preamble, if found decode / descramble data",
|
||||
"lf em 4x05 demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
uint32_t dummy = 0;
|
||||
return em4x05_demod_resp(&dummy, false);
|
||||
}
|
||||
|
@ -514,11 +495,11 @@ int CmdEM4x05Demod(const char *Cmd) {
|
|||
int CmdEM4x05Dump(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em dump",
|
||||
CLIParserInit(&ctx, "lf em 4x05 dump",
|
||||
"Dump EM4x05/EM4x69. Tag must be on antenna.",
|
||||
"lf em dump\n"
|
||||
"lf em dump -p 11223344\n"
|
||||
"lf em dump -f myfile -p 11223344"
|
||||
"lf em 4x05 dump\n"
|
||||
"lf em 4x05 dump -p 11223344\n"
|
||||
"lf em 4x05 dump -f myfile -p 11223344"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -734,29 +715,43 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
}
|
||||
|
||||
int CmdEM4x05Read(const char *Cmd) {
|
||||
uint8_t addr;
|
||||
uint32_t pwd;
|
||||
bool usePwd = false;
|
||||
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_read();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05 read",
|
||||
"Read EM4x05/EM4x69. Tag must be on antenna.",
|
||||
"lf em 4x05 read -a 1\n"
|
||||
"lf em 4x05 read --addr 1 --pwd 11223344"
|
||||
);
|
||||
|
||||
addr = param_get8ex(Cmd, 0, 50, 10);
|
||||
pwd = param_get32ex(Cmd, 1, 0xFFFFFFFF, 16);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int1("a", "addr", "<dec>", "memory address to read. (0-15)"),
|
||||
arg_str0("p", "pwd", "<hex>", "optional - password, 4 bytes hex"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
uint8_t addr = (uint8_t)arg_get_int_def(ctx, 1, 50);
|
||||
uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 2, 0xFFFFFFFFFFFFFFFF);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint32_t pwd = 0;
|
||||
bool use_pwd = false;
|
||||
|
||||
if (addr > 15) {
|
||||
PrintAndLogEx(WARNING, "Address must be between 0 and 15");
|
||||
return PM3_ESOFT;
|
||||
PrintAndLogEx(ERR, "Address must be between 0 and 15");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (pwd == 0xFFFFFFFF) {
|
||||
|
||||
if (inputpwd == 0xFFFFFFFFFFFFFFFF) {
|
||||
PrintAndLogEx(INFO, "Reading address %02u", addr);
|
||||
} else {
|
||||
usePwd = true;
|
||||
pwd = (inputpwd & 0xFFFFFFFF);
|
||||
use_pwd = true;
|
||||
PrintAndLogEx(INFO, "Reading address %02u using password %08X", addr, pwd);
|
||||
}
|
||||
|
||||
uint32_t word = 0;
|
||||
int status = em4x05_read_word_ext(addr, pwd, usePwd, &word);
|
||||
int status = em4x05_read_word_ext(addr, pwd, use_pwd, &word);
|
||||
if (status == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Address %02d | %08X - %s", addr, word, (addr > 13) ? "Lock" : "");
|
||||
else if (status == PM3_EFAILED)
|
||||
|
@ -767,55 +762,61 @@ int CmdEM4x05Read(const char *Cmd) {
|
|||
}
|
||||
|
||||
int CmdEM4x05Write(const char *Cmd) {
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_write();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05 write",
|
||||
"Write EM4x05/EM4x69. Tag must be on antenna.",
|
||||
"lf em 4x05 write -a 1 -d deadc0de\n"
|
||||
"lf em 4x05 write --addr 1 --pwd 11223344 --data deadc0de\n"
|
||||
"lf em 4x05 write --po --pwd 11223344 --data deadc0de\n"
|
||||
);
|
||||
|
||||
bool usePwd = false;
|
||||
uint8_t addr;
|
||||
uint32_t data, pwd;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0("a", "addr", "<dec>", "memory address to write to. (0-13)"),
|
||||
arg_str1("d", "data", "<hex>", "data to write, 4 bytes hex"),
|
||||
arg_str0("p", "pwd", "<hex>", "optional - password, 4 bytes hex"),
|
||||
arg_lit0(NULL, "po", "protect operation"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
uint8_t addr = (uint8_t)arg_get_int_def(ctx, 1, 50);
|
||||
uint32_t data = arg_get_u32(ctx, 2);
|
||||
uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 3, 0xFFFFFFFFFFFFFFFF);
|
||||
bool protect_operation = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
addr = param_get8ex(Cmd, 0, 50, 10);
|
||||
data = param_get32ex(Cmd, 1, 0, 16);
|
||||
pwd = param_get32ex(Cmd, 2, 0xFFFFFFFF, 16);
|
||||
bool protectOperation = addr == 99; // will do better with cliparser...
|
||||
|
||||
if ((addr > 13) && (!protectOperation)) {
|
||||
if ((addr > 13) && (protect_operation == false)) {
|
||||
PrintAndLogEx(WARNING, "Address must be between 0 and 13");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
bool use_pwd = false;
|
||||
uint32_t pwd = ( inputpwd != 0xFFFFFFFFFFFFFFFF) ? (inputpwd & 0xFFFFFFFF) : 0;
|
||||
if (pwd == 0xFFFFFFFF) {
|
||||
if (protectOperation)
|
||||
if (protect_operation)
|
||||
PrintAndLogEx(INFO, "Writing protection words data %08X", data);
|
||||
else
|
||||
PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data);
|
||||
} else {
|
||||
usePwd = true;
|
||||
if (protectOperation)
|
||||
use_pwd = true;
|
||||
if (protect_operation)
|
||||
PrintAndLogEx(INFO, "Writing protection words data %08X using password %08X", data, pwd);
|
||||
else
|
||||
PrintAndLogEx(INFO, "Writing address %d data %08X using password %08X", addr, data, pwd);
|
||||
}
|
||||
|
||||
if (protectOperation) { // set Protect Words
|
||||
struct {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t usepwd;
|
||||
} PACKED payload;
|
||||
|
||||
payload.password = pwd;
|
||||
payload.data = data;
|
||||
payload.usepwd = usePwd;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_PROTECTWORD, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_PROTECTWORD, &resp, 2000)) {
|
||||
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
|
||||
return PM3_ETIMEOUT;
|
||||
int res = PM3_SUCCESS;
|
||||
// set Protect Words
|
||||
if (protect_operation) {
|
||||
res = em4x05_protect(pwd, use_pwd, data);
|
||||
if ( res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
em4x05_write_word_ext(addr, pwd, usePwd, data);
|
||||
res = em4x05_write_word_ext(addr, pwd, use_pwd, data);
|
||||
if ( res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (em4x05_download_samples() == false)
|
||||
|
@ -826,86 +827,111 @@ int CmdEM4x05Write(const char *Cmd) {
|
|||
if (status == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Data written and verified");
|
||||
else if (status == PM3_EFAILED)
|
||||
PrintAndLogEx(ERR, "Tag denied %s operation", protectOperation ? "Protect" : "Write");
|
||||
PrintAndLogEx(ERR, "Tag denied %s operation", protect_operation ? "Protect" : "Write");
|
||||
else
|
||||
PrintAndLogEx(DEBUG, "No answer from tag");
|
||||
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05_read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05 read`") " to verify");
|
||||
return status;
|
||||
}
|
||||
|
||||
int CmdEM4x05Wipe(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05 wipe",
|
||||
"Wipe EM4x05/EM4x69. Tag must be on antenna.",
|
||||
"lf em 4x05 wipe --4305 -p 11223344 -> wipe EM 4305 w pwd\n"
|
||||
"lf em 4x05 wipe --4205 -> wipe EM 4205\n"
|
||||
"lf em 4x05 wipe --4369 -> wipe EM 4369"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0(NULL, "4205", "target chip type EM 4205"),
|
||||
arg_lit0(NULL, "4305", "target chip type EM 4305 (default)"),
|
||||
arg_lit0(NULL, "4369", "target chip type EM 4369"),
|
||||
arg_lit0(NULL, "4369", "target chip type EM 4469"),
|
||||
arg_str0("p", "pwd", "<hex>", "optional - password, 4 bytes hex"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool target_4205 = arg_get_lit(ctx, 1);
|
||||
bool target_4305 = arg_get_lit(ctx, 2);
|
||||
bool target_4369 = arg_get_lit(ctx, 3);
|
||||
bool target_4469 = arg_get_lit(ctx, 4);
|
||||
uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 5, 0xFFFFFFFFFFFFFFFF);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t foo = target_4205 + target_4305 + target_4369 + target_4469;
|
||||
|
||||
if (foo > 1) {
|
||||
PrintAndLogEx(ERR, "Can't target multiple chip types at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t addr = 0;
|
||||
uint32_t chip_info = 0x00040072; // Chip info/User Block normal 4305 Chip Type
|
||||
uint32_t chip_UID = 0x614739AE; // UID normally readonly, but just in case
|
||||
uint32_t block_data = 0x00000000; // UserBlock/Password (set to 0x00000000 for a wiped card1
|
||||
uint32_t config = 0x0001805F; // Default config (no password)
|
||||
|
||||
if (target_4205) {
|
||||
chip_info = 0x00040070;
|
||||
}
|
||||
if (target_4369) {
|
||||
chip_info = 0x00020078; // found on HID Prox
|
||||
}
|
||||
if (target_4469) {
|
||||
// chip_info = 0x00020078; // need to get a normal 4469 chip info block
|
||||
}
|
||||
|
||||
bool use_pwd = false;
|
||||
uint32_t pwd = 0;
|
||||
uint8_t cmdp = 0;
|
||||
uint8_t chipType = 1; // em4305
|
||||
uint32_t chipInfo = 0x00040072; // Chip info/User Block normal 4305 Chip Type
|
||||
uint32_t chipUID = 0x614739AE; // UID normally readonly, but just in case
|
||||
uint32_t blockData = 0x00000000; // UserBlock/Password (set to 0x00000000 for a wiped card1
|
||||
uint32_t config = 0x0001805F; // Default config (no password)
|
||||
int success = PM3_SUCCESS;
|
||||
char cmdStr [100];
|
||||
char optchk[10];
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00) {
|
||||
// check if cmd is a 1 byte option
|
||||
param_getstr(Cmd, cmdp, optchk, sizeof(optchk));
|
||||
if (strlen(optchk) == 1) { // Have a single character so option not part of password
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'c': // chip type
|
||||
if (param_getchar(Cmd, cmdp) != 0x00)
|
||||
chipType = param_get8ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'h': // return usage_lf_em4x05_wipe();
|
||||
default : // Unknown or 'h' send help
|
||||
return usage_lf_em4x05_wipe();
|
||||
break;
|
||||
};
|
||||
} else { // Not a single character so assume password
|
||||
pwd = param_get32ex(Cmd, cmdp, 1, 16);
|
||||
cmdp++;
|
||||
}
|
||||
if ( inputpwd != 0xFFFFFFFFFFFFFFFF) {
|
||||
pwd = (inputpwd & 0xFFFFFFFF);
|
||||
use_pwd = true;
|
||||
}
|
||||
|
||||
switch (chipType) {
|
||||
case 0 : // em4205
|
||||
chipInfo = 0x00040070;
|
||||
config = 0x0001805F;
|
||||
break;
|
||||
case 1 : // em4305
|
||||
chipInfo = 0x00040072;
|
||||
config = 0x0001805F;
|
||||
break;
|
||||
default : // Type 0/Default : EM4305
|
||||
chipInfo = 0x00040072;
|
||||
config = 0x0001805F;
|
||||
}
|
||||
|
||||
// block 0 : User Data or Chip Info
|
||||
sprintf(cmdStr, "%d %08X %08X", 0, chipInfo, pwd);
|
||||
CmdEM4x05Write(cmdStr);
|
||||
int res = em4x05_write_word_ext(0, pwd, use_pwd, chip_info);
|
||||
if ( res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// block 1 : UID - this should be read only for EM4205 and EM4305 not sure about others
|
||||
sprintf(cmdStr, "%d %08X %08X", 1, chipUID, pwd);
|
||||
CmdEM4x05Write(cmdStr);
|
||||
res = em4x05_write_word_ext(1, pwd, use_pwd, chip_UID);
|
||||
if ( res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "UID block write failed");
|
||||
}
|
||||
|
||||
// block 2 : password
|
||||
sprintf(cmdStr, "%d %08X %08X", 2, blockData, pwd);
|
||||
CmdEM4x05Write(cmdStr);
|
||||
pwd = blockData; // Password should now have changed, so use new password
|
||||
res = em4x05_write_word_ext(2, pwd, use_pwd, block_data);
|
||||
if ( res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Password should now have changed, so use new password
|
||||
pwd = block_data;
|
||||
// block 3 : user data
|
||||
sprintf(cmdStr, "%d %08X %08X", 3, blockData, pwd);
|
||||
CmdEM4x05Write(cmdStr);
|
||||
res = em4x05_write_word_ext(3, pwd, use_pwd, block_data);
|
||||
if ( res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// block 4 : config
|
||||
sprintf(cmdStr, "%d %08X %08X", 4, config, pwd);
|
||||
CmdEM4x05Write(cmdStr);
|
||||
res = em4x05_write_word_ext(4, pwd, use_pwd, config);
|
||||
if ( res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Remainder of user/data blocks
|
||||
for (addr = 5; addr < 14; addr++) {// Clear user data blocks
|
||||
sprintf(cmdStr, "%d %08X %08X", addr, blockData, pwd);
|
||||
CmdEM4x05Write(cmdStr);
|
||||
res = em4x05_write_word_ext(addr, pwd, use_pwd, block_data);
|
||||
if ( res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static const char *printEM4x05_known(uint32_t word) {
|
||||
|
@ -1174,24 +1200,37 @@ static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//quick test for EM4x05/EM4x69 tag
|
||||
bool em4x05_isblock0(uint32_t *word) {
|
||||
return (em4x05_read_word_ext(0, 0, false, word) == PM3_SUCCESS);
|
||||
}
|
||||
|
||||
int CmdEM4x05Info(const char *Cmd) {
|
||||
uint32_t pwd;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05 info",
|
||||
"Tag information EM4205/4305/4469//4569 tags. Tag must be on antenna.",
|
||||
"lf em 4x05 info\n"
|
||||
"lf em 4x05 info -p 11223344"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("p", "pwd", "<hex>", "optional - password, 4 hex bytes"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 1, 0xFFFFFFFFFFFFFFFF);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
bool use_pwd = false;
|
||||
uint32_t pwd = 0;
|
||||
if (inputpwd != 0xFFFFFFFFFFFFFFFF) {
|
||||
pwd = inputpwd & 0xFFFFFFFF;
|
||||
use_pwd = true;
|
||||
}
|
||||
|
||||
uint32_t word = 0, block0 = 0, serial = 0;
|
||||
bool usePwd = false;
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_lf_em4x05_info();
|
||||
|
||||
// for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
|
||||
pwd = param_get32ex(Cmd, 0, 0xFFFFFFFF, 16);
|
||||
|
||||
if (pwd != 0xFFFFFFFF)
|
||||
usePwd = true;
|
||||
|
||||
// read word 0 (chip info)
|
||||
// block 0 can be read even without a password.
|
||||
|
@ -1209,7 +1248,7 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
|
||||
// read word 4 (config block)
|
||||
// needs password if one is set
|
||||
if (em4x05_read_word_ext(EM_CONFIG_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
if (em4x05_read_word_ext(EM_CONFIG_BLOCK, pwd, use_pwd, &word) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(DEBUG, "(CmdEM4x05Info) failed to read CONFIG BLOCK");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -1221,7 +1260,7 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
if (card_type == EM_4205 || card_type == EM_4305) {
|
||||
|
||||
// read word 14 and 15 to see which is being used for the protection bits
|
||||
if (em4x05_read_word_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
if (em4x05_read_word_ext(EM4305_PROT1_BLOCK, pwd, use_pwd, &word) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -1229,7 +1268,7 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
printEM4x05ProtectionBits(word, EM4305_PROT1_BLOCK);
|
||||
return PM3_SUCCESS;
|
||||
} else { // if status bit says this is not the used protection word
|
||||
if (em4x05_read_word_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
if (em4x05_read_word_ext(EM4305_PROT2_BLOCK, pwd, use_pwd, &word) != PM3_SUCCESS)
|
||||
return PM3_ESOFT;
|
||||
if (word & 0x8000) {
|
||||
printEM4x05ProtectionBits(word, EM4305_PROT2_BLOCK);
|
||||
|
@ -1238,7 +1277,7 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
}
|
||||
} else if (card_type == EM_4369 || card_type == EM_4469) {
|
||||
// read word 3 to see which is being used for the protection bits
|
||||
if (em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
if (em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, use_pwd, &word) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
printEM4x05ProtectionBits(word, EM4469_PROT_BLOCK);
|
||||
|
@ -1259,11 +1298,11 @@ static bool is_cancelled(void) {
|
|||
int CmdEM4x05Chk(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05_chk",
|
||||
CLIParserInit(&ctx, "lf em 4x05 chk",
|
||||
"This command uses a dictionary attack against EM4205/4305/4469/4569",
|
||||
"lf em 4x05_chk\n"
|
||||
"lf em 4x05_chk -e 000022B8 -> remember to use 0x for hex\n"
|
||||
"lf em 4x05_chk -f t55xx_default_pwds -> use T55xx default dictionary"
|
||||
"lf em 4x05 chk\n"
|
||||
"lf em 4x05 chk -e 000022B8 -> remember to use 0x for hex\n"
|
||||
"lf em 4x05 chk -f t55xx_default_pwds -> use T55xx default dictionary"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -1360,12 +1399,12 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
|
||||
int CmdEM4x05Brute(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05_brute",
|
||||
CLIParserInit(&ctx, "lf em 4x05 brute",
|
||||
"This command tries to bruteforce the password of a EM4205/4305/4469/4569\n",
|
||||
"Note: if you get many false positives, change position on the antenna"
|
||||
"lf em 4x05_brute\n"
|
||||
"lf em 4x05_brute -n 1 -> stop after first candidate found\n"
|
||||
"lf em 4x05_brute -s 000022B8 -> remember to use 0x for hex"
|
||||
"lf em 4x05 brute\n"
|
||||
"lf em 4x05 brute -n 1 -> stop after first candidate found\n"
|
||||
"lf em 4x05 brute -s 000022B8 -> remember to use 0x for hex"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -1464,11 +1503,11 @@ static void unlock_add_item(em4x05_unlock_item_t *array, uint8_t len, uint32_t v
|
|||
int CmdEM4x05Unlock(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05_unlock",
|
||||
CLIParserInit(&ctx, "lf em 4x05 unlock",
|
||||
"execute tear off against EM4205/4305/4469/4569",
|
||||
"lf em 4x05_unlock\n"
|
||||
"lf em 4x05_unlock -s 4100 -e 4100 -> lock on and autotune at 4100us\n"
|
||||
"lf em 4x05_unlock -n 10 -s 3000 -e 4400 -> scan delays 3000us -> 4400us"
|
||||
"lf em 4x05 unlock\n"
|
||||
"lf em 4x05 unlock -s 4100 -e 4100 -> lock on and autotune at 4100us\n"
|
||||
"lf em 4x05 unlock -n 10 -s 3000 -e 4400 -> scan delays 3000us -> 4400us"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -2082,3 +2121,29 @@ int CmdEM4x05Sniff(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"},
|
||||
{"chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords from dictionary"},
|
||||
{"demod", CmdEM4x05Demod, AlwaysAvailable, "demodulate a EM4x05/EM4x69 tag from the GraphBuffer"},
|
||||
{"dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"},
|
||||
{"info", CmdEM4x05Info, IfPm3Lf, "tag information EM4x05/EM4x69"},
|
||||
{"read", CmdEM4x05Read, IfPm3Lf, "read word data from EM4x05/EM4x69"},
|
||||
{"sniff", CmdEM4x05Sniff, AlwaysAvailable, "Attempt to recover em4x05 commands from sample buffer"},
|
||||
{"unlock", CmdEM4x05Unlock, IfPm3Lf, "execute tear off against EM4x05/EM4x69"},
|
||||
{"wipe", CmdEM4x05Wipe, IfPm3Lf, "wipe EM4x05/EM4x69 tag"},
|
||||
{"write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFEM4X05(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
|
@ -30,7 +30,9 @@
|
|||
#define EM4305_NORALSY_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK, data rate 32, 3 data blocks
|
||||
#define EM4305_PRESCO_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/MAN, data rate 32, 4 data blocks
|
||||
#define EM4305_SECURAKEY_CONFIG_BLOCK (EM4x05_SET_BITRATE(40) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK/MAN, data rate 40, 3 data blocks
|
||||
#define EM4305_GALLAGHER_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK/MAN, data rate 32, 3 data blocks
|
||||
|
||||
#define EM4305_DESTRON_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
|
||||
#define EM4305_HID_26_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
|
||||
#define EM4305_PARADOX_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
|
||||
#define EM4305_AWID_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
|
||||
|
@ -47,6 +49,7 @@
|
|||
#define EM4305_GUARDPROXII_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(3) ) // Biphase, data rate 64, Direct modulation, 3 data blocks
|
||||
#define EM4305_NEDAP_64_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(2) ) // Biphase, data rate 64, 2 data blocks
|
||||
#define EM4305_NEDAP_128_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // Biphase, data rate 64, 4 data blocks
|
||||
#define EM4305_FDXB_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // Biphase, data rate 32, 4 data blocks
|
||||
|
||||
#define EM4305_PAC_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_NRZ | EM4x05_SET_NUM_BLOCKS(4) ) // NRZ, data rate 32, 4 data blocks
|
||||
#define EM4305_VERICHIP_CONFIG_BLOCK (EM4x05_SET_BITRATE(40) | EM4x05_MODULATION_NRZ | EM4x05_SET_NUM_BLOCKS(4) ) // NRZ, data rate 40, 4 data blocks
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2020 tharexde
|
||||
//
|
||||
// modified iceman, 2020
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
|
@ -10,11 +12,14 @@
|
|||
|
||||
#include "cmdlfem4x50.h"
|
||||
#include <ctype.h>
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "fileutils.h"
|
||||
#include "comms.h"
|
||||
#include "commonutil.h"
|
||||
#include "em4x50.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_em4x50_info(void) {
|
||||
PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag must be on antenna.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -749,3 +754,25 @@ int CmdEM4x50Wipe(const char *Cmd) {
|
|||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"},
|
||||
{"info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"},
|
||||
{"write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"},
|
||||
{"write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change password of EM4x50 tag"},
|
||||
{"read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"},
|
||||
{"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe data from EM4x50"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFEM4X50(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include"common.h"
|
||||
#include "em4x50.h"
|
||||
|
||||
int CmdLFEM4X50(const char *Cmd);
|
||||
|
||||
int read_em4x50_uid(void);
|
||||
bool detect_4x50_block(void);
|
||||
int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose);
|
||||
|
|
|
@ -9,23 +9,22 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlffdxb.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h> // tolower
|
||||
|
||||
#include <ctype.h> // tolower
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "commonutil.h"
|
||||
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h" // lf read
|
||||
#include "crc16.h" // for checksum crc-16_ccitt
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cmdlf.h" // lf read
|
||||
#include "crc16.h" // for checksum crc-16_ccitt
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
/*
|
||||
FDX-B ISO11784/85 demod (aka animal tag) BIPHASE, inverted, rf/32, with preamble of 00000000001 (128bits)
|
||||
|
@ -48,55 +47,63 @@
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_fdxb_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "Clone a FDX-B animal tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdxb clone [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
|
||||
PrintAndLogEx(NORMAL, " n <national> : (dec) National code");
|
||||
PrintAndLogEx(NORMAL, " e <extended> : (hex) Extended data");
|
||||
PrintAndLogEx(NORMAL, " s : Set animal bit");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb clone c 999 n 112233 s"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb clone c 999 n 112233 e 16a"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits) {
|
||||
|
||||
static int usage_lf_fdxb_read(void) {
|
||||
PrintAndLogEx(NORMAL, "Read FDX-B animal tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdxb read [h] [@]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " @ : run continuously until a key is pressed (optional)");
|
||||
PrintAndLogEx(NORMAL, "Note that the continuous mode is less verbose");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
// add preamble ten 0x00 and one 0x01
|
||||
memset(bits, 0x00, 10);
|
||||
bits[10] = 1;
|
||||
|
||||
static int usage_lf_fdxb_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of FDX-B animal tag");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdxb sim [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
|
||||
PrintAndLogEx(NORMAL, " n <national> : (dec) National code");
|
||||
PrintAndLogEx(NORMAL, " e <extended> : (hex) Extended data");
|
||||
PrintAndLogEx(NORMAL, " s : Set animal bit");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb sim c 999 n 112233 s"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb sim c 999 n 112233 e 16a"));
|
||||
// 128bits
|
||||
// every 9th bit is 0x01, but we can just fill the rest with 0x01 and overwrite
|
||||
memset(bits, 0x01, 128);
|
||||
|
||||
// add preamble ten 0x00 and one 0x01
|
||||
memset(bits, 0x00, 10);
|
||||
|
||||
// add reserved
|
||||
num_to_bytebitsLSBF(0x00, 7, bits + 66);
|
||||
num_to_bytebitsLSBF(0x00 >> 7, 7, bits + 74);
|
||||
|
||||
// add animal flag - OK
|
||||
bits[81] = is_animal;
|
||||
|
||||
// add extended flag - OK
|
||||
bits[65] = is_extended;
|
||||
|
||||
// add national code 40bits - OK
|
||||
num_to_bytebitsLSBF(national_code >> 0, 8, bits + 11);
|
||||
num_to_bytebitsLSBF(national_code >> 8, 8, bits + 20);
|
||||
num_to_bytebitsLSBF(national_code >> 16, 8, bits + 29);
|
||||
num_to_bytebitsLSBF(national_code >> 24, 8, bits + 38);
|
||||
num_to_bytebitsLSBF(national_code >> 32, 6, bits + 47);
|
||||
|
||||
// add country code - OK
|
||||
num_to_bytebitsLSBF(country_code >> 0, 2, bits + 53);
|
||||
num_to_bytebitsLSBF(country_code >> 2, 8, bits + 56);
|
||||
|
||||
// add crc-16 - OK
|
||||
uint8_t raw[8];
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
raw[i] = bytebits_to_byte(bits + 11 + i * 9, 8);
|
||||
|
||||
init_table(CRC_11784);
|
||||
uint16_t crc = crc16_fdxb(raw, 8);
|
||||
num_to_bytebitsLSBF(crc >> 0, 8, bits + 83);
|
||||
num_to_bytebitsLSBF(crc >> 8, 8, bits + 92);
|
||||
|
||||
// extended data - OK
|
||||
num_to_bytebitsLSBF(extended >> 0, 8, bits + 101);
|
||||
num_to_bytebitsLSBF(extended >> 8, 8, bits + 110);
|
||||
num_to_bytebitsLSBF(extended >> 16, 8, bits + 119);
|
||||
|
||||
// 8 16 24 32 40 48 49
|
||||
// A8 28 0C 92 EA 6F 00 01
|
||||
// A8 28 0C 92 EA 6F 80 00
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// clearing the topbit needed for the preambl detection.
|
||||
static void verify_values(uint64_t *animalid, uint32_t *countryid, uint32_t *extended, uint8_t *is_animal) {
|
||||
static void verify_values(uint64_t *animalid, uint32_t *countryid, uint32_t *extended) {
|
||||
if ((*animalid & 0x3FFFFFFFFF) != *animalid) {
|
||||
*animalid &= 0x3FFFFFFFFF;
|
||||
PrintAndLogEx(INFO, "Animal ID truncated to 38bits: " _YELLOW_("%"PRIx64), *animalid);
|
||||
|
@ -105,12 +112,10 @@ static void verify_values(uint64_t *animalid, uint32_t *countryid, uint32_t *ext
|
|||
*countryid &= 0x3FF;
|
||||
PrintAndLogEx(INFO, "Country ID truncated to 10bits:" _YELLOW_("%03d"), *countryid);
|
||||
}
|
||||
if ((*extended & 0xFFF) != *extended) {
|
||||
*extended &= 0xFFF;
|
||||
if ((*extended & 0xFFFFFF) != *extended) {
|
||||
*extended &= 0xFFFFFF;
|
||||
PrintAndLogEx(INFO, "Extended truncated to 24bits: " _YELLOW_("0x%03X"), *extended);
|
||||
}
|
||||
|
||||
*is_animal &= 0x01;
|
||||
}
|
||||
|
||||
static inline uint32_t bitcount(uint32_t a) {
|
||||
|
@ -607,71 +612,75 @@ int demodFDXB(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdFdxBDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf fdxb demod",
|
||||
"Try to find FDX-B preamble, if found decode / descramble data",
|
||||
"lf fdxb demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodFDXB(true);
|
||||
}
|
||||
|
||||
static int CmdFdxBRead(const char *Cmd) {
|
||||
static int CmdFdxBReader(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf fdxb reader",
|
||||
"read a FDX-B animal tag\n"
|
||||
"Note that the continuous mode is less verbose",
|
||||
"lf fdxb 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);
|
||||
|
||||
sample_config config;
|
||||
memset(&config, 0, sizeof(sample_config));
|
||||
int retval = lf_getconfig(&config);
|
||||
if (retval != PM3_SUCCESS) {
|
||||
int res = lf_getconfig(&config);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "failed to get current device LF config");
|
||||
return retval;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool errors = false;
|
||||
bool continuous = false;
|
||||
uint8_t cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_fdxb_read();
|
||||
case '@':
|
||||
continuous = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Validations
|
||||
if (errors) return usage_lf_fdxb_read();
|
||||
int16_t tmp_div = config.divisor;
|
||||
if (tmp_div != LF_DIVISOR_134) {
|
||||
config.divisor = LF_DIVISOR_134;
|
||||
config.verbose = false;
|
||||
retval = lf_config(&config);
|
||||
if (retval != PM3_SUCCESS) {
|
||||
res = lf_config(&config);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "failed to change LF configuration");
|
||||
return retval;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (continuous) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit");
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
int ret = PM3_SUCCESS;
|
||||
do {
|
||||
retval = lf_read(false, 10000);
|
||||
if (retval != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "failed to get LF read from device");
|
||||
return retval;
|
||||
}
|
||||
ret = demodFDXB(!continuous); // be verbose only if not in continuous mode
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
PrintAndLogEx(INPLACE, "");
|
||||
} while (continuous);
|
||||
lf_read(false, 10000);
|
||||
ret = demodFDXB(!cm); // be verbose only if not in continuous mode
|
||||
//PrintAndLogEx(INPLACE, "");
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
if (tmp_div != LF_DIVISOR_134) {
|
||||
config.divisor = tmp_div;
|
||||
retval = lf_config(&config);
|
||||
if (retval != PM3_SUCCESS) {
|
||||
res = lf_config(&config);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "failed to restore LF configuration");
|
||||
return retval;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
@ -679,145 +688,159 @@ static int CmdFdxBRead(const char *Cmd) {
|
|||
|
||||
static int CmdFdxBClone(const char *Cmd) {
|
||||
|
||||
uint32_t country_code = 0, extended = 0;
|
||||
uint64_t national_code = 0;
|
||||
uint8_t is_animal = 0, cmdp = 0;
|
||||
bool errors = false, has_extended = false, q5 = false;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf fdxb clone",
|
||||
"clone a FDX-B tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf fdxb clone --country 999 --national 1337 --animal\n"
|
||||
"lf fdxb clone --country 999 --national 1337 --extended 016A\n"
|
||||
"lf fdxb clone --q5 --country 999 --national 1337 -> encode for Q5/T5555 tag\n"
|
||||
"lf fdxb clone --em --country 999 --national 1337 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_fdxb_clone();
|
||||
case 'c': {
|
||||
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
national_code = param_get64ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'e': {
|
||||
extended = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
||||
has_extended = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
is_animal = 1;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
q5 = true;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1("c", "country", "<dec>", "country code"),
|
||||
arg_u64_1("n", "national", "<dec>", "national code"),
|
||||
arg_str0(NULL, "extended", "<hex>", "extended data"),
|
||||
arg_lit0("a", "animal", "optional - set animal bit"),
|
||||
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 country_code = arg_get_u32_def(ctx, 1, 0);
|
||||
uint64_t national_code = arg_get_u64_def(ctx, 2, 0);
|
||||
|
||||
int extended_len = 0;
|
||||
uint8_t edata[3] = {0};
|
||||
CLIGetHexWithReturn(ctx, 3, edata, &extended_len);
|
||||
|
||||
bool is_animal = arg_get_lit(ctx, 4);
|
||||
bool q5 = arg_get_lit(ctx, 5);
|
||||
bool em = arg_get_lit(ctx, 6);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (errors || strlen(Cmd) == 0) return usage_lf_fdxb_clone();
|
||||
|
||||
verify_values(&national_code, &country_code, &extended, &is_animal);
|
||||
uint32_t extended = 0;
|
||||
bool has_extended = false;
|
||||
if (extended_len) {
|
||||
extended = bytes_to_num(edata, extended_len);
|
||||
has_extended = true;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, " Country code %"PRIu32, country_code);
|
||||
PrintAndLogEx(INFO, " National code %"PRIu64, national_code);
|
||||
PrintAndLogEx(INFO, " Set animal bit %c", (is_animal) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, "Set data block bit %c", (has_extended) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, " Extended data 0x%"PRIX32, extended);
|
||||
PrintAndLogEx(INFO, " RFU 0");
|
||||
verify_values(&national_code, &country_code, &extended);
|
||||
|
||||
uint8_t *bits = calloc(128, sizeof(uint8_t));
|
||||
if (getFDXBBits(national_code, country_code, is_animal, has_extended, extended, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Country code........ %"PRIu32, country_code);
|
||||
PrintAndLogEx(INFO, "National code....... %"PRIu64, national_code);
|
||||
PrintAndLogEx(INFO, "Set animal bit...... %c", (is_animal) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, "Set data block bit.. %c", (has_extended) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, "Extended data....... 0x%"PRIX32, extended);
|
||||
PrintAndLogEx(INFO, "RFU................. 0");
|
||||
|
||||
uint8_t *bs = calloc(128, sizeof(uint8_t));
|
||||
if (getFDXBBits(national_code, country_code, is_animal, has_extended, extended, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
free(bs);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint32_t blocks[5] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0, 0};
|
||||
char cardtype[16] = {"T55x7"};
|
||||
|
||||
//Q5
|
||||
if (q5)
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_FDXB_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
// convert from bit stream to block data
|
||||
blocks[1] = bytebits_to_byte(bits, 32);
|
||||
blocks[2] = bytebits_to_byte(bits + 32, 32);
|
||||
blocks[3] = bytebits_to_byte(bits + 64, 32);
|
||||
blocks[4] = bytebits_to_byte(bits + 96, 32);
|
||||
blocks[1] = bytebits_to_byte(bs, 32);
|
||||
blocks[2] = bytebits_to_byte(bs + 32, 32);
|
||||
blocks[3] = bytebits_to_byte(bs + 64, 32);
|
||||
blocks[4] = bytebits_to_byte(bs + 96, 32);
|
||||
|
||||
free(bits);
|
||||
free(bs);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone FDX-B to " _YELLOW_("%s") " with animal ID: " _GREEN_("%04u-%"PRIu64), (q5) ? "Q5/T5555" : "T55x7", country_code, national_code);
|
||||
PrintAndLogEx(INFO, "Preparing to clone FDX-B to " _YELLOW_("%s") " with animal ID: " _GREEN_("%04u-%"PRIu64)
|
||||
, cardtype
|
||||
, country_code
|
||||
, national_code
|
||||
);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdxb read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdxb reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdFdxBSim(const char *Cmd) {
|
||||
|
||||
uint32_t country_code = 0, extended = 0;
|
||||
uint64_t national_code = 0;
|
||||
uint8_t is_animal = 0, cmdp = 0;
|
||||
bool errors = false, has_extended = false;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf fdxb sim",
|
||||
"Enables simulation of FDX-B animal tag.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf fdxb sim --country 999 --national 1337 --animal\n"
|
||||
"lf fdxb sim --country 999 --national 1337 --extended 016A\n"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_fdxb_sim();
|
||||
case 'c': {
|
||||
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
national_code = param_get64ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'e': {
|
||||
extended = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
has_extended = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
is_animal = 1;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1("c", "country", "<dec>", "country code"),
|
||||
arg_u64_1("n", "national", "<dec>", "national code"),
|
||||
arg_str0(NULL, "extended", "<hex>", "extended data"),
|
||||
arg_lit0("a", "animal", "optional - set animal bit"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint32_t country_code = arg_get_u32_def(ctx, 1, 0);
|
||||
uint64_t national_code = arg_get_u64_def(ctx, 2, 0);
|
||||
int extended_len = 0;
|
||||
uint8_t edata[3] = {0};
|
||||
CLIGetHexWithReturn(ctx, 3, edata, &extended_len);
|
||||
|
||||
bool is_animal = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint32_t extended = 0;
|
||||
bool has_extended = false;
|
||||
if (extended_len) {
|
||||
extended = bytes_to_num(edata, extended_len);
|
||||
has_extended = true;
|
||||
}
|
||||
if (errors) return usage_lf_fdxb_sim();
|
||||
|
||||
verify_values(&national_code, &country_code, &extended, &is_animal);
|
||||
verify_values(&national_code, &country_code, &extended);
|
||||
|
||||
PrintAndLogEx(INFO, " Country code %"PRIu32, country_code);
|
||||
PrintAndLogEx(INFO, " National code %"PRIu64, national_code);
|
||||
PrintAndLogEx(INFO, " Set animal bit %c", (is_animal) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, "Set data block bit %c", (has_extended) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, " Extended data 0x%"PRIX32, extended);
|
||||
PrintAndLogEx(INFO, " RFU 0");
|
||||
PrintAndLogEx(INFO, "Country code........ %"PRIu32, country_code);
|
||||
PrintAndLogEx(INFO, "National code....... %"PRIu64, national_code);
|
||||
PrintAndLogEx(INFO, "Set animal bit...... %c", (is_animal) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, "Set data block bit.. %c", (has_extended) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, "Extended data....... 0x%"PRIX16, extended);
|
||||
PrintAndLogEx(INFO, "RFU................. 0");
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _GREEN_("%04u-%"PRIu64), country_code, national_code);
|
||||
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _YELLOW_("%04u-%"PRIu64), country_code, national_code);
|
||||
|
||||
uint8_t *bits = calloc(128, sizeof(uint8_t));
|
||||
if (getFDXBBits(national_code, country_code, is_animal, (extended > 0), extended, bits) != PM3_SUCCESS) {
|
||||
uint8_t *bs = calloc(128, sizeof(uint8_t));
|
||||
if (getFDXBBits(national_code, country_code, is_animal, (extended > 0), extended, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
free(bs);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -827,12 +850,12 @@ static int CmdFdxBSim(const char *Cmd) {
|
|||
payload->invert = 1;
|
||||
payload->separator = 0;
|
||||
payload->clock = 32;
|
||||
memcpy(payload->data, bits, 128);
|
||||
memcpy(payload->data, bs, 128);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + 128);
|
||||
|
||||
free(bits);
|
||||
free(bs);
|
||||
free(payload);
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
@ -846,11 +869,11 @@ static int CmdFdxBSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdFdxBDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
|
||||
{"read", CmdFdxBRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
|
||||
{"clone", CmdFdxBClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdFdxBSim, IfPm3Lf, "simulate Animal ID tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdFdxBDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
|
||||
{"reader", CmdFdxBReader, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
|
||||
{"clone", CmdFdxBClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdFdxBSim, IfPm3Lf, "simulate Animal ID tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -878,59 +901,3 @@ int detectFDXB(uint8_t *dest, size_t *size) {
|
|||
//return start position
|
||||
return (int)startIdx;
|
||||
}
|
||||
|
||||
int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits) {
|
||||
|
||||
// add preamble ten 0x00 and one 0x01
|
||||
memset(bits, 0x00, 10);
|
||||
bits[10] = 1;
|
||||
|
||||
// 128bits
|
||||
// every 9th bit is 0x01, but we can just fill the rest with 0x01 and overwrite
|
||||
memset(bits, 0x01, 128);
|
||||
|
||||
// add preamble ten 0x00 and one 0x01
|
||||
memset(bits, 0x00, 10);
|
||||
|
||||
// add reserved
|
||||
num_to_bytebitsLSBF(0x00, 7, bits + 66);
|
||||
num_to_bytebitsLSBF(0x00 >> 7, 7, bits + 74);
|
||||
|
||||
// add animal flag - OK
|
||||
bits[81] = is_animal;
|
||||
|
||||
// add extended flag - OK
|
||||
bits[65] = is_extended;
|
||||
|
||||
// add national code 40bits - OK
|
||||
num_to_bytebitsLSBF(national_code >> 0, 8, bits + 11);
|
||||
num_to_bytebitsLSBF(national_code >> 8, 8, bits + 20);
|
||||
num_to_bytebitsLSBF(national_code >> 16, 8, bits + 29);
|
||||
num_to_bytebitsLSBF(national_code >> 24, 8, bits + 38);
|
||||
num_to_bytebitsLSBF(national_code >> 32, 6, bits + 47);
|
||||
|
||||
// add country code - OK
|
||||
num_to_bytebitsLSBF(country_code >> 0, 2, bits + 53);
|
||||
num_to_bytebitsLSBF(country_code >> 2, 8, bits + 56);
|
||||
|
||||
// add crc-16 - OK
|
||||
uint8_t raw[8];
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
raw[i] = bytebits_to_byte(bits + 11 + i * 9, 8);
|
||||
|
||||
init_table(CRC_11784);
|
||||
uint16_t crc = crc16_fdxb(raw, 8);
|
||||
num_to_bytebitsLSBF(crc >> 0, 8, bits + 83);
|
||||
num_to_bytebitsLSBF(crc >> 8, 8, bits + 92);
|
||||
|
||||
// extended data - OK
|
||||
num_to_bytebitsLSBF(extended >> 0, 8, bits + 101);
|
||||
num_to_bytebitsLSBF(extended >> 8, 8, bits + 110);
|
||||
num_to_bytebitsLSBF(extended >> 16, 8, bits + 119);
|
||||
|
||||
// 8 16 24 32 40 48 49
|
||||
// A8 28 0C 92 EA 6F 00 01
|
||||
// A8 28 0C 92 EA 6F 80 00
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ typedef struct {
|
|||
int CmdLFFdxB(const char *Cmd);
|
||||
int detectFDXB(uint8_t *dest, size_t *size);
|
||||
int demodFDXB(bool verbose);
|
||||
int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
|
||||
//int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint16_t extended, uint8_t *bits);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -10,36 +10,25 @@
|
|||
// sample Q5 , ASK RF/32, STT, 96 bits (3blocks) ( 0x9000F006)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfgallagher.h"
|
||||
|
||||
#include <ctype.h> //tolower
|
||||
#include <string.h> // memcpy
|
||||
#include <ctype.h> // tolower
|
||||
#include <stdio.h>
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "common.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "crc.h" // CRC8/Cardx
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "crc.h" // CRC8/Cardx
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_gallagher_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a GALLAGHER tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf gallagher 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 gallagher clone b 0FFD5461A9DA1346B2D1AC32"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void descramble(uint8_t *arr, uint8_t len) {
|
||||
|
||||
uint8_t lut[] = {
|
||||
|
@ -134,73 +123,169 @@ int demodGallagher(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdGallagherDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf gallagher demod",
|
||||
"Try to find GALLAGHER preamble, if found decode / descramble data",
|
||||
"lf gallagher demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodGallagher(true);
|
||||
}
|
||||
|
||||
static int CmdGallagherRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 4096 * 2 + 20);
|
||||
return demodGallagher(true);
|
||||
static int CmdGallagherReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf gallagher reader",
|
||||
"read a GALLAGHER tag",
|
||||
"lf gallagher 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 4096 * 2 + 20);
|
||||
demodGallagher(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdGallagherClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[4];
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf gallagher clone",
|
||||
"clone a GALLAGHER tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf gallagher clone --raw 0FFD5461A9DA1346B2D1AC32\n"
|
||||
"lf gallagher clone --q5 --raw 0FFD5461A9DA1346B2D1AC32 -> encode for Q5/T5555 tag\n"
|
||||
"lf gallagher clone --em --raw 0FFD5461A9DA1346B2D1AC32 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_gallagher_clone();
|
||||
case 'b': {
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t rawhex[12] = {0};
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_gallagher_clone();
|
||||
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));
|
||||
}
|
||||
|
||||
//Pac - compat mode, NRZ, data rate 40, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_MANCHESTER | 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(32) | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Gallagher to T55x7 with raw hex");
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_GALLAGHER_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Gallagher to " _YELLOW_("%s") " with raw hex", cardtype);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gallagher read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gallagher reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdGallagherSim(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf gallagher sim",
|
||||
"Enables simulation of GALLAGHER card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n",
|
||||
"lf gallagher sim --raw 0FFD5461A9DA1346B2D1AC32"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// ASK/MAN sim.
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
PrintAndLogEx(SUCCESS, "Simulating Gallagher - 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 = 32;
|
||||
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[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdGallagherDemod, AlwaysAvailable, "Demodulate an GALLAGHER tag from the GraphBuffer"},
|
||||
{"read", CmdGallagherRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdGallagherClone, IfPm3Lf, "clone GALLAGHER tag to T55x7"},
|
||||
{"sim", CmdGallagherSim, IfPm3Lf, "simulate GALLAGHER tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdGallagherDemod, AlwaysAvailable, "Demodulate an GALLAGHER tag from the GraphBuffer"},
|
||||
{"reader", CmdGallagherReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdGallagherClone, IfPm3Lf, "clone GALLAGHER tag to T55x7"},
|
||||
{"sim", CmdGallagherSim, IfPm3Lf, "simulate GALLAGHER tag"},
|
||||
{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,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
|
@ -8,63 +9,28 @@
|
|||
// Biphase, rf/ , 96 bits (unknown key calc + some bits)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfguard.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_guard_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Guardall 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 work only on 26bit");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf gprox clone [h] <format> <Facility-Code> <Card-Number> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " <format> : format length 26|32|36|40");
|
||||
PrintAndLogEx(NORMAL, " <Facility-Code> : 8-bit value facility code");
|
||||
PrintAndLogEx(NORMAL, " <Card Number> : 16-bit value card number");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf gprox clone 26 123 11223"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_guard_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of Guardall 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 gprox sim [h] <format> <Facility-Code> <Card-Number>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " <format> : format length 26|32|36|40");
|
||||
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 gprox sim 26 123 11223"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
//by marshmellow
|
||||
//attempts to demodulate and identify a G_Prox_II verex/chubb card
|
||||
//WARNING: if it fails during some points it will destroy the DemodBuffer data
|
||||
// attempts to demodulate and identify a G_Prox_II verex/chubb card
|
||||
// WARNING: if it fails during some points it will destroy the DemodBuffer data
|
||||
// but will leave the GraphBuffer intact.
|
||||
//if successful it will push askraw data back to demod buffer ready for emulation
|
||||
// if successful it will push askraw data back to demod buffer ready for emulation
|
||||
int demodGuard(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
//Differential Biphase
|
||||
|
@ -150,43 +116,108 @@ int demodGuard(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdGuardDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf gproxii demod",
|
||||
"Try to find Guardall Prox-II preamble, if found decode / descramble data",
|
||||
"lf gproxii demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodGuard(true);
|
||||
}
|
||||
|
||||
static int CmdGuardRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 10000);
|
||||
return demodGuard(true);
|
||||
static int CmdGuardReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf gproxii reader",
|
||||
"read a Guardall tag",
|
||||
"lf gproxii 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 10000);
|
||||
demodGuard(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdGuardClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf gproxii clone",
|
||||
"clone a Guardall tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
|
||||
"Currently work only on 26bit",
|
||||
"lf gproxii clone --fmt 26 --fc 123 --cn 1337\n"
|
||||
"lf gproxii clone --q5 --fmt 26 --fc 123 --cn 1337 -> encode for Q5/T5555 tag\n"
|
||||
"lf gproxii clone --em --fmt 26 --fc 123 --cn 1337 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_guard_clone();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|32|36|40"),
|
||||
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 facilitycode = 0, cardnumber = 0, fc = 0, cn = 0, fmtlen = 0;
|
||||
uint32_t fmtlen = arg_get_u32_def(ctx, 1, 0);
|
||||
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
|
||||
bool q5 = arg_get_lit(ctx, 4);
|
||||
bool em = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (sscanf(Cmd, "%u %u %u", &fmtlen, &fc, &cn) != 3) return usage_lf_guard_clone();
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
fmtlen &= 0x7f;
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
uint32_t facilitycode = (fc & 0x000000FF);
|
||||
uint32_t cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
//GuardProxII - compat mode, ASK/Biphase, data rate 64, 3 data blocks
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_BIPHASE | T55x7_BITRATE_RF_64 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
|
||||
uint8_t *bs = calloc(96, sizeof(uint8_t));
|
||||
|
||||
if (getGuardBits(fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bs);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_BIPHASE | T55x7_BITRATE_RF_64 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0};
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 3)) == 'q';
|
||||
if (q5)
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_SET_BITRATE(64) | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_GUARDPROXII_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[1] = bytebits_to_byte(bs, 32);
|
||||
blocks[2] = bytebits_to_byte(bs + 32, 32);
|
||||
|
@ -194,37 +225,65 @@ static int CmdGuardClone(const char *Cmd) {
|
|||
|
||||
free(bs);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", (q5) ? "Q5/T5555" : "T55x7", facilitycode, cardnumber);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u")
|
||||
, cardtype
|
||||
, facilitycode
|
||||
, cardnumber
|
||||
);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gprox read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gproxii reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdGuardSim(const char *Cmd) {
|
||||
|
||||
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0, fmtlen = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf gproxii sim",
|
||||
"Enables simulation of Guardall 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 gproxii sim --fmt 26 --fc 123 --cn 1337\n"
|
||||
);
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_guard_sim();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fmt", "<dec>", "format length 26|32|36|40"),
|
||||
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);
|
||||
|
||||
if (sscanf(Cmd, "%u %u %u", &fmtlen, &fc, &cn) != 3) return usage_lf_guard_sim();
|
||||
uint32_t fmtlen = arg_get_u32_def(ctx, 1, 0);
|
||||
uint32_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
uint32_t cn = arg_get_u32_def(ctx, 3, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
fmtlen &= 0x7F;
|
||||
uint32_t facilitycode = (fc & 0x000000FF);
|
||||
uint32_t cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
uint8_t bs[96];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
|
||||
fmtlen &= 0x7F;
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
if (getGuardBits(fmtlen, facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Guardall - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u")
|
||||
, facilitycode
|
||||
, cardnumber
|
||||
);
|
||||
|
||||
// Guard uses: clk: 64, invert: 0, encoding: 2 (ASK Biphase)
|
||||
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
|
||||
|
@ -250,7 +309,7 @@ static int CmdGuardSim(const char *Cmd) {
|
|||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdGuardDemod, AlwaysAvailable, "demodulate a G Prox II tag from the GraphBuffer"},
|
||||
{"read", CmdGuardRead, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
|
||||
{"reader", CmdGuardReader, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdGuardClone, IfPm3Lf, "clone Guardall tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdGuardSim, IfPm3Lf, "simulate Guardall tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
@ -267,7 +326,6 @@ int CmdLFGuard(const char *Cmd) {
|
|||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
// by marshmellow
|
||||
// demod gProxIIDemod
|
||||
// error returns as -x
|
||||
// success returns start position in bitstream
|
||||
|
|
|
@ -19,13 +19,10 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfhid.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
|
@ -38,6 +35,7 @@
|
|||
#include "lfdemod.h"
|
||||
#include "wiegand_formats.h"
|
||||
#include "wiegand_formatutils.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
#ifndef BITS
|
||||
# define BITS 96
|
||||
|
@ -47,8 +45,7 @@ static int CmdHelp(const char *Cmd);
|
|||
|
||||
// sending three times. Didn't seem to break the previous sim?
|
||||
static int sendPing(void) {
|
||||
SendCommandNG(CMD_PING, NULL, 0);
|
||||
SendCommandNG(CMD_PING, NULL, 0);
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
SendCommandNG(CMD_PING, NULL, 0);
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
|
@ -66,13 +63,20 @@ static int sendTry(uint8_t format_idx, wiegand_card_t *card, uint32_t delay, boo
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "Trying FC: %u; CN: %"PRIu64"; Issue level: %u; OEM: %u", card->FacilityCode, card->CardNumber, card->IssueLevel, card->OEM);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Trying FC: " _YELLOW_("%u") " CN: " _YELLOW_("%"PRIu64) " Issue level: " _YELLOW_("%u") " OEM: " _YELLOW_("%u")
|
||||
, card->FacilityCode
|
||||
, card->CardNumber
|
||||
, card->IssueLevel
|
||||
, card->OEM
|
||||
);
|
||||
}
|
||||
|
||||
lf_hidsim_t payload;
|
||||
payload.hi2 = packed.Top;
|
||||
payload.hi = packed.Mid;
|
||||
payload.lo = packed.Bot;
|
||||
payload.longFMT = (packed.Mid > 0xFFF);
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
|
@ -153,15 +157,48 @@ int demodHID(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdHIDDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf hid demod",
|
||||
"Try to find HID Prox preamble, if found decode / descramble data",
|
||||
"lf hid demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodHID(true);
|
||||
}
|
||||
|
||||
// this read is the "normal" read, which download lf signal and tries to demod here.
|
||||
static int CmdHIDRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 16000);
|
||||
return demodHID(true);
|
||||
static int CmdHIDReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf hid reader",
|
||||
"read a HID Prox tag",
|
||||
"lf hid 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 16000);
|
||||
demodHID(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// this read loops on device side.
|
||||
|
@ -196,7 +233,8 @@ static int CmdHIDSim(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf hid sim",
|
||||
"Enables simulation of HID card with card number.",
|
||||
"Enables simulation of HID card with card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf hid sim -r 2006ec0c86 -> HID 10301 26 bit\n"
|
||||
"lf hid sim -r 2e0ec00c87 -> HID Corporate 35 bit\n"
|
||||
"lf hid sim -r 01f0760643c3 -> HID P10001 40 bit\n"
|
||||
|
@ -209,10 +247,9 @@ static int CmdHIDSim(const char *Cmd) {
|
|||
arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
|
||||
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card number"),
|
||||
arg_int0("i", NULL, "<dec>", "issue level"),
|
||||
arg_int0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_u64_0("i", NULL, "<dec>", "issue level"),
|
||||
arg_u64_0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_strx0("r", "raw", "<hex>", "raw bytes"),
|
||||
// arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -231,8 +268,6 @@ static int CmdHIDSim(const char *Cmd) {
|
|||
int raw_len = 0;
|
||||
char raw[40] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
|
||||
|
||||
//bool q5 = arg_get_lit(ctx, 7);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
wiegand_message_t packed;
|
||||
|
@ -288,15 +323,17 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf hid clone",
|
||||
"Clone HID to T55x7. Tag must be on antenna!",
|
||||
"lf hid clone -r 2006ec0c86 -> HID 10301 26 bit\n"
|
||||
"lf hid clone -r 2e0ec00c87 -> HID Corporate 35 bit\n"
|
||||
"lf hid clone -r 01f0760643c3 -> HID P10001 40 bit\n"
|
||||
"lf hid clone -r 01400076000c86 -> HID Corporate 48 bit\n"
|
||||
"lf hid clone -w H10301 --fc 118 --cn 1603 -> HID 10301 26 bit\n"
|
||||
"clone a HID Prox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"Tag must be on the antenna when issuing this command.",
|
||||
"lf hid clone -r 2006ec0c86 -> write raw value (HID 10301 26 bit)\n"
|
||||
"lf hid clone -r 2e0ec00c87 -> write raw value (HID Corporate 35 bit)\n"
|
||||
"lf hid clone -r 01f0760643c3 -> write raw value (HID P10001 40 bit)\n"
|
||||
"lf hid clone -r 01400076000c86 -> write raw value (HID Corporate 48 bit)\n"
|
||||
"lf hid clone -w H10301 --fc 118 --cn 1603 -> write raw value (HID 10301 26 bit)\n"
|
||||
"lf hid clone -w H10301 --fc 118 --cn 1603 --q5 -> HID 10301 26 bit, encode for Q5/T5555 tag\n"
|
||||
"lf hid clone -w H10301 --fc 118 --cn 1603 --em -> HID 10301 26 bit, encode for EM4305/4469"
|
||||
);
|
||||
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
|
||||
|
@ -305,7 +342,8 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
arg_int0("i", NULL, "<dec>", "issue level"),
|
||||
arg_int0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_strx0("r", "raw", "<hex>", "raw 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
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -325,9 +363,15 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
char raw[40] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
|
||||
|
||||
//bool q5 = arg_get_lit(ctx, 7);
|
||||
bool q5 = arg_get_lit(ctx, 7);
|
||||
bool em = arg_get_lit(ctx, 8);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
wiegand_message_t packed;
|
||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
|
@ -351,6 +395,17 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
if (raw_len == 0) {
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag");
|
||||
HIDTryUnpack(&packed, false);
|
||||
|
@ -363,11 +418,22 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
payload.hi = packed.Mid;
|
||||
payload.lo = packed.Bot;
|
||||
payload.longFMT = (packed.Mid > 0xFFF);
|
||||
payload.Q5 = q5;
|
||||
payload.EM = em;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_HID_CLONE, (uint8_t *)&payload, sizeof(payload));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid read`") " to verify");
|
||||
|
||||
PacketResponseNG resp;
|
||||
WaitForResponse(CMD_LF_HID_CLONE, &resp);
|
||||
if (resp.status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Done");
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "Failed cloning");
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid reader`") " to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -405,17 +471,18 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
"lf hid brute -w H10301 --fc 224\n"
|
||||
"lf hid brute -w H10301 --fc 21 -d 2000\n"
|
||||
"lf hid brute -v -w H10301 --fc 21 --cn 200 -d 2000\n"
|
||||
"lf hid brute -v -w H10301 --fc 21 --cn 200 -d 2000 --up\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "verbose logging, show all tries"),
|
||||
arg_str1("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
|
||||
arg_int0(NULL, "fn", "<dec>", "facility code"),
|
||||
arg_int0(NULL, "cn", "<dec>", "card number to start with"),
|
||||
arg_int0("i", "issue", "<dec>", "issue level"),
|
||||
arg_int0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_int0("d", "delay", "<dec>", "delay betweens attempts in ms. Default 1000ms"),
|
||||
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card number to start with"),
|
||||
arg_u64_0("i", "issue", "<dec>", "issue level"),
|
||||
arg_u64_0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_u64_0("d", "delay", "<dec>", "delay betweens attempts in ms. Default 1000ms"),
|
||||
arg_lit0(NULL, "up", "direction to increment card number. (default is both directions)"),
|
||||
arg_lit0(NULL, "down", "direction to decrement card number. (default is both directions)"),
|
||||
arg_param_end
|
||||
|
@ -433,11 +500,11 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
cn_hi.FacilityCode = arg_get_int_def(ctx, 3, 0);
|
||||
cn_hi.CardNumber = arg_get_int_def(ctx, 4, 0);
|
||||
cn_hi.IssueLevel = arg_get_int_def(ctx, 5, 0);
|
||||
cn_hi.OEM = arg_get_int_def(ctx, 6, 0);
|
||||
delay = arg_get_int_def(ctx, 7, 1000);
|
||||
cn_hi.FacilityCode = arg_get_u32_def(ctx, 3, 0);
|
||||
cn_hi.CardNumber = arg_get_u32_def(ctx, 4, 0);
|
||||
cn_hi.IssueLevel = arg_get_u32_def(ctx, 5, 0);
|
||||
cn_hi.OEM = arg_get_u32_def(ctx, 6, 0);
|
||||
delay = arg_get_u32_def(ctx, 7, 1000);
|
||||
|
||||
if (arg_get_lit(ctx, 8) && arg_get_lit(ctx, 9)) {
|
||||
direction = 0;
|
||||
|
@ -457,20 +524,20 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Card#............ %" PRIu64, cn_hi.CardNumber);
|
||||
switch (direction) {
|
||||
case 0:
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("BOTH"));
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("BOTH") " delay " _YELLOW_("%d"), delay);
|
||||
break;
|
||||
case 1:
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("UP"));
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("UP") " delay " _YELLOW_("%d"), delay);
|
||||
break;
|
||||
case 2:
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("DOWN"));
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("DOWN") " delay " _YELLOW_("%d"), delay);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(INFO, "Brute-forcing HID reader");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation or press `enter` to exit");
|
||||
PrintAndLogEx(INFO, "Started brute-forcing HID Prox reader");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation or press " _GREEN_("`<enter>`") " to exit");
|
||||
|
||||
// copy values to low.
|
||||
cn_low = cn_hi;
|
||||
|
@ -496,7 +563,9 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
if (direction != 2) {
|
||||
if (cn_hi.CardNumber < 0xFFFF) {
|
||||
cn_hi.CardNumber++;
|
||||
if (sendTry(format_idx, &cn_hi, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
|
||||
if (sendTry(format_idx, &cn_hi, delay, verbose) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
fin_hi = true;
|
||||
}
|
||||
|
@ -506,7 +575,9 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
if (direction != 1) {
|
||||
if (cn_low.CardNumber > 0) {
|
||||
cn_low.CardNumber--;
|
||||
if (sendTry(format_idx, &cn_low, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
|
||||
if (sendTry(format_idx, &cn_low, delay, verbose) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
fin_low = true;
|
||||
}
|
||||
|
@ -537,7 +608,7 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdHIDDemod, AlwaysAvailable, "demodulate HID Prox tag from the GraphBuffer"},
|
||||
{"read", CmdHIDRead, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"reader", CmdHIDReader, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdHIDClone, IfPm3Lf, "clone HID tag to T55x7"},
|
||||
{"sim", CmdHIDSim, IfPm3Lf, "simulate HID tag"},
|
||||
{"brute", CmdHIDBrute, IfPm3Lf, "bruteforce card number against reader"},
|
||||
|
|
|
@ -9,13 +9,10 @@
|
|||
// PSK
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfidteck.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
|
@ -23,6 +20,8 @@
|
|||
#include "cmdlf.h"
|
||||
#include "lfdemod.h"
|
||||
#include "commonutil.h" // num_to_bytes
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -87,20 +86,53 @@ int demodIdteck(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdIdteckDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf idteck demod",
|
||||
"Try to find Idteck preamble, if found decode / descramble data",
|
||||
"lf idteck demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodIdteck(true);
|
||||
}
|
||||
|
||||
static int CmdIdteckRead(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
lf_read(false, 5000);
|
||||
return demodIdteck(true);
|
||||
static int CmdIdteckReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf idteck reader",
|
||||
"read a Idteck tag",
|
||||
"lf idteck 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 5000);
|
||||
demodIdteck(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdIdteckDemod, AlwaysAvailable, "Demodulate an Idteck tag from the GraphBuffer"},
|
||||
{"read", CmdIdteckRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdIdteckDemod, AlwaysAvailable, "Demodulate an Idteck tag from the GraphBuffer"},
|
||||
{"reader", CmdIdteckReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,13 +9,10 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfindala.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "graph.h"
|
||||
|
@ -28,6 +25,8 @@
|
|||
#include "cmdlf.h" // lf_read
|
||||
#include "protocols.h" // t55 defines
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
#define INDALA_ARR_LEN 64
|
||||
|
||||
|
@ -39,41 +38,6 @@ static uint8_t preamble224[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|||
// standard 64 bit indala formats including 26 bit 40134 format
|
||||
static uint8_t preamble64[] = {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
|
||||
static int usage_lf_indala_demod(void) {
|
||||
PrintAndLogEx(NORMAL, "Tries to psk demodulate the graphbuffer as Indala ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf indala demod [h] <clock> <0|1> <maxerror>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " clock : Set clock (as integer) optional, if not set, autodetect.");
|
||||
PrintAndLogEx(NORMAL, " invert : 1 for invert output");
|
||||
PrintAndLogEx(NORMAL, " maxerror : Set maximum allowed errors, default = 100.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf indala demod"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf indala demod 32") " = demod a Indala tag from GraphBuffer using a clock of RF/32");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf indala demod 32 1") " = demod a Indala tag from GraphBuffer using a clock of RF/32 and inverting data");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf indala demod 64 1 0") " = demod a Indala tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_indala_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of Indala card with specified uid.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf indala sim [h] <u uid> <c cardnum>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " u <uid> : 64/224 UID");
|
||||
PrintAndLogEx(NORMAL, " c <cardnum> : Cardnumber for Heden 2L format (decimal)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf indala sim deadc0de"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
#define HEDEN2L_OFFSET 31
|
||||
static void encodeHeden2L(uint8_t *dest, uint32_t cardnumber) {
|
||||
|
||||
|
@ -145,7 +109,7 @@ static void decodeHeden2L(uint8_t *bits) {
|
|||
if (bits[offset + 7]) cardnumber += 16384;
|
||||
if (bits[offset + 23]) cardnumber += 32768;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "\tHeden-2L | " _GREEN_("%u"), cardnumber);
|
||||
PrintAndLogEx(SUCCESS, " Heden-2L | %u", cardnumber);
|
||||
}
|
||||
|
||||
// Indala 26 bit decode
|
||||
|
@ -187,7 +151,7 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
|
|||
uint64_t foo = uid2 & 0x7FFFFFFF;
|
||||
|
||||
if (DemodBufferLen == 64) {
|
||||
PrintAndLogEx(SUCCESS, "Indala - len %zu, Raw: %x%08x", DemodBufferLen, uid1, uid2);
|
||||
PrintAndLogEx(SUCCESS, "Indala (len %zu) Raw: " _GREEN_("%x%08x"), DemodBufferLen, uid1, uid2);
|
||||
|
||||
uint16_t p1 = 0;
|
||||
p1 |= DemodBuffer[32 + 3] << 8;
|
||||
|
@ -242,8 +206,8 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
|
|||
);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Possible de-scramble patterns");
|
||||
PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1);
|
||||
PrintAndLogEx(SUCCESS, "\tInternal ID | %" PRIu64, foo);
|
||||
PrintAndLogEx(SUCCESS, " Printed | __%04d__ [0x%X]", p1, p1);
|
||||
PrintAndLogEx(SUCCESS, " Internal ID | %" PRIu64, foo);
|
||||
decodeHeden2L(DemodBuffer);
|
||||
|
||||
} else {
|
||||
|
@ -254,7 +218,7 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
|
|||
uint32_t uid7 = bytebits_to_byte(DemodBuffer + 192, 32);
|
||||
PrintAndLogEx(
|
||||
SUCCESS
|
||||
, "Indala - len %zu, Raw: %x%08x%08x%08x%08x%08x%08x"
|
||||
, "Indala (len %zu) Raw: " _GREEN_("%x%08x%08x%08x%08x%08x%08x")
|
||||
, DemodBufferLen
|
||||
, uid1
|
||||
, uid2
|
||||
|
@ -279,28 +243,55 @@ int demodIndala(bool verbose) {
|
|||
|
||||
static int CmdIndalaDemod(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_lf_indala_demod();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf indala demod",
|
||||
"Tries to psk demodulate the graphbuffer as Indala",
|
||||
"lf indala demod\n"
|
||||
"lf indala demod --clock 32 -> demod a Indala tag from GraphBuffer using a clock of RF/32\n"
|
||||
"lf indala demod --clock 32 -i -> demod a Indala tag from GraphBuffer using a clock of RF/32 and inverting data\n"
|
||||
"lf indala demod --clock 64 -i --maxerror 0 -> demod a Indala tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"
|
||||
);
|
||||
|
||||
int clk = 32, invert = 0, maxErr = 100;
|
||||
if (strlen(Cmd) > 0) {
|
||||
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr);
|
||||
}
|
||||
if (clk == 1) {
|
||||
invert = 1;
|
||||
clk = 0;
|
||||
}
|
||||
if (invert != 0 && invert != 1) {
|
||||
PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
return demodIndalaEx(clk, invert, maxErr, true);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0(NULL, "clock", "<dec>", "optional - set clock (as integer), if not set, autodetect."),
|
||||
arg_int0(NULL, "maxerr", "<dec>", "optional - set maximum allowed errors, default = 100"),
|
||||
arg_lit0("i", "invert", "optional - invert output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
uint32_t clk = arg_get_u32_def(ctx, 1, 32);
|
||||
uint32_t max_err = arg_get_u32_def(ctx, 2, 100);
|
||||
bool invert = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
return demodIndalaEx(clk, invert, max_err, true);
|
||||
}
|
||||
|
||||
// older alternative indala demodulate (has some positives and negatives)
|
||||
// returns false positives more often - but runs against more sets of samples
|
||||
// poor psk signal can be difficult to demod this approach might succeed when the other fails
|
||||
// but the other appears to currently be more accurate than this approach most of the time.
|
||||
static int CmdIndalaDemodAlt(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf indala altdemod",
|
||||
"Tries to psk demodulate the graphbuffer as Indala\n"
|
||||
"This is uses a alternative way to demodulate and was used from the beginning in the Pm3 client.\n"
|
||||
"It's now considered obsolete but remains because it has sometimes its advantages.",
|
||||
"lf indala altdemod\n"
|
||||
"lf indala altdemod --long -> demod a Indala tag from GraphBuffer as 224 bit long format"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("l", "long", "optional - demod as 224b long format"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool is_long = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
|
||||
int state = -1;
|
||||
int count = 0;
|
||||
|
@ -361,7 +352,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
|
|||
|
||||
// Finding the start of a UID
|
||||
int uidlen, long_wait;
|
||||
if (strcmp(Cmd, "224") == 0) {
|
||||
if (is_long) {
|
||||
uidlen = 224;
|
||||
long_wait = 30;
|
||||
} else {
|
||||
|
@ -499,40 +490,91 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
|
|||
}
|
||||
|
||||
// this read is the "normal" read, which download lf signal and tries to demod here.
|
||||
static int CmdIndalaRead(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_lf_indala_demod();
|
||||
static int CmdIndalaReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf indala reader",
|
||||
"read a Indala tag",
|
||||
"lf indala reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
int clk = 32, invert = 0, maxErr = 100;
|
||||
if (strlen(Cmd) > 0) {
|
||||
sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0(NULL, "clock", "<dec>", "optional - set clock (as integer), if not set, autodetect."),
|
||||
arg_int0(NULL, "maxerr", "<dec>", "optional - set maximum allowed errors, default = 100"),
|
||||
arg_lit0("i", "invert", "optional - invert output"),
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
uint32_t clk = arg_get_u32_def(ctx, 1, 32);
|
||||
uint32_t max_err = arg_get_u32_def(ctx, 2, 100);
|
||||
bool invert = arg_get_lit(ctx, 3);
|
||||
bool cm = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
lf_read(false, 30000);
|
||||
return demodIndalaEx(clk, invert, maxErr, true);
|
||||
|
||||
do {
|
||||
lf_read(false, 30000);
|
||||
demodIndalaEx(clk, invert, max_err, !cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdIndalaSim(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_indala_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf indala sim",
|
||||
"Enables simulation of Indala card with specified facility-code and card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf indala sim --heden 888\n"
|
||||
"lf indala sim --raw a0000000a0002021\n"
|
||||
"lf indala sim --raw 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("r", "raw", "<hex>", "raw bytes"),
|
||||
arg_int0(NULL, "heden", "<decimal>", "Cardnumber for Heden 2L format"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
// raw param
|
||||
int raw_len = 0;
|
||||
uint8_t raw[(7 * 4) + 1 ];
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
bool is_long_uid = (raw_len == 28);
|
||||
|
||||
int32_t cardnumber;
|
||||
bool got_cn = false;
|
||||
if (is_long_uid == false) {
|
||||
|
||||
// Heden param
|
||||
cardnumber = arg_get_int_def(ctx, 2, -1);
|
||||
got_cn = (cardnumber != -1);
|
||||
}
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (got_cn) {
|
||||
encodeHeden2L(raw, cardnumber);
|
||||
raw_len = 8;
|
||||
}
|
||||
|
||||
// convert to binarray
|
||||
uint8_t bs[224];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
|
||||
// uid
|
||||
uint8_t hexuid[100];
|
||||
int len = 0;
|
||||
param_gethex_ex(Cmd, 0, hexuid, &len);
|
||||
|
||||
if (len > 28)
|
||||
return usage_lf_indala_sim();
|
||||
|
||||
// convert to binarray
|
||||
uint8_t counter = 223;
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
for (uint8_t i = 0; i < raw_len; i++) {
|
||||
uint8_t tmp = raw[i];
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
bs[counter--] = hexuid[i] & 1;
|
||||
hexuid[i] >>= 1;
|
||||
bs[counter--] = tmp & 1;
|
||||
tmp >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,7 +582,10 @@ static int CmdIndalaSim(const char *Cmd) {
|
|||
// It has to send either 64bits (8bytes) or 224bits (28bytes). Zero padding needed if not.
|
||||
// lf simpsk 1 c 32 r 2 d 0102030405060708
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Indala UID: %s", sprint_hex(hexuid, len));
|
||||
PrintAndLogEx(SUCCESS, "Simulating " _YELLOW_("%s") " Indala raw " _YELLOW_("%s")
|
||||
, (is_long_uid) ? "224b" : "64b"
|
||||
, sprint_hex_inrow(raw, raw_len)
|
||||
);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
|
||||
|
||||
// indala PSK, clock 32, carrier 0
|
||||
|
@ -550,8 +595,6 @@ static int CmdIndalaSim(const char *Cmd) {
|
|||
payload->clock = 32;
|
||||
memcpy(payload->data, bs, sizeof(bs));
|
||||
|
||||
PrintAndLogEx(INFO, "Simulating");
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs));
|
||||
free(payload);
|
||||
|
@ -568,39 +611,37 @@ static int CmdIndalaSim(const char *Cmd) {
|
|||
static int CmdIndalaClone(const char *Cmd) {
|
||||
|
||||
int32_t cardnumber;
|
||||
uint32_t blocks[8] = {0};
|
||||
uint8_t max = 0;
|
||||
uint8_t fc = 0;
|
||||
uint16_t cn = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf indala clone",
|
||||
"clone INDALA UID to T55x7 or Q5/T5555 tag",
|
||||
"clone Indala UID to T55x7 or Q5/T5555 tag\n"
|
||||
_RED_("\nWarning, encoding with FC/CN doesn't always work"),
|
||||
"lf indala clone --heden 888\n"
|
||||
"lf indala clone --fc 123 --cn 1337\n"
|
||||
"lf indala clone -r a0000000a0002021\n"
|
||||
"lf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
|
||||
"lf indala clone -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("l", "long", "optional - long UID 224 bits"),
|
||||
arg_int0("c", "heden", "<decimal>", "Cardnumber for Heden 2L format"),
|
||||
arg_strx0("r", "raw", "<hex>", "raw bytes"),
|
||||
arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_int0(NULL, "fc", "<decimal>", "Facility Code (26 bit format)"),
|
||||
arg_int0(NULL, "cn", "<decimal>", "Cardnumber (26 bit format)"),
|
||||
arg_strx0("r", "raw", "<hex>", "raw bytes"),
|
||||
arg_int0(NULL, "heden", "<decimal>", "Cardnumber for Heden 2L format"),
|
||||
arg_int0(NULL, "fc", "<decimal>", "Facility Code (26 bit H10301 format)"),
|
||||
arg_int0(NULL, "cn", "<decimal>", "Cardnumber (26 bit H10301 format)"),
|
||||
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);
|
||||
|
||||
bool is_long_uid = arg_get_lit(ctx, 1);
|
||||
|
||||
// raw param
|
||||
int datalen = 0;
|
||||
uint8_t data[(7 * 4) + 1 ];
|
||||
CLIGetHexWithReturn(ctx, 3, data, &datalen);
|
||||
int raw_len = 0;
|
||||
uint8_t raw[(7 * 4) + 1];
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
bool is_t5555 = arg_get_lit(ctx, 4);
|
||||
bool is_long_uid = (raw_len == 28);
|
||||
bool q5 = arg_get_lit(ctx, 5);
|
||||
bool em = arg_get_lit(ctx, 6);
|
||||
|
||||
bool got_cn = false, got_26 = false;
|
||||
if (is_long_uid == false) {
|
||||
|
@ -610,43 +651,59 @@ static int CmdIndalaClone(const char *Cmd) {
|
|||
got_cn = (cardnumber != -1);
|
||||
|
||||
// 26b FC/CN param
|
||||
fc = arg_get_int_def(ctx, 5, 0);
|
||||
cn = arg_get_int_def(ctx, 6, 0);
|
||||
fc = arg_get_int_def(ctx, 3, 0);
|
||||
cn = arg_get_int_def(ctx, 4, 0);
|
||||
got_26 = (fc != 0 && cn != 0);
|
||||
}
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(INFO, "Target chip " _YELLOW_("%s"), (is_t5555) ? "Q5/T5555" : "T55x7");
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t max = 0;
|
||||
uint32_t blocks[8] = {0};
|
||||
char cardtype[16] = {"T55x7"};
|
||||
|
||||
if (is_long_uid) {
|
||||
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT);
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT);
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
if (em) {
|
||||
blocks[0] = EM4305_INDALA_224_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[1] = bytes_to_num(raw, 4);
|
||||
blocks[2] = bytes_to_num(raw + 4, 4);
|
||||
blocks[3] = bytes_to_num(raw + 8, 4);
|
||||
blocks[4] = bytes_to_num(raw + 12, 4);
|
||||
blocks[5] = bytes_to_num(raw + 16, 4);
|
||||
blocks[6] = bytes_to_num(raw + 20, 4);
|
||||
blocks[7] = bytes_to_num(raw + 24, 4);
|
||||
max = 8;
|
||||
|
||||
// 224 BIT UID
|
||||
// config for Indala (RF/32;PSK2 with RF/2;Maxblock=7)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag");
|
||||
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit to " _YELLOW_("%s") " raw " _GREEN_("%s")
|
||||
, cardtype
|
||||
, sprint_hex_inrow(raw, raw_len)
|
||||
);
|
||||
|
||||
if (is_t5555)
|
||||
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT);
|
||||
else
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT);
|
||||
|
||||
blocks[1] = bytes_to_num(data, 4);
|
||||
blocks[2] = bytes_to_num(data + 4, 4);
|
||||
blocks[3] = bytes_to_num(data + 8, 4);
|
||||
blocks[4] = bytes_to_num(data + 12, 4);
|
||||
blocks[5] = bytes_to_num(data + 16, 4);
|
||||
blocks[6] = bytes_to_num(data + 20, 4);
|
||||
blocks[7] = bytes_to_num(data + 24, 4);
|
||||
max = 8;
|
||||
} else {
|
||||
// 64 BIT UID
|
||||
if (got_cn) {
|
||||
PrintAndLogEx(INFO, "Using Indala HEDEN cardnumber %u", cardnumber);
|
||||
encodeHeden2L(data, cardnumber);
|
||||
datalen = 8;
|
||||
encodeHeden2L(raw, cardnumber);
|
||||
raw_len = 8;
|
||||
} else if (got_26) {
|
||||
|
||||
PrintAndLogEx(INFO, "Using Indala 26b FC %u CN %u", fc, cn);
|
||||
PrintAndLogEx(INFO, "Using Indala 26b FC " _GREEN_("%u") " CN " _GREEN_("%u"), fc, cn);
|
||||
|
||||
// Used with the 26bit FC/CSN
|
||||
uint8_t *bits = calloc(INDALA_ARR_LEN, sizeof(uint8_t));
|
||||
|
@ -661,45 +718,60 @@ static int CmdIndalaClone(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
data[0] = bytebits_to_byte(bits, 8);
|
||||
data[1] = bytebits_to_byte(bits + 8, 8);
|
||||
data[2] = bytebits_to_byte(bits + 16, 8);
|
||||
data[3] = bytebits_to_byte(bits + 24, 8);
|
||||
data[4] = bytebits_to_byte(bits + 32, 8);
|
||||
data[5] = bytebits_to_byte(bits + 40, 8);
|
||||
data[6] = bytebits_to_byte(bits + 48, 8);
|
||||
data[7] = bytebits_to_byte(bits + 56, 8);
|
||||
datalen = 8;
|
||||
raw[0] = bytebits_to_byte(bits, 8);
|
||||
raw[1] = bytebits_to_byte(bits + 8, 8);
|
||||
raw[2] = bytebits_to_byte(bits + 16, 8);
|
||||
raw[3] = bytebits_to_byte(bits + 24, 8);
|
||||
raw[4] = bytebits_to_byte(bits + 32, 8);
|
||||
raw[5] = bytebits_to_byte(bits + 40, 8);
|
||||
raw[6] = bytebits_to_byte(bits + 48, 8);
|
||||
raw[7] = bytebits_to_byte(bits + 56, 8);
|
||||
raw_len = 8;
|
||||
|
||||
free(bits);
|
||||
}
|
||||
|
||||
// config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag");
|
||||
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
|
||||
|
||||
if (is_t5555)
|
||||
if (q5) {
|
||||
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);
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
blocks[1] = bytes_to_num(data, 4);
|
||||
blocks[2] = bytes_to_num(data + 4, 4);
|
||||
if (em) {
|
||||
blocks[0] = EM4305_INDALA_64_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[1] = bytes_to_num(raw, 4);
|
||||
blocks[2] = bytes_to_num(raw + 4, 4);
|
||||
max = 3;
|
||||
|
||||
// config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit to " _YELLOW_("%s") " raw " _GREEN_("%s")
|
||||
, cardtype
|
||||
, sprint_hex_inrow(raw, raw_len)
|
||||
);
|
||||
}
|
||||
|
||||
print_blocks(blocks, max);
|
||||
int res = clone_t55xx_tag(blocks, max);
|
||||
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf indala read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf indala reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdIndalaDemod, AlwaysAvailable, "demodulate an indala tag (PSK1) from GraphBuffer"},
|
||||
{"altdemod", CmdIndalaDemodAlt, AlwaysAvailable, "alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
|
||||
{"read", CmdIndalaRead, IfPm3Lf, "read an Indala Prox tag from the antenna"},
|
||||
{"demod", CmdIndalaDemod, AlwaysAvailable, "demodulate an Indala tag (PSK1) from GraphBuffer"},
|
||||
{"altdemod", CmdIndalaDemodAlt, AlwaysAvailable, "alternative method to demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
|
||||
{"reader", CmdIndalaReader, IfPm3Lf, "read an Indala tag from the antenna"},
|
||||
{"clone", CmdIndalaClone, IfPm3Lf, "clone Indala tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdIndalaSim, IfPm3Lf, "simulate Indala tag"},
|
||||
{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,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
|
@ -9,78 +10,41 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfio.h"
|
||||
|
||||
#include <stdio.h> // sscanf
|
||||
#include <stdio.h> // sscanf
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" //ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "graph.h"
|
||||
#include "cmdlf.h"
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "lfdemod.h" // parityTest, bitbytes_to_byte
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "ui.h" // PrintAndLog
|
||||
#include "lfdemod.h" // parityTest, bitbytes_to_byte
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "cmddata.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 usage_lf_io_watch(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables IOProx compatible reader mode printing details of scanned tags.");
|
||||
PrintAndLogEx(NORMAL, "By default, values are printed and logged until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf io watch");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf io watch"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_io_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of IOProx card with specified facility-code and card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf io sim [h] <version> <facility-code> <card-number>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <version> : 8bit version (" _YELLOW_("decimal") ")");
|
||||
PrintAndLogEx(NORMAL, " <facility-code> : 8bit value facility code (" _YELLOW_("hex") ")");
|
||||
PrintAndLogEx(NORMAL, " <card number> : 16bit value card number (" _YELLOW_("decimal") ")");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf io sim 01 101 1337"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_io_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables cloning of IOProx card with specified facility-code and card number onto T55x7 or Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "The T55x7 must be on the antenna when issuing this command. T55x7 blocks are calculated and printed in the process.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf io clone [h] <version> <facility-code> <card-number> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <version> : 8bit version (" _YELLOW_("decimal") ")");
|
||||
PrintAndLogEx(NORMAL, " <facility-code> : 8bit value facility code (" _YELLOW_("hex") ")");
|
||||
PrintAndLogEx(NORMAL, " <card number> : 16bit value card number (" _YELLOW_("decimal") ")");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : optional - specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf io clone 01 101 1337"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// this read loops on device side.
|
||||
// uses the demod in lfops.c
|
||||
static int CmdIOProxWatch(const char *Cmd) {
|
||||
uint8_t c = tolower(param_getchar(Cmd, 0));
|
||||
if (c == 'h') return usage_lf_io_watch();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf io watch",
|
||||
"Enables ioProx compatible reader mode printing details.\n"
|
||||
"By default, values are printed and logged until the button is pressed or another USB command is issued.",
|
||||
"lf io watch"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Watching for IO Prox cards - place tag on antenna");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
||||
|
@ -92,9 +56,8 @@ static int CmdIOProxWatch(const char *Cmd) {
|
|||
return resp.status;
|
||||
}
|
||||
|
||||
//by marshmellow
|
||||
//IO-Prox demod - FSK RF/64 with preamble of 000000001
|
||||
//print ioprox ID and some format details
|
||||
//print ioProx ID and some format details
|
||||
int demodIOProx(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
int idx = 0, retval = PM3_SUCCESS;
|
||||
|
@ -192,43 +155,85 @@ int demodIOProx(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdIOProxDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf io demod",
|
||||
"Try to find ioProx preamble, if found decode / descramble data",
|
||||
"lf io demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodIOProx(true);
|
||||
}
|
||||
// this read is the "normal" read, which download lf signal and tries to demod here.
|
||||
static int CmdIOProxRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 12000);
|
||||
return demodIOProx(true);
|
||||
static int CmdIOProxReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf io reader",
|
||||
"read a ioProx tag",
|
||||
"lf io 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);
|
||||
demodIOProx(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdIOProxSim(const char *Cmd) {
|
||||
uint16_t cn = 0;
|
||||
uint8_t version = 0, fc = 0;
|
||||
uint8_t bs[64];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_io_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf io sim",
|
||||
"Enables simulation of ioProx card with specified facility-code and card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf io sim --vn 1 --fc 101 --cn 1337"
|
||||
);
|
||||
|
||||
version = param_get8(Cmd, 0);
|
||||
fc = param_get8ex(Cmd, 1, 0, 16);
|
||||
cn = param_get32ex(Cmd, 2, 0, 10);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "vn", "<dec>", "8bit version"),
|
||||
arg_u64_1(NULL, "fc", "<dec>", "8bit facility code"),
|
||||
arg_u64_1(NULL, "cn", "<dec>", "16bit card number"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
if (!version || !fc || !cn) return usage_lf_io_sim();
|
||||
uint8_t version = arg_get_u32_def(ctx, 1, 0);
|
||||
uint8_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
uint16_t cn = arg_get_u32_def(ctx, 3, 0);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ((cn & 0xFFFF) != cn) {
|
||||
cn &= 0xFFFF;
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (IOProx): %u", cn);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (ioProx): %u", cn);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating IOProx version: %u FC: %u; CN: %u\n", version, fc, cn);
|
||||
PrintAndLogEx(SUCCESS, "Simulating ioProx version: " _YELLOW_("%u") " FC: " _YELLOW_("%u (0x%02x)") " CN: " _YELLOW_("%u"), version, fc, fc, cn);
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
|
||||
|
||||
uint8_t bs[64];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
|
||||
if (getIOProxBits(version, fc, cn, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
// IOProx uses: fcHigh: 10, fcLow: 8, clk: 64, invert: 1
|
||||
// ioProx uses: fcHigh: 10, fcLow: 8, clk: 64, invert: 1
|
||||
// arg1 --- fcHigh<<8 + fcLow
|
||||
// arg2 --- Invert and clk setting
|
||||
// size --- 64 bits == 8 bytes
|
||||
|
@ -242,10 +247,8 @@ static int CmdIOProxSim(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_FSK_SIMULATE, (uint8_t *)payload, sizeof(lf_fsksim_t) + sizeof(bs));
|
||||
free(payload);
|
||||
|
||||
PacketResponseNG resp;
|
||||
WaitForResponse(CMD_LF_FSK_SIMULATE, &resp);
|
||||
|
||||
PrintAndLogEx(INFO, "Done");
|
||||
if (resp.status != PM3_EOPABORTED)
|
||||
return resp.status;
|
||||
|
@ -254,23 +257,42 @@ static int CmdIOProxSim(const char *Cmd) {
|
|||
|
||||
static int CmdIOProxClone(const char *Cmd) {
|
||||
|
||||
uint16_t cn = 0;
|
||||
uint8_t version = 0, fc = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf io clone",
|
||||
"Enables simulation of ioProx card with specified facility-code and card number.\n"
|
||||
"Tag must be on the antenna when issuing this command.",
|
||||
"lf io clone --vn 1 --fc 101 --cn 1337"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "vn", "<dec>", "8bit version"),
|
||||
arg_u64_1(NULL, "fc", "<dec>", "8bit facility code"),
|
||||
arg_u64_1(NULL, "cn", "<dec>", "16bit 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);
|
||||
|
||||
uint8_t version = arg_get_u32_def(ctx, 1, 0);
|
||||
uint8_t fc = arg_get_u32_def(ctx, 2, 0);
|
||||
uint16_t cn = arg_get_u32_def(ctx, 3, 0);
|
||||
bool q5 = arg_get_lit(ctx, 4);
|
||||
bool em = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t bits[64];
|
||||
memset(bits, 0, sizeof(bits));
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_io_clone();
|
||||
|
||||
version = param_get8(Cmd, 0);
|
||||
fc = param_get8ex(Cmd, 1, 0, 16);
|
||||
cn = param_get32ex(Cmd, 2, 0, 10);
|
||||
|
||||
if (!version || !fc || !cn) return usage_lf_io_clone();
|
||||
|
||||
if ((cn & 0xFFFF) != cn) {
|
||||
cn &= 0xFFFF;
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (IOProx): %u", cn);
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (ioProx): %u", cn);
|
||||
}
|
||||
|
||||
if (getIOProxBits(version, fc, cn, bits) != PM3_SUCCESS) {
|
||||
|
@ -279,30 +301,49 @@ static int CmdIOProxClone(const char *Cmd) {
|
|||
}
|
||||
|
||||
uint32_t blocks[3] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0};
|
||||
|
||||
bool q5 = tolower(param_getchar(Cmd, 3) == 'q');
|
||||
if (q5)
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_IOPROX_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[1] = bytebits_to_byte(bits, 32);
|
||||
blocks[2] = bytebits_to_byte(bits + 32, 32);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone IOProx to " _YELLOW_("%s") " with Version: %u FC: %u, CN: %u", (q5) ? "Q5/T5555" : "T55x7", version, fc, cn);
|
||||
PrintAndLogEx(INFO, "Preparing to clone ioProx to " _YELLOW_("%s") " with Version: " _GREEN_("%u") " FC: " _GREEN_("%u (0x%02x)") " CN: " _GREEN_("%u")
|
||||
, cardtype
|
||||
, version
|
||||
, fc
|
||||
, fc
|
||||
, cn
|
||||
);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf io read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf io reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdIOProxDemod, AlwaysAvailable, "demodulate an IOProx tag from the GraphBuffer"},
|
||||
{"read", CmdIOProxRead, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdIOProxClone, IfPm3Lf, "clone IOProx tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdIOProxSim, IfPm3Lf, "simulate IOProx tag"},
|
||||
{"watch", CmdIOProxWatch, IfPm3Lf, "continuously watch for cards. Reader mode"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdIOProxDemod, AlwaysAvailable, "demodulate an ioProx tag from the GraphBuffer"},
|
||||
{"reader", CmdIOProxReader, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdIOProxClone, IfPm3Lf, "clone ioProx tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdIOProxSim, IfPm3Lf, "simulate ioProx tag"},
|
||||
{"watch", CmdIOProxWatch, IfPm3Lf, "continuously watch for cards. Reader mode"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,55 +9,26 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfjablotron.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
#define JABLOTRON_ARR_LEN 64
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_jablotron_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Jablotron tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf jablotron clone [h] <card ID> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <card ID> : jablotron card ID");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf jablotron clone 112233"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_jablotron_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of jablotron 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 jablotron sim [h] <card ID>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <card ID> : jablotron card ID");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf jablotron sim 112233"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t jablontron_chksum(uint8_t *bits) {
|
||||
uint8_t chksum = 0;
|
||||
for (int i = 16; i < 56; i += 8) {
|
||||
|
@ -134,30 +105,97 @@ int demodJablotron(bool verbose) {
|
|||
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdJablotronDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf jablotron demod",
|
||||
"Try to find Jablotron preamble, if found decode / descramble data",
|
||||
"lf jablotron demod\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodJablotron(true);
|
||||
}
|
||||
|
||||
static int CmdJablotronRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 16000);
|
||||
return demodJablotron(true);
|
||||
static int CmdJablotronReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf jablotron reader",
|
||||
"read a jablotron tag",
|
||||
"lf jablotron 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 16000);
|
||||
demodJablotron(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdJablotronClone(const char *Cmd) {
|
||||
|
||||
uint64_t fullcode = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf jablotron clone",
|
||||
"clone a Jablotron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf jablotron clone --cn 01b669\n"
|
||||
"lf jablotron clone --q5 --cn 01b669 -> encode for Q5/T5555 tag\n"
|
||||
"lf jablotron clone --em --cn 01b669 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1(NULL, "cn", "<hex>", "Jablotron card ID - 5 bytes max"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int raw_len = 0;
|
||||
uint8_t raw[5] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[3] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0};
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_clone();
|
||||
|
||||
fullcode = param_get64ex(Cmd, 0, 0, 16);
|
||||
|
||||
//Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 1)) == 'q';
|
||||
if (q5)
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_JABLOTRON_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
|
||||
uint64_t fullcode = bytes_to_num(raw, raw_len);
|
||||
|
||||
// clearing the topbit needed for the preambl detection.
|
||||
if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
|
||||
|
@ -181,19 +219,43 @@ static int CmdJablotronClone(const char *Cmd) {
|
|||
|
||||
free(bits);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Jablotron to " _YELLOW_("%s") " with FullCode: %"PRIx64, (q5) ? "Q5/T5555" : "T55x7", fullcode);
|
||||
uint64_t id = getJablontronCardId(fullcode);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Jablotron to " _YELLOW_("%s") " with FullCode: " _GREEN_("%"PRIx64)" id: " _GREEN_("%"PRIx64), cardtype, fullcode, id);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf jablotron reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdJablotronSim(const char *Cmd) {
|
||||
uint64_t fullcode = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf jablotron sim",
|
||||
"Enables simulation of jablotron card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf jablotron sim --cn 01b669"
|
||||
);
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_sim();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1(NULL, "cn", "<hex>", "Jablotron card ID - 5 bytes max"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
fullcode = param_get64ex(Cmd, 0, 0, 16);
|
||||
int raw_len = 0;
|
||||
uint8_t raw[5] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint64_t fullcode = bytes_to_num(raw, raw_len);
|
||||
|
||||
// clearing the topbit needed for the preambl detection.
|
||||
if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
|
||||
|
@ -201,7 +263,7 @@ static int CmdJablotronSim(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: %"PRIx64, fullcode);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: " _YELLOW_("%"PRIx64), fullcode);
|
||||
|
||||
uint8_t *bs = calloc(JABLOTRON_ARR_LEN, sizeof(uint8_t));
|
||||
if (bs == NULL) {
|
||||
|
@ -236,7 +298,7 @@ static int CmdJablotronSim(const char *Cmd) {
|
|||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdJablotronDemod, AlwaysAvailable, "Demodulate an Jablotron tag from the GraphBuffer"},
|
||||
{"read", CmdJablotronRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"reader", CmdJablotronReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdJablotronClone, IfPm3Lf, "clone jablotron tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdJablotronSim, IfPm3Lf, "simulate jablotron tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
|
|
@ -175,72 +175,75 @@ int demodKeri(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdKeriDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
return demodKeri(true);
|
||||
}
|
||||
|
||||
static int CmdKeriRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 10000);
|
||||
return demodKeri(true);
|
||||
}
|
||||
|
||||
static int CmdKeriClone(const char *Cmd) {
|
||||
|
||||
bool q5 = false, em = false;
|
||||
|
||||
uint8_t keritype[2] = {'i'}; // default to internalid
|
||||
int typeLen = 0;
|
||||
uint32_t fc = 0;
|
||||
uint32_t cid = 0;
|
||||
uint32_t internalid = 0;
|
||||
uint32_t blocks[3] = {
|
||||
T55x7_TESTMODE_DISABLED |
|
||||
T55x7_X_MODE |
|
||||
T55x7_MODULATION_PSK1 |
|
||||
T55x7_PSKCF_RF_2 |
|
||||
2 << T55x7_MAXBLOCK_SHIFT,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
// dynamic bitrate used
|
||||
blocks[0] |= 0xF << 18;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf keri clone",
|
||||
"clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag",
|
||||
"lf keri clone -t i --id 12345\n"
|
||||
"lf keri clone -t m --fc 6 --id 12345\n");
|
||||
CLIParserInit(&ctx, "lf keri demod",
|
||||
"Try to find KERI preamble, if found decode / descramble data",
|
||||
"lf keri demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodKeri(true);
|
||||
}
|
||||
|
||||
static int CmdKeriReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf keri reader",
|
||||
"read a keri tag",
|
||||
"lf keri reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 10000);
|
||||
demodKeri(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdKeriClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf keri clone",
|
||||
"clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag",
|
||||
"lf keri clone -t i --cn 12345 -> Internal ID\n"
|
||||
"lf keri clone -t m --fc 6 --cn 12345 -> MS ID\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("q", "q5", "specify writing to Q5/T5555 tag"),
|
||||
arg_str0("t", "type", "<m|i>", "Type m - MS, i - Internal ID"),
|
||||
arg_int0(NULL, "fc", "<dec>", "Facility Code"),
|
||||
arg_int1(NULL, "id", "<dec>", "Keri ID"),
|
||||
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"),
|
||||
arg_int1(NULL, "cn", "<dec>", "KERI card ID"),
|
||||
arg_lit0(NULL, "q5", "specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
if (arg_get_lit(ctx, 1)) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
q5 = true;
|
||||
}
|
||||
if (arg_get_lit(ctx, 5)) {
|
||||
blocks[0] = EM4305_KERI_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
em = true;
|
||||
}
|
||||
uint8_t keritype[2] = {'i'}; // default to internalid
|
||||
int typeLen = sizeof(keritype);
|
||||
CLIGetStrWithReturn(ctx, 1, keritype, &typeLen);
|
||||
|
||||
typeLen = sizeof(keritype);
|
||||
CLIGetStrWithReturn(ctx, 2, keritype, &typeLen);
|
||||
|
||||
fc = arg_get_int_def(ctx, 3, 0);
|
||||
cid = arg_get_int_def(ctx, 4, 0);
|
||||
uint32_t fc = arg_get_int_def(ctx, 2, 0);
|
||||
uint32_t cid = arg_get_int_def(ctx, 3, 0);
|
||||
bool q5 = arg_get_lit(ctx, 4);
|
||||
bool em = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
|
@ -249,6 +252,7 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
}
|
||||
|
||||
// Setup card data/build internal id
|
||||
uint32_t internalid = 0;
|
||||
switch (keritype[0]) {
|
||||
case 'i' : // Internal ID
|
||||
// MSB is ONE
|
||||
|
@ -262,6 +266,24 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[3];
|
||||
blocks[0] = T55x7_TESTMODE_DISABLED | T55x7_X_MODE | T55x7_MODULATION_PSK1 | T55x7_PSKCF_RF_2 | 2 << T55x7_MAXBLOCK_SHIFT;
|
||||
// dynamic bitrate used
|
||||
blocks[0] |= 0xF << 18;
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
if (em) {
|
||||
blocks[0] = EM4305_KERI_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
|
||||
// Prepare and write to card
|
||||
// 3 LSB is ONE
|
||||
uint64_t data = ((uint64_t)internalid << 3) + 7;
|
||||
|
@ -288,19 +310,18 @@ static int CmdKeriSim(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf keri sim",
|
||||
"Enables simulation of KERI card with card number.",
|
||||
"lf keri sim --id 112233"
|
||||
"Enables simulation of KERI card with internal ID.\n"
|
||||
"You supply a KERI card id and it will converted to a KERI internal ID.",
|
||||
"lf keri sim --cn 112233"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int1(NULL, "id", "<dec>", "KERI Internal ID"),
|
||||
arg_u64_1(NULL, "id", "<dec>", "KERI card ID"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint64_t internalid = arg_get_int_def(ctx, 1, 0);
|
||||
|
||||
uint64_t internalid = arg_get_u64_def(ctx, 1, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
internalid |= 0x80000000;
|
||||
|
@ -314,7 +335,7 @@ static int CmdKeriSim(const char *Cmd) {
|
|||
bs[j++] = ((internalid >> i) & 1);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating KERI - Internal Id: %" PRIu64, internalid);
|
||||
PrintAndLogEx(SUCCESS, "Simulating KERI - Internal Id " _YELLOW_("%" PRIu64), internalid);
|
||||
|
||||
lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs));
|
||||
payload->carrier = 2;
|
||||
|
@ -322,8 +343,6 @@ static int CmdKeriSim(const char *Cmd) {
|
|||
payload->clock = 32;
|
||||
memcpy(payload->data, bs, sizeof(bs));
|
||||
|
||||
PrintAndLogEx(INFO, "Simulating");
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs));
|
||||
free(payload);
|
||||
|
@ -338,11 +357,11 @@ static int CmdKeriSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"},
|
||||
{"read", CmdKeriRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"},
|
||||
{"reader", CmdKeriReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,22 +9,20 @@
|
|||
// PSK1, RF/32, 64 bits long, at 74 kHz
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfmotorola.h"
|
||||
|
||||
#include <ctype.h> //tolower
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include <ctype.h> // tolower
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "common.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cmdlf.h" // cmdlfconfig
|
||||
#include "cliparser.h" // cli parse input
|
||||
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cmdlf.h" // cmdlfconfig
|
||||
#include "cliparser.h" // cli parse input
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -35,6 +33,7 @@ int demodMotorola(bool verbose) {
|
|||
PrintAndLogEx(DEBUG, "DEBUG: Error - Motorola: PSK Demod failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
size_t size = DemodBufferLen;
|
||||
int ans = detectMotorola(DemodBuffer, &size);
|
||||
if (ans < 0) {
|
||||
|
@ -118,13 +117,42 @@ int demodMotorola(bool verbose) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
//see PSKDemod for what args are accepted
|
||||
static int CmdMotorolaDemod(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf motorola demod",
|
||||
"Try to find Motorola preamble, if found decode / descramble data",
|
||||
"lf motorola demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
// Motorola Flexpass seem to work at 74 kHz
|
||||
// and take about 4400 samples to befor modulating
|
||||
sample_config sc = {
|
||||
|
@ -138,65 +166,104 @@ static int CmdMotorolaRead(const char *Cmd) {
|
|||
};
|
||||
lf_config(&sc);
|
||||
|
||||
// 64 * 32 * 2 * n-ish
|
||||
lf_read(false, 5000);
|
||||
int res;
|
||||
do {
|
||||
// 64 * 32 * 2 * n-ish
|
||||
lf_read(false, 5000);
|
||||
res = demodMotorola(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
// reset back to 125 kHz
|
||||
sc.divisor = LF_DIVISOR_125;
|
||||
sc.samples_to_skip = 0;
|
||||
lf_config(&sc);
|
||||
return demodMotorola(true);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdMotorolaClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[3] = {0};
|
||||
uint8_t data[8];
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf motorola clone",
|
||||
"clone Motorola UID to T55x7 or Q5/T5555 tag\n"
|
||||
"clone Motorola UID to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"defaults to 64 bit format",
|
||||
"lf motorola clone -r a0000000a0002021"
|
||||
"lf motorola clone --raw a0000000a0002021\n"
|
||||
"lf motorola clone --q5 --raw a0000000a0002021 -> encode for Q5/T5555 tag\n"
|
||||
"lf motorola clone --em --raw a0000000a0002021 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx1("r", "raw", "<hex>", "raw bytes"),
|
||||
arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_strx1("r", "raw", "<hex>", "raw hex bytes. 8 bytes"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIGetHexWithReturn(ctx, 1, data, &datalen);
|
||||
bool is_t5555 = arg_get_lit(ctx, 2);
|
||||
|
||||
int raw_len = 0;
|
||||
uint8_t raw[8];
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
//TODO add selection of chip for Q5 or T55x7
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Target chip " _YELLOW_("%s"), (is_t5555) ? "Q5/T5555" : "T55x7");
|
||||
//TODO add selection of chip for Q5 or T55x7
|
||||
uint32_t blocks[3] = {0};
|
||||
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_MOTOROLA_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[1] = bytes_to_num(raw, 4);
|
||||
blocks[2] = bytes_to_num(raw + 4, 4);
|
||||
|
||||
// config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag");
|
||||
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
|
||||
|
||||
if (is_t5555)
|
||||
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
else
|
||||
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
|
||||
|
||||
|
||||
blocks[1] = bytes_to_num(data, 4);
|
||||
blocks[2] = bytes_to_num(data + 4, 4);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit to " _YELLOW_("%s") " with raw " _GREEN_("%s")
|
||||
, cardtype
|
||||
, sprint_hex_inrow(raw, sizeof(raw))
|
||||
);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdMotorolaSim(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf motorola sim",
|
||||
"Enables simulation of Motorola card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf motorola sim"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// PSK sim.
|
||||
PrintAndLogEx(INFO, " PSK1 at 66 kHz... Interesting.");
|
||||
|
@ -205,11 +272,11 @@ static int CmdMotorolaSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdMotorolaDemod, AlwaysAvailable, "Demodulate an MOTOROLA tag from the GraphBuffer"},
|
||||
{"read", CmdMotorolaRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdMotorolaClone, IfPm3Lf, "clone MOTOROLA tag to T55x7"},
|
||||
{"sim", CmdMotorolaSim, IfPm3Lf, "simulate MOTOROLA tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdMotorolaDemod, AlwaysAvailable, "Demodulate an MOTOROLA tag from the GraphBuffer"},
|
||||
{"reader", CmdMotorolaReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdMotorolaClone, IfPm3Lf, "clone MOTOROLA tag to T55x7"},
|
||||
{"sim", CmdMotorolaSim, IfPm3Lf, "simulate MOTOROLA tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -266,5 +333,5 @@ int detectMotorola(uint8_t *dest, size_t *size) {
|
|||
}
|
||||
|
||||
int readMotorolaUid(void) {
|
||||
return (CmdMotorolaRead("") == PM3_SUCCESS);
|
||||
return (CmdMotorolaReader("") == PM3_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -11,10 +11,8 @@
|
|||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "crc16.h"
|
||||
|
@ -24,6 +22,9 @@
|
|||
#include "cmdlf.h"
|
||||
#include "lfdemod.h"
|
||||
#include "protocols.h"
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
#include "commonutil.h"
|
||||
|
||||
#define FIXED_71 0x71
|
||||
#define FIXED_40 0x40
|
||||
|
@ -32,60 +33,6 @@
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_nedap_gen(void) {
|
||||
PrintAndLogEx(NORMAL, "generate Nedap bitstream in DemodBuffer");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf nedap generate [h] [s <subtype>] c <code> i <id> [l]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " s <subtype> : optional, default=5");
|
||||
PrintAndLogEx(NORMAL, " c <code> : customerCode");
|
||||
PrintAndLogEx(NORMAL, " i <id> : ID (max 99999)");
|
||||
PrintAndLogEx(NORMAL, " l : optional - long (128), default to short (64)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nedap generate s 1 c 123 i 12345"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_nedap_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Nedap tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf nedap clone [h] [s <subtype>] c <code> i <id> [l] <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " s <subtype> : optional, default=5");
|
||||
PrintAndLogEx(NORMAL, " c <code> : customerCode");
|
||||
PrintAndLogEx(NORMAL, " i <id> : ID (max 99999)");
|
||||
PrintAndLogEx(NORMAL, " l : optional - long (128), default to short (64)");
|
||||
PrintAndLogEx(NORMAL, " Q5 : optional - specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nedap clone s 1 c 123 i 12345"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_nedap_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "simulate Nedap card.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf nedap sim [h] [s <subtype>] c <code> i <id> [l]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " s <subtype> : subtype, default=5");
|
||||
PrintAndLogEx(NORMAL, " c <code> : customerCode");
|
||||
PrintAndLogEx(NORMAL, " i <id> : ID (max 99999)");
|
||||
PrintAndLogEx(NORMAL, " l : long (128), default to short (64)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
// TODO proper example?
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf nedap sim s 1 c 7 i 1337"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
const uint8_t translateTable[10] = {8, 2, 1, 12, 4, 5, 10, 13, 0, 9};
|
||||
const uint8_t invTranslateTable[16] = {8, 2, 1, 0xff, 4, 5, 0xff, 0xff, 0, 9, 6, 0xff, 3, 7, 0xff, 0xff};
|
||||
const uint8_t preamble[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}; // zero inside
|
||||
|
@ -197,7 +144,14 @@ int demodNedap(bool verbose) {
|
|||
|
||||
badgeId = r1 * 10000 + r2 * 1000 + r3 * 100 + r4 * 10 + r5;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "NEDAP - Card: " _YELLOW_("%05u") " subtype: " _YELLOW_("%1u")" customer code: " _YELLOW_("%03x") ", Raw: " _YELLOW_("%s"), badgeId, subtype, customerCode, sprint_hex_inrow(data, size / 8));
|
||||
PrintAndLogEx(SUCCESS, "NEDAP (%s) - ID: " _YELLOW_("%05u") " subtype: " _YELLOW_("%1u")" customer code: " _YELLOW_("%u / 0x%03X") " Raw: " _YELLOW_("%s")
|
||||
, (size == 128) ? "128b" : "64b"
|
||||
, badgeId
|
||||
, subtype
|
||||
, customerCode
|
||||
, customerCode
|
||||
, sprint_hex_inrow(data, size / 8)
|
||||
);
|
||||
PrintAndLogEx(DEBUG, "Checksum (%s) 0x%04X", _GREEN_("ok"), checksum);
|
||||
|
||||
} else {
|
||||
|
@ -262,7 +216,18 @@ int demodNedap(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdLFNedapDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nedap demod",
|
||||
"Try to find Nedap preamble, if found decode / descramble data",
|
||||
"lf nedap demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodNedap(true);
|
||||
}
|
||||
/* Index map E E
|
||||
|
@ -309,10 +274,32 @@ lf t55xx wr b 4 d 4c0003ff
|
|||
|
||||
*/
|
||||
|
||||
static int CmdLFNedapRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 16000);
|
||||
return demodNedap(true);
|
||||
static int CmdLFNedapReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nedap reader",
|
||||
"read a Nedap tag",
|
||||
"lf nedap 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 16000);
|
||||
demodNedap(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void NedapGen(uint8_t subType, uint16_t customerCode, uint32_t id, bool isLong, uint8_t *data) { // 8 or 16
|
||||
|
@ -374,147 +361,182 @@ static void NedapGen(uint8_t subType, uint16_t customerCode, uint32_t id, bool i
|
|||
}
|
||||
}
|
||||
|
||||
static int (*usage_to_be_displayed)(void) = NULL;
|
||||
static int CmdLFNedapClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nedap clone",
|
||||
"clone a Nedap tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf nedap clone --st 1 --cc 101 --id 1337"
|
||||
);
|
||||
|
||||
static int CmdLfNedapGen(const char *Cmd) {
|
||||
uint8_t cmdp = 0, subType = 5, data[16], i, bin[128];
|
||||
uint16_t customerCode = 0;
|
||||
uint32_t id = 0;
|
||||
bool isLong = false, errors = false;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_0(NULL, "st", "<dec>", "optional - sub type (default 5)"),
|
||||
arg_u64_1(NULL, "cc", "<dec>", "customer code (0-4095)"),
|
||||
arg_u64_1(NULL, "id", "<dec>", "ID (0-99999)"),
|
||||
arg_lit0("l", "long", "optional - long (128), default to short (64)"),
|
||||
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 (*usage)(void) = usage_lf_nedap_gen;
|
||||
if (usage_to_be_displayed != NULL) {
|
||||
usage = usage_to_be_displayed;
|
||||
usage_to_be_displayed = NULL;
|
||||
uint8_t sub_type = arg_get_u32_def(ctx, 1, 5);
|
||||
uint16_t customer_code = arg_get_u32_def(ctx, 2, 0);
|
||||
uint32_t id = arg_get_u32_def(ctx, 3, 0);
|
||||
bool is_long = arg_get_lit(ctx, 4);
|
||||
bool q5 = arg_get_lit(ctx, 5);
|
||||
bool em = arg_get_lit(ctx, 6);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// Validations
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 's':
|
||||
subType = param_get8ex(Cmd, cmdp + 1, 5, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'c':
|
||||
customerCode = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'i':
|
||||
id = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'l':
|
||||
isLong = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'q':
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Validations
|
||||
if ((!customerCode) || (!id) || (subType > 0xF) || (customerCode > 0xFFF) || (id > 99999))
|
||||
errors = true;
|
||||
|
||||
if (errors || cmdp == 0) {
|
||||
usage();
|
||||
if (sub_type > 0xF) {
|
||||
PrintAndLogEx(FAILED, "out-of-range, valid subtype is between 0-15");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS,
|
||||
"Tag - subtype: %1u , customer code: %03x , ID: %05u | %s"
|
||||
, subType
|
||||
, customerCode
|
||||
if (customer_code > 0xFFF) {
|
||||
PrintAndLogEx(FAILED, "out-of-range, valid customer code is between 0-4095");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (id > 99999) {
|
||||
PrintAndLogEx(FAILED, "out-of-range, id max value is 99999");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "NEDAP (%s) - ID: " _GREEN_("%05u") " subtype: " _GREEN_("%1u") " customer code: " _GREEN_("%u / 0x%03X")
|
||||
, is_long ? "128b" : "64b"
|
||||
, id
|
||||
, isLong ? "(128b)" : "(64b)"
|
||||
, sub_type
|
||||
, customer_code
|
||||
, customer_code
|
||||
);
|
||||
|
||||
NedapGen(subType, customerCode, id, isLong, data);
|
||||
|
||||
for (i = 0; i < (isLong ? 16 : 8); i++)
|
||||
num_to_bytebits(data[i], 8, bin + i * 8);
|
||||
|
||||
setDemodBuff(bin, (isLong ? 128 : 64), 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFNedapClone(const char *Cmd) {
|
||||
uint8_t max;
|
||||
uint32_t blocks[5] = {0};
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_nedap_clone();
|
||||
|
||||
usage_to_be_displayed = usage_lf_nedap_clone;
|
||||
|
||||
int ret = CmdLfNedapGen(Cmd);
|
||||
if (ret != PM3_SUCCESS)
|
||||
return ret;
|
||||
|
||||
if ((DemodBufferLen != 128) && (DemodBufferLen != 64)) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
//NEDAP - compat mode, ASK/DIphase, data rate 64, 4 data blocks
|
||||
// DI-phase (CDP) T55x7_MODULATION_DIPHASE
|
||||
|
||||
if (DemodBufferLen == 64) {
|
||||
max = 3;
|
||||
blocks[0] = T55X7_NEDAP_64_CONFIG_BLOCK;
|
||||
} else {
|
||||
uint8_t max;
|
||||
uint32_t blocks[5] = {0};
|
||||
if (is_long) {
|
||||
max = 5;
|
||||
blocks[0] = T55X7_NEDAP_128_CONFIG_BLOCK;
|
||||
} else {
|
||||
max = 3;
|
||||
blocks[0] = T55X7_NEDAP_64_CONFIG_BLOCK;
|
||||
}
|
||||
bool q5 = (strstr(Cmd, "q") != NULL);
|
||||
char cardtype[16] = {"T55x7"};
|
||||
|
||||
// Q5
|
||||
if (q5) {
|
||||
if (DemodBufferLen == 64) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
} else {
|
||||
if (is_long) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 4 << T5555_MAXBLOCK_SHIFT;
|
||||
} else {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 1; i < max ; i++) {
|
||||
blocks[i] = bytebits_to_byte(DemodBuffer + ((i - 1) * 32), 32);
|
||||
// EM4305
|
||||
if (em) {
|
||||
if (is_long) {
|
||||
blocks[0] = EM4305_NEDAP_128_CONFIG_BLOCK;
|
||||
} else {
|
||||
blocks[0] = EM4305_NEDAP_64_CONFIG_BLOCK;
|
||||
}
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Preparing to clone NEDAP to " _YELLOW_("%s") " tag", (q5) ? "Q5/T5555" : "T55x7");
|
||||
// generate nedap bitstream
|
||||
uint8_t data[16];
|
||||
NedapGen(sub_type, customer_code, id, is_long, data);
|
||||
|
||||
for (uint8_t i = 1; i < max ; i++) {
|
||||
blocks[i] = bytes_to_num (data + ((i - 1) * 4), 4);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Preparing to clone NEDAP to " _YELLOW_("%s") " tag", cardtype);
|
||||
print_blocks(blocks, max);
|
||||
|
||||
int res = clone_t55xx_tag(blocks, max);
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "The block 0 was changed (eXtended) which can be hard to detect.");
|
||||
PrintAndLogEx(INFO, " Configure it manually " _YELLOW_("`lf t55xx config b 64 d BI i 1 o 32`"));
|
||||
PrintAndLogEx(INFO, "Configure it manually " _YELLOW_("`lf t55xx config b 64 d BI i 1 o 32`"));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nedap read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nedap reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdLFNedapSim(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_nedap_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nedap sim",
|
||||
"Enables simulation of NEDAP card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf nedap sim --st 1 --cc 101 --id 1337"
|
||||
);
|
||||
|
||||
usage_to_be_displayed = usage_lf_nedap_sim;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_0(NULL, "st", "<dec>", "optional - sub type (default 5)"),
|
||||
arg_u64_1(NULL, "cc", "<dec>", "customer code (0-4095)"),
|
||||
arg_u64_1(NULL, "id", "<dec>", "ID (0-99999)"),
|
||||
arg_lit0("l", "long", "optional - long (128), default to short (64)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int ret = CmdLfNedapGen(Cmd);
|
||||
if (ret != PM3_SUCCESS)
|
||||
return ret;
|
||||
uint8_t sub_type = arg_get_u32_def(ctx, 1, 5);
|
||||
uint16_t customer_code = arg_get_u32_def(ctx, 2, 0);
|
||||
uint32_t id = arg_get_u32_def(ctx, 3, 0);
|
||||
bool is_long = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ((DemodBufferLen != 128) && (DemodBufferLen != 64)) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
if (sub_type > 0xF) {
|
||||
PrintAndLogEx(FAILED, "out-of-range, valid subtype is between 0-15");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating NEDAP - Raw");
|
||||
CmdPrintDemodBuff("x");
|
||||
if (customer_code > 0xFFF) {
|
||||
PrintAndLogEx(FAILED, "out-of-range, valid customer code is between 0-4095");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (id > 99999) {
|
||||
PrintAndLogEx(FAILED, "out-of-range, id max value is 99999");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "NEDAP (%s) - ID: " _GREEN_("%05u") " subtype: " _GREEN_("%1u") " customer code: " _GREEN_("%u / 0x%03X")
|
||||
, is_long ? "128b" : "64b"
|
||||
, id
|
||||
, sub_type
|
||||
, customer_code
|
||||
, customer_code
|
||||
);
|
||||
|
||||
// generate nedap bitstream
|
||||
uint8_t max = (is_long) ? 16 : 8;
|
||||
uint8_t data[16];
|
||||
NedapGen(sub_type, customer_code, id, is_long, data);
|
||||
|
||||
uint8_t bs[16 * 8];
|
||||
for (uint8_t i = 0; i < max; i++) {
|
||||
num_to_bytebits(data[i], 8, bs + i * 8);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating NEDAP - Raw: " _YELLOW_("%s"), sprint_hex_inrow(data, max));
|
||||
|
||||
// NEDAP, Biphase = 2, clock 64, inverted, (DIPhase == inverted BIphase)
|
||||
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + DemodBufferLen);
|
||||
|
@ -522,7 +544,7 @@ static int CmdLFNedapSim(const char *Cmd) {
|
|||
payload->invert = 1;
|
||||
payload->separator = 0;
|
||||
payload->clock = 64;
|
||||
memcpy(payload->data, DemodBuffer, DemodBufferLen);
|
||||
memcpy(payload->data, bs, (max * 8));
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + DemodBufferLen);
|
||||
|
@ -539,12 +561,11 @@ static int CmdLFNedapSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdLFNedapDemod, AlwaysAvailable, "Demodulate Nedap tag from the GraphBuffer"},
|
||||
{"generate", CmdLfNedapGen, AlwaysAvailable, "Generate Nedap bitstream in DemodBuffer"},
|
||||
{"read", CmdLFNedapRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdLFNedapClone, IfPm3Lf, "Clone Nedap tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdLFNedapSim, IfPm3Lf, "Simulate Nedap tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdLFNedapDemod, AlwaysAvailable, "Demodulate Nedap tag from the GraphBuffer"},
|
||||
{"reader", CmdLFNedapReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdLFNedapClone, IfPm3Lf, "Clone Nedap tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdLFNedapSim, IfPm3Lf, "Simulate Nedap tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,20 +9,21 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfnexwatch.h"
|
||||
#include <inttypes.h> // PRIu
|
||||
#include <inttypes.h> // PRIu
|
||||
#include <string.h>
|
||||
#include <ctype.h> // tolower
|
||||
#include <stdlib.h> // free, alloc
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include <ctype.h> // tolower
|
||||
#include <stdlib.h> // free, alloc
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h" // preamblesearch
|
||||
#include "cmddata.h" // preamblesearch
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h"
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
typedef enum {
|
||||
SCRAMBLE,
|
||||
|
@ -31,49 +32,6 @@ typedef enum {
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_nexwatch_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Nexwatch tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "You can use raw hex values or create a credential based on id, mode");
|
||||
PrintAndLogEx(NORMAL, "and type of credential (Nexkey/Quadrakey)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf nexwatch clone [h] [b <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)
|
||||
static uint8_t nexwatch_parity_swap(uint8_t parity) {
|
||||
uint8_t a = (((parity >> 3) & 1));
|
||||
|
@ -259,172 +217,249 @@ int demodNexWatch(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdNexWatchDemod(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nexwatch demod",
|
||||
"Try to find Nexwatch preamble, if found decode / descramble data",
|
||||
"lf nexwatch demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodNexWatch(true);
|
||||
}
|
||||
|
||||
//by marshmellow
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdNexWatchRead(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
lf_read(false, 20000);
|
||||
return demodNexWatch(true);
|
||||
static int CmdNexWatchReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nexwatch reader",
|
||||
"read a Nexwatch tag",
|
||||
"lf nexwatch reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 20000);
|
||||
demodNexWatch(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdNexWatchClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nexwatch clone",
|
||||
"clone a Nexwatch tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"You can use raw hex values or create a credential based on id, mode\n"
|
||||
"and type of credential (Nexkey / Quadrakey)",
|
||||
"lf nexwatch clone --raw 5600000000213C9F8F150C00\n"
|
||||
"lf nexwatch clone --cn 521512301 -m 1 -n -> Nexkey credential\n"
|
||||
"lf nexwatch clone --cn 521512301 -m 1 -q -> Quadrakey credential\n"
|
||||
);
|
||||
|
||||
// 56000000 00213C9F 8F150C00
|
||||
uint32_t blocks[4];
|
||||
bool use_raw = false;
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
uint8_t magic = 0xBE;
|
||||
uint32_t cn = 0;
|
||||
uint8_t rawhex[12] = {0x56, 0};
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card id"),
|
||||
arg_u64_0("m", "mode", "<dec>", "mode (decimal) (0-15, defaults to 1)"),
|
||||
arg_lit0("n", NULL, "Nexkey credential"),
|
||||
arg_lit0("q", NULL, "Quadrakey credential"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_nexwatch_clone();
|
||||
case 'r': {
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0x56, 0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
use_raw = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
uint32_t scrambled;
|
||||
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
|
||||
num_to_bytes(scrambled, 4, rawhex + 5);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
uint8_t mode = param_get8ex(Cmd, cmdp + 1, 1, 10);
|
||||
mode &= 0x0F;
|
||||
rawhex[9] |= (mode << 4);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
magic = 0x88;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
magic = 0xBE;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
uint32_t cn = arg_get_u32_def(ctx, 2, -1);
|
||||
uint32_t mode = arg_get_u32_def(ctx, 3, -1);
|
||||
bool use_nexkey = arg_get_lit(ctx, 4);
|
||||
bool use_quadrakey = arg_get_lit(ctx, 5);
|
||||
bool q5 = arg_get_lit(ctx, 6);
|
||||
bool em = arg_get_lit(ctx, 7);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (use_nexkey && use_quadrakey) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_nexwatch_clone();
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// 56000000 00213C9F 8F150C00
|
||||
bool use_raw = (raw_len != 0);
|
||||
|
||||
if (use_raw && cn != -1) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (cn != -1) {
|
||||
uint32_t scrambled;
|
||||
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
|
||||
num_to_bytes(scrambled, 4, raw + 5);
|
||||
}
|
||||
|
||||
if (mode != -1) {
|
||||
if (mode > 15) {
|
||||
mode = 1;
|
||||
}
|
||||
mode &= 0x0F;
|
||||
raw[9] |= (mode << 4);
|
||||
}
|
||||
|
||||
uint8_t magic = 0xBE;
|
||||
if (use_nexkey)
|
||||
magic = 0x88;
|
||||
|
||||
if (use_quadrakey)
|
||||
magic = 0xBE;
|
||||
|
||||
uint32_t blocks[4];
|
||||
|
||||
//Nexwatch - compat mode, PSK, data rate 40, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_PSK1 | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_NEXWATCH_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
if (use_raw == false) {
|
||||
uint8_t parity = nexwatch_parity(rawhex + 5) & 0xF;
|
||||
rawhex[9] |= parity;
|
||||
rawhex[10] |= nexwatch_checksum(magic, cn, parity);
|
||||
uint8_t parity = nexwatch_parity(raw + 5) & 0xF;
|
||||
raw[9] |= parity;
|
||||
raw[10] |= nexwatch_checksum(magic, cn, parity);
|
||||
}
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone NexWatch to T55x7 with raw hex");
|
||||
PrintAndLogEx(INFO, "Preparing to clone NexWatch to " _YELLOW_("%s") " raw " _YELLOW_("%s"), cardtype, sprint_hex_inrow(raw, sizeof(raw)));
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdNexWatchSim(const char *Cmd) {
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
bool use_raw = false;
|
||||
uint8_t rawhex[12] = {0x56, 0};
|
||||
int rawlen = sizeof(rawhex);
|
||||
uint8_t magic = 0xBE;
|
||||
uint32_t cn = 0;
|
||||
uint8_t bs[128];
|
||||
memset(bs, 0, sizeof(bs));
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf nexwatch sim",
|
||||
"Enables simulation of secura card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"You can use raw hex values or create a credential based on id, mode\n"
|
||||
"and type of credential (Nexkey/Quadrakey)",
|
||||
"lf nexwatch sim --raw 5600000000213C9F8F150C00\n"
|
||||
"lf nexwatch sim --cn 521512301 -m 1 -n -> Nexkey credential\n"
|
||||
"lf nexwatch sim --cn 521512301 -m 1 -q -> Quadrakey credential"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_nexwatch_clone();
|
||||
case 'r': {
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &rawlen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card id"),
|
||||
arg_u64_0("m", "mode", "<dec>", "mode (decimal) (0-15, defaults to 1)"),
|
||||
arg_lit0("n", NULL, "Nexkey credential"),
|
||||
arg_lit0("q", NULL, "Quadrakey credential"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
use_raw = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
uint32_t scrambled;
|
||||
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
|
||||
num_to_bytes(scrambled, 4, rawhex + 5);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
uint8_t mode = param_get8ex(Cmd, cmdp + 1, 1, 10);
|
||||
mode &= 0x0F;
|
||||
rawhex[9] |= (mode << 4);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
magic = 0x88;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
magic = 0xBE;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0x56, 0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
uint32_t cn = arg_get_u32_def(ctx, 2, -1);
|
||||
uint32_t mode = arg_get_u32_def(ctx, 3, -1);
|
||||
bool use_nexkey = arg_get_lit(ctx, 4);
|
||||
bool use_quadrakey = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (use_nexkey && use_quadrakey) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_nexwatch_sim();
|
||||
bool use_raw = (raw_len != 0);
|
||||
|
||||
if (use_raw && cn != -1) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (cn != -1) {
|
||||
uint32_t scrambled;
|
||||
nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
|
||||
num_to_bytes(scrambled, 4, raw + 5);
|
||||
}
|
||||
|
||||
if (mode != -1) {
|
||||
if (mode > 15) {
|
||||
mode = 1;
|
||||
}
|
||||
mode &= 0x0F;
|
||||
raw[9] |= (mode << 4);
|
||||
}
|
||||
|
||||
uint8_t magic = 0xBE;
|
||||
if (use_nexkey)
|
||||
magic = 0x88;
|
||||
|
||||
if (use_quadrakey)
|
||||
magic = 0xBE;
|
||||
|
||||
if (use_raw == false) {
|
||||
uint8_t parity = nexwatch_parity(rawhex + 5) & 0xF;
|
||||
rawhex[9] |= parity;
|
||||
rawhex[10] |= nexwatch_checksum(magic, cn, parity);
|
||||
uint8_t parity = nexwatch_parity(raw + 5) & 0xF;
|
||||
raw[9] |= parity;
|
||||
raw[10] |= nexwatch_checksum(magic, cn, parity);
|
||||
}
|
||||
|
||||
// hex to bits.
|
||||
uint32_t rawblocks[3];
|
||||
for (size_t i = 0; i < ARRAYLEN(rawblocks); i++) {
|
||||
rawblocks[i] = bytes_to_num(rawhex + (i * sizeof(uint32_t)), sizeof(uint32_t));
|
||||
num_to_bytebits(rawblocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
|
||||
uint8_t bs[96];
|
||||
memset(bs, 0, sizeof(bs));
|
||||
|
||||
// hex to bits. (3 * 32 == 96)
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
uint32_t tmp = bytes_to_num(raw + (i * sizeof(uint32_t)), sizeof(uint32_t));
|
||||
num_to_bytebits(tmp, sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating NexWatch - raw: %s", sprint_hex_inrow(rawhex, rawlen));
|
||||
PrintAndLogEx(SUCCESS, "Simulating NexWatch - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
|
||||
|
||||
lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs));
|
||||
payload->carrier = 2;
|
||||
|
@ -447,11 +482,11 @@ static int CmdNexWatchSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdNexWatchDemod, AlwaysAvailable, "Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"},
|
||||
{"read", CmdNexWatchRead, IfPm3Lf, "Attempt to Read and Extract tag data from the antenna"},
|
||||
{"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"},
|
||||
{"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdNexWatchDemod, AlwaysAvailable, "Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"},
|
||||
{"reader", CmdNexWatchReader, IfPm3Lf, "Attempt to Read and Extract tag data from the antenna"},
|
||||
{"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"},
|
||||
{"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,52 +8,23 @@
|
|||
// ASK/Manchester, STT, RF/32, 96 bits long (some bits unknown)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfnoralsy.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_noralsy_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Noralsy tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf noralsy clone [h] <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) {
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < len; i += 4)
|
||||
|
@ -132,32 +103,91 @@ int demodNoralsy(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdNoralsyDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf noralsy demod",
|
||||
"Try to find Noralsy preamble, if found decode / descramble data",
|
||||
"lf noralsy demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodNoralsy(true);
|
||||
}
|
||||
|
||||
static int CmdNoralsyRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 8000);
|
||||
return demodNoralsy(true);
|
||||
static int CmdNoralsyReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf noralsy reader",
|
||||
"read a Noralsy tag",
|
||||
"lf noralsy reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 8000);
|
||||
demodNoralsy(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdNoralsyClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf noralsy clone",
|
||||
"clone a Noralsy tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf noralsy clone --cn 112233\n"
|
||||
"lf noralsy clone --cn 112233 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf noralsy clone --cn 112233 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "cn", "<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};
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_noralsy_clone();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
year = param_get32ex(Cmd, 1, 2000, 10);
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
//Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 2) == 'q');
|
||||
if (q5)
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_NORALSY_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
uint8_t *bits = calloc(96, sizeof(uint8_t));
|
||||
if (getnoralsyBits(id, year, bits) != PM3_SUCCESS) {
|
||||
|
@ -172,36 +202,50 @@ static int CmdNoralsyClone(const char *Cmd) {
|
|||
|
||||
free(bits);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Noralsy to " _YELLOW_("%s") " with CardId: %u", (q5) ? "Q5/T5555" : "T55x7", id);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Noralsy to " _YELLOW_("%s") " with Card id: " _GREEN_("%u"), cardtype, id);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdNoralsySim(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf noralsy sim",
|
||||
"Enables simulation of Noralsy card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n",
|
||||
"lf noralsy sim --cn 1337\n"
|
||||
"lf noralsy sim --cn 1337 --year 2010"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "cn", "<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];
|
||||
memset(bs, 0, sizeof(bs));
|
||||
|
||||
uint16_t year = 0;
|
||||
uint32_t id = 0;
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h')
|
||||
return usage_lf_noralsy_sim();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
year = param_get32ex(Cmd, 1, 2000, 10);
|
||||
|
||||
if (getnoralsyBits(id, year, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: %u", id);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: " _YELLOW_("%u") " year " _YELLOW_("%u"), id, year);
|
||||
|
||||
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
|
||||
payload->encoding = 1;
|
||||
|
@ -225,11 +269,11 @@ static int CmdNoralsySim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"},
|
||||
{"read", CmdNoralsyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"},
|
||||
{"reader", CmdNoralsyReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -272,7 +316,6 @@ int getnoralsyBits(uint32_t id, uint16_t year, uint8_t *bits) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// by iceman
|
||||
// find Noralsy preamble in already demoded data
|
||||
int detectNoralsy(uint8_t *dest, size_t *size) {
|
||||
if (*size < 96) return -1; //make sure buffer has data
|
||||
|
|
|
@ -25,40 +25,14 @@
|
|||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone
|
||||
#include "parity.h"
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_pac_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a PAC/Stanley tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pac clone [h] [c <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
|
||||
// all bytes following 8 bit preamble are one start bit (0), 7 data bits (lsb first), odd parity bit, and one stop bit (1)
|
||||
static int demodbuf_to_pacid(uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_size) {
|
||||
static int pac_buf_to_cardid(uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_size) {
|
||||
const size_t byteLength = 10; // start bit, 7 data bits, parity bit, stop bit
|
||||
const size_t startIndex = 8 + (3 * byteLength) + 1; // skip 8 bits preamble, STX, '2', '0', and first start bit
|
||||
const size_t dataLength = 9;
|
||||
|
@ -93,35 +67,33 @@ static int demodbuf_to_pacid(uint8_t *src, const size_t src_size, uint8_t *dst,
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
// convert a 16 byte array of raw demod data (FF204990XX...) to 8 bytes of PAC_8byte ID
|
||||
// performs no parity or checksum validation
|
||||
static void pacRawToCardId(uint8_t* outCardId, const uint8_t* rawBytes) {
|
||||
static void pac_raw_to_cardid(const uint8_t *src, uint8_t *dst) {
|
||||
for (int i = 4; i < 12; i++) {
|
||||
uint8_t shift = 7 - (i + 3) % 4 * 2;
|
||||
size_t index = i + (i - 1) / 4;
|
||||
|
||||
outCardId[i - 4] = reflect8((((rawBytes[index] << 8) | (rawBytes[index + 1])) >> shift) & 0xFE);
|
||||
dst[i - 4] = reflect8((((src[index] << 8) | (src[index + 1])) >> shift) & 0xFE);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// convert 8 bytes of PAC_8byte ID to 16 byte array of raw data (FF204990XX...)
|
||||
static void pacCardIdToRaw(uint8_t *outRawBytes, const char *cardId) {
|
||||
static void pac_cardid_to_raw(const char *src, uint8_t *dst) {
|
||||
uint8_t idbytes[10];
|
||||
|
||||
// prepend PAC_8byte card type "20"
|
||||
idbytes[0] = '2';
|
||||
idbytes[1] = '0';
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
idbytes[i + 2] = toupper(cardId[i]);
|
||||
idbytes[i + 2] = toupper(src[i]);
|
||||
|
||||
// initialise array with start and stop bits
|
||||
for (size_t i = 0; i < 16; i++)
|
||||
outRawBytes[i] = 0x40 >> (i + 3) % 5 * 2;
|
||||
dst[i] = 0x40 >> (i + 3) % 5 * 2;
|
||||
|
||||
outRawBytes[0] = 0xFF; // mark + stop
|
||||
outRawBytes[1] = 0x20; // start + reflect8(STX)
|
||||
dst[0] = 0xFF; // mark + stop
|
||||
dst[1] = 0x20; // start + reflect8(STX)
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for (size_t i = 2; i < 13; i++) {
|
||||
|
@ -138,8 +110,8 @@ static void pacCardIdToRaw(uint8_t *outRawBytes, const char *cardId) {
|
|||
}
|
||||
pattern <<= shift;
|
||||
|
||||
outRawBytes[index] |= pattern >> 8 & 0xFF;
|
||||
outRawBytes[index + 1] |= pattern & 0xFF;
|
||||
dst[index] |= pattern >> 8 & 0xFF;
|
||||
dst[index + 1] |= pattern & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,7 +148,7 @@ int demodPac(bool verbose) {
|
|||
|
||||
const size_t idLen = 9; // 8 bytes + null terminator
|
||||
uint8_t cardid[idLen];
|
||||
int retval = demodbuf_to_pacid(DemodBuffer, DemodBufferLen, cardid, sizeof(cardid));
|
||||
int retval = pac_buf_to_cardid(DemodBuffer, DemodBufferLen, cardid, sizeof(cardid));
|
||||
|
||||
if (retval == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "PAC/Stanley - Card: " _GREEN_("%s") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4);
|
||||
|
@ -185,97 +157,202 @@ int demodPac(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdPacDemod(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pac demod",
|
||||
"Try to find PAC/Stanley preamble, if found decode / descramble data",
|
||||
"lf pac demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodPac(true);
|
||||
}
|
||||
|
||||
static int CmdPacRead(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
lf_read(false, 4096 * 2 + 20);
|
||||
return demodPac(true);
|
||||
static int CmdPacReader(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pac reader",
|
||||
"read a PAC/Stanley 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);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 4096 * 2 + 20);
|
||||
demodPac(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdPacClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[5];
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pac clone",
|
||||
"clone a PAC/Stanley tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf pac clone --cn CD4F5552\n"
|
||||
"lf pac clone --cn CD4F5552 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf pac clone --cn CD4F5552 --em -> encode for EM4305/4469\n"
|
||||
"lf pac clone --raw FF2049906D8511C593155B56D5B2649F"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_pac_clone();
|
||||
case 'c': {
|
||||
// skip first block, 4*4 = 16 bytes left
|
||||
uint8_t rawhex[16] = {0};
|
||||
char cardid[9];
|
||||
int res = param_getstr(Cmd, cmdp + 1, cardid, sizeof(cardid));
|
||||
if (res < 8)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0(NULL, "cn", "<dec>", "8 byte PAC/Stanley card ID"),
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 16 bytes max"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
pacCardIdToRaw(rawhex, cardid);
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
// skip first block, 4*4 = 16 bytes left
|
||||
uint8_t rawhex[16] = {0};
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
uint8_t cnstr[9];
|
||||
int cnlen = 9;
|
||||
memset(cnstr, 0x00, sizeof(cnstr));
|
||||
CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen);
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
// skip first block, 4*4 = 16 bytes left
|
||||
int raw_len = 0;
|
||||
uint8_t raw[16] = {0};
|
||||
CLIGetHexWithReturn(ctx, 2, raw, &raw_len);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 3);
|
||||
bool em = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (cnlen && raw_len) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both CardID and raw hex at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_pac_clone();
|
||||
if (cnlen && cnlen < 8) {
|
||||
PrintAndLogEx(FAILED, "Card ID must be 8 or 9 hex digits (%d)", cnlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
//Pac - compat mode, NRZ, data rate 32, 3 data blocks
|
||||
if (cnlen == 8 || cnlen == 9) {
|
||||
pac_cardid_to_raw((char *)cnstr, raw);
|
||||
} else {
|
||||
pac_raw_to_cardid(raw, cnstr);
|
||||
}
|
||||
|
||||
uint32_t blocks[5];
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Pac - compat mode, NRZ, data rate 32, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_DIRECT | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_DIRECT | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_PAC_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to " _YELLOW_("%s") " with ID " _GREEN_("%s") " raw " _GREEN_("%s")
|
||||
, cardtype
|
||||
, cnstr
|
||||
, sprint_hex_inrow(raw, sizeof(raw))
|
||||
);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to T55x7 with raw hex");
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdPacSim(const char *Cmd) {
|
||||
|
||||
// NRZ sim.
|
||||
char cardid[9] = { 0 };
|
||||
uint8_t rawBytes[16] = { 0 };
|
||||
uint32_t rawBlocks[4];
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pac_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pac sim",
|
||||
"Enables simulation of PAC/Stanley card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"The card ID is 8 byte number. Larger values are truncated.",
|
||||
"lf pac sim --cn CD4F5552\n"
|
||||
"lf pac sim --raw FF2049906D8511C593155B56D5B2649F"
|
||||
);
|
||||
|
||||
int res = param_getstr(Cmd, 0, cardid, sizeof(cardid));
|
||||
if (res < 8) return usage_lf_pac_sim();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0(NULL, "cn", "<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];
|
||||
pacCardIdToRaw(rawBytes, cardid);
|
||||
for (size_t i = 0; i < ARRAYLEN(rawBlocks); i++) {
|
||||
rawBlocks[i] = bytes_to_num(rawBytes + (i * sizeof(uint32_t)), sizeof(uint32_t));
|
||||
num_to_bytebits(rawBlocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
|
||||
uint8_t cnstr[10];
|
||||
int cnlen = 9;
|
||||
memset(cnstr, 0x00, sizeof(cnstr));
|
||||
CLIGetStrWithReturn(ctx, 1, cnstr, &cnlen);
|
||||
|
||||
// skip first block, 4*4 = 16 bytes left
|
||||
int raw_len = 0;
|
||||
uint8_t raw[16] = {0};
|
||||
CLIGetHexWithReturn(ctx, 2, raw, &raw_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cnlen && raw_len) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both CardID and raw hex at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating PAC/Stanley - ID " _YELLOW_("%s")" raw "_YELLOW_("%08X%08X%08X%08X"), cardid, rawBlocks[0], rawBlocks[1], rawBlocks[2], rawBlocks[3]);
|
||||
if (cnlen && cnlen < 8) {
|
||||
PrintAndLogEx(FAILED, "Card ID must be 8 or 9 hex digits (%d)", cnlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (cnlen == 8 || cnlen == 9) {
|
||||
pac_cardid_to_raw((char *)cnstr, raw);
|
||||
} else {
|
||||
pac_raw_to_cardid(raw, cnstr);
|
||||
}
|
||||
|
||||
uint8_t bs[128];
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
uint32_t tmp = bytes_to_num(raw + (i * sizeof(uint32_t)), sizeof(uint32_t));
|
||||
num_to_bytebits(tmp, sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating PAC/Stanley - ID " _YELLOW_("%s")" raw " _YELLOW_("%s")
|
||||
, cnstr
|
||||
, sprint_hex_inrow(raw, sizeof(raw))
|
||||
);
|
||||
|
||||
// NRZ sim.
|
||||
lf_nrzsim_t *payload = calloc(1, sizeof(lf_nrzsim_t) + sizeof(bs));
|
||||
payload->invert = 0;
|
||||
payload->separator = 0;
|
||||
|
@ -297,11 +374,11 @@ static int CmdPacSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"},
|
||||
{"read", CmdPacRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"},
|
||||
{"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"},
|
||||
{"reader", CmdPacReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"},
|
||||
{"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Marshmellow
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
|
@ -8,13 +9,11 @@
|
|||
// FSK2a, rf/50, 96 bits (completely known)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfparadox.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
|
@ -25,40 +24,11 @@
|
|||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "crc.h" // maxim
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_paradox_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Paradox tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf paradox clone [h] [b <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[] = {
|
||||
0xDB, 0xFC, 0x3F, 0xC5, 0x50, 0x14, 0x05, 0x47,
|
||||
0x9F, 0xED, 0x7D, 0x59, 0x22, 0x84, 0x21, 0x4E,
|
||||
|
@ -71,9 +41,9 @@ const uint8_t paradox_lut[] = {
|
|||
|
||||
#define PARADOX_PREAMBLE_LEN 8
|
||||
|
||||
//by marshmellow
|
||||
//Paradox Prox demod - FSK2a RF/50 with preamble of 00001111 (then manchester encoded)
|
||||
//print full Paradox Prox ID and some bit format details if found
|
||||
// by marshmellow
|
||||
// Paradox Prox demod - FSK2a RF/50 with preamble of 00001111 (then manchester encoded)
|
||||
// print full Paradox Prox ID and some bit format details if found
|
||||
|
||||
int demodParadox(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
|
@ -200,95 +170,160 @@ int demodParadox(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdParadoxDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox demod",
|
||||
"Try to find Paradox preamble, if found decode / descramble data",
|
||||
"lf paradox demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodParadox(true);
|
||||
}
|
||||
|
||||
//by marshmellow
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdParadoxRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 10000);
|
||||
return demodParadox(true);
|
||||
static int CmdParadoxReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox reader",
|
||||
"read a Paradox tag",
|
||||
"lf Paradox reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 10000);
|
||||
demodParadox(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdParadoxClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[4];
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox clone",
|
||||
"clone a paradox tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf paradox clone --raw 0f55555695596a6a9999a59a\n"
|
||||
"lf paradox clone -r 0f55555695596a6a9999a59a --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf paradox clone -r 0f55555695596a6a9999a59a --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_paradox_clone();
|
||||
case 'b': {
|
||||
// skip first block, 3*4 =12 bytes left
|
||||
uint8_t rawhex[12] = {0};
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_paradox_clone();
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
//Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks
|
||||
uint32_t blocks[4];
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// Paradox - FSK2a, data rate 50, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_INVERT_OUTPUT | T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Paradox to T55x7 with raw hex");
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_PARADOX_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Paradox to " _YELLOW_("%s") " with raw hex", cardtype);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf paradox read`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdParadoxSim(const char *Cmd) {
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/*
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_paradox_sim();
|
||||
|
||||
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf paradox sim",
|
||||
"Enables simulation of paradox card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf paradox sim --raw 0f55555695596a6a9999a59a"
|
||||
);
|
||||
|
||||
uint8_t bs[96];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<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
|
||||
uint8_t clk = 50, invert = 1, high = 10, low = 8;
|
||||
|
||||
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_paradox_sim();
|
||||
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
// if ( GetParadoxBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
// PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Paradox - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
|
||||
uint8_t clk = 50, high = 10, low = 8;
|
||||
|
||||
lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs));
|
||||
payload->fchigh = high;
|
||||
payload->fclow = low;
|
||||
payload->separator = invert;
|
||||
payload->separator = 0;
|
||||
payload->clock = clk;
|
||||
memcpy(payload->data, bs, sizeof(bs));
|
||||
|
||||
|
@ -302,15 +337,30 @@ static int CmdParadoxSim(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Done");
|
||||
if (resp.status != PM3_EOPABORTED)
|
||||
return resp.status;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/*
|
||||
|
||||
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_paradox_sim();
|
||||
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
// if ( GetParadoxBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
// PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
PrintAndLogEx(NORMAL, "Simulating Paradox - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
|
||||
|
||||
*/
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdParadoxDemod, AlwaysAvailable, "Demodulate a Paradox FSK tag from the GraphBuffer"},
|
||||
{"read", CmdParadoxRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"clone", CmdParadoxClone, IfPm3Lf, "clone paradox tag to T55x7"},
|
||||
{"sim", CmdParadoxSim, IfPm3Lf, "simulate paradox tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdParadoxDemod, AlwaysAvailable, "Demodulate a Paradox FSK tag from the GraphBuffer"},
|
||||
{"reader", CmdParadoxReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"clone", CmdParadoxClone, IfPm3Lf, "clone paradox tag"},
|
||||
{"sim", CmdParadoxSim, IfPm3Lf, "simulate paradox tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,13 +9,12 @@
|
|||
// Low frequency PCF7931 commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfpcf7931.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -37,87 +36,106 @@ int pcf7931_resetConfig(void) {
|
|||
configPcf.InitDelay = PCF7931_DEFAULT_INITDELAY;
|
||||
configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH;
|
||||
configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION;
|
||||
PrintAndLogEx(INFO, "Configuration resetted");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pcf7931 config`") " to view current settings");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int pcf7931_printConfig(void) {
|
||||
PrintAndLogEx(NORMAL, "Password (LSB first on bytes) : %s", sprint_hex(configPcf.Pwd, sizeof(configPcf.Pwd)));
|
||||
PrintAndLogEx(NORMAL, "Tag initialization delay : %d us", configPcf.InitDelay);
|
||||
PrintAndLogEx(NORMAL, "Offset low pulses width : %d us", configPcf.OffsetWidth);
|
||||
PrintAndLogEx(NORMAL, "Offset low pulses position : %d us", configPcf.OffsetPosition);
|
||||
PrintAndLogEx(INFO, "Password (LSB first on bytes)... " _YELLOW_("%s"), sprint_hex(configPcf.Pwd, sizeof(configPcf.Pwd)));
|
||||
PrintAndLogEx(INFO, "Tag initialization delay........ " _YELLOW_("%d") " us", configPcf.InitDelay);
|
||||
PrintAndLogEx(INFO, "Offset low pulses width......... " _YELLOW_("%d") " us", configPcf.OffsetWidth);
|
||||
PrintAndLogEx(INFO, "Offset low pulses position...... " _YELLOW_("%d") " us", configPcf.OffsetPosition);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_pcf7931_read(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pcf7931 read [h] ");
|
||||
PrintAndLogEx(NORMAL, "This command tries to read a PCF7931 tag.");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 read");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int CmdLFPCF7931Reader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pcf7931 reader",
|
||||
"read a PCF7931 tag",
|
||||
"lf pcf7931 reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
static int usage_pcf7931_write(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pcf7931 write [h] <block address> <byte address> <data>");
|
||||
PrintAndLogEx(NORMAL, "This command tries to write a PCF7931 tag.");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, " blockaddress Block to save [0-7]");
|
||||
PrintAndLogEx(NORMAL, " byteaddress Index of byte inside block to write [0-15]");
|
||||
PrintAndLogEx(NORMAL, " data one byte of data (hex)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 write 2 1 FF");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
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);
|
||||
|
||||
static int usage_pcf7931_config(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pcf7931 config [h] [r] <pwd> <delay> <offset width> <offset position>");
|
||||
PrintAndLogEx(NORMAL, "This command tries to set the configuration used with PCF7931 commands");
|
||||
PrintAndLogEx(NORMAL, "The time offsets could be useful to correct slew rate generated by the antenna");
|
||||
PrintAndLogEx(NORMAL, "Caling without some parameter will print the current configuration.");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, " r Reset configuration to default values");
|
||||
PrintAndLogEx(NORMAL, " pwd Password, hex, 7bytes, LSB-order");
|
||||
PrintAndLogEx(NORMAL, " delay Tag initialization delay (in us) decimal");
|
||||
PrintAndLogEx(NORMAL, " offset Low pulses width (in us) decimal");
|
||||
PrintAndLogEx(NORMAL, " offset Low pulses position (in us) decimal");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 config");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 config r");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 config 11223344556677 20000");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 config 11223344556677 17500 -10 30");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFPCF7931Read(const char *Cmd) {
|
||||
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_pcf7931_read();
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_PCF7931_READ, NULL, 0);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_PCF7931_READ, NULL, 0);
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFPCF7931Config(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pcf7931 config",
|
||||
"This command tries to set the configuration used with PCF7931 commands\n"
|
||||
"The time offsets could be useful to correct slew rate generated by the antenna\n"
|
||||
"Caling without some parameter will print the current configuration.",
|
||||
"lf pcf7931 config --reset\n"
|
||||
"lf pcf7931 config --pwd 11223344556677 -d 20000\n"
|
||||
"lf pcf7931 config --pwd 11223344556677 -d 17500 --lw -10 --lp 30"
|
||||
);
|
||||
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 0) return pcf7931_printConfig();
|
||||
if (ctmp == 'h') return usage_pcf7931_config();
|
||||
if (ctmp == 'r') return pcf7931_resetConfig();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("r", "reset", "Reset configuration to default values"),
|
||||
arg_str0("p", "pwd", "<hex>", "Password, 7bytes, LSB-order"),
|
||||
arg_u64_0("d", "delay", "<dec>", "Tag initialization delay (in us)"),
|
||||
arg_int0(NULL, "lw", "<dec>", "offset, low pulses width (in us)"),
|
||||
arg_int0(NULL, "lp", "<dec>", "offset, low pulses position (in us)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
if (param_gethex(Cmd, 0, configPcf.Pwd, 14)) return usage_pcf7931_config();
|
||||
bool use_reset = arg_get_lit(ctx, 1);
|
||||
if (use_reset) {
|
||||
CLIParserFree(ctx);
|
||||
return pcf7931_resetConfig();
|
||||
}
|
||||
|
||||
configPcf.InitDelay = (param_get32ex(Cmd, 1, 0, 10) & 0xFFFF);
|
||||
configPcf.OffsetWidth = (int)(param_get32ex(Cmd, 2, 0, 10) & 0xFFFF);
|
||||
configPcf.OffsetPosition = (int)(param_get32ex(Cmd, 3, 0, 10) & 0xFFFF);
|
||||
int pwd_len = 0;
|
||||
uint8_t pwd[7] = {0};
|
||||
CLIGetHexWithReturn(ctx, 2, pwd, &pwd_len);
|
||||
|
||||
uint32_t delay = arg_get_u32_def(ctx, 3, -1);
|
||||
int ow = arg_get_int_def(ctx, 4, 0xFFFF);
|
||||
int op = arg_get_int_def(ctx, 5, 0xFFFF);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (pwd_len && pwd_len < sizeof(pwd)) {
|
||||
PrintAndLogEx(ERR, "Password must be 7 bytes");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (pwd_len) {
|
||||
memcpy(configPcf.Pwd, pwd, sizeof(configPcf.Pwd));
|
||||
}
|
||||
if (delay != -1) {
|
||||
configPcf.InitDelay = (delay & 0xFFFF);
|
||||
}
|
||||
if (ow != 0xFFFF) {
|
||||
configPcf.OffsetWidth = (ow & 0xFFFF);
|
||||
}
|
||||
if (op != 0xFFFF) {
|
||||
configPcf.OffsetPosition =(op & 0xFFFF);
|
||||
}
|
||||
|
||||
pcf7931_printConfig();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -125,21 +143,39 @@ static int CmdLFPCF7931Config(const char *Cmd) {
|
|||
|
||||
static int CmdLFPCF7931Write(const char *Cmd) {
|
||||
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || ctmp == 'h') return usage_pcf7931_write();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pcf7931 write",
|
||||
"This command tries to write a PCF7931 tag.",
|
||||
"lf pcf7931 write --blk 2 --idx 1 -d FF -> Write 0xFF to block 2, index 1 "
|
||||
);
|
||||
|
||||
uint8_t block = 0, bytepos = 0, data = 0;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1("b", "blk", "<dec>", "[0-7] block number"),
|
||||
arg_u64_1("i", "idx", "<dec>", "[0-15] index of byte inside block"),
|
||||
arg_str1("d", "data", "<hex>", "one byte to be written"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
uint8_t block = arg_get_u32_def(ctx, 1, 0);
|
||||
uint8_t idx = arg_get_u32_def(ctx, 2, 0);
|
||||
|
||||
if (param_getdec(Cmd, 0, &block)) return usage_pcf7931_write();
|
||||
if (param_getdec(Cmd, 1, &bytepos)) return usage_pcf7931_write();
|
||||
int data_len = 0;
|
||||
uint8_t data[1] = {0};
|
||||
CLIGetHexWithReturn(ctx, 3, data, &data_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ((block > 7) || (bytepos > 15)) return usage_pcf7931_write();
|
||||
if (block > 7) {
|
||||
PrintAndLogEx(ERR, "out-of-range error, block must be between 0-7");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
data = param_get8ex(Cmd, 2, 0, 16);
|
||||
if (idx > 15) {
|
||||
PrintAndLogEx(ERR, "out-of-range error, index must be between 0-15");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Writing block: %d", block);
|
||||
PrintAndLogEx(INFO, " pos: %d", bytepos);
|
||||
PrintAndLogEx(INFO, " data: 0x%02X", data);
|
||||
PrintAndLogEx(INFO, "Writing block %u at idx %u with data 0x%02X", block, idx, data[0]);
|
||||
|
||||
uint32_t buf[10]; // TODO sparse struct, 7 *bytes* then words at offset 4*7!
|
||||
memcpy(buf, configPcf.Pwd, sizeof(configPcf.Pwd));
|
||||
|
@ -148,16 +184,16 @@ static int CmdLFPCF7931Write(const char *Cmd) {
|
|||
buf[9] = configPcf.InitDelay;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf));
|
||||
SendCommandMIX(CMD_LF_PCF7931_WRITE, block, idx, data[0], buf, sizeof(buf));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pcf7931 read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pcf7931 reader`") " to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"read", CmdLFPCF7931Read, IfPm3Lf, "Read content of a PCF7931 transponder"},
|
||||
{"reader", CmdLFPCF7931Reader, IfPm3Lf, "Read content of a PCF7931 transponder"},
|
||||
{"write", CmdLFPCF7931Write, IfPm3Lf, "Write data on a PCF7931 transponder."},
|
||||
{"config", CmdLFPCF7931Config, AlwaysAvailable, "Configure the password, the tags initialization delay and time offsets (optional)"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
|
|
@ -8,51 +8,64 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfpresco.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_presco_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d <Card-ID> c <hex-ID> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " d <Card-ID> : 9 digit presco card ID");
|
||||
PrintAndLogEx(NORMAL, " c <hex-ID> : 8 digit hex card number");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf presco clone d 123456789"));
|
||||
// find presco preamble 0x10D in already demoded data
|
||||
static int detectPresco(uint8_t *dest, size_t *size) {
|
||||
if (*size < 128 * 2) return -1; //make sure buffer has data
|
||||
size_t startIdx = 0;
|
||||
uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
|
||||
return -2; //preamble not found
|
||||
if (*size != 128) return -3; //wrong demoded size
|
||||
//return start position
|
||||
return (int)startIdx;
|
||||
}
|
||||
|
||||
// convert base 12 ID to sitecode & usercode & 8 bit other unknown code
|
||||
static int getWiegandFromPrintedPresco(void *arr, uint32_t *fullcode) {
|
||||
char *s = (char *)arr;
|
||||
uint8_t val = 0;
|
||||
for (int i = 0; i < strlen(s); ++i) {
|
||||
// Get value from number string.
|
||||
if (s[i] == '*')
|
||||
val = 10;
|
||||
if (s[i] == '#')
|
||||
val = 11;
|
||||
if (s[i] >= 0x30 && s[i] <= 0x39)
|
||||
val = s[i] - 0x30;
|
||||
|
||||
*fullcode += val;
|
||||
|
||||
// last digit is only added, not multipled.
|
||||
if (i < strlen(s) - 1)
|
||||
*fullcode *= 12;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_presco_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of presco card with specified card number.");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf presco sim [h] d <Card-ID> or c <hex-ID>");
|
||||
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"));
|
||||
// calc not certain - intended to get bitstream for programming / sim
|
||||
static int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) {
|
||||
num_to_bytebits(0x10D00000, 32, prescoBits);
|
||||
num_to_bytebits(0x00000000, 32, prescoBits + 32);
|
||||
num_to_bytebits(0x00000000, 32, prescoBits + 64);
|
||||
num_to_bytebits(fullcode, 32, prescoBits + 96);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -85,53 +98,142 @@ int demodPresco(bool verbose) {
|
|||
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
||||
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
|
||||
uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32);
|
||||
uint32_t cardid = raw4;
|
||||
PrintAndLogEx(SUCCESS, "Presco - Card: " _GREEN_("%08X") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4);
|
||||
uint32_t fullcode = raw4;
|
||||
uint32_t usercode = fullcode & 0x0000FFFF;
|
||||
uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
|
||||
|
||||
uint32_t sitecode = 0, usercode = 0, fullcode = 0;
|
||||
bool Q5 = false;
|
||||
char cmd[12] = {0};
|
||||
sprintf(cmd, "H %08X", cardid);
|
||||
getWiegandFromPresco(cmd, &sitecode, &usercode, &fullcode, &Q5);
|
||||
PrintAndLogEx(SUCCESS, "SiteCode: " _GREEN_("%u") " UserCode: " _GREEN_("%u") " FullCode: " _GREEN_("%08X"), sitecode, usercode, fullcode);
|
||||
PrintAndLogEx(SUCCESS, "Presco Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08X") " Raw: " _YELLOW_("%08X%08X%08X%08X")
|
||||
, sitecode
|
||||
, usercode
|
||||
, fullcode
|
||||
, raw1, raw2, raw3, raw4
|
||||
);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdPrescoDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf presco demod",
|
||||
"Try to find presco preamble, if found decode / descramble data",
|
||||
"lf presco demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodPresco(true);
|
||||
}
|
||||
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdPrescoRead(const char *Cmd) {
|
||||
// Presco Number: 123456789 --> Sitecode 30 | usercode 8665
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 12000);
|
||||
return demodPresco(true);
|
||||
static int CmdPrescoReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf presco reader",
|
||||
"read a presco tag",
|
||||
"lf presco reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 12000);
|
||||
demodPresco(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// takes base 12 ID converts to hex
|
||||
// Or takes 8 digit hex ID
|
||||
static int CmdPrescoClone(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf presco clone",
|
||||
"clone a presco tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf presco clone -d 018363467\n"
|
||||
"lf presco clone -d 018363467 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf presco clone -d 018363467 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("c", NULL, "<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};
|
||||
|
||||
// get wiegand from printed number.
|
||||
if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) return usage_lf_presco_clone();
|
||||
|
||||
if (Q5)
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_PRESCO_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
if ((sitecode & 0xFF) != sitecode) {
|
||||
sitecode &= 0xFF;
|
||||
PrintAndLogEx(INFO, "Facility-Code Truncated to 8-bits (Presco): %u", sitecode);
|
||||
PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode);
|
||||
}
|
||||
|
||||
if ((usercode & 0xFFFF) != usercode) {
|
||||
usercode &= 0xFFFF;
|
||||
PrintAndLogEx(INFO, "Card Number Truncated to 16-bits (Presco): %u", usercode);
|
||||
PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode);
|
||||
}
|
||||
|
||||
blocks[1] = 0x10D00000; //preamble
|
||||
|
@ -139,25 +241,84 @@ static int CmdPrescoClone(const char *Cmd) {
|
|||
blocks[3] = 0x00000000;
|
||||
blocks[4] = fullcode;
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Presco to " _YELLOW_("%s") " with SiteCode: %u, UserCode: %u, FullCode: %08x", (Q5) ? "Q5/T5555" : "T55x7", sitecode, usercode, fullcode);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Presco to " _GREEN_("%s") " with Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08x")
|
||||
, cardtype
|
||||
, sitecode
|
||||
, usercode
|
||||
, fullcode
|
||||
);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
// takes base 12 ID converts to hex
|
||||
// Or takes 8 digit hex ID
|
||||
static int CmdPrescoSim(const char *Cmd) {
|
||||
uint32_t sitecode = 0, usercode = 0, fullcode = 0;
|
||||
bool Q5 = false;
|
||||
// get wiegand from printed number.
|
||||
if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG)
|
||||
return usage_lf_presco_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf presco sim",
|
||||
"Enables simulation of presco card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.",
|
||||
"lf presco sim -d 018363467"
|
||||
);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Presco - SiteCode: %u, UserCode: %u, FullCode: %08X", sitecode, usercode, fullcode);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("c", NULL, "<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];
|
||||
getPrescoBits(fullcode, bs);
|
||||
|
@ -185,9 +346,9 @@ static int CmdPrescoSim(const char *Cmd) {
|
|||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"},
|
||||
{"read", CmdPrescoRead, IfPm3Lf, "Attempt to read and Extract tag data"},
|
||||
{"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"},
|
||||
{"reader", CmdPrescoReader, IfPm3Lf, "Attempt to read and Extract tag data"},
|
||||
{"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -201,86 +362,3 @@ int CmdLFPresco(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
// find presco preamble 0x10D in already demoded data
|
||||
int detectPresco(uint8_t *dest, size_t *size) {
|
||||
if (*size < 128 * 2) return -1; //make sure buffer has data
|
||||
size_t startIdx = 0;
|
||||
uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
|
||||
return -2; //preamble not found
|
||||
if (*size != 128) return -3; //wrong demoded size
|
||||
//return start position
|
||||
return (int)startIdx;
|
||||
}
|
||||
|
||||
// convert base 12 ID to sitecode & usercode & 8 bit other unknown code
|
||||
int getWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5) {
|
||||
|
||||
bool hex = false, errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
char id[11];
|
||||
int stringlen = 0;
|
||||
memset(id, 0x00, sizeof(id));
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return PM3_EINVARG;
|
||||
case 'c':
|
||||
hex = true;
|
||||
//get hex
|
||||
*fullcode = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
//param get string int param_getstr(const char *line, int paramnum, char * str)
|
||||
stringlen = param_getstr(Cmd, cmdp + 1, id, sizeof(id));
|
||||
if (stringlen < 2) return PM3_EINVARG;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'q':
|
||||
*Q5 = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Validations
|
||||
if (errors || cmdp == 0) return PM3_EINVARG;
|
||||
|
||||
if (!hex) {
|
||||
uint8_t val = 0;
|
||||
for (int index = 0; index < strlen(id); ++index) {
|
||||
// Get value from number string.
|
||||
if (id[index] == '*')
|
||||
val = 10;
|
||||
if (id[index] == '#')
|
||||
val = 11;
|
||||
if (id[index] >= 0x30 && id[index] <= 0x39)
|
||||
val = id[index] - 0x30;
|
||||
|
||||
*fullcode += val;
|
||||
|
||||
// last digit is only added, not multipled.
|
||||
if (index < strlen(id) - 1)
|
||||
*fullcode *= 12;
|
||||
}
|
||||
}
|
||||
|
||||
*usercode = *fullcode & 0x0000FFFF; //% 65566
|
||||
*sitecode = (*fullcode >> 24) & 0x000000FF; // /= 16777216;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// calc not certain - intended to get bitstream for programming / sim
|
||||
int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) {
|
||||
num_to_bytebits(0x10D00000, 32, prescoBits);
|
||||
num_to_bytebits(0x00000000, 32, prescoBits + 32);
|
||||
num_to_bytebits(0x00000000, 32, prescoBits + 64);
|
||||
num_to_bytebits(fullcode, 32, prescoBits + 96);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -12,11 +12,6 @@
|
|||
#include "common.h"
|
||||
|
||||
int CmdLFPresco(const char *Cmd);
|
||||
|
||||
int demodPresco(bool verbose);
|
||||
int detectPresco(uint8_t *dest, size_t *size);
|
||||
int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits);
|
||||
int getWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode, uint32_t *fullcode, bool *Q5);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
|
@ -27,43 +26,11 @@
|
|||
#include "lfdemod.h" // parityTest
|
||||
#include "crc.h"
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM Defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_pyramid_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Farpointe/Pyramid tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. ");
|
||||
PrintAndLogEx(NORMAL, "Currently only works on 26bit");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf pyramid clone [h] <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)
|
||||
//print full Farpointe Data/Pyramid Prox ID and some bit format details if found
|
||||
int demodPyramid(bool verbose) {
|
||||
|
@ -211,30 +178,90 @@ int demodPyramid(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdPyramidDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pyramid demod",
|
||||
"Try to find Farpoint/Pyramid preamble, if found decode / descramble data",
|
||||
"lf pyramid demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodPyramid(true);
|
||||
}
|
||||
|
||||
static int CmdPyramidRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 15000);
|
||||
return demodPyramid(true);
|
||||
static int CmdPyramidReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pyramid reader",
|
||||
"read a Farpointe/Pyramid tag",
|
||||
"lf pyramid reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 15000);
|
||||
demodPyramid(true);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdPyramidClone(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pyramid_clone();
|
||||
uint32_t facilitycode = 0, cardnumber = 0, fc = 0, cn = 0;
|
||||
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_pyramid_clone();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pyramid clone",
|
||||
"clone a Farpointe/Pyramid tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
|
||||
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
|
||||
"Currently only works on 26bit",
|
||||
"lf pyramid clone --fc 123 --cn 11223\n"
|
||||
"lf pyramid clone --fc 123 --cn 11223 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf pyramid clone --fc 123 --cn 11223 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fc", "<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];
|
||||
uint8_t *bs = calloc(128, sizeof(uint8_t));
|
||||
if (bs == NULL) {
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
uint32_t facilitycode = (fc & 0x000000FF);
|
||||
uint32_t cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
|
@ -243,11 +270,18 @@ static int CmdPyramidClone(const char *Cmd) {
|
|||
|
||||
//Pyramid - compat mode, FSK2a, data rate 50, 4 data blocks
|
||||
blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
|
||||
// Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 2)) == 'q';
|
||||
if (q5)
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 4 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_PYRAMID_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[1] = bytebits_to_byte(bs, 32);
|
||||
blocks[2] = bytebits_to_byte(bs + 32, 32);
|
||||
|
@ -256,36 +290,53 @@ static int CmdPyramidClone(const char *Cmd) {
|
|||
|
||||
free(bs);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", (q5) ? "Q5/T5555" : "T55x7", facilitycode, cardnumber);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", cardtype, facilitycode, cardnumber);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdPyramidSim(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf pyramid sim",
|
||||
"Enables simulation of Farpointe/Pyramid card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated.\n"
|
||||
"Currently work only on 26bit",
|
||||
"lf pyramid sim --fc 123 --cn 1337"
|
||||
);
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pyramid_sim();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "fc", "<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];
|
||||
memset(bs, 0x00, sizeof(bs));
|
||||
|
||||
if (sscanf(Cmd, "%u %u", &fc, &cn) != 2) return usage_lf_pyramid_sim();
|
||||
|
||||
facilitycode = (fc & 0x000000FF);
|
||||
cardnumber = (cn & 0x0000FFFF);
|
||||
|
||||
if (getPyramidBits(facilitycode, cardnumber, bs) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating Farpointe/Pyramid - Facility Code: %u, CardNumber: %u", facilitycode, cardnumber);
|
||||
PrintAndLogEx(SUCCESS, "Simulating Farpointe/Pyramid - Facility Code: " _YELLOW_("%u") ", CardNumber: " _YELLOW_("%u"), facilitycode, cardnumber);
|
||||
|
||||
// Pyramid uses: fcHigh: 10, fcLow: 8, clk: 50, invert: 0
|
||||
lf_fsksim_t *payload = calloc(1, sizeof(lf_fsksim_t) + sizeof(bs));
|
||||
|
@ -309,11 +360,11 @@ static int CmdPyramidSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"},
|
||||
{"read", CmdPyramidRead, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"},
|
||||
{"reader", CmdPyramidReader, IfPm3Lf, "attempt to read and extract tag data"},
|
||||
{"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,36 +8,23 @@
|
|||
// ASK/Manchester, RF/40, 96 bits long (unknown cs)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfsecurakey.h"
|
||||
|
||||
#include <string.h> // memcpy
|
||||
#include <ctype.h> // tolower
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include <string.h> // memcpy
|
||||
#include <ctype.h> // tolower
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "parity.h" // for wiegand parity test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "parity.h" // for wiegand parity test
|
||||
#include "protocols.h" // t55xx defines
|
||||
#include "cmdlft55xx.h" // clone..
|
||||
#include "cliparser.h"
|
||||
#include "cmdlfem4x05.h" // EM defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_securakey_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Securakey tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf securakey clone [h] [b <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
|
||||
int demodSecurakey(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
|
@ -118,79 +105,188 @@ int demodSecurakey(bool verbose) {
|
|||
if (bitLen <= 32)
|
||||
PrintAndLogEx(SUCCESS, "Wiegand: " _GREEN_("%08X") " parity (%s)", (lWiegand << (bitLen / 2)) | rWiegand, parity ? _GREEN_("ok") : _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown");
|
||||
PrintAndLogEx(INFO, "How the checksum is calculated is unknown");
|
||||
PrintAndLogEx(INFO, "Help the community identify this format further\n by sharing your tag on the pm3 forum or with forum members");
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "\nHow the FC translates to printed FC is unknown");
|
||||
PrintAndLogEx(INFO, "How the checksum is calculated is unknown");
|
||||
PrintAndLogEx(INFO, "Help the community identify this format further\nby sharing your tag on the pm3 forum or discord");
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdSecurakeyDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf securakey demod",
|
||||
"Try to find Securakey preamble, if found decode / descramble data",
|
||||
"lf securakey demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodSecurakey(true);
|
||||
}
|
||||
|
||||
static int CmdSecurakeyRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 8000);
|
||||
return demodSecurakey(true);
|
||||
static int CmdSecurakeyReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf securakey reader",
|
||||
"read a Securakey tag",
|
||||
"lf securakey reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 8000);
|
||||
demodSecurakey(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdSecurakeyClone(const char *Cmd) {
|
||||
|
||||
uint32_t blocks[4];
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
int datalen = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf securakey clone",
|
||||
"clone a Securakey tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf securakey clone --raw 7FCB400001ADEA5344300000\n"
|
||||
"lf securakey clone --q5 --raw 7FCB400001ADEA5344300000 -> encode for Q5/T5555 tag\n"
|
||||
"lf securakey clone --em --raw 7FCB400001ADEA5344300000 -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_securakey_clone();
|
||||
case 'b': {
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t rawhex[12] = {0};
|
||||
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
|
||||
if (res != 0)
|
||||
errors = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("r", "raw", "<hex>", "raw hex data. 12 bytes"),
|
||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
int raw_len = 0;
|
||||
// skip first block, 3*4 = 12 bytes left
|
||||
uint8_t raw[12] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (errors || cmdp == 0) return usage_lf_securakey_clone();
|
||||
if (raw_len != 12) {
|
||||
PrintAndLogEx(ERR, "Data must be 12 bytes (24 HEX characters) %d", raw_len);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[4];
|
||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||
}
|
||||
|
||||
//Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks
|
||||
blocks[0] = T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_40 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(40) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Securakey to T55x7 with raw hex");
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_SECURAKEY_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Securakey to " _YELLOW_("%s") " with raw hex", cardtype);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em) {
|
||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||
} else {
|
||||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdSecurakeySim(const char *Cmd) {
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf securakey sim",
|
||||
"Enables simulation of secura card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.",
|
||||
"lf securakey sim --raw 7FCB400001ADEA5344300000"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("r", "raw", "<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;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdSecurakeyDemod, AlwaysAvailable, "Demodulate an Securakey tag from the GraphBuffer"},
|
||||
{"read", CmdSecurakeyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdSecurakeyClone, IfPm3Lf, "clone Securakey tag to T55x7"},
|
||||
{"sim", CmdSecurakeySim, IfPm3Lf, "simulate Securakey tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdSecurakeyDemod, AlwaysAvailable, "Demodulate an Securakey tag from the GraphBuffer"},
|
||||
{"reader", CmdSecurakeyReader, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdSecurakeyClone, IfPm3Lf, "clone Securakey tag to T55x7"},
|
||||
{"sim", CmdSecurakeySim, IfPm3Lf, "simulate Securakey tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
// Low frequency TI commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfti.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "commonutil.h"
|
||||
#include "comms.h"
|
||||
|
@ -19,7 +19,7 @@
|
|||
#include "ui.h"
|
||||
#include "proxgui.h"
|
||||
#include "graph.h"
|
||||
#include "cmdlfti.h"
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -272,43 +272,99 @@ out:
|
|||
}
|
||||
|
||||
static int CmdTIDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf ti demod",
|
||||
"Try to find TI preamble, if found decode / descramble data",
|
||||
"lf ti demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodTI(true);
|
||||
}
|
||||
|
||||
// read a TI tag and return its ID
|
||||
static int CmdTIRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_TI_READ, NULL, 0);
|
||||
static int CmdTIReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf ti reader",
|
||||
"read a TI tag",
|
||||
"lf ti reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_TI_READ, NULL, 0);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// write new data to a r/w TI tag
|
||||
static int CmdTIWrite(const char *Cmd) {
|
||||
int res = 0;
|
||||
uint64_t arg0, arg1, arg2;
|
||||
res = sscanf(Cmd, "%012" SCNx64 " %012" SCNx64 " %012" SCNx64 "", &arg0, &arg1, &arg2);
|
||||
|
||||
if (res == 2)
|
||||
arg2 = 0;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf ti write",
|
||||
"write to a r/w TI tag.",
|
||||
"lf ti write --raw 1122334455667788\n"
|
||||
"lf ti write --raw 1122334455667788 --crc 1122\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("r", "raw", "<hex>", "raw hex data. 8 bytes max"),
|
||||
arg_str0(NULL, "crc", "<hex>", "optional - crc"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int raw_len = 0;
|
||||
uint8_t raw[8] = {0};
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||
|
||||
int crc_len = 0;
|
||||
uint8_t crc[2] = {0};
|
||||
CLIGetHexWithReturn(ctx, 2, crc, &crc_len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
struct {
|
||||
uint32_t high;
|
||||
uint32_t low;
|
||||
uint16_t crc;
|
||||
} PACKED payload;
|
||||
|
||||
payload.high = bytes_to_num(raw, 4);
|
||||
payload.low = bytes_to_num(raw + 4, 4);
|
||||
payload.crc = bytes_to_num(crc, crc_len);
|
||||
|
||||
if (res < 2) {
|
||||
PrintAndLogEx(WARNING, "Please specify the data as two hex strings, optionally the CRC as a third");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0);
|
||||
SendCommandNG(CMD_LF_TI_WRITE, (uint8_t*)&payload, sizeof(payload));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti reader`") " to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI-type LF tag from the GraphBuffer"},
|
||||
{"read", CmdTIRead, IfPm3Lf, "Read and decode a TI 134 kHz tag"},
|
||||
{"write", CmdTIWrite, IfPm3Lf, "Write new data to a r/w TI 134 kHz tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdTIDemod, AlwaysAvailable, "Demodulate raw bits for TI LF tag from the GraphBuffer"},
|
||||
{"reader", CmdTIReader, IfPm3Lf, "Read and decode a TI 134 kHz tag"},
|
||||
{"write", CmdTIWrite, IfPm3Lf, "Write new data to a r/w TI 134 kHz tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -9,13 +9,10 @@
|
|||
// ASK/Manchester, RF/32, 64 bits (complete)
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfviking.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
|
@ -23,36 +20,10 @@
|
|||
#include "cmdlf.h"
|
||||
#include "lfdemod.h"
|
||||
#include "commonutil.h" // num_to_bytes
|
||||
#include "cliparser.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_viking_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Viking AM tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf viking clone <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
|
||||
int demodViking(bool verbose) {
|
||||
(void) verbose; // unused so far
|
||||
|
@ -83,45 +54,110 @@ int demodViking(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdVikingDemod(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf viking demod",
|
||||
"Try to find Viking AM preamble, if found decode / descramble data",
|
||||
"lf viking demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodViking(true);
|
||||
}
|
||||
|
||||
//see ASKDemod for what args are accepted
|
||||
static int CmdVikingRead(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
lf_read(false, 10000);
|
||||
return demodViking(true);
|
||||
static int CmdVikingReader(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf viking reader",
|
||||
"read a Viking AM tag",
|
||||
"lf viking reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 10000);
|
||||
demodViking(true);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdVikingClone(const char *Cmd) {
|
||||
uint32_t id = 0;
|
||||
uint64_t rawID = 0;
|
||||
bool Q5 = false;
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_viking_clone();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 16);
|
||||
if (id == 0) return usage_lf_viking_clone();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf viking clone",
|
||||
"clone a Viking AM tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf viking clone --cn 01A337\n"
|
||||
"lf viking clone --cn 01A337 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf viking clone --cn 112233 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
cmdp = tolower(param_getchar(Cmd, 1));
|
||||
if (cmdp == 'q')
|
||||
Q5 = true;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0(NULL, "cn", "<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 {
|
||||
bool Q5;
|
||||
bool EM;
|
||||
uint8_t blocks[8];
|
||||
} PACKED payload;
|
||||
payload.Q5 = Q5;
|
||||
payload.Q5 = q5;
|
||||
payload.EM = em;
|
||||
|
||||
num_to_bytes(rawID, 8, &payload.blocks[0]);
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
if (q5)
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
else if (em)
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Viking tag on " _YELLOW_("%s") " - ID " _YELLOW_("%08X")" raw " _YELLOW_("%s")
|
||||
, (Q5) ? "Q5/T5555" : "T55x7"
|
||||
, cardtype
|
||||
, id
|
||||
, sprint_hex(payload.blocks, sizeof(payload.blocks))
|
||||
, sprint_hex(payload.blocks, sizeof(payload.blocks))
|
||||
);
|
||||
|
||||
clearCommandBuffer();
|
||||
|
@ -133,20 +169,40 @@ static int CmdVikingClone(const char *Cmd) {
|
|||
return PM3_ETIMEOUT;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking reader`") " to verify");
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
static int CmdVikingSim(const char *Cmd) {
|
||||
uint32_t id = 0;
|
||||
uint64_t rawID = 0;
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_viking_sim();
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 16);
|
||||
if (id == 0) return usage_lf_viking_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf viking sim",
|
||||
"Enables simulation of viking card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n"
|
||||
"Per viking format, the card number is 8 digit hex number. Larger values are truncated.",
|
||||
"lf viking sim --cn 01A337"
|
||||
);
|
||||
|
||||
rawID = getVikingBits(id);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0(NULL, "cn", "<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));
|
||||
|
||||
|
@ -176,7 +232,7 @@ static int CmdVikingSim(const char *Cmd) {
|
|||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdVikingDemod, AlwaysAvailable, "Demodulate a Viking tag from the GraphBuffer"},
|
||||
{"read", CmdVikingRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"reader", CmdVikingReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
|
||||
{"clone", CmdVikingClone, IfPm3Lf, "clone Viking tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdVikingSim, IfPm3Lf, "simulate Viking tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
@ -201,7 +257,7 @@ uint64_t getVikingBits(uint32_t id) {
|
|||
ret |= checksum;
|
||||
return ret;
|
||||
}
|
||||
// by marshmellow
|
||||
|
||||
// find viking preamble 0xF200 in already demoded data
|
||||
int detectViking(uint8_t *src, size_t *size) {
|
||||
//make sure buffer has data
|
||||
|
|
|
@ -27,41 +27,14 @@
|
|||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // write verify
|
||||
#include "cmdlfem4x05.h" //
|
||||
#include "cliparser.h"
|
||||
|
||||
#define BL0CK1 0x56495332
|
||||
#ifndef VISA2k_BL0CK1
|
||||
#define VISA2k_BL0CK1 0x56495332
|
||||
#endif
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_visa2k_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a Visa2000 tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf visa2000 clone [h] <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) {
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 0; i < 32; i += 4)
|
||||
|
@ -160,52 +133,96 @@ int demodVisa2k(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdVisa2kDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf visa2000 demod",
|
||||
"Try to find visa2000 preamble, if found decode / descramble data",
|
||||
"lf visa2000 demod"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return demodVisa2k(true);
|
||||
}
|
||||
|
||||
// 64*96*2=12288 samples just in case we just missed the first preamble we can still catch 2 of them
|
||||
static int CmdVisa2kRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 20000);
|
||||
return demodVisa2k(true);
|
||||
static int CmdVisa2kReader(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf visa2000 reader",
|
||||
"read a visa2000 tag",
|
||||
"lf visa2000 reader -@ -> continuous reader mode"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool cm = arg_get_lit(ctx, 1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (cm) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
}
|
||||
|
||||
do {
|
||||
lf_read(false, 20000);
|
||||
demodVisa2k(!cm);
|
||||
} while (cm && !kbd_enter_pressed());
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdVisa2kClone(const char *Cmd) {
|
||||
|
||||
uint64_t id = 0;
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, BL0CK1, 0};
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf visa2000 clone",
|
||||
"clone a Visa2000 tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||
"lf visa2000 clone --cn 112233\n"
|
||||
"lf visa2000 clone --cn 112233 --q5 -> encode for Q5/T5555 tag\n"
|
||||
"lf visa2000 clone --cn 112233 --em -> encode for EM4305/4469"
|
||||
);
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h')
|
||||
return usage_lf_visa2k_clone();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "cn", "<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);
|
||||
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 1)) == 'q';
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
bool em = tolower(param_getchar(Cmd, 1)) == 'e';
|
||||
if (em) {
|
||||
blocks[0] = EM4305_VISA2000_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
uint32_t id = arg_get_u32_def(ctx, 1, 0);
|
||||
bool q5 = arg_get_lit(ctx, 2);
|
||||
bool em = arg_get_lit(ctx, 3);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_64 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, VISA2k_BL0CK1, 0};
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
if (q5) {
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
|
||||
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
|
||||
}
|
||||
|
||||
// EM4305
|
||||
if (em) {
|
||||
blocks[0] = EM4305_VISA2000_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||
}
|
||||
|
||||
blocks[2] = id;
|
||||
blocks[3] = (visa_parity(id) << 4) | visa_chksum(id);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, cardtype, id);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: " _GREEN_("%"PRIu32), cardtype, id);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res;
|
||||
|
@ -215,22 +232,31 @@ static int CmdVisa2kClone(const char *Cmd) {
|
|||
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 reader`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdVisa2kSim(const char *Cmd) {
|
||||
|
||||
uint32_t id = 0;
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h')
|
||||
return usage_lf_visa2k_sim();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf visa2000 sim",
|
||||
"Enables simulation of visa2k card with specified card number.\n"
|
||||
"Simulation runs until the button is pressed or another USB command is issued.\n",
|
||||
"lf visa2000 sim --cn 1337"
|
||||
);
|
||||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_1(NULL, "cn", "<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];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
|
@ -257,11 +283,11 @@ static int CmdVisa2kSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"},
|
||||
{"read", CmdVisa2kRead, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"},
|
||||
{"reader", CmdVisa2kReader, IfPm3Lf, "attempt to read and extract tag data from the antenna"},
|
||||
{"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -155,13 +155,26 @@ static int CmdAuto(const char *Cmd) {
|
|||
CmdPlot("");
|
||||
lf_read(false, 40000);
|
||||
char *fname = calloc(100, sizeof(uint8_t));
|
||||
AppendDate(fname, 100, "f lf_unknown_%Y-%m-%d_%H:%M");
|
||||
AppendDate(fname, 100, "-f lf_unknown_%Y-%m-%d_%H:%M");
|
||||
CmdSave(fname);
|
||||
free(fname);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdRem(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "rem",
|
||||
"Add a text line in log file",
|
||||
"rem"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
char buf[22] = {0};
|
||||
AppendDate(buf, sizeof(buf), NULL);
|
||||
PrintAndLogEx(NORMAL, "%s remark: %s", buf, Cmd);
|
||||
|
|
|
@ -32,12 +32,12 @@
|
|||
#include "fileutils.h"
|
||||
|
||||
#ifdef HAVE_LUA_SWIG
|
||||
extern int luaopen_pm3(lua_State* L);
|
||||
extern int luaopen_pm3(lua_State *L);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
#ifdef HAVE_PYTHON_SWIG
|
||||
extern PyObject* PyInit__pm3(void);
|
||||
extern PyObject *PyInit__pm3(void);
|
||||
#endif // HAVE_PYTHON_SWIG
|
||||
|
||||
// Partly ripped from PyRun_SimpleFileExFlags
|
||||
|
|
|
@ -519,8 +519,8 @@ static int CmdTraceLoad(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "trace load",
|
||||
"Load protocol data from binary file to trace buffer\n"
|
||||
"File extension is (.trace)",
|
||||
"trace load -f mytracefile"
|
||||
"File extension is <.trace>",
|
||||
"trace load -f mytracefile -> w/o file extension"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -555,13 +555,13 @@ static int CmdTraceSave(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "trace save",
|
||||
"Save protocol data from trace buffer to binary file\n"
|
||||
"File extension is (.trace)",
|
||||
"trace save -f mytracefile"
|
||||
"File extension is <.trace>",
|
||||
"trace save -f mytracefile -> w/o file extension"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("f", "file", "<filename>", "trace file to load"),
|
||||
arg_strx0("f", "file", "<filename>", "trace file to save"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
|
|
@ -151,8 +151,8 @@ int CmdWiegandDecode(const char *Cmd) {
|
|||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdWiegandList, AlwaysAvailable, "List available wiegand formats"},
|
||||
{"encode", CmdWiegandEncode, AlwaysAvailable, "Encode to wiegand raw hex"},
|
||||
{"decode", CmdWiegandDecode, AlwaysAvailable, "Convert raw hex to decoded wiegand format"},
|
||||
{"encode", CmdWiegandEncode, AlwaysAvailable, "Encode to wiegand raw hex (currently for HID Prox)"},
|
||||
{"decode", CmdWiegandDecode, AlwaysAvailable, "Convert raw hex to decoded wiegand format (currently for HID Prox)"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -778,7 +778,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
if (sdad_tlv) {
|
||||
PrintAndLogEx(INFO, "* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
|
||||
|
||||
const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
|
||||
struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
|
||||
if (!atc_db) {
|
||||
PrintAndLogEx(ERR, "Error: Can't recover IDN (ICC Dynamic Number)");
|
||||
emv_pk_free(pk);
|
||||
|
@ -804,9 +804,10 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
emv_pk_free(pk);
|
||||
emv_pk_free(issuer_pk);
|
||||
emv_pk_free(icc_pk);
|
||||
atc_db = NULL;
|
||||
tlvdb_free(atc_db);
|
||||
return 9;
|
||||
}
|
||||
|
||||
} else {
|
||||
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||
if (dac_db) {
|
||||
|
|
|
@ -39,13 +39,14 @@
|
|||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include "cipherutils.h"
|
||||
#include "cipher.h"
|
||||
#include "ikeys.h"
|
||||
#include "elite_crack.h"
|
||||
#include "fileutils.h"
|
||||
#include "des.h"
|
||||
#include "mbedtls/des.h"
|
||||
#include "util_posix.h"
|
||||
|
||||
/**
|
||||
|
@ -70,8 +71,7 @@
|
|||
* @param dest
|
||||
*/
|
||||
void permutekey(uint8_t key[8], uint8_t dest[8]) {
|
||||
int i;
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
for (uint8_t i = 0 ; i < 8 ; i++) {
|
||||
dest[i] = (((key[7] & (0x80 >> i)) >> (7 - i)) << 7) |
|
||||
(((key[6] & (0x80 >> i)) >> (7 - i)) << 6) |
|
||||
(((key[5] & (0x80 >> i)) >> (7 - i)) << 5) |
|
||||
|
@ -164,12 +164,16 @@ rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
|
|||
**/
|
||||
static void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) {
|
||||
memcpy(outp_key, key, 8);
|
||||
uint8_t j;
|
||||
while (n-- > 0) {
|
||||
for (j = 0; j < 8 ; j++)
|
||||
outp_key[j] = rl(outp_key[j]);
|
||||
outp_key[0] = rl(outp_key[0]);
|
||||
outp_key[1] = rl(outp_key[1]);
|
||||
outp_key[2] = rl(outp_key[2]);
|
||||
outp_key[3] = rl(outp_key[3]);
|
||||
outp_key[4] = rl(outp_key[4]);
|
||||
outp_key[5] = rl(outp_key[5]);
|
||||
outp_key[6] = rl(outp_key[6]);
|
||||
outp_key[7] = rl(outp_key[7]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static mbedtls_des_context ctx_enc;
|
||||
|
@ -214,16 +218,22 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) {
|
|||
uint8_t z[8][8] = {{0}, {0}};
|
||||
uint8_t temp_output[8] = {0};
|
||||
//calculate complement of key
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
key64_negated[i] = ~key64[i];
|
||||
key64_negated[0] = ~key64[0];
|
||||
key64_negated[1] = ~key64[1];
|
||||
key64_negated[2] = ~key64[2];
|
||||
key64_negated[3] = ~key64[3];
|
||||
key64_negated[4] = ~key64[4];
|
||||
key64_negated[5] = ~key64[5];
|
||||
key64_negated[6] = ~key64[6];
|
||||
key64_negated[7] = ~key64[7];
|
||||
|
||||
// Once again, key is on iclass-format
|
||||
desencrypt_iclass(key64, key64_negated, z[0]);
|
||||
|
||||
// PrintAndLogEx(NORMAL, "");
|
||||
// PrintAndLogEx(INFO, "High security custom key (Kcus):");
|
||||
// PrintAndLogEx(INFO, "z0 %s", sprint_hex(z[0],8));
|
||||
if (g_debugMode > 0) {
|
||||
PrintAndLogEx(DEBUG, "High security custom key (Kcus):");
|
||||
PrintAndLogEx(DEBUG, "z0 %s", sprint_hex(z[0], 8));
|
||||
}
|
||||
|
||||
uint8_t y[8][8] = {{0}, {0}};
|
||||
|
||||
|
@ -232,7 +242,7 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) {
|
|||
desdecrypt_iclass(z[0], key64_negated, y[0]);
|
||||
// PrintAndLogEx(INFO, "y0 %s", sprint_hex(y[0],8));
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
for (uint8_t i = 1; i < 8; i++) {
|
||||
// z [i] = DES dec (rk(K cus , i), z [i−1] )
|
||||
rk(key64, i, temp_output);
|
||||
//y [i] = DES enc (rk(K cus , i), y [i−1] )
|
||||
|
@ -242,7 +252,7 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) {
|
|||
}
|
||||
|
||||
if (outp_keytable != NULL) {
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
for (uint8_t i = 0 ; i < 8 ; i++) {
|
||||
memcpy(outp_keytable + i * 16, y[i], 8);
|
||||
memcpy(outp_keytable + 8 + i * 16, z[i], 8);
|
||||
}
|
||||
|
@ -280,25 +290,121 @@ static int _readFromDump(uint8_t dump[], dumpdata *item, uint8_t i) {
|
|||
return 0;
|
||||
}
|
||||
*/
|
||||
//static uint32_t startvalue = 0;
|
||||
/**
|
||||
* @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
|
||||
*This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
|
||||
*on the fly. If it finds that more than three bytes need to be bruteforced, it aborts.
|
||||
*It updates the keytable with the findings, also using the upper half of the 16-bit ints
|
||||
*to signal if the particular byte has been cracked or not.
|
||||
*
|
||||
* @param dump The dumpdata from iclass reader attack.
|
||||
* @param keytable where to write found values.
|
||||
* @return
|
||||
*/
|
||||
int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
||||
|
||||
int found = false;
|
||||
uint8_t key_sel_p[8] = {0};
|
||||
uint8_t div_key[8] = {0};
|
||||
uint8_t key_sel[8] = {0};
|
||||
uint8_t calculated_MAC[4] = {0};
|
||||
typedef struct {
|
||||
int thread_idx;
|
||||
uint32_t endmask;
|
||||
uint8_t numbytes_to_recover;
|
||||
uint8_t bytes_to_recover[3];
|
||||
uint8_t key_index[8];
|
||||
uint16_t keytable[128];
|
||||
loclass_dumpdata_t item;
|
||||
} loclass_thread_arg_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t values[3];
|
||||
} loclass_thread_ret_t;
|
||||
|
||||
static size_t loclass_tc = 1;
|
||||
static int loclass_found = 0;
|
||||
|
||||
static void *bf_thread(void *thread_arg) {
|
||||
|
||||
loclass_thread_arg_t *targ = (loclass_thread_arg_t *)thread_arg;
|
||||
const uint32_t endmask = targ->endmask;
|
||||
const uint8_t numbytes_to_recover = targ->numbytes_to_recover;
|
||||
uint32_t brute = targ->thread_idx;
|
||||
|
||||
uint8_t csn[8];
|
||||
uint8_t cc_nr[12];
|
||||
uint8_t mac[4];
|
||||
uint8_t key_index[8];
|
||||
uint8_t bytes_to_recover[3];
|
||||
uint16_t keytable[128];
|
||||
|
||||
memcpy(csn, targ->item.csn, sizeof(csn));
|
||||
memcpy(cc_nr, targ->item.cc_nr, sizeof(cc_nr));
|
||||
memcpy(mac, targ->item.mac, sizeof(mac));
|
||||
memcpy(key_index, targ->key_index, sizeof(key_index));
|
||||
memcpy(bytes_to_recover, targ->bytes_to_recover, sizeof(bytes_to_recover));
|
||||
memcpy(keytable, targ->keytable, sizeof(keytable));
|
||||
|
||||
int found;
|
||||
while (!(brute & endmask)) {
|
||||
|
||||
found = __atomic_load_n(&loclass_found, __ATOMIC_SEQ_CST);
|
||||
|
||||
if (found != 0xFF) return NULL;
|
||||
|
||||
//Update the keytable with the brute-values
|
||||
for (uint8_t i = 0; i < numbytes_to_recover; i++) {
|
||||
keytable[bytes_to_recover[i]] &= 0xFF00;
|
||||
keytable[bytes_to_recover[i]] |= (brute >> (i * 8) & 0xFF);
|
||||
}
|
||||
|
||||
uint8_t key_sel[8] = {0};
|
||||
|
||||
// Piece together the key
|
||||
key_sel[0] = keytable[key_index[0]] & 0xFF;
|
||||
key_sel[1] = keytable[key_index[1]] & 0xFF;
|
||||
key_sel[2] = keytable[key_index[2]] & 0xFF;
|
||||
key_sel[3] = keytable[key_index[3]] & 0xFF;
|
||||
key_sel[4] = keytable[key_index[4]] & 0xFF;
|
||||
key_sel[5] = keytable[key_index[5]] & 0xFF;
|
||||
key_sel[6] = keytable[key_index[6]] & 0xFF;
|
||||
key_sel[7] = keytable[key_index[7]] & 0xFF;
|
||||
|
||||
// Permute from iclass format to standard format
|
||||
|
||||
uint8_t key_sel_p[8] = {0};
|
||||
permutekey_rev(key_sel, key_sel_p);
|
||||
|
||||
// Diversify
|
||||
uint8_t div_key[8] = {0};
|
||||
diversifyKey(csn, key_sel_p, div_key);
|
||||
|
||||
// Calc mac
|
||||
uint8_t calculated_MAC[4] = {0};
|
||||
doMAC(cc_nr, div_key, calculated_MAC);
|
||||
|
||||
// success
|
||||
if (memcmp(calculated_MAC, mac, 4) == 0) {
|
||||
|
||||
loclass_thread_ret_t *r = (loclass_thread_ret_t *)malloc(sizeof(loclass_thread_ret_t));
|
||||
|
||||
for (uint8_t i = 0 ; i < numbytes_to_recover; i++) {
|
||||
r->values[i] = keytable[bytes_to_recover[i]] & 0xFF;
|
||||
}
|
||||
__atomic_store_n(&loclass_found, targ->thread_idx, __ATOMIC_SEQ_CST);
|
||||
pthread_exit((void *)r);
|
||||
}
|
||||
|
||||
brute += loclass_tc;
|
||||
|
||||
#define _CLR_ "\x1b[0K"
|
||||
|
||||
if (numbytes_to_recover == 3) {
|
||||
if ((brute > 0) && ((brute & 0xFFFF) == 0)) {
|
||||
PrintAndLogEx(INPLACE, "[ %02x %02x %02x ] %8u / %u", bytes_to_recover[0], bytes_to_recover[1], bytes_to_recover[2], brute, 0xFFFFFF);
|
||||
}
|
||||
} else if (numbytes_to_recover == 2) {
|
||||
if ((brute > 0) && ((brute & 0x3F) == 0))
|
||||
PrintAndLogEx(INPLACE, "[ %02x %02x ] %5u / %u" _CLR_, bytes_to_recover[0], bytes_to_recover[1], brute, 0xFFFF);
|
||||
} else {
|
||||
if ((brute > 0) && ((brute & 0x1F) == 0))
|
||||
PrintAndLogEx(INPLACE, "[ %02x ] %3u / %u" _CLR_, bytes_to_recover[0], brute, 0xFF);
|
||||
}
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
|
||||
void *dummyptr = NULL;
|
||||
return dummyptr;
|
||||
}
|
||||
|
||||
int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) {
|
||||
|
||||
// reset thread signals
|
||||
loclass_found = 0xFF;
|
||||
|
||||
//Get the key index (hash1)
|
||||
uint8_t key_index[8] = {0};
|
||||
|
@ -317,13 +423,12 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
|||
* Only the lower eight bits correspond to the (hopefully cracked) key-value.
|
||||
**/
|
||||
uint8_t bytes_to_recover[3] = {0};
|
||||
uint8_t numbytes_to_recover = 0 ;
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue;
|
||||
uint8_t numbytes_to_recover = 0;
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
if (keytable[key_index[i]] & (LOCLASS_CRACKED | LOCLASS_BEING_CRACKED)) continue;
|
||||
|
||||
bytes_to_recover[numbytes_to_recover++] = key_index[i];
|
||||
keytable[key_index[i]] |= BEING_CRACKED;
|
||||
keytable[key_index[i]] |= LOCLASS_BEING_CRACKED;
|
||||
|
||||
if (numbytes_to_recover > 3) {
|
||||
PrintAndLogEx(FAILED, "The CSN requires > 3 byte bruteforce, not supported");
|
||||
|
@ -331,35 +436,159 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
|||
PrintAndLogEx(INFO, "HASH1 %s", sprint_hex(key_index, 8));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
//Before we exit, reset the 'BEING_CRACKED' to zero
|
||||
keytable[bytes_to_recover[0]] &= ~BEING_CRACKED;
|
||||
keytable[bytes_to_recover[1]] &= ~BEING_CRACKED;
|
||||
keytable[bytes_to_recover[2]] &= ~BEING_CRACKED;
|
||||
keytable[bytes_to_recover[0]] &= ~LOCLASS_BEING_CRACKED;
|
||||
keytable[bytes_to_recover[1]] &= ~LOCLASS_BEING_CRACKED;
|
||||
keytable[bytes_to_recover[2]] &= ~LOCLASS_BEING_CRACKED;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes,
|
||||
*/
|
||||
//uint32_t brute = startvalue;
|
||||
uint32_t brute = 0;
|
||||
/*
|
||||
Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
|
||||
(when brute reaches 0x100). And so on...
|
||||
bytes_to_recover = 1 --> endmask = 0x000000100
|
||||
bytes_to_recover = 2 --> endmask = 0x000010000
|
||||
bytes_to_recover = 3 --> endmask = 0x001000000
|
||||
*/
|
||||
if (numbytes_to_recover == 0) {
|
||||
PrintAndLogEx(INFO, "No bytes to recover, exiting");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
loclass_thread_arg_t args[loclass_tc];
|
||||
// init thread arguments
|
||||
for (int i = 0; i < loclass_tc; i++) {
|
||||
args[i].thread_idx = i;
|
||||
args[i].numbytes_to_recover = numbytes_to_recover;
|
||||
args[i].endmask = 1 << 8 * numbytes_to_recover;
|
||||
|
||||
memcpy((void *)&args[i].item, (void *)&item, sizeof(loclass_dumpdata_t));
|
||||
memcpy(args[i].bytes_to_recover, bytes_to_recover, sizeof(args[i].bytes_to_recover));
|
||||
memcpy(args[i].key_index, key_index, sizeof(args[i].key_index));
|
||||
memcpy(args[i].keytable, keytable, sizeof(args[i].keytable));
|
||||
}
|
||||
|
||||
pthread_t threads[loclass_tc];
|
||||
// create threads
|
||||
for (int i = 0; i < loclass_tc; i++) {
|
||||
int res = pthread_create(&threads[i], NULL, bf_thread, (void *)&args[i]);
|
||||
if (res) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(WARNING, "Failed to create pthreads. Quitting");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
// wait for threads to terminate:
|
||||
void *ptrs[loclass_tc];
|
||||
for (int i = 0; i < loclass_tc; i++)
|
||||
pthread_join(threads[i], &ptrs[i]);
|
||||
|
||||
// was it a success?
|
||||
int res = PM3_SUCCESS;
|
||||
if (loclass_found == 0xFF) {
|
||||
res = PM3_ESOFT;
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(WARNING, "Failed to recover %d bytes using the following CSN", numbytes_to_recover);
|
||||
PrintAndLogEx(INFO, "CSN %s", sprint_hex(item.csn, 8));
|
||||
|
||||
//Before we exit, reset the 'BEING_CRACKED' to zero
|
||||
for (uint8_t i = 0; i < numbytes_to_recover; i++) {
|
||||
keytable[bytes_to_recover[i]] &= 0xFF;
|
||||
keytable[bytes_to_recover[i]] |= LOCLASS_CRACK_FAILED;
|
||||
}
|
||||
|
||||
} else {
|
||||
loclass_thread_ret_t ice = *((loclass_thread_ret_t *)ptrs[loclass_found]);
|
||||
|
||||
for (uint8_t i = 0; i < numbytes_to_recover; i++) {
|
||||
keytable[bytes_to_recover[i]] = ice.values[i];
|
||||
keytable[bytes_to_recover[i]] &= 0xFF;
|
||||
keytable[bytes_to_recover[i]] |= LOCLASS_CRACKED;
|
||||
}
|
||||
for (uint8_t i = 0; i < loclass_tc; i++) {
|
||||
free(ptrs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
memset(args, 0x00, sizeof(args));
|
||||
memset(threads, 0x00, sizeof(threads));
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
|
||||
*This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
|
||||
*on the fly. If it finds that more than three bytes need to be bruteforced, it aborts.
|
||||
*It updates the keytable with the findings, also using the upper half of the 16-bit ints
|
||||
*to signal if the particular byte has been cracked or not.
|
||||
*
|
||||
* @param dump The dumpdata from iclass reader attack.
|
||||
* @param keytable where to write found values.
|
||||
* @return
|
||||
*/
|
||||
/*
|
||||
int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) {
|
||||
|
||||
//Get the key index (hash1)
|
||||
uint8_t key_index[8] = {0};
|
||||
hash1(item.csn, key_index);
|
||||
*/
|
||||
/*
|
||||
* Determine which bytes to retrieve. A hash is typically
|
||||
* 01010000454501
|
||||
* We go through that hash, and in the corresponding keytable, we put markers
|
||||
* on what state that particular index is:
|
||||
* - CRACKED (this has already been cracked)
|
||||
* - BEING_CRACKED (this is being bruteforced now)
|
||||
* - CRACK_FAILED (self-explaining...)
|
||||
*
|
||||
* The markers are placed in the high area of the 16 bit key-table.
|
||||
* Only the lower eight bits correspond to the (hopefully cracked) key-value.
|
||||
**/
|
||||
|
||||
|
||||
/*
|
||||
uint8_t bytes_to_recover[3] = {0};
|
||||
uint8_t numbytes_to_recover = 0 ;
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
if (keytable[key_index[i]] & (LOCLASS_CRACKED | LOCLASS_BEING_CRACKED)) continue;
|
||||
|
||||
bytes_to_recover[numbytes_to_recover++] = key_index[i];
|
||||
keytable[key_index[i]] |= LOCLASS_BEING_CRACKED;
|
||||
|
||||
if (numbytes_to_recover > 3) {
|
||||
PrintAndLogEx(FAILED, "The CSN requires > 3 byte bruteforce, not supported");
|
||||
PrintAndLogEx(INFO, "CSN %s", sprint_hex(item.csn, 8));
|
||||
PrintAndLogEx(INFO, "HASH1 %s", sprint_hex(key_index, 8));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
//Before we exit, reset the 'BEING_CRACKED' to zero
|
||||
keytable[bytes_to_recover[0]] &= ~LOCLASS_BEING_CRACKED;
|
||||
keytable[bytes_to_recover[1]] &= ~LOCLASS_BEING_CRACKED;
|
||||
keytable[bytes_to_recover[2]] &= ~LOCLASS_BEING_CRACKED;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t key_sel_p[8] = {0};
|
||||
uint8_t div_key[8] = {0};
|
||||
uint8_t key_sel[8] = {0};
|
||||
uint8_t calculated_MAC[4] = {0};
|
||||
|
||||
|
||||
//A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes,
|
||||
uint32_t brute = 0;
|
||||
*/
|
||||
/*
|
||||
Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
|
||||
(when brute reaches 0x100). And so on...
|
||||
bytes_to_recover = 1 --> endmask = 0x000000100
|
||||
bytes_to_recover = 2 --> endmask = 0x000010000
|
||||
bytes_to_recover = 3 --> endmask = 0x001000000
|
||||
*/
|
||||
/*
|
||||
uint32_t endmask = 1 << 8 * numbytes_to_recover;
|
||||
PrintAndLogEx(NORMAL, "----------------------------");
|
||||
for (i = 0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++)
|
||||
PrintAndLogEx(INFO, "Bruteforcing byte %d", bytes_to_recover[i]);
|
||||
for (uint8_t i = 0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++)
|
||||
PrintAndLogEx(INFO, "Bruteforcing %d", bytes_to_recover[i]);
|
||||
|
||||
bool found = false;
|
||||
while (!found && !(brute & endmask)) {
|
||||
|
||||
//Update the keytable with the brute-values
|
||||
for (i = 0; i < numbytes_to_recover; i++) {
|
||||
for (uint8_t i = 0; i < numbytes_to_recover; i++) {
|
||||
keytable[bytes_to_recover[i]] &= 0xFF00;
|
||||
keytable[bytes_to_recover[i]] |= (brute >> (i * 8) & 0xFF);
|
||||
}
|
||||
|
@ -376,16 +605,15 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
|||
|
||||
//Permute from iclass format to standard format
|
||||
permutekey_rev(key_sel, key_sel_p);
|
||||
//Diversify
|
||||
|
||||
diversifyKey(item.csn, key_sel_p, div_key);
|
||||
//Calc mac
|
||||
doMAC(item.cc_nr, div_key, calculated_MAC);
|
||||
|
||||
// success
|
||||
if (memcmp(calculated_MAC, item.mac, 4) == 0) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
for (i = 0 ; i < numbytes_to_recover; i++) {
|
||||
PrintAndLogEx(INFO, "%d: 0x%02x", bytes_to_recover[i], 0xFF & keytable[bytes_to_recover[i]]);
|
||||
for (uint8_t i = 0 ; i < numbytes_to_recover; i++) {
|
||||
PrintAndLogEx(SUCCESS, "%d: 0x%02x", bytes_to_recover[i], keytable[bytes_to_recover[i]] & 0xFF);
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
|
@ -393,9 +621,7 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
|||
|
||||
brute++;
|
||||
if ((brute & 0xFFFF) == 0) {
|
||||
PrintAndLogEx(NORMAL, "%3d," NOLF, (brute >> 16) & 0xFF);
|
||||
if (((brute >> 16) % 0x10) == 0)
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INPLACE, "%3d", (brute >> 16) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,19 +634,20 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
|||
errors = PM3_ESOFT;
|
||||
|
||||
//Before we exit, reset the 'BEING_CRACKED' to zero
|
||||
for (i = 0; i < numbytes_to_recover; i++) {
|
||||
for (uint8_t i = 0; i < numbytes_to_recover; i++) {
|
||||
keytable[bytes_to_recover[i]] &= 0xFF;
|
||||
keytable[bytes_to_recover[i]] |= CRACK_FAILED;
|
||||
keytable[bytes_to_recover[i]] |= LOCLASS_CRACK_FAILED;
|
||||
}
|
||||
} else {
|
||||
//PrintAndLogEx(SUCCESS, "DES calcs: %u", brute);
|
||||
for (i = 0; i < numbytes_to_recover; i++) {
|
||||
for (uint8_t i = 0; i < numbytes_to_recover; i++) {
|
||||
keytable[bytes_to_recover[i]] &= 0xFF;
|
||||
keytable[bytes_to_recover[i]] |= CRACKED;
|
||||
keytable[bytes_to_recover[i]] |= LOCLASS_CRACKED;
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* From dismantling iclass-paper:
|
||||
|
@ -434,7 +661,7 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
|||
* @param master_key where to put the master key
|
||||
* @return 0 for ok, 1 for failz
|
||||
*/
|
||||
int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]) {
|
||||
int calculateMasterKey(uint8_t first16bytes[], uint8_t kcus[]) {
|
||||
mbedtls_des_context ctx_e;
|
||||
|
||||
uint8_t z_0[8] = {0};
|
||||
|
@ -457,9 +684,14 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]) {
|
|||
mbedtls_des_setkey_enc(&ctx_e, z_0_rev);
|
||||
mbedtls_des_crypt_ecb(&ctx_e, y_0, key64_negated);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 8 ; i++)
|
||||
key64[i] = ~key64_negated[i];
|
||||
key64[0] = ~key64_negated[0];
|
||||
key64[1] = ~key64_negated[1];
|
||||
key64[2] = ~key64_negated[2];
|
||||
key64[3] = ~key64_negated[3];
|
||||
key64[4] = ~key64_negated[4];
|
||||
key64[5] = ~key64_negated[5];
|
||||
key64[6] = ~key64_negated[6];
|
||||
key64[7] = ~key64_negated[7];
|
||||
|
||||
// Can we verify that the key is correct?
|
||||
// Once again, key is on iclass-format
|
||||
|
@ -468,21 +700,20 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]) {
|
|||
|
||||
mbedtls_des_setkey_enc(&ctx_e, key64_stdformat);
|
||||
mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result);
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
PrintAndLogEx(SUCCESS, "-- High security custom key (Kcus) --");
|
||||
PrintAndLogEx(SUCCESS, "Standard format %s", sprint_hex(key64_stdformat, 8));
|
||||
PrintAndLogEx(SUCCESS, "iClass format %s", sprint_hex(key64, 8));
|
||||
|
||||
if (master_key != NULL)
|
||||
memcpy(master_key, key64, 8);
|
||||
if (kcus != NULL)
|
||||
memcpy(kcus, key64, 8);
|
||||
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
if (memcmp(z_0, result, 4) != 0) {
|
||||
PrintAndLogEx(WARNING, _RED_("Failed to verify") " calculated master key (k_cus)! Something is wrong.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("Key verified ok!"));
|
||||
PrintAndLogEx(SUCCESS, "----- " _CYAN_("High security custom key (Kcus)") " -----");
|
||||
PrintAndLogEx(SUCCESS, "Standard format %s", sprint_hex(key64_stdformat, 8));
|
||||
PrintAndLogEx(SUCCESS, "iCLASS format " _GREEN_("%s"), sprint_hex(key64, 8));
|
||||
PrintAndLogEx(SUCCESS, "Key verified (" _GREEN_("ok") ")");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/**
|
||||
|
@ -494,28 +725,32 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]) {
|
|||
*/
|
||||
int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) {
|
||||
uint8_t i;
|
||||
size_t itemsize = sizeof(dumpdata);
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
dumpdata *attack = (dumpdata *) calloc(itemsize, sizeof(uint8_t));
|
||||
size_t itemsize = sizeof(loclass_dumpdata_t);
|
||||
loclass_dumpdata_t *attack = (loclass_dumpdata_t *) calloc(itemsize, sizeof(uint8_t));
|
||||
if (attack == NULL) {
|
||||
PrintAndLogEx(WARNING, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
loclass_tc = num_CPUs();
|
||||
PrintAndLogEx(INFO, "bruteforce using " _YELLOW_("%zu") " threads", loclass_tc);
|
||||
|
||||
int res = 0;
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
for (i = 0 ; i * itemsize < dumpsize ; i++) {
|
||||
memcpy(attack, dump + i * itemsize, itemsize);
|
||||
res += bruteforceItem(*attack, keytable);
|
||||
res = bruteforceItem(*attack, keytable);
|
||||
if (res != PM3_SUCCESS)
|
||||
break;
|
||||
}
|
||||
free(attack);
|
||||
t1 = msclock() - t1;
|
||||
PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds", t1 / 1000);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "time " _YELLOW_("%" PRIu64) " seconds", t1 / 1000);
|
||||
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "loclass exiting. Try run " _YELLOW_("`hf iclass sim 2`") " again and collect new data");
|
||||
PrintAndLogEx(ERR, "loclass exiting. Try run " _YELLOW_("`hf iclass sim -t 2`") " again and collect new data");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -524,11 +759,10 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) {
|
|||
// indicate crack-status. Those must be discarded for the
|
||||
// master key calculation
|
||||
uint8_t first16bytes[16] = {0};
|
||||
|
||||
for (i = 0 ; i < 16 ; i++) {
|
||||
first16bytes[i] = keytable[i] & 0xFF;
|
||||
|
||||
if (!(keytable[i] & CRACKED)) {
|
||||
if ((keytable[i] & LOCLASS_CRACKED) != LOCLASS_CRACKED) {
|
||||
PrintAndLogEx(WARNING, "Warning: we are missing byte %d, custom key calculation will fail...", i);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -620,7 +854,7 @@ static int _test_iclass_key_permutation(void) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Iclass key permutation (%s)", _GREEN_("OK"));
|
||||
PrintAndLogEx(SUCCESS, " Iclass key permutation (%s)", _GREEN_("ok"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -640,8 +874,8 @@ static int _testHash1(void) {
|
|||
}
|
||||
|
||||
int testElite(bool slowtests) {
|
||||
PrintAndLogEx(INFO, "Testing iClass Elite functinality...");
|
||||
PrintAndLogEx(INFO, "Testing hash2");
|
||||
PrintAndLogEx(INFO, "Testing iClass Elite functionality");
|
||||
PrintAndLogEx(INFO, "Testing hash2...");
|
||||
uint8_t k_cus[8] = {0x5B, 0x7C, 0x62, 0xC4, 0x91, 0xC1, 0x1B, 0x39};
|
||||
|
||||
/**
|
||||
|
@ -661,20 +895,19 @@ int testElite(bool slowtests) {
|
|||
*/
|
||||
uint8_t keytable[128] = {0};
|
||||
hash2(k_cus, keytable);
|
||||
printarr_human_readable("Hash2", keytable, 128);
|
||||
printarr_human_readable("---------------------- Hash2 ----------------------", keytable, sizeof(keytable));
|
||||
if (keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95) {
|
||||
PrintAndLogEx(SUCCESS, " Hash2 (%s)", _GREEN_("ok"));
|
||||
PrintAndLogEx(SUCCESS, " hash2 (%s)", _GREEN_("ok"));
|
||||
}
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
PrintAndLogEx(INFO, "Testing hash1...");
|
||||
res += _testHash1();
|
||||
PrintAndLogEx(INFO, " hash1 (%s)", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail"));
|
||||
PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " hash1 (%s)", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(INFO, "Testing key diversification...");
|
||||
res += _test_iclass_key_permutation();
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(INFO, " key diversification (%s)", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail"));
|
||||
PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " key diversification (%s)", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail"));
|
||||
|
||||
if (slowtests)
|
||||
res += _testBruteforce();
|
||||
|
|
|
@ -38,6 +38,22 @@
|
|||
|
||||
#ifndef ELITE_CRACK_H
|
||||
#define ELITE_CRACK_H
|
||||
|
||||
//Crack status, see below
|
||||
#define LOCLASS_CRACKED 0x0100
|
||||
#define LOCLASS_BEING_CRACKED 0x0200
|
||||
#define LOCLASS_CRACK_FAILED 0x0400
|
||||
|
||||
/**
|
||||
This is how we expect each 'entry' in a dumpfile to look
|
||||
**/
|
||||
typedef struct {
|
||||
uint8_t csn[8];
|
||||
uint8_t cc_nr[12];
|
||||
uint8_t mac[4];
|
||||
} loclass_dumpdata_t;
|
||||
|
||||
|
||||
void permutekey(uint8_t key[8], uint8_t dest[8]);
|
||||
/**
|
||||
* Permutes a key from iclass specific format to NIST format
|
||||
|
@ -46,10 +62,6 @@ void permutekey(uint8_t key[8], uint8_t dest[8]);
|
|||
* @param dest
|
||||
*/
|
||||
void permutekey_rev(uint8_t key[8], uint8_t dest[8]);
|
||||
//Crack status, see below
|
||||
#define CRACKED 0x0100
|
||||
#define BEING_CRACKED 0x0200
|
||||
#define CRACK_FAILED 0x0400
|
||||
|
||||
/**
|
||||
* Perform a bruteforce against a file which has been saved by pm3
|
||||
|
@ -69,7 +81,7 @@ int bruteforceFile(const char *filename, uint16_t keytable[]);
|
|||
*/
|
||||
int bruteforceFileNoKeys(const char *filename);
|
||||
/**
|
||||
* @brief Same as bruteforcefile, but uses a an array of dumpdata instead
|
||||
* @brief Same as bruteforcefile, but uses a an array of loclass_dumpdata_t instead
|
||||
* @param dump
|
||||
* @param dumpsize
|
||||
* @param keytable
|
||||
|
@ -77,15 +89,6 @@ int bruteforceFileNoKeys(const char *filename);
|
|||
*/
|
||||
int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]);
|
||||
|
||||
/**
|
||||
This is how we expect each 'entry' in a dumpfile to look
|
||||
**/
|
||||
typedef struct {
|
||||
uint8_t csn[8];
|
||||
uint8_t cc_nr[12];
|
||||
uint8_t mac[4];
|
||||
} dumpdata;
|
||||
|
||||
/**
|
||||
* @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
|
||||
*This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
|
||||
|
@ -93,11 +96,11 @@ typedef struct {
|
|||
*It updates the keytable with the findings, also using the upper half of the 16-bit ints
|
||||
*to signal if the particular byte has been cracked or not.
|
||||
*
|
||||
* @param dump The dumpdata from iclass reader attack.
|
||||
* @param loclass_dumpdata_t The dumpdata from iclass reader attack.
|
||||
* @param keytable where to write found values.
|
||||
* @return
|
||||
*/
|
||||
int bruteforceItem(dumpdata item, uint16_t keytable[]);
|
||||
int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]);
|
||||
/**
|
||||
* Hash1 takes CSN as input, and determines what bytes in the keytable will be used
|
||||
* when constructing the K_sel.
|
||||
|
@ -118,7 +121,7 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable);
|
|||
* @param master_key where to put the master key
|
||||
* @return 0 for ok, 1 for failz
|
||||
*/
|
||||
int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[]);
|
||||
int calculateMasterKey(uint8_t first16bytes[], uint8_t master_key[]);
|
||||
|
||||
/**
|
||||
* @brief Test function
|
||||
|
@ -141,5 +144,4 @@ int testElite(bool slowtests);
|
|||
|
||||
**/
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,7 @@ From "Dismantling iclass":
|
|||
|
||||
#include "fileutils.h"
|
||||
#include "cipherutils.h"
|
||||
#include "des.h"
|
||||
#include "mbedtls/des.h"
|
||||
|
||||
uint8_t pi[35] = {
|
||||
0x0F, 0x17, 0x1B, 0x1D, 0x1E, 0x27, 0x2B, 0x2D,
|
||||
|
@ -80,9 +80,6 @@ uint8_t pi[35] = {
|
|||
0x72, 0x74, 0x78
|
||||
};
|
||||
|
||||
static mbedtls_des_context ctx_enc;
|
||||
static mbedtls_des_context ctx_dec;
|
||||
|
||||
/**
|
||||
* @brief The key diversification algorithm uses 6-bit bytes.
|
||||
* This implementation uses 64 bit uint to pack seven of them into one
|
||||
|
@ -94,16 +91,19 @@ static mbedtls_des_context ctx_dec;
|
|||
* @param n bitnumber
|
||||
* @return
|
||||
*/
|
||||
static uint8_t getSixBitByte(uint64_t c, int n) {
|
||||
#define getSixBitByte(c, n) ((uint8_t)(((c) >> (42 - 6 * (n))) & 0x3F))
|
||||
/*
|
||||
static inline uint8_t getSixBitByte(uint64_t c, int n) {
|
||||
return (c >> (42 - 6 * n)) & 0x3F;
|
||||
}
|
||||
|
||||
*/
|
||||
/**
|
||||
* @brief Puts back a six-bit 'byte' into a uint64_t.
|
||||
* @param c buffer
|
||||
* @param z the value to place there
|
||||
* @param n bitnumber.
|
||||
*/
|
||||
|
||||
static void pushbackSixBitByte(uint64_t *c, uint8_t z, int n) {
|
||||
//0x XXXX YYYY ZZZZ ZZZZ ZZZZ
|
||||
// ^z0 ^z7
|
||||
|
@ -210,14 +210,14 @@ static void permute(BitstreamIn *p_in, uint64_t z, int l, int r, BitstreamOut *o
|
|||
return;
|
||||
|
||||
bool pn = tailBit(p_in);
|
||||
if (pn) { // pn = 1
|
||||
if (pn) {
|
||||
// pn = 1
|
||||
uint8_t zl = getSixBitByte(z, l);
|
||||
|
||||
push6bits(out, zl + 1);
|
||||
permute(p_in, z, l + 1, r, out);
|
||||
} else { // otherwise
|
||||
} else {
|
||||
// otherwise
|
||||
uint8_t zr = getSixBitByte(z, r);
|
||||
|
||||
push6bits(out, zr);
|
||||
permute(p_in, z, l, r + 1, out);
|
||||
}
|
||||
|
@ -226,6 +226,7 @@ static void permute(BitstreamIn *p_in, uint64_t z, int l, int r, BitstreamOut *o
|
|||
static void printState(const char *desc, uint64_t c) {
|
||||
if (g_debugMode == 0)
|
||||
return;
|
||||
|
||||
char s[60] = {0};
|
||||
snprintf(s, sizeof(s), "%s : ", desc);
|
||||
|
||||
|
@ -254,8 +255,10 @@ static void printState(const char *desc, uint64_t c) {
|
|||
void hash0(uint64_t c, uint8_t k[8]) {
|
||||
c = swapZvalues(c);
|
||||
|
||||
PrintAndLogEx(DEBUG, " | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
|
||||
printState("origin", c);
|
||||
if (g_debugMode > 0) {
|
||||
PrintAndLogEx(DEBUG, " | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
|
||||
printState("origin", c);
|
||||
}
|
||||
//These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
|
||||
// x = 8 bits
|
||||
// y = 8 bits
|
||||
|
@ -266,9 +269,7 @@ void hash0(uint64_t c, uint8_t k[8]) {
|
|||
|
||||
for (int n = 0; n < 4 ; n++) {
|
||||
uint8_t zn = getSixBitByte(c, n);
|
||||
|
||||
uint8_t zn4 = getSixBitByte(c, n + 4);
|
||||
|
||||
uint8_t _zn = (zn % (63 - n)) + n;
|
||||
uint8_t _zn4 = (zn4 % (64 - n)) + n;
|
||||
|
||||
|
@ -276,17 +277,18 @@ void hash0(uint64_t c, uint8_t k[8]) {
|
|||
pushbackSixBitByte(&zP, _zn4, n + 4);
|
||||
}
|
||||
|
||||
printState("0|0|z'", zP);
|
||||
if (g_debugMode > 0) printState("0|0|z'", zP);
|
||||
|
||||
uint64_t zCaret = check(zP);
|
||||
printState("0|0|z^", zP);
|
||||
|
||||
if (g_debugMode > 0) printState("0|0|z^", zP);
|
||||
|
||||
uint8_t p = pi[x % 35];
|
||||
|
||||
if (x & 1) //Check if x7 is 1
|
||||
p = ~p;
|
||||
|
||||
PrintAndLogEx(DEBUG, "p: %02x", p);
|
||||
if (g_debugMode > 0) PrintAndLogEx(DEBUG, " p : %02x", p);
|
||||
|
||||
BitstreamIn p_in = { &p, 8, 0 };
|
||||
uint8_t outbuffer[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
@ -301,9 +303,8 @@ void hash0(uint64_t c, uint8_t k[8]) {
|
|||
|
||||
zTilde >>= 16;
|
||||
|
||||
printState("0|0|z~", zTilde);
|
||||
if (g_debugMode > 0) printState("0|0|z~", zTilde);
|
||||
|
||||
// int zerocounter = 0 ;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// the key on index i is first a bit from y
|
||||
// then six bits from z,
|
||||
|
@ -317,8 +318,6 @@ void hash0(uint64_t c, uint8_t k[8]) {
|
|||
// First, place y(7-i) leftmost in k
|
||||
k[i] |= (y << (7 - i)) & 0x80 ;
|
||||
|
||||
|
||||
|
||||
uint8_t zTilde_i = getSixBitByte(zTilde, i);
|
||||
// zTildeI is now on the form 00XXXXXX
|
||||
// with one leftshift, it'll be
|
||||
|
@ -342,9 +341,6 @@ void hash0(uint64_t c, uint8_t k[8]) {
|
|||
k[i] |= zTilde_i & 0x7E;
|
||||
k[i] |= (~p_i) & 1;
|
||||
}
|
||||
// if ((k[i] & 1) == 0) {
|
||||
// zerocounter++;
|
||||
// }
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
@ -354,18 +350,17 @@ void hash0(uint64_t c, uint8_t k[8]) {
|
|||
* @param div_key
|
||||
*/
|
||||
void diversifyKey(uint8_t *csn, uint8_t *key, uint8_t *div_key) {
|
||||
// Prepare the DES key
|
||||
mbedtls_des_setkey_enc(&ctx_enc, key);
|
||||
|
||||
uint8_t crypted_csn[8] = {0};
|
||||
|
||||
// Calculate DES(CSN, KEY)
|
||||
mbedtls_des_context ctx_enc;
|
||||
mbedtls_des_setkey_enc(&ctx_enc, key);
|
||||
mbedtls_des_crypt_ecb(&ctx_enc, csn, crypted_csn);
|
||||
mbedtls_des_free(&ctx_enc);
|
||||
|
||||
//Calculate HASH0(DES))
|
||||
uint64_t c_csn = x_bytes_to_num(crypted_csn, sizeof(crypted_csn));
|
||||
//uint64_t crypted_csn_swapped = swapZvalues(crypt_csn);
|
||||
|
||||
hash0(c_csn, div_key);
|
||||
}
|
||||
/*
|
||||
|
@ -420,28 +415,38 @@ typedef struct {
|
|||
uint8_t uid[8];
|
||||
uint8_t t_key[8];
|
||||
uint8_t div_key[8];
|
||||
} Testcase;
|
||||
} testcase_t;
|
||||
|
||||
static int testDES(Testcase testcase) {
|
||||
static int testDES(uint8_t *key, testcase_t testcase) {
|
||||
uint8_t des_encrypted_csn[8] = {0};
|
||||
uint8_t decrypted[8] = {0};
|
||||
uint8_t div_key[8] = {0};
|
||||
|
||||
mbedtls_des_context ctx_enc;
|
||||
mbedtls_des_context ctx_dec;
|
||||
|
||||
mbedtls_des_setkey_enc(&ctx_enc, key);
|
||||
mbedtls_des_setkey_dec(&ctx_dec, key);
|
||||
|
||||
int retval = mbedtls_des_crypt_ecb(&ctx_enc, testcase.uid, des_encrypted_csn);
|
||||
retval |= mbedtls_des_crypt_ecb(&ctx_dec, des_encrypted_csn, decrypted);
|
||||
|
||||
mbedtls_des_free(&ctx_enc);
|
||||
mbedtls_des_free(&ctx_dec);
|
||||
|
||||
if (memcmp(testcase.uid, decrypted, 8) != 0) {
|
||||
//Decryption fail
|
||||
PrintAndLogEx(FAILED, "Encryption <-> Decryption FAIL");
|
||||
printarr("Input", testcase.uid, 8);
|
||||
printarr("Decrypted", decrypted, 8);
|
||||
printarr(" input", testcase.uid, 8);
|
||||
printarr(" decrypted", decrypted, 8);
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
if (memcmp(des_encrypted_csn, testcase.t_key, 8) != 0) {
|
||||
//Encryption fail
|
||||
PrintAndLogEx(FAILED, "Encryption != Expected result");
|
||||
printarr("Output", des_encrypted_csn, 8);
|
||||
printarr("Expected", testcase.t_key, 8);
|
||||
printarr(" output", des_encrypted_csn, 8);
|
||||
printarr(" expected", testcase.t_key, 8);
|
||||
retval = 1;
|
||||
}
|
||||
uint64_t crypted_csn = x_bytes_to_num(des_encrypted_csn, 8);
|
||||
|
@ -453,7 +458,7 @@ static int testDES(Testcase testcase) {
|
|||
printarr(" csn ", testcase.uid, 8);
|
||||
printarr("{csn} ", des_encrypted_csn, 8);
|
||||
printarr("hash0 ", div_key, 8);
|
||||
printarr("Expected", testcase.div_key, 8);
|
||||
printarr(" expected", testcase.div_key, 8);
|
||||
retval = 1;
|
||||
}
|
||||
return retval;
|
||||
|
@ -461,9 +466,12 @@ static int testDES(Testcase testcase) {
|
|||
static bool des_getParityBitFromKey(uint8_t key) {
|
||||
// The top 7 bits is used
|
||||
bool parity = ((key & 0x80) >> 7)
|
||||
^ ((key & 0x40) >> 6) ^ ((key & 0x20) >> 5)
|
||||
^ ((key & 0x10) >> 4) ^ ((key & 0x08) >> 3)
|
||||
^ ((key & 0x04) >> 2) ^ ((key & 0x02) >> 1);
|
||||
^ ((key & 0x40) >> 6)
|
||||
^ ((key & 0x20) >> 5)
|
||||
^ ((key & 0x10) >> 4)
|
||||
^ ((key & 0x08) >> 3)
|
||||
^ ((key & 0x04) >> 2)
|
||||
^ ((key & 0x02) >> 1);
|
||||
return !parity;
|
||||
}
|
||||
|
||||
|
@ -480,11 +488,11 @@ static void des_checkParity(uint8_t *key) {
|
|||
if (fails) {
|
||||
PrintAndLogEx(FAILED, "parity fails: %d", fails);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Key syntax is with parity bits inside each byte");
|
||||
PrintAndLogEx(SUCCESS, " Key syntax is with parity bits inside each byte (%s)", _GREEN_("ok"));
|
||||
}
|
||||
}
|
||||
|
||||
Testcase testcases[] = {
|
||||
testcase_t testcases[] = {
|
||||
|
||||
{{0x8B, 0xAC, 0x60, 0x1F, 0x53, 0xB8, 0xED, 0x11}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x02, 0x04, 0x06, 0x08, 0x01, 0x03, 0x05, 0x07}},
|
||||
{{0xAE, 0x51, 0xE5, 0x62, 0xE7, 0x9A, 0x99, 0x39}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, {0x04, 0x02, 0x06, 0x08, 0x01, 0x03, 0x05, 0x07}},
|
||||
|
@ -555,14 +563,14 @@ Testcase testcases[] = {
|
|||
{{0}, {0}, {0}}
|
||||
};
|
||||
|
||||
static int testKeyDiversificationWithMasterkeyTestcases(void) {
|
||||
static int testKeyDiversificationWithMasterkeyTestcases(uint8_t *key) {
|
||||
int i, error = 0;
|
||||
uint8_t empty[8] = {0};
|
||||
|
||||
PrintAndLogEx(INFO, "Testing encryption/decryption");
|
||||
|
||||
for (i = 0; memcmp(testcases + i, empty, 8); i++)
|
||||
error += testDES(testcases[i]);
|
||||
error += testDES(key, testcases[i]);
|
||||
|
||||
if (error)
|
||||
PrintAndLogEx(FAILED, "%d errors occurred (%d testcases)", error, i);
|
||||
|
@ -581,7 +589,7 @@ static int testCryptedCSN(uint64_t crypted_csn, uint64_t expected) {
|
|||
PrintAndLogEx(DEBUG, "");
|
||||
PrintAndLogEx(DEBUG, " {csn} %"PRIx64, crypted_csn);
|
||||
PrintAndLogEx(DEBUG, " {csn-revz} %"PRIx64, crypted_csn_swapped);
|
||||
PrintAndLogEx(DEBUG, " hash0 %"PRIx64 " (%s)", resultbyte, (resultbyte == expected) ? _GREEN_("OK") : _RED_("FAIL"));
|
||||
PrintAndLogEx(DEBUG, " hash0 %"PRIx64 " (%s)", resultbyte, (resultbyte == expected) ? _GREEN_("ok") : _RED_("fail"));
|
||||
|
||||
if (resultbyte != expected) {
|
||||
PrintAndLogEx(DEBUG, " expected " _YELLOW_("%"PRIx64), expected);
|
||||
|
@ -590,19 +598,22 @@ static int testCryptedCSN(uint64_t crypted_csn, uint64_t expected) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int testDES2(uint64_t csn, uint64_t expected) {
|
||||
static int testDES2(uint8_t *key, uint64_t csn, uint64_t expected) {
|
||||
uint8_t result[8] = {0};
|
||||
uint8_t input[8] = {0};
|
||||
|
||||
PrintAndLogEx(DEBUG, " csn %"PRIx64, csn);
|
||||
x_num_to_bytes(csn, 8, input);
|
||||
|
||||
mbedtls_des_context ctx_enc;
|
||||
mbedtls_des_setkey_enc(&ctx_enc, key);
|
||||
mbedtls_des_crypt_ecb(&ctx_enc, input, result);
|
||||
mbedtls_des_free(&ctx_enc);
|
||||
|
||||
uint64_t crypt_csn = x_bytes_to_num(result, 8);
|
||||
|
||||
PrintAndLogEx(DEBUG, " {csn} %"PRIx64, crypt_csn);
|
||||
PrintAndLogEx(DEBUG, " expected %"PRIx64 " (%s)", expected, (expected == crypt_csn) ? _GREEN_("OK") : _RED_("FAIL"));
|
||||
PrintAndLogEx(DEBUG, " expected %"PRIx64 " (%s)", expected, (expected == crypt_csn) ? _GREEN_("ok") : _RED_("fail"));
|
||||
|
||||
if (expected != crypt_csn)
|
||||
return PM3_ESOFT;
|
||||
|
@ -619,8 +630,7 @@ static int doTestsWithKnownInputs(void) {
|
|||
PrintAndLogEx(INFO, "Testing DES encryption");
|
||||
uint8_t key[8] = {0x6c, 0x8d, 0x44, 0xf9, 0x2a, 0x2d, 0x01, 0xbf};
|
||||
|
||||
mbedtls_des_setkey_enc(&ctx_enc, key);
|
||||
testDES2(0xbbbbaaaabbbbeeee, 0xd6ad3ca619659e6b);
|
||||
testDES2(key, 0xbbbbaaaabbbbeeee, 0xd6ad3ca619659e6b);
|
||||
|
||||
PrintAndLogEx(INFO, "Testing hashing algorithm");
|
||||
|
||||
|
@ -681,11 +691,10 @@ int doKeyTests(void) {
|
|||
PrintAndLogEx(SUCCESS, "Key present");
|
||||
PrintAndLogEx(SUCCESS, "Checking key parity...");
|
||||
des_checkParity(key);
|
||||
mbedtls_des_setkey_enc(&ctx_enc, key);
|
||||
mbedtls_des_setkey_dec(&ctx_dec, key);
|
||||
|
||||
// Test hashing functions
|
||||
PrintAndLogEx(SUCCESS, "The following tests require the correct 8-byte master key");
|
||||
testKeyDiversificationWithMasterkeyTestcases();
|
||||
testKeyDiversificationWithMasterkeyTestcases(key);
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(INFO, "Testing key diversification with non-sensitive keys...");
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "util_posix.h"
|
||||
#include "comms.h"
|
||||
|
||||
pm3_device* pm3_open(char *port) {
|
||||
pm3_device *pm3_open(char *port) {
|
||||
pm3_init();
|
||||
OpenProxmark(&session.current_device, port, false, 20, false, USART_BAUD_RATE);
|
||||
if (session.pm3_present && (TestProxmark(session.current_device) != PM3_SUCCESS)) {
|
||||
|
@ -30,7 +30,7 @@ pm3_device* pm3_open(char *port) {
|
|||
return session.current_device;
|
||||
}
|
||||
|
||||
void pm3_close(pm3_device* dev) {
|
||||
void pm3_close(pm3_device *dev) {
|
||||
// Clean up the port
|
||||
if (session.pm3_present) {
|
||||
clearCommandBuffer();
|
||||
|
@ -40,16 +40,16 @@ void pm3_close(pm3_device* dev) {
|
|||
}
|
||||
}
|
||||
|
||||
int pm3_console(pm3_device* dev, char *Cmd) {
|
||||
int pm3_console(pm3_device *dev, char *Cmd) {
|
||||
// For now, there is no real device context:
|
||||
(void) dev;
|
||||
return CommandReceived(Cmd);
|
||||
}
|
||||
|
||||
const char *pm3_name_get(pm3_device* dev) {
|
||||
const char *pm3_name_get(pm3_device *dev) {
|
||||
return dev->conn->serial_port_name;
|
||||
}
|
||||
|
||||
pm3_device* pm3_get_current_dev(void) {
|
||||
pm3_device *pm3_get_current_dev(void) {
|
||||
return session.current_device;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,7 @@
|
|||
#include <string.h>
|
||||
#include "proxguiqt.h"
|
||||
#include "proxmark3.h"
|
||||
#include "ui.h" // for prints
|
||||
|
||||
static ProxGuiQT *gui = NULL;
|
||||
static WorkerThread *main_loop_thread = NULL;
|
||||
|
@ -28,8 +29,15 @@ void WorkerThread::run() {
|
|||
}
|
||||
|
||||
extern "C" void ShowGraphWindow(void) {
|
||||
if (!gui)
|
||||
if (!gui) {
|
||||
// Show a notice if X11/XQuartz isn't available
|
||||
#if defined(__MACH__) && defined(__APPLE__)
|
||||
PrintAndLogEx(WARNING, "You appear to be on a MacOS device without XQuartz.\nYou may need to install XQuartz (https://www.xquartz.org/) to make the plot work.");
|
||||
#else
|
||||
PrintAndLogEx(WARNING, "You appear to be on an environment without an X11 server or without DISPLAY environment variable set.\nPlot may not work until you resolve these issues.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
gui->ShowGraphWindow();
|
||||
}
|
||||
|
|
|
@ -1350,7 +1350,7 @@ int set_pm3_libraries(lua_State *L) {
|
|||
{"WaitForResponseTimeout", l_WaitForResponseTimeout},
|
||||
{"mfDarkside", l_mfDarkside},
|
||||
{"foobar", l_foobar},
|
||||
{"kbd_enter_pressed", l_kbd_enter_pressed},
|
||||
{"kbd_enter_pressed", l_kbd_enter_pressed},
|
||||
{"clearCommandBuffer", l_clearCommandBuffer},
|
||||
{"console", l_CmdConsole},
|
||||
{"iso15693_crc", l_iso15693_crc},
|
||||
|
|
|
@ -446,6 +446,25 @@ void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest) {
|
|||
}
|
||||
}
|
||||
|
||||
void bytes_to_bytebits(void *src, size_t srclen, void *dest) {
|
||||
|
||||
uint8_t *s = (uint8_t *)src;
|
||||
uint8_t *d = (uint8_t *)dest;
|
||||
|
||||
uint32_t i = srclen * 8;
|
||||
while (srclen--) {
|
||||
uint8_t b = s[srclen];
|
||||
d[--i] = (b >> 0) & 1;
|
||||
d[--i] = (b >> 1) & 1;
|
||||
d[--i] = (b >> 2) & 1;
|
||||
d[--i] = (b >> 3) & 1;
|
||||
d[--i] = (b >> 4) & 1;
|
||||
d[--i] = (b >> 5) & 1;
|
||||
d[--i] = (b >> 6) & 1;
|
||||
d[--i] = (b >> 7) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
// aa,bb,cc,dd,ee,ff,gg,hh, ii,jj,kk,ll,mm,nn,oo,pp
|
||||
// to
|
||||
// hh,gg,ff,ee,dd,cc,bb,aa, pp,oo,nn,mm,ll,kk,jj,ii
|
||||
|
|
|
@ -56,6 +56,7 @@ void print_blocks(uint32_t *data, size_t len);
|
|||
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen);
|
||||
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
|
||||
void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
|
||||
void bytes_to_bytebits(void *src, size_t srclen, void *dest);
|
||||
|
||||
// Swap endian on arrays up to 64bytes.
|
||||
uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
|
||||
|
|
|
@ -139,13 +139,16 @@ endif
|
|||
ifneq ($(strip $(filter $(PLATFORM_DEFS),$(STANDALONE_REQ_DEFS))),$(strip $(STANDALONE_REQ_DEFS)))
|
||||
$(error Chosen Standalone mode $(STANDALONE) requires $(strip $(STANDALONE_REQ_DEFS)), unsupported by $(PLTNAME))
|
||||
endif
|
||||
PLATFORM_DEFS+=$(STANDALONE_PLATFORM_DEFS)
|
||||
ifneq (,$(STANDALONE_PLATFORM_DEFS))
|
||||
PLATFORM_DEFS+=$(STANDALONE_PLATFORM_DEFS)
|
||||
endif
|
||||
|
||||
$(info $(findstring WITH_STANDALONE_*,$(PLATFORM_DEFS)))
|
||||
|
||||
# Misc
|
||||
#PLATFORM_DEFS += -DWITH_LCD
|
||||
|
||||
# Misc (LCD support)
|
||||
ifneq (,$(findstring WITH_LCD,$(PLATFORM_DEFS)))
|
||||
#PLATFORM_DEFS += -DWITH_LCD
|
||||
endif
|
||||
|
||||
# Add flags dependencies :
|
||||
|
||||
|
|
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.
|
||||
|
||||
![](./t55xx_mem_map.png)
|
||||
|
||||
|
||||
|
||||
## What data is on my T5577
|
||||
|
||||
Let’s have a look and see what a card might look in the proxmark3
|
||||
software. Since we can change the configuration of how the T5577 will
|
||||
output data, the proxmark3 software need to work out how to interpreted
|
||||
the data it receives, we do this with the following command.
|
||||
|
||||
It should be noted that the T5577 has many clones. As such the default
|
||||
setup of each card may be different. If the tractability data is
|
||||
present, then this will vary based on the batch of cards.
|
||||
|
||||
Always run this command when you place a t5577 on the proxmark3. In all
|
||||
examples shown, it will be assumed you have run the detect command.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx detect
|
||||
```
|
||||
You should see a results simular to the following:
|
||||
```
|
||||
Chip Type : T55x7
|
||||
Modulation : ASK
|
||||
Bit Rate : 2 - RF/32
|
||||
Inverted : No
|
||||
Offset : 32
|
||||
Seq. Term. : Yes
|
||||
Block0 : 0x000880E0
|
||||
Downlink Mode : default/fixed bit length
|
||||
```
|
||||
Now that the proxmark3 has detected a T55x7 chip, and found some
|
||||
information about it, we should be able to see all the data on the chip.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx dump
|
||||
```
|
||||
Your results should look similar to the following:
|
||||
```
|
||||
[+] Reading Page 0:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] Reading Page 1:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
|
||||
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
|
||||
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
```
|
||||
I will cover the meaning of this data as we go, but for now, lets keep
|
||||
it simple.
|
||||
|
||||
## Read and Write Blocks of Data
|
||||
|
||||
The basic function of using the proxmark3 with rfid cards is to read and
|
||||
write data. This reading and writing must be done in the correct way
|
||||
needed for the chip (and its configuration). Lucky for us, the
|
||||
developers have done a great job and gave us commands. What we need to
|
||||
know is that with the T5577 data is read/written one complete block at a
|
||||
time. Each block holds 32 bits of data (hence the binary output shown)
|
||||
|
||||
Since we know that the card has data and configuration blocks, lets say
|
||||
away from those while we learn how to read and write. I suggest you
|
||||
follow along and perform each command and check the results as we go.
|
||||
|
||||
We can store our own data in blocks 1-7 (remember that block 7 will be
|
||||
needed if we want to set a password).
|
||||
|
||||
(Don’t forget to run the detect command: lf t55xx detect, and ensure you
|
||||
can see the card)
|
||||
|
||||
1) Check what is stored in block 1. The following command can be read
|
||||
as, run a low frequency (lf) command for the T55xx chip (t55xx) and
|
||||
read block (b) number 1.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx read b 1
|
||||
```
|
||||
result:
|
||||
```
|
||||
[+] Reading Page 0:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
```
|
||||
Note: Depending on the history of your card your data may vary, but
|
||||
should match the dump data.
|
||||
|
||||
2) Write some new data into block 1 on the card.
|
||||
|
||||
We use the d option to supply the data ‘12345678’
|
||||
```
|
||||
[usb] pm3 --> lf t55xx write b 1 d 12345678
|
||||
```
|
||||
result:
|
||||
```
|
||||
[=] Writing page 0 block: 01 data: 0x12345678
|
||||
```
|
||||
3) Now, lets check if the data was written.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx read b 1
|
||||
```
|
||||
result:
|
||||
```
|
||||
[+] Reading Page 0:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 01 | 12345678 | 00010010001101000101011001111000 | .4Vx
|
||||
```
|
||||
4) The data is written in Hexadecimal. A single hex digit holds 4 bits
|
||||
of data. So to store 32 bits in a block we need to supply 8 hex
|
||||
digits (8 \* 4 = 32). If you are familiar with hex and binary do a
|
||||
little bit of home work to learn. The following is a quick start.
|
||||
|
||||
| Hex | Binary | Decimal |
|
||||
|:---:|:------:|:-------:|
|
||||
| 0 | 0000 | 0 |
|
||||
| 1 | 0001 | 1 |
|
||||
| 2 | 0010 | 2 |
|
||||
| 3 | 0011 | 3 |
|
||||
| 4 | 0100 | 4 |
|
||||
| 5 | 0101 | 5 |
|
||||
| 6 | 0110 | 6 |
|
||||
| 7 | 0111 | 7 |
|
||||
| 8 | 1000 | 8 |
|
||||
| 9 | 1001 | 9 |
|
||||
| A | 1010 | 10 |
|
||||
| B | 1011 | 11 |
|
||||
| C | 1100 | 12 |
|
||||
| D | 1101 | 13 |
|
||||
| E | 1110 | 14 |
|
||||
| F | 1111 | 15 |
|
||||
|
||||
To use all the bits we supply the data in Hex format and it will
|
||||
always be 8 hex digits.
|
||||
|
||||
Lets try and write 89ABCDEF
|
||||
```
|
||||
[usb] pm3 --> lf t55xx write b 1 d 89abcdef
|
||||
```
|
||||
result:
|
||||
```
|
||||
[=] Writing page 0 block: 01 data: 0x89ABCDEF
|
||||
```
|
||||
and check
|
||||
```
|
||||
[usb] pm3 --> lf t55xx read b 1
|
||||
```
|
||||
result:
|
||||
```
|
||||
[+] Reading Page 0:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 01 | 89ABCDEF | 10001001101010111100110111101111 | ....
|
||||
```
|
||||
|
||||
### Exercise 1
|
||||
|
||||
Using the read and write commands you have learnt see if you can make
|
||||
the lf t55 dump command show the following data for blocks 1-7 (Page 0).
|
||||
Do not write to block 0 or try and change the data on page 1.
|
||||
```
|
||||
[usb] pm3 --> lf t55 dump
|
||||
```
|
||||
result:
|
||||
```
|
||||
[+] Reading Page 0:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||
[+] 01 | 89ABCDEF | 10001001101010111100110111101111 | ....
|
||||
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] Reading Page 1:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
|
||||
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
|
||||
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
```
|
||||
|
||||
Practice reading and writing to blocks 1 to 7 until you are happy you
|
||||
can do it and get the results you wanted (i.e. the data you want stored
|
||||
is written to the block you want it stored in).
|
||||
|
||||
## How do I use a password
|
||||
|
||||
This can be a little tricky for beginners.
|
||||
***If you forget your password you will lose access to your card***.
|
||||
|
||||
To tell the T5577 to use a password we have to change the data in the
|
||||
configuration block (0). To help learn this and make it as simple as I
|
||||
can, please read and follow exactly. If your results DON’T match 100% as
|
||||
required, please do not proceed.
|
||||
|
||||
1) Lets start with a known card state and wipe the card. This will set
|
||||
a default configuration to block 0 and set all the data in blocks
|
||||
1-7 to a default.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx wipe
|
||||
```
|
||||
Result:
|
||||
```
|
||||
[=] Begin wiping T55x7 tag
|
||||
|
||||
[=] Default configation block 000880E0
|
||||
[=] Writing page 0 block: 00 data: 0x000880E0
|
||||
[=] Writing page 0 block: 01 data: 0x00000000
|
||||
[=] Writing page 0 block: 02 data: 0x00000000
|
||||
[=] Writing page 0 block: 03 data: 0x00000000
|
||||
[=] Writing page 0 block: 04 data: 0x00000000
|
||||
[=] Writing page 0 block: 05 data: 0x00000000
|
||||
[=] Writing page 0 block: 06 data: 0x00000000
|
||||
[=] Writing page 0 block: 07 data: 0x00000000
|
||||
```
|
||||
|
||||
2) Check that the card is in the desired state.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx detect
|
||||
```
|
||||
result:
|
||||
```
|
||||
Chip Type : T55x7
|
||||
Modulation : ASK
|
||||
Bit Rate : 2 - RF/32
|
||||
Inverted : No
|
||||
Offset : 32
|
||||
Seq. Term. : Yes
|
||||
Block0 : 0x000880E0
|
||||
Downlink Mode : default/fixed bit length
|
||||
```
|
||||
|
||||
If block 0 does not hold the hex data **0x00088040 resolve this
|
||||
first before proceeding.**
|
||||
|
||||
3) Set the password we want to use. For this example lets use the
|
||||
password : ***12345678***
|
||||
|
||||
The password is saved in block 7 of page 0.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx write b 7 d 12345678
|
||||
```
|
||||
result:
|
||||
```
|
||||
[=] Writing page 0 block: 07 data: 0x12345678
|
||||
```
|
||||
|
||||
4) Lets verify both block 0 and block 7
|
||||
```
|
||||
[usb] pm3 --> lf t55xx dump
|
||||
```
|
||||
result:
|
||||
```
|
||||
[+] Reading Page 0:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
[+] 07 | 12345678 | 00010010001101000101011001111000 | .4Vx
|
||||
[+] Reading Page 1:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
|
||||
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
|
||||
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
|
||||
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
|
||||
```
|
||||
***Important : If block 0 and block 7 don’t match exactly, do not continue.***
|
||||
|
||||
5) Now we have a known configuration block and a known password of
|
||||
12345678, we are ready to tell the card to use the password.
|
||||
|
||||
To do this the datasheet tells us we need to set the 28<sup>th</sup>
|
||||
bit “PWD”. Check your datasheet and see the entire table (remember
|
||||
the data sheet is your friend).
|
||||
|
||||
![](./t55xx_block0.png)
|
||||
|
||||
We will cover other things in the configuration later. But the key
|
||||
note here is we ONLY want to change bit 28 and nothing else.
|
||||
|
||||
Current Block 0 : ***00088040***
|
||||
New Block 0 : ***00088050***
|
||||
|
||||
To understand what happened to get from 00088040 to 00088050 we need
|
||||
to look at the binary data.
|
||||
|
||||
While this can be confusing it is important to understand this as we
|
||||
do more advanced things.
|
||||
|
||||
Bit Location (28)
|
||||
000000000011111111112222222 ***2*** 2233
|
||||
123456789012345678901234567 ***8*** 9012
|
||||
|
||||
| Hex Data | Binary Data |
|
||||
|:--------:|:---------------------------------------|
|
||||
| 00088040 | 000000000000100010000000010***0***0000 |
|
||||
| 00088050 | 000000000000100010000000010***1***0000 |
|
||||
|
||||
|
||||
|
||||
See how in the above we change the bit in location 28 from a 0 to 1
|
||||
0 = No Password, 1 = Use Password
|
||||
|
||||
Note how we did NOT change any other part of the configuration, only bit 28.
|
||||
|
||||
To re-cap.
|
||||
We put the card into a known configuration Block 0 : 00088040
|
||||
We set the a known password Block 7 : 12345678
|
||||
We altered the config data to tell the T5577 to use the password.
|
||||
New Block 0 : 00088050
|
||||
|
||||
If you have completed all steps and have the exact same results, we are
|
||||
ready to apply the new configuration.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx write b 0 d 00088050
|
||||
```
|
||||
result:
|
||||
```
|
||||
[=] Writing page 0 block: 00 data: 0x00088050
|
||||
```
|
||||
|
||||
6) Lets check what happens when the password is set.
|
||||
```
|
||||
[usb] pm3 --> lf t55 detect
|
||||
```
|
||||
result:
|
||||
```
|
||||
[!] Could not detect modulation automatically. Try setting it manually with 'lf t55xx config'
|
||||
```
|
||||
Note how the lf t55 detect no longer seems to work\!
|
||||
|
||||
In this case, this is due to needing a password to read/write to the
|
||||
card.
|
||||
|
||||
Lets try again, but this time supply the password. We use the option
|
||||
p followed by the password.
|
||||
```
|
||||
[usb] pm3 --> lf t55 detect p 12345678
|
||||
```
|
||||
result:
|
||||
```
|
||||
Chip Type : T55x7
|
||||
Modulation : ASK
|
||||
Bit Rate : 2 - RF/32
|
||||
Inverted : No
|
||||
Offset : 32
|
||||
Seq. Term. : Yes
|
||||
Block0 : 0x00088050
|
||||
Downlink Mode : default/fixed bit length
|
||||
```
|
||||
|
||||
7) Write a block of data with a password
|
||||
```
|
||||
[usb] pm3 --> lf t55xx write b 1 d 1234abcd p 12345678
|
||||
```
|
||||
result:
|
||||
```
|
||||
[=] Writing page 0 block: 01 data: 0x1234ABCD pwd: 0x12345678
|
||||
```
|
||||
|
||||
8) Read a block of data with a password
|
||||
|
||||
***\*\*\*\* Important \*\*\*\****
|
||||
|
||||
***Reading a T5577 block with a password when a password is not
|
||||
enabled can result in locking the card. Please only use read with a
|
||||
password when it is known that a password is in use.***
|
||||
|
||||
The proxmark3 has a safety check\!
|
||||
```
|
||||
[usb] pm3 --> lf t55xx read b 1 p 12345678
|
||||
```
|
||||
result:
|
||||
```
|
||||
[+] Reading Page 0:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[!] Safety check: Could not detect if PWD bit is set in config block. Exits.
|
||||
```
|
||||
|
||||
Note that the proxmark3 did not read the block, the safty kicked in
|
||||
and wants us to confirm by supply the override option ‘o’.
|
||||
|
||||
Lets try again with the ‘o’ option as we know the password is set.
|
||||
```
|
||||
[usb] pm3 --> lf t55xx read b 1 p 12345678 o
|
||||
```
|
||||
result:
|
||||
```
|
||||
[+] Reading Page 0:
|
||||
[+] blk | hex data | binary | ascii
|
||||
[+] ----+----------+----------------------------------+-------
|
||||
[=] Safety check overridden - proceeding despite risk
|
||||
[+] 01 | 1234ABCD | 00010010001101001010101111001101 | .4..
|
||||
```
|
||||
This time, we can see the data we wrote to block 1 is found with the
|
||||
read command.
|
||||
|
||||
9) Remove the need to supply the password.
|
||||
|
||||
To do this we need to clear Bit 28 (set to 0) in the config. We have
|
||||
this from above.
|
||||
|
||||
Remember if we don’t know the config and write this config to the
|
||||
card, it will over write all other settings. This can recoved the
|
||||
card, but will lose any settings you may want. So it’s a good idea
|
||||
to read the config, and set bit 28 to 0, rather than just overwrite
|
||||
the config and change the way the card works.
|
||||
|
||||
In our examples we know what it should be : 00088040
|
||||
```
|
||||
[usb] pm3 --> lf t55xx write b 0 d 00088040 p 12345678
|
||||
```
|
||||
result:
|
||||
```
|
||||
[=] Writing page 0 block: 00 data: 0x00088040 pwd: 0x12345678
|
||||
```
|
||||
Now check if we can detect without a password
|
||||
```
|
||||
[usb] pm3 --> lf t55 detect
|
||||
```
|
||||
result:
|
||||
```
|
||||
Chip Type : T55x7
|
||||
Modulation : ASK
|
||||
Bit Rate : 2 - RF/32
|
||||
Inverted : No
|
||||
Offset : 32
|
||||
Seq. Term. : Yes
|
||||
Block0 : 0x00088040
|
||||
Downlink Mode : default/fixed bit length
|
||||
```
|
||||
Yes we can and we can see Block 0 is the correct config 00088040
|
||||
|
||||
# Part 2 – Configuration Blocks
|
||||
|
||||
One of the things a lot of people have trouble with or miss, is that the
|
||||
T5577 has two different and separate communications protocols, each with
|
||||
their own sub-protocols.
|
||||
|
||||
- Card to Reader
|
||||
- Reader to Card
|
||||
|
||||
In Card to Reader, the T5577 will encode its data using the settings
|
||||
from Block 0 in Page 0. It will use this in both default read mode
|
||||
(where is sends out the blocks from 1 to x on power up), as well as when
|
||||
it responds to commands.
|
||||
|
||||
In the Read To Card, the T5577 will encode the data using the settings
|
||||
from Block 3 Page 1. If the command is not encoded correctly it will
|
||||
ignore the command and revert back to default read mode.
|
||||
|
||||
## The configuration Block – Block 0 Page 0
|
||||
|
||||
For this configuration the settings chosen will be for the purpose of
|
||||
the card when used in production. E.G. If you want the card to act like
|
||||
an EM4100, then we need to choose the settings that work like the
|
||||
EM4100; same goes for others like HID. I am not going to cover these
|
||||
here, rather use an example. Others have collect these and posted on the
|
||||
forum.
|
||||
|
||||
To get started lets look back at the tech sheet.
|
||||
|
||||
![](./t55xx_clock0_cfg.png)
|
||||
|
||||
The non-password protect EM4100 could have a block 0 config of 00148040,
|
||||
so what does it mean.
|
||||
|
||||
To decode this config, we need to look at it in binary
|
||||
00000000000101001000000001000000. Note that it had 32 bits and the
|
||||
config block 0 is 32 bits. Now we can break it down.
|
||||
|
||||
| Bits | Purpose | Value |
|
||||
| ------- | ---------------------- | ----------- |
|
||||
| 0000 | Master Key | Nothing Set |
|
||||
| 0000000 | Not used in Basic Mode | |
|
||||
| 101 | Data Bit Rate | RF/64 |
|
||||
| 0 | Not used in Basic Mode | |
|
||||
| 01000 | Modulation | Manchester |
|
||||
| 00 | PSKCF | RF/2 |
|
||||
| 0 | AOR | Not Set |
|
||||
| 0 | Not used in Basic Mode | |
|
||||
| 010 | Max Block | 2 |
|
||||
| 0 | Password | Not Set |
|
||||
| 0 | ST Sequence Terminator | Not Set |
|
||||
| 00 | Not used in Basic Mode | |
|
||||
| 0 | Init Delay | Not Set |
|
||||
|
||||
To get more detail on each item, read through the data sheet.
|
||||
|
||||
Lets see how the proxmark3 can help us learn. We will assume the T5577
|
||||
is in the same state from Part 1, where we can write to the card with no
|
||||
password set (if not, review and get you card back to this state).
|
||||
|
||||
1) Lets turn you T5577 into an EM4100 with ID 1122334455
|
||||
```
|
||||
[usb] pm3 --> lf em 410x_write 1122334455 1
|
||||
```
|
||||
result:
|
||||
```
|
||||
[+] Writing T55x7 tag with UID 0x1122334455 (clock rate: 64)
|
||||
#db# Started writing T55x7 tag ...
|
||||
#db# Clock rate: 64
|
||||
#db# Tag T55x7 written with 0xff8c65298c94a940
|
||||
```
|
||||
|
||||
2) Check this has work.
|
||||
```
|
||||
[usb] pm3 --> lf search
|
||||
```
|
||||
result:
|
||||
```
|
||||
[=] NOTE: some demods output possible binary
|
||||
[=] if it finds something that looks like a tag
|
||||
[=] False Positives ARE possible
|
||||
[=]
|
||||
[=] Checking for known tags...
|
||||
|
||||
[+] EM410x pattern found
|
||||
|
||||
EM TAG ID : 1122334455
|
||||
|
||||
Possible de-scramble patterns
|
||||
|
||||
Unique TAG ID : 8844CC22AA
|
||||
HoneyWell IdentKey {
|
||||
DEZ 8 : 03359829
|
||||
DEZ 10 : 0573785173
|
||||
DEZ 5.5 : 08755.17493
|
||||
DEZ 3.5A : 017.17493
|
||||
DEZ 3.5B : 034.17493
|
||||
DEZ 3.5C : 051.17493
|
||||
DEZ 14/IK2 : 00073588229205
|
||||
DEZ 15/IK3 : 000585269781162
|
||||
DEZ 20/ZK : 08080404121202021010
|
||||
}
|
||||
Other : 17493_051_03359829
|
||||
Pattern Paxton : 289899093 [0x11478255]
|
||||
Pattern 1 : 5931804 [0x5A831C]
|
||||
Pattern Sebury : 17493 51 3359829 [0x4455 0x33 0x334455]
|
||||
|
||||
[+] Valid EM410x ID found!
|
||||
|
||||
|
||||
[+] Chipset detection : T55xx found
|
||||
|
||||
[+] Try `lf t55xx` commands
|
||||
```
|
||||
Looks good.
|
||||
|
||||
3) Now lest see what the T5577 detect and info shows
|
||||
```
|
||||
[usb] pm3 --> lf t55 detect
|
||||
```
|
||||
result:
|
||||
```
|
||||
[usb] pm3 --> lf t55 detect
|
||||
Chip Type : T55x7
|
||||
Modulation : ASK
|
||||
Bit Rate : 5 - RF/64
|
||||
Inverted : No
|
||||
Offset : 32
|
||||
Seq. Term. : Yes
|
||||
Block0 : 0x00148040
|
||||
Downlink Mode : default/fixed bit length
|
||||
```
|
||||
```
|
||||
[usb] pm3 --> lf t55xx info
|
||||
```
|
||||
result:
|
||||
```
|
||||
|
||||
-- T55x7 Configuration & Tag Information --------------------
|
||||
-------------------------------------------------------------
|
||||
Safer key : 0
|
||||
reserved : 0
|
||||
Data bit rate : 5 - RF/64
|
||||
eXtended mode : No
|
||||
Modulation : 8 - Manchester
|
||||
PSK clock frequency : 0 - RF/2
|
||||
AOR - Answer on Request : No
|
||||
OTP - One Time Pad : No
|
||||
Max block : 2
|
||||
Password mode : No
|
||||
Sequence Terminator : No
|
||||
Fast Write : No
|
||||
Inverse data : No
|
||||
POR-Delay : No
|
||||
-------------------------------------------------------------
|
||||
Raw Data - Page 0
|
||||
Block 0 : 0x00148040 00000000000101001000000001000000
|
||||
|
||||
Config block match : EM unique, Paxton
|
||||
-------------------------------------------------------------
|
||||
```
|
||||
We can see that the info gave us more information and confirmed what
|
||||
we decoded by hand. But remember, the detect is still needed so the
|
||||
proxmark3 software will know how to decode the info block.
|
||||
|
||||
We can see that for the EM4100 emulation we have two blocks of data
|
||||
(Max Block = 2). On the T5577 these will be Blocks 1 and 2.
|
||||
|
||||
## Exercise 2
|
||||
|
||||
Using the skills form part 1, see if you can view the data in blocks 1 and 2.
|
||||
|
||||
Note: the EM4100 ID of 1122334455 is encoded, so don’t expect to see
|
||||
those bytes as such. To learn how to do that, you guessed it, find the
|
||||
datasheet and review.
|
||||
|
||||
At this point we have an EM4100 card. If we wanted to password protect
|
||||
it, we can follow the password section and update the config from
|
||||
00148040 to 00148050.
|
||||
|
||||
***Important : Don’t forget to set a valid password in block 7 and remember it.***
|
||||
|
||||
## The configuration Block – Block 3 Page 1
|
|
@ -62,57 +62,75 @@ Dump iCLASS card contents
|
|||
```
|
||||
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
|
||||
```
|
||||
Options
|
||||
---
|
||||
b <block> : The block number as 2 hex symbols
|
||||
k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory
|
||||
-k, --key <hex> Access key as 16 hex symbols
|
||||
-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
|
||||
```
|
||||
Options
|
||||
---
|
||||
b <block> : The block number as 2 hex symbols
|
||||
d <data> : Set the Data to write as 16 hex symbols
|
||||
k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory
|
||||
-k, --key <hex> Access key as 16 hex symbols
|
||||
-b, --block <dec> The block number to read as an integer
|
||||
-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
|
||||
```
|
||||
Options
|
||||
---
|
||||
p : print keys loaded into memory
|
||||
-p, --print Print keys loaded into memory
|
||||
|
||||
pm3 --> hf iclass managekeys p
|
||||
|
||||
pm3 --> hf iclass managekeys -p
|
||||
```
|
||||
|
||||
Add key to keystore [0-7]
|
||||
```
|
||||
Options
|
||||
---
|
||||
n <keynbr> : specify the keyNbr to set in memory
|
||||
k <key> : set a key in memory
|
||||
-f, --file <filename> Specify a filename to use with load or save operations
|
||||
--ki <dec> Specify key index to set key in memory
|
||||
|
||||
pm3 --> hf iclass managekeys n 3 k AFA785A7DAB33378
|
||||
pm3 --> hf iclass managekeys --ki 3 -k AFA785A7DAB33378
|
||||
```
|
||||
|
||||
Encrypt iCLASS Block
|
||||
```
|
||||
Options
|
||||
---
|
||||
-d, --data <block data> data to encrypt
|
||||
-k, --key <transport key> 3DES transport key
|
||||
-d, --data <hex> data to encrypt
|
||||
-k, --key <hex> 3DES transport key
|
||||
-v, --verbose verbose output
|
||||
|
||||
pm3 --> hf iclass encrypt -d 0000000f2aa3dba8
|
||||
|
@ -123,8 +141,8 @@ Decrypt iCLASS Block / file
|
|||
Options
|
||||
---
|
||||
-f, --file <filename> filename of dumpfile
|
||||
-d, --data <encrypted blk> 3DES encrypted data
|
||||
-k, --key <transport key> 3DES transport key
|
||||
-d, --data <hex> 3DES encrypted data
|
||||
-k, --key <hex> 3DES transport key
|
||||
-v, --verbose verbose output
|
||||
|
||||
pm3 --> hf iclass decrypt -d 2AD4C8211F996871
|
||||
|
@ -142,28 +160,31 @@ pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin
|
|||
|
||||
Clone iCLASS Legacy Sequence
|
||||
```
|
||||
pm3 --> hf iclass rdbl b 7 k 0
|
||||
pm3 --> hf iclass wrbl b 7 d 6ce099fe7e614fd0 k 0
|
||||
pm3 --> hf iclass rdbl -b 7 --ki 0
|
||||
pm3 --> hf iclass wrbl -b 7 -d 6ce099fe7e614fd0 --ki 0
|
||||
```
|
||||
|
||||
Simulate iCLASS
|
||||
```
|
||||
Options
|
||||
---
|
||||
0 <CSN> simulate the given CSN
|
||||
-t, --type <int> Simulation type to use
|
||||
--csn <hex> Specify CSN as 8 bytes (16 hex symbols) to use with sim type 0
|
||||
Types:
|
||||
0 simulate the given CSN
|
||||
1 simulate default CSN
|
||||
2 Runs online part of LOCLASS attack
|
||||
3 Full simulation using emulator memory (see 'hf iclass eload')
|
||||
4 Runs online part of LOCLASS attack against reader in keyroll mode
|
||||
|
||||
pm3 --> hf iclass sim 3
|
||||
pm3 --> hf iclass sim -t 3
|
||||
```
|
||||
|
||||
Simulate iCLASS Sequence
|
||||
```
|
||||
pm3 --> hf iclass dump k 0
|
||||
pm3 --> hf iclass dump --ki 0
|
||||
pm3 --> hf iclass eload -f hf-iclass-db883702f8ff12e0.bin
|
||||
pm3 --> hf iclass sim 3
|
||||
pm3 --> hf iclass sim -t 3
|
||||
```
|
||||
|
||||
Extract custom iCLASS key (loclass attack)
|
||||
|
@ -172,25 +193,26 @@ Options
|
|||
---
|
||||
f <filename> : specify a filename to clone from
|
||||
k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory
|
||||
e : If 'e' is specified, elite computations applied to key
|
||||
--elite : Elite computations applied to key
|
||||
|
||||
pm3 --> hf iclass sim 2
|
||||
pm3 --> hf iclass sim -t 2
|
||||
pm3 --> hf iclass loclass -f iclass_mac_attack.bin
|
||||
pm3 --> hf iclass managekeys n 7 k <Kcus>
|
||||
pm3 --> hf iclass dump k 7 e
|
||||
pm3 --> hf iclass managekeys --ki 7 -k <Kcus>
|
||||
pm3 --> hf iclass dump --ki 7 --elite
|
||||
```
|
||||
|
||||
Verify custom iCLASS key
|
||||
```
|
||||
Options
|
||||
---
|
||||
f <filename> : Dictionary file with default iCLASS keys
|
||||
u : CSN
|
||||
p : EPURSE
|
||||
m : macs
|
||||
e : elite
|
||||
-f, --file <filename> Dictionary file with default iclass keys
|
||||
--csn <hex> Specify CSN as 8 bytes (16 hex symbols)
|
||||
--epurse <hex> Specify ePurse as 8 bytes (16 hex symbols)
|
||||
--macs <hex> MACs
|
||||
--raw no computations applied to key (raw)
|
||||
--elite Elite computations applied to key
|
||||
|
||||
pm3 --> hf iclass lookup u 010a0ffff7ff12e0 p feffffffffffffff m 66348979153c41b9 f iclass_default_keys e
|
||||
pm3 --> hf iclass lookup --csn 010a0ffff7ff12e0 --epurse feffffffffffffff --macs 66348979153c41b9 -f iclass_default_keys --elite
|
||||
```
|
||||
|
||||
## MIFARE
|
||||
|
|
219
doc/cliparser_todo.txt
Normal file
219
doc/cliparser_todo.txt
Normal file
|
@ -0,0 +1,219 @@
|
|||
clear
|
||||
pref
|
||||
analyse lcr
|
||||
analyse crc
|
||||
analyse chksum
|
||||
analyse dates
|
||||
analyse tea
|
||||
analyse lfsr
|
||||
analyse a
|
||||
analyse nuid
|
||||
analyse demodbuff
|
||||
analyse freq
|
||||
analyse foo
|
||||
data biphaserawdecode
|
||||
data detectclock
|
||||
data fsktonrz
|
||||
data manrawdecode
|
||||
data rawdemod
|
||||
data askedgedetect
|
||||
data autocorr
|
||||
data dirthreshold
|
||||
data hide
|
||||
data hpf
|
||||
data iir
|
||||
data grid
|
||||
data ltrim
|
||||
data mtrim
|
||||
data norm
|
||||
data plot
|
||||
data rtrim
|
||||
data setgraphmarkers
|
||||
data shiftgraphzero
|
||||
data zerocrossings
|
||||
data convertbitstream
|
||||
data getbitstream
|
||||
data bin2hex
|
||||
data bitsamples
|
||||
data clear
|
||||
data hexsamples
|
||||
data hex2bin
|
||||
data print
|
||||
data samples
|
||||
data setdebugmode
|
||||
data tune
|
||||
hf tune
|
||||
hf search
|
||||
hf sniff
|
||||
hf 14a reader
|
||||
hf 14a cuids
|
||||
hf 14a sim
|
||||
hf 14a sniff
|
||||
hf 14a config
|
||||
hf 14b sriwrite
|
||||
hf 15 dump
|
||||
hf 15 info
|
||||
hf 15 raw
|
||||
hf 15 rdbl
|
||||
hf 15 readmulti
|
||||
hf 15 restore
|
||||
hf 15 wrbl
|
||||
hf 15 writeafi
|
||||
hf 15 writedsfid
|
||||
hf epa cnonces
|
||||
hf epa preplay
|
||||
hf felica reader
|
||||
hf felica sniff
|
||||
hf felica raw
|
||||
hf felica rdunencrypted
|
||||
hf felica wrunencrypted
|
||||
hf felica rqservice
|
||||
hf felica rqresponse
|
||||
hf felica scsvcode
|
||||
hf felica rqsyscode
|
||||
hf felica auth1
|
||||
hf felica auth2
|
||||
hf felica rqspecver
|
||||
hf felica resetmode
|
||||
hf felica litesim
|
||||
hf felica litedump
|
||||
hf fido info
|
||||
hf legic reader
|
||||
hf legic info
|
||||
hf legic dump
|
||||
hf legic restore
|
||||
hf legic rdbl
|
||||
hf legic sim
|
||||
hf legic wrbl
|
||||
hf legic crc
|
||||
hf legic eload
|
||||
hf legic esave
|
||||
hf legic wipe
|
||||
hf mf darkside
|
||||
hf mf nested
|
||||
hf mf hardnested
|
||||
hf mf staticnested
|
||||
hf mf autopwn
|
||||
hf mf nack
|
||||
hf mf chk
|
||||
hf mf fchk
|
||||
hf mf decrypt
|
||||
hf mf dump
|
||||
hf mf rdbl
|
||||
hf mf rdsc
|
||||
hf mf restore
|
||||
hf mf setmod
|
||||
hf mf wrbl
|
||||
hf mf sim
|
||||
hf mf ecfill
|
||||
hf mf eclr
|
||||
hf mf egetblk
|
||||
hf mf egetsc
|
||||
hf mf ekeyprn
|
||||
hf mf eload
|
||||
hf mf esave
|
||||
hf mf eset
|
||||
hf mf eview
|
||||
hf mf cgetblk
|
||||
hf mf cgetsc
|
||||
hf mf cload
|
||||
hf mf csave
|
||||
hf mf csetblk
|
||||
hf mf csetuid
|
||||
hf mf cview
|
||||
hf mf gen3uid
|
||||
hf mf gen3blk
|
||||
hf mf gen3freeze
|
||||
hf mf ice
|
||||
hf mfu info
|
||||
hf mfu dump
|
||||
hf mfu restore
|
||||
hf mfu eload
|
||||
hf mfu rdbl
|
||||
hf mfu wrbl
|
||||
hf mfu cauth
|
||||
hf mfu setpwd
|
||||
hf mfu setuid
|
||||
hf mfu sim
|
||||
hf mfu gen
|
||||
hf mfu pwdgen
|
||||
hf mfu otptear
|
||||
hf mfdes enum
|
||||
hf mfdes getuid
|
||||
hf mfdes info
|
||||
hf thinfilm info
|
||||
hf thinfilm sim
|
||||
hf topaz info
|
||||
hf topaz reader
|
||||
hf topaz sim
|
||||
hf topaz sniff
|
||||
hf topaz raw
|
||||
hw connect
|
||||
hw dbg
|
||||
hw detectreader
|
||||
hw fpgaoff
|
||||
hw lcd
|
||||
hw lcdreset
|
||||
hw ping
|
||||
hw readmem
|
||||
hw reset
|
||||
hw setlfdivisor
|
||||
hw setmux
|
||||
hw standalone
|
||||
hw status
|
||||
hw tia
|
||||
hw tune
|
||||
hw version
|
||||
lf config
|
||||
lf cmdread
|
||||
lf read
|
||||
lf search
|
||||
lf sim
|
||||
lf simask
|
||||
lf simfsk
|
||||
lf simpsk
|
||||
lf simbidir
|
||||
lf sniff
|
||||
lf em 410x
|
||||
lf em 4x05
|
||||
lf em 4x50
|
||||
lf hitag reader
|
||||
lf hitag sim
|
||||
lf hitag writer
|
||||
lf hitag dump
|
||||
lf hitag cc
|
||||
lf t55xx config
|
||||
lf t55xx dangerraw
|
||||
lf t55xx detect
|
||||
lf t55xx deviceconfig
|
||||
lf t55xx dump
|
||||
lf t55xx info
|
||||
lf t55xx p1detect
|
||||
lf t55xx read
|
||||
lf t55xx resetread
|
||||
lf t55xx restore
|
||||
lf t55xx trace
|
||||
lf t55xx wakeup
|
||||
lf t55xx write
|
||||
lf t55xx bruteforce
|
||||
lf t55xx chk
|
||||
lf t55xx protect
|
||||
lf t55xx recoverpw
|
||||
lf t55xx sniff
|
||||
lf t55xx special
|
||||
lf t55xx wipe
|
||||
smart info
|
||||
smart reader
|
||||
smart raw
|
||||
smart upgrade
|
||||
smart setclock
|
||||
smart brute
|
||||
script run
|
||||
usart btpin
|
||||
usart btfactory
|
||||
usart tx
|
||||
usart rx
|
||||
usart txrx
|
||||
usart txhex
|
||||
usart rxhex
|
||||
usart config
|
|
@ -11,7 +11,7 @@ Check column "offline" for their availability.
|
|||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`auto `|N |`Automated detection process for unknown tags`
|
||||
|`clear `|Y |`clear screen`
|
||||
|`clear `|Y |`Clear screen`
|
||||
|`help `|Y |`This help. Use '<command> help' for details of a particular command.`
|
||||
|`hints `|Y |`Turn hints on / off`
|
||||
|`msleep `|Y |`Add a pause in milliseconds`
|
||||
|
@ -38,6 +38,7 @@ Check column "offline" for their availability.
|
|||
|`analyse nuid `|Y |`create NUID from 7byte UID`
|
||||
|`analyse demodbuff `|Y |`Load binary string to demodbuffer`
|
||||
|`analyse freq `|Y |`Calc wave lengths`
|
||||
|`analyse foo `|Y |`muxer`
|
||||
|
||||
|
||||
### data
|
||||
|
@ -256,7 +257,6 @@ Check column "offline" for their availability.
|
|||
|`hf iclass restore `|N |`[options..] Restore a dump file onto a Picopass / iCLASS tag`
|
||||
|`hf iclass sniff `|N |` Eavesdrop Picopass / iCLASS communication`
|
||||
|`hf iclass wrbl `|N |`[options..] Write Picopass / iCLASS block`
|
||||
|`hf iclass autopwn `|N |`[options..] Automatic key recovery tool for iCLASS`
|
||||
|`hf iclass chk `|N |`[options..] Check keys`
|
||||
|`hf iclass loclass `|Y |`[options..] Use loclass to perform bruteforce reader attack`
|
||||
|`hf iclass lookup `|Y |`[options..] Uses authentication trace to check for key in dictionary file`
|
||||
|
@ -268,7 +268,7 @@ Check column "offline" for their availability.
|
|||
|`hf iclass encrypt `|Y |`[options..] Encrypt given block data`
|
||||
|`hf iclass decrypt `|Y |`[options..] Decrypt given block data or tag dump file`
|
||||
|`hf iclass managekeys `|Y |`[options..] Manage keys to use with iclass commands`
|
||||
|`hf iclass permute `|N |` Permute function from 'heart of darkness' paper`
|
||||
|`hf iclass permutekey `|N |` Permute function from 'heart of darkness' paper`
|
||||
|`hf iclass view `|Y |`[options..] Display content from tag dump file`
|
||||
|
||||
|
||||
|
@ -539,7 +539,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf awid help `|Y |`this help`
|
||||
|`lf awid demod `|Y |`demodulate an AWID FSK tag from the GraphBuffer`
|
||||
|`lf awid read `|N |`attempt to read and extract tag data`
|
||||
|`lf awid reader `|N |`attempt to read and extract tag data`
|
||||
|`lf awid clone `|N |`clone AWID tag to T55x7 or Q5/T5555`
|
||||
|`lf awid sim `|N |`simulate AWID tag`
|
||||
|`lf awid brute `|N |`Bruteforce card number against reader`
|
||||
|
@ -554,7 +554,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf cotag help `|Y |`This help`
|
||||
|`lf cotag demod `|Y |`Tries to decode a COTAG signal`
|
||||
|`lf cotag read `|N |`Attempt to read and extract tag data`
|
||||
|`lf cotag reader `|N |`Attempt to read and extract tag data`
|
||||
|
||||
|
||||
### lf destron
|
||||
|
@ -565,41 +565,21 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf destron help `|Y |`This help`
|
||||
|`lf destron demod `|Y |`Demodulate an Destron tag from the GraphBuffer`
|
||||
|`lf destron read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf destron reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf destron clone `|N |`Clone Destron tag to T55x7`
|
||||
|`lf destron sim `|N |`Simulate Destron tag`
|
||||
|
||||
|
||||
### lf em
|
||||
|
||||
{ EM4X CHIPs & RFIDs... }
|
||||
{ EM CHIPs & RFIDs... }
|
||||
|
||||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`lf em help `|Y |`This help`
|
||||
|`lf em 410x_demod `|Y |`demodulate a EM410x tag from the GraphBuffer`
|
||||
|`lf em 410x_read `|N |`attempt to read and extract tag data`
|
||||
|`lf em 410x_sim `|N |`simulate EM410x tag`
|
||||
|`lf em 410x_brute `|N |`reader bruteforce attack by simulating EM410x tags`
|
||||
|`lf em 410x_watch `|N |`watches for EM410x 125/134 kHz tags (option 'h' for 134)`
|
||||
|`lf em 410x_spoof `|N |`watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)`
|
||||
|`lf em 410x_clone `|N |`write EM410x UID to T55x7 or Q5/T5555 tag`
|
||||
|`lf em 4x05_chk `|N |`Check passwords from dictionary`
|
||||
|`lf em 4x05_demod `|Y |`demodulate a EM4x05/EM4x69 tag from the GraphBuffer`
|
||||
|`lf em 4x05_dump `|N |`dump EM4x05/EM4x69 tag`
|
||||
|`lf em 4x05_wipe `|N |`wipe EM4x05/EM4x69 tag`
|
||||
|`lf em 4x05_info `|N |`tag information EM4x05/EM4x69`
|
||||
|`lf em 4x05_read `|N |`read word data from EM4x05/EM4x69`
|
||||
|`lf em 4x05_write `|N |`write word data to EM4x05/EM4x69`
|
||||
|`lf em 4x05_unlock `|N |`execute tear off against EM4x05/EM4x69`
|
||||
|`lf em 4x05_sniff `|Y |`Attempt to recover em4x05 commands from sample buffer`
|
||||
|`lf em 4x05_brute `|N |`Bruteforce password`
|
||||
|`lf em 4x50_dump `|N |`dump EM4x50 tag`
|
||||
|`lf em 4x50_info `|N |`tag information EM4x50`
|
||||
|`lf em 4x50_write `|N |`write word data to EM4x50`
|
||||
|`lf em 4x50_write_password`|N |`change password of EM4x50 tag`
|
||||
|`lf em 4x50_read `|N |`read word data from EM4x50`
|
||||
|`lf em 4x50_wipe `|N |`wipe data from EM4x50`
|
||||
|`lf em 410x `|Y |`EM 410x commands...`
|
||||
|`lf em 4x05 `|Y |`EM 4x05 commands...`
|
||||
|`lf em 4x50 `|Y |`EM 4x50 commands...`
|
||||
|
||||
|
||||
### lf fdxb
|
||||
|
@ -610,7 +590,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf fdxb help `|Y |`this help`
|
||||
|`lf fdxb demod `|Y |`demodulate a FDX-B ISO11784/85 tag from the GraphBuffer`
|
||||
|`lf fdxb read `|N |`attempt to read at 134kHz and extract tag data`
|
||||
|`lf fdxb reader `|N |`attempt to read at 134kHz and extract tag data`
|
||||
|`lf fdxb clone `|N |`clone animal ID tag to T55x7 or Q5/T5555`
|
||||
|`lf fdxb sim `|N |`simulate Animal ID tag`
|
||||
|
||||
|
@ -623,7 +603,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf gallagher help `|Y |`This help`
|
||||
|`lf gallagher demod `|Y |`Demodulate an GALLAGHER tag from the GraphBuffer`
|
||||
|`lf gallagher read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf gallagher reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf gallagher clone `|N |`clone GALLAGHER tag to T55x7`
|
||||
|`lf gallagher sim `|N |`simulate GALLAGHER tag`
|
||||
|
||||
|
@ -636,7 +616,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf gproxii help `|Y |`this help`
|
||||
|`lf gproxii demod `|Y |`demodulate a G Prox II tag from the GraphBuffer`
|
||||
|`lf gproxii read `|N |`attempt to read and extract tag data from the antenna`
|
||||
|`lf gproxii reader `|N |`attempt to read and extract tag data from the antenna`
|
||||
|`lf gproxii clone `|N |`clone Guardall tag to T55x7 or Q5/T5555`
|
||||
|`lf gproxii sim `|N |`simulate Guardall tag`
|
||||
|
||||
|
@ -649,7 +629,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf hid help `|Y |`this help`
|
||||
|`lf hid demod `|Y |`demodulate HID Prox tag from the GraphBuffer`
|
||||
|`lf hid read `|N |`attempt to read and extract tag data`
|
||||
|`lf hid reader `|N |`attempt to read and extract tag data`
|
||||
|`lf hid clone `|N |`clone HID tag to T55x7`
|
||||
|`lf hid sim `|N |`simulate HID tag`
|
||||
|`lf hid brute `|N |`bruteforce card number against reader`
|
||||
|
@ -681,7 +661,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf idteck help `|Y |`This help`
|
||||
|`lf idteck demod `|Y |`Demodulate an Idteck tag from the GraphBuffer`
|
||||
|`lf idteck read `|N |`Attempt to read and Extract tag data from the antenna`
|
||||
|`lf idteck reader `|N |`Attempt to read and Extract tag data from the antenna`
|
||||
|
||||
|
||||
### lf indala
|
||||
|
@ -693,7 +673,7 @@ Check column "offline" for their availability.
|
|||
|`lf indala help `|Y |`this help`
|
||||
|`lf indala demod `|Y |`demodulate an indala tag (PSK1) from GraphBuffer`
|
||||
|`lf indala altdemod `|Y |`alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)`
|
||||
|`lf indala read `|N |`read an Indala Prox tag from the antenna`
|
||||
|`lf indala reader `|N |`read an Indala Prox tag from the antenna`
|
||||
|`lf indala clone `|N |`clone Indala tag to T55x7 or Q5/T5555`
|
||||
|`lf indala sim `|N |`simulate Indala tag`
|
||||
|
||||
|
@ -706,7 +686,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf io help `|Y |`this help`
|
||||
|`lf io demod `|Y |`demodulate an IOProx tag from the GraphBuffer`
|
||||
|`lf io read `|N |`attempt to read and extract tag data`
|
||||
|`lf io reader `|N |`attempt to read and extract tag data`
|
||||
|`lf io clone `|N |`clone IOProx tag to T55x7 or Q5/T5555`
|
||||
|`lf io sim `|N |`simulate IOProx tag`
|
||||
|`lf io watch `|N |`continuously watch for cards. Reader mode`
|
||||
|
@ -720,7 +700,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf jablotron help `|Y |`This help`
|
||||
|`lf jablotron demod `|Y |`Demodulate an Jablotron tag from the GraphBuffer`
|
||||
|`lf jablotron read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf jablotron reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf jablotron clone `|N |`clone jablotron tag to T55x7 or Q5/T5555`
|
||||
|`lf jablotron sim `|N |`simulate jablotron tag`
|
||||
|
||||
|
@ -733,7 +713,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf keri help `|Y |`This help`
|
||||
|`lf keri demod `|Y |`Demodulate an KERI tag from the GraphBuffer`
|
||||
|`lf keri read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf keri reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf keri clone `|N |`clone KERI tag to T55x7 or Q5/T5555`
|
||||
|`lf keri sim `|N |`simulate KERI tag`
|
||||
|
||||
|
@ -746,7 +726,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf motorola help `|Y |`This help`
|
||||
|`lf motorola demod `|Y |`Demodulate an MOTOROLA tag from the GraphBuffer`
|
||||
|`lf motorola read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf motorola reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf motorola clone `|N |`clone MOTOROLA tag to T55x7`
|
||||
|`lf motorola sim `|N |`simulate MOTOROLA tag`
|
||||
|
||||
|
@ -759,8 +739,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf nedap help `|Y |`This help`
|
||||
|`lf nedap demod `|Y |`Demodulate Nedap tag from the GraphBuffer`
|
||||
|`lf nedap generate `|Y |`Generate Nedap bitstream in DemodBuffer`
|
||||
|`lf nedap read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf nedap reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf nedap clone `|N |`Clone Nedap tag to T55x7 or Q5/T5555`
|
||||
|`lf nedap sim `|N |`Simulate Nedap tag`
|
||||
|
||||
|
@ -773,7 +752,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf nexwatch help `|Y |`This help`
|
||||
|`lf nexwatch demod `|Y |`Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer`
|
||||
|`lf nexwatch read `|N |`Attempt to Read and Extract tag data from the antenna`
|
||||
|`lf nexwatch reader `|N |`Attempt to Read and Extract tag data from the antenna`
|
||||
|`lf nexwatch clone `|N |`clone NexWatch tag to T55x7`
|
||||
|`lf nexwatch sim `|N |`simulate NexWatch tag`
|
||||
|
||||
|
@ -786,7 +765,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf noralsy help `|Y |`This help`
|
||||
|`lf noralsy demod `|Y |`Demodulate an Noralsy tag from the GraphBuffer`
|
||||
|`lf noralsy read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf noralsy reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf noralsy clone `|N |`clone Noralsy tag to T55x7 or Q5/T5555`
|
||||
|`lf noralsy sim `|N |`simulate Noralsy tag`
|
||||
|
||||
|
@ -799,7 +778,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf pac help `|Y |`This help`
|
||||
|`lf pac demod `|Y |`Demodulate a PAC tag from the GraphBuffer`
|
||||
|`lf pac read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf pac reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf pac clone `|N |`clone PAC tag to T55x7`
|
||||
|`lf pac sim `|N |`simulate PAC tag`
|
||||
|
||||
|
@ -812,8 +791,8 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf paradox help `|Y |`This help`
|
||||
|`lf paradox demod `|Y |`Demodulate a Paradox FSK tag from the GraphBuffer`
|
||||
|`lf paradox read `|N |`Attempt to read and Extract tag data from the antenna`
|
||||
|`lf paradox clone `|N |`clone paradox tag to T55x7`
|
||||
|`lf paradox reader `|N |`Attempt to read and Extract tag data from the antenna`
|
||||
|`lf paradox clone `|N |`clone paradox tag`
|
||||
|`lf paradox sim `|N |`simulate paradox tag`
|
||||
|
||||
|
||||
|
@ -824,7 +803,7 @@ Check column "offline" for their availability.
|
|||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`lf pcf7931 help `|Y |`This help`
|
||||
|`lf pcf7931 read `|N |`Read content of a PCF7931 transponder`
|
||||
|`lf pcf7931 reader `|N |`Read content of a PCF7931 transponder`
|
||||
|`lf pcf7931 write `|N |`Write data on a PCF7931 transponder.`
|
||||
|`lf pcf7931 config `|Y |`Configure the password, the tags initialization delay and time offsets (optional)`
|
||||
|
||||
|
@ -837,7 +816,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf presco help `|Y |`This help`
|
||||
|`lf presco demod `|Y |`demodulate Presco tag from the GraphBuffer`
|
||||
|`lf presco read `|N |`Attempt to read and Extract tag data`
|
||||
|`lf presco reader `|N |`Attempt to read and Extract tag data`
|
||||
|`lf presco clone `|N |`clone presco tag to T55x7 or Q5/T5555`
|
||||
|`lf presco sim `|N |`simulate presco tag`
|
||||
|
||||
|
@ -850,7 +829,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf pyramid help `|Y |`this help`
|
||||
|`lf pyramid demod `|Y |`demodulate a Pyramid FSK tag from the GraphBuffer`
|
||||
|`lf pyramid read `|N |`attempt to read and extract tag data`
|
||||
|`lf pyramid reader `|N |`attempt to read and extract tag data`
|
||||
|`lf pyramid clone `|N |`clone pyramid tag to T55x7 or Q5/T5555`
|
||||
|`lf pyramid sim `|N |`simulate pyramid tag`
|
||||
|
||||
|
@ -863,7 +842,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf securakey help `|Y |`This help`
|
||||
|`lf securakey demod `|Y |`Demodulate an Securakey tag from the GraphBuffer`
|
||||
|`lf securakey read `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf securakey reader `|N |`Attempt to read and extract tag data from the antenna`
|
||||
|`lf securakey clone `|N |`clone Securakey tag to T55x7`
|
||||
|`lf securakey sim `|N |`simulate Securakey tag`
|
||||
|
||||
|
@ -875,8 +854,8 @@ Check column "offline" for their availability.
|
|||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`lf ti help `|Y |`This help`
|
||||
|`lf ti demod `|Y |`Demodulate raw bits for TI-type LF tag from the GraphBuffer`
|
||||
|`lf ti read `|N |`Read and decode a TI 134 kHz tag`
|
||||
|`lf ti demod `|Y |`Demodulate raw bits for TI LF tag from the GraphBuffer`
|
||||
|`lf ti reader `|N |`Read and decode a TI 134 kHz tag`
|
||||
|`lf ti write `|N |`Write new data to a r/w TI 134 kHz tag`
|
||||
|
||||
|
||||
|
@ -918,7 +897,7 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf viking help `|Y |`This help`
|
||||
|`lf viking demod `|Y |`Demodulate a Viking tag from the GraphBuffer`
|
||||
|`lf viking read `|N |`Attempt to read and Extract tag data from the antenna`
|
||||
|`lf viking reader `|N |`Attempt to read and Extract tag data from the antenna`
|
||||
|`lf viking clone `|N |`clone Viking tag to T55x7 or Q5/T5555`
|
||||
|`lf viking sim `|N |`simulate Viking tag`
|
||||
|
||||
|
@ -931,14 +910,14 @@ Check column "offline" for their availability.
|
|||
|------- |------- |-----------
|
||||
|`lf visa2000 help `|Y |`This help`
|
||||
|`lf visa2000 demod `|Y |`demodulate an VISA2000 tag from the GraphBuffer`
|
||||
|`lf visa2000 read `|N |`attempt to read and extract tag data from the antenna`
|
||||
|`lf visa2000 reader `|N |`attempt to read and extract tag data from the antenna`
|
||||
|`lf visa2000 clone `|N |`clone Visa2000 tag to T55x7 or Q5/T5555`
|
||||
|`lf visa2000 sim `|N |`simulate Visa2000 tag`
|
||||
|
||||
|
||||
### mem
|
||||
|
||||
{ Flash Memory manipulation... }
|
||||
{ Flash memory manipulation... }
|
||||
|
||||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|
@ -953,7 +932,7 @@ Check column "offline" for their availability.
|
|||
|
||||
### reveng
|
||||
|
||||
{ CRC calculations from RevEng software }
|
||||
{ CRC calculations from RevEng software... }
|
||||
|
||||
[=] reveng: no mode switch specified. Use reveng -h for help.
|
||||
|
||||
|
@ -975,7 +954,7 @@ Check column "offline" for their availability.
|
|||
|
||||
### script
|
||||
|
||||
{ Scripting commands }
|
||||
{ Scripting commands... }
|
||||
|
||||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|
|
|
@ -4,7 +4,7 @@ This document is primarily intended for understanding `hf iclass loclass` and fi
|
|||
|
||||
LOCLASS aim is to recover the used masterkey for that specific reader configured in Elite mode / High Security mode.
|
||||
|
||||
LOCLASS, is a two part attack. First is the online part where you gather needed information from the reader by presenting a carefully selected CSN and save the responses to file. For the first part you run `hf iclass sim 2` and take notice of the saved filename.
|
||||
LOCLASS, is a two part attack. First is the online part where you gather needed information from the reader by presenting a carefully selected CSN and save the responses to file. For the first part you run `hf iclass sim -t 2` and take notice of the saved filename.
|
||||
|
||||
The second part is offline, where the information gathered from the first step is used in a series of DES operations to figure out the used
|
||||
masterkey.
|
||||
|
@ -21,6 +21,6 @@ run `hf iclass loclass --test`.
|
|||
This test mode uses two files.
|
||||
|
||||
- `iclass_dump.bin`
|
||||
this is a sample file from `hf iclass sim 2`, with complete keytable recovery, using 128 carefully selected CSN and the file contains the MAC results from reader.
|
||||
this is a sample file from `hf iclass sim -t 2`, with complete keytable recovery, using 128 carefully selected CSN and the file contains the MAC results from reader.
|
||||
- `iclass_key.bin`
|
||||
this is file shall contain the legacy masterkey, AA1 key. loclass uses it to verify that permutation / reversing / generation of key is correct.
|
|
@ -238,6 +238,8 @@ hf 14a info
|
|||
|
||||
## MIFARE Classic DirectWrite aka Gen2 aka CUID
|
||||
|
||||
(also referred as MCT compatible by some sellers)
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
|
|
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 |
|
@ -238,6 +238,8 @@ typedef struct {
|
|||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
uint8_t longFMT;
|
||||
bool Q5;
|
||||
bool EM;
|
||||
} PACKED lf_hidsim_t;
|
||||
|
||||
// For CMD_LF_FSK_SIMULATE (FSK)
|
||||
|
|
6
pm3
6
pm3
|
@ -133,7 +133,7 @@ function get_pm3_list_Windows {
|
|||
# Need to look for this first, the call to Win32_serialport "crashes" then native bt serial port. Don't ask why.
|
||||
#BT direct SERIAL PORTS (COM)
|
||||
if $FINDBTRFCOMM; then
|
||||
for DEV in $(powershell.exe -command "Get-CimInstance -ClassName Win32_PnPEntity | Where-Object Caption -like 'Standard Serial over Bluetooth link (COM*' | Select Name" 2> /dev/null | awk 'match($0,/COM([0-9]+)/,m){print m[1]}'); do
|
||||
for DEV in $(wmic /locale:ms_409 path Win32_PnPEntity Where "Caption LIKE '%Bluetooth%(COM%'" Get Name 2> /dev/null | awk -b 'match($0,/(COM[0-9]+)/,m){print m[1]}'); do
|
||||
DEV=${DEV/ */}
|
||||
PM3LIST+=("$DEV")
|
||||
if [ ${#PM3LIST[*]} -ge "$N" ]; then
|
||||
|
@ -143,7 +143,7 @@ function get_pm3_list_Windows {
|
|||
fi
|
||||
|
||||
# Normal SERIAL PORTS (COM)
|
||||
for DEV in $(powershell.exe -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_9AC4&PID_4B8F*' | Select DeviceID" 2>/dev/null | awk '/^COM/{print $1}'); do
|
||||
for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
|
||||
DEV=${DEV/ */}
|
||||
PM3LIST+=("$DEV")
|
||||
if [ ${#PM3LIST[*]} -ge "$N" ]; then
|
||||
|
@ -153,7 +153,7 @@ function get_pm3_list_Windows {
|
|||
|
||||
#white BT dongle SERIAL PORTS (COM)
|
||||
if $FINDBTDONGLE; then
|
||||
for DEV in $(powershell.exe -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_10C4&PID_EA60*' | Select DeviceID" 2>/dev/null | awk '/^COM/{print $1}'); do
|
||||
for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_10C4&PID_EA60%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
|
||||
DEV=${DEV/ */}
|
||||
PM3LIST+=("$DEV")
|
||||
if [ ${#PM3LIST[*]} -ge "$N" ]; then
|
||||
|
|
|
@ -363,7 +363,7 @@ while true; do
|
|||
if ! CheckExecute slow "lf T55 awid 50 test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_awid_50.pm3; lf awid demod'" \
|
||||
"AWID - len: 50 FC: 2001 Card: 13371337 - Wiegand: 20fa201980f92, Raw: 0128b12eb1811d7117e22111"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 em410x test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_em410x.pm3; lf search 1'" "EM410x ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 em410x test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_em410x.pm3; lf em 410x_demod demod'" \
|
||||
if ! CheckExecute slow "lf T55 em410x test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_em410x.pm3; lf em 410x demod'" \
|
||||
"EM TAG ID : 0F0368568B"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 fdxb_animal test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_animal.pm3; lf search 1'" "FDX-B ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 fdxb_animal test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_animal.pm3; lf fdxb demod'" \
|
||||
|
@ -391,7 +391,7 @@ while true; do
|
|||
"Fmt 26 FC: 123 Card: 1337 checksum: 10"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 indala_224 test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_224.pm3; lf search 1'" "Indala ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 indala_224 test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_224.pm3; lf indala demod'" \
|
||||
"Indala - len 224, Raw: 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"; then break; fi
|
||||
"Indala - len 224 Raw: 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 io test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_io.pm3; lf search 1'" "IO Prox ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 io test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_io.pm3; lf io demod'" \
|
||||
"IO Prox - XSF(01)01:01337, Raw: 007840603059cf3f (ok)"; then break; fi
|
||||
|
@ -412,7 +412,7 @@ while true; do
|
|||
"Motorola - fmt: 26 FC: 258 Card: 2, Raw: A0000000A0002021"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 nedap test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_nedap.pm3; lf search 1'" "NEDAP ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 nedap test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_nedap.pm3; lf nedap demod'" \
|
||||
"NEDAP - Card: 12345 subtype: 1 customer code: 123, Raw: FF82246508209953"; then break; fi
|
||||
"NEDAP (64b) - ID: 12345 subtype: 1 customer code: 291 / 0x123 Raw: FF82246508209953"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 nexwatch test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_nexwatch.pm3; lf search 1'" "NexWatch ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 nexwatch test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_nexwatch.pm3; lf nexwatch demod'" \
|
||||
"Raw : 56000000213C9F8F150C00"; then break; fi
|
||||
|
@ -433,7 +433,7 @@ while true; do
|
|||
"Paradox - ID: 004209dea FC: 96 Card: 40426, Checksum: b2, Raw: 0f55555695596a6a9999a59a"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 presco test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_presco.pm3; lf search 1'" "Presco ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 presco test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_presco.pm3; lf presco demod'" \
|
||||
"Presco - Card: 1E8021D9, Raw: 10D0000000000000000000001E8021D9"; then break; fi
|
||||
"Presco Site code: 30 User code: 8665 Full code: 1E8021D9 Raw: 10D0000000000000000000001E8021D9"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 pyramid test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_pyramid.pm3; lf search 1'" "Pyramid ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 pyramid test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_pyramid.pm3; lf pyramid demod'" \
|
||||
"Pyramid - len: 26, FC: 123 Card: 11223 - Wiegand: 2f657ae, Raw: 00010101010101010101016eb35e5da4"; then break; fi
|
||||
|
@ -450,7 +450,7 @@ while true; do
|
|||
echo -e "\n${C_BLUE}Testing HF:${C_NC}"
|
||||
if ! CheckExecute "hf mf offline text" "$CLIENTBIN -c 'hf mf'" "at_enc"; then break; fi
|
||||
if ! CheckExecute slow retry ignore "hf mf hardnested long test" "$CLIENTBIN -c 'hf mf hardnested t 1 000000000000'" "found:"; then break; fi
|
||||
if ! CheckExecute slow "hf iclass long test" "$CLIENTBIN -c 'hf iclass loclass --long'" "verified ok"; then break; fi
|
||||
if ! CheckExecute slow "hf iclass long test" "$CLIENTBIN -c 'hf iclass loclass --long'" "verified (ok)"; then break; fi
|
||||
if ! CheckExecute slow "emv long test" "$CLIENTBIN -c 'emv test -l'" "Test(s) \[ ok"; then break; fi
|
||||
if ! $SLOWTESTS; then
|
||||
if ! CheckExecute "hf iclass test" "$CLIENTBIN -c 'hf iclass loclass --test'" "key diversification (ok)"; then break; fi
|
||||
|
|
Loading…
Reference in a new issue