Merge pull request #62 from RfidResearchGroup/master

Update
This commit is contained in:
mwalker33 2020-12-06 10:06:53 +11:00 committed by GitHub
commit a7d145c9d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
101 changed files with 11212 additions and 8456 deletions

View file

@ -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)

View file

@ -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 )

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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();

View file

@ -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");

View file

@ -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: {

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);

View file

@ -108,6 +108,8 @@
#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();

View file

@ -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();
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
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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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 \

View file

@ -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

View file

@ -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

View file

@ -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

View 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)

View 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)

View file

@ -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");
}
}

View file

@ -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();

View file

@ -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();

View file

@ -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

View file

@ -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);

View file

@ -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") " ---------------------------");

View file

@ -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;
}

View file

@ -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 "comms.h"
#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;
}
if (readCOTAGUid()) {
PrintAndLogEx(INPLACE, "Searching for COTAG tag...");
if (readCOTAGUid()) {
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... }"},

View file

@ -11,96 +11,27 @@
// FSK2a, RF/50, 96 bits (complete)
//-----------------------------------------------------------------------------
#include "cmdlfawid.h" // AWID function declarations
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#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 "util_posix.h"
#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
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);
return demodAWID(true);
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"},

View file

@ -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, "");
@ -128,10 +161,9 @@ 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"},
{"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);
}

View file

@ -7,7 +7,6 @@
// Low frequency FDX-A FECAVA Destron tag commands
//-----------------------------------------------------------------------------
#include "cmdlfdestron.h"
#include <ctype.h> // tolower
#include <string.h> // memcpy
#include "commonutil.h" // ARRAYLEN
@ -21,8 +20,9 @@
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "cmdlf.h" // cmdlfconfig
#include "cliparser.h" // cli parse input
#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,65 +77,149 @@ 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;
}
@ -141,7 +227,7 @@ static int CmdDestronSim(const char *Cmd) {
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"},
{"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
View 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
View 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

View file

@ -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);
}

View file

@ -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);

View file

@ -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) {
uint8_t addr = 0;
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;
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
};
} else { // Not a single character so assume password
pwd = param_get32ex(Cmd, cmdp, 1, 16);
cmdp++;
}
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;
}
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;
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;
if ( inputpwd != 0xFFFFFFFFFFFFFFFF) {
pwd = (inputpwd & 0xFFFFFFFF);
use_pwd = true;
}
// 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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -9,16 +9,13 @@
//-----------------------------------------------------------------------------
#include "cmdlffdxb.h"
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h> // tolower
#include "cmdparser.h" // command_t
#include "comms.h"
#include "commonutil.h"
#include "ui.h" // PrintAndLog
#include "cmddata.h"
#include "cmdlf.h" // lf read
@ -26,6 +23,8 @@
#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;
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;
}
case 'n': {
national_code = param_get64ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
}
case 'e': {
extended = param_get32ex(Cmd, cmdp + 1, 0, 16);
uint32_t extended = 0;
bool has_extended = false;
if (extended_len) {
extended = bytes_to_num(edata, extended_len);
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;
}
}
}
if (errors || strlen(Cmd) == 0) return usage_lf_fdxb_clone();
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%"PRIX32, extended);
PrintAndLogEx(INFO, "RFU................. 0");
uint8_t *bits = calloc(128, sizeof(uint8_t));
if (getFDXBBits(national_code, country_code, is_animal, has_extended, extended, bits) != PM3_SUCCESS) {
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)
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);
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;
cmdp += 2;
break;
}
case 's': {
is_animal = 1;
cmdp++;
break;
}
default: {
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
}
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;
@ -848,7 +871,7 @@ 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"},
{"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;
}

View file

@ -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

View file

@ -10,7 +10,7 @@
// sample Q5 , ASK RF/32, STT, 96 bits (3blocks) ( 0x9000F006)
//-----------------------------------------------------------------------------
#include "cmdlfgallagher.h"
#include <string.h> // memcpy
#include <ctype.h> // tolower
#include <stdio.h>
#include "commonutil.h" // ARRAYLEN
@ -24,22 +24,11 @@
#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,71 +123,167 @@ 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
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);
return demodGallagher(true);
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': {
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);
int raw_len = 0;
// 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;
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;
}
uint32_t blocks[4];
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));
}
cmdp += 2;
break;
}
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (errors || cmdp == 0) return usage_lf_gallagher_clone();
//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"},
{"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}

View file

@ -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,12 +9,10 @@
// 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 "cmdparser.h" // command_t
#include "comms.h"
@ -23,44 +22,11 @@
#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
// but will leave the GraphBuffer intact.
@ -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
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);
return demodGuard(true);
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

View file

@ -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
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);
return demodHID(true);
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"},

View file

@ -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;
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);
return demodIdteck(true);
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"},
{"reader", CmdIdteckReader, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"},
{NULL, NULL, NULL, NULL}
};

View file

@ -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");
}
do {
lf_read(false, 30000);
return demodIndalaEx(clk, invert, maxErr, true);
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_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));
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);
if (q5) {
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT);
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
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}

View file

@ -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,13 +10,10 @@
//-----------------------------------------------------------------------------
#include "cmdlfio.h"
#include <stdio.h> // sscanf
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "comms.h"
@ -26,61 +24,27 @@
#include "protocols.h" // for T55xx config register definitions
#include "cmddata.h"
#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
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);
return demodIOProx(true);
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,29 +301,48 @@ 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"},
{"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}
};

View file

@ -9,12 +9,10 @@
//-----------------------------------------------------------------------------
#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
@ -24,40 +22,13 @@
#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
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);
return demodJablotron(true);
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);
char cardtype[16] = {"T55x7"};
// Q5
bool q5 = tolower(param_getchar(Cmd, 1)) == 'q';
if (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}

View file

@ -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_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);
@ -340,7 +359,7 @@ 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"},
{"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}

View file

@ -9,9 +9,7 @@
// PSK1, RF/32, 64 bits long, at 74 kHz
//-----------------------------------------------------------------------------
#include "cmdlfmotorola.h"
#include <ctype.h> // tolower
#include "commonutil.h" // ARRAYLEN
#include "common.h"
#include "cmdparser.h" // command_t
@ -24,7 +22,7 @@
#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);
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.");
@ -207,7 +274,7 @@ 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"},
{"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);
}

View file

@ -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
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);
return demodNedap(true);
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,118 +361,112 @@ 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);
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 (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
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;
}
bool q5 = (strstr(Cmd, "q") != NULL);
if (q5) {
if (DemodBufferLen == 64) {
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
} else {
max = 3;
blocks[0] = T55X7_NEDAP_64_CONFIG_BLOCK;
}
char cardtype[16] = {"T55x7"};
// Q5
if (q5) {
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;
}
}
// 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");
}
// 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] = bytebits_to_byte(DemodBuffer + ((i - 1) * 32), 32);
blocks[i] = bytes_to_num (data + ((i - 1) * 4), 4);
}
PrintAndLogEx(SUCCESS, "Preparing to clone NEDAP to " _YELLOW_("%s") " tag", (q5) ? "Q5/T5555" : "T55x7");
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`"));
@ -493,28 +474,69 @@ static int CmdLFNedapClone(const char *Cmd) {
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);
@ -541,8 +563,7 @@ 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"},
{"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}

View file

@ -13,7 +13,6 @@
#include <string.h>
#include <ctype.h> // tolower
#include <stdlib.h> // free, alloc
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "comms.h"
@ -23,6 +22,8 @@
#include "lfdemod.h"
#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;
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);
return demodNexWatch(true);
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"
);
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);
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);
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 (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
// 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};
bool use_raw = (raw_len != 0);
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;
use_raw = true;
cmdp += 2;
break;
if (use_raw && cn != -1) {
PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time");
return PM3_EINVARG;
}
case 'c': {
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
if (cn != -1) {
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;
}
num_to_bytes(scrambled, 4, raw + 5);
}
if (errors || cmdp == 0) return usage_lf_nexwatch_clone();
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;
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;
}
case 'c': {
cn = param_get32ex(Cmd, cmdp + 1, 0, 10);
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, 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;
}
num_to_bytes(scrambled, 4, raw + 5);
}
if (errors || cmdp == 0) return usage_lf_nexwatch_sim();
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;
@ -449,7 +484,7 @@ 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"},
{"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}

View file

@ -8,11 +8,9 @@
// 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 "cmdparser.h" // command_t
#include "comms.h"
@ -22,38 +20,11 @@
#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
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);
return demodNoralsy(true);
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;
@ -227,7 +271,7 @@ 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"},
{"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

View file

@ -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;
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);
return demodPac(true);
demodPac(!cm);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
static int CmdPacClone(const char *Cmd) {
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"
);
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);
uint8_t cnstr[9];
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);
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 (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);
}
uint32_t blocks[5];
bool errors = false;
uint8_t cmdp = 0;
int datalen = 0;
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;
pacCardIdToRaw(rawhex, cardid);
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));
}
cmdp += 2;
break;
}
case 'b': {
// skip first block, 4*4 = 16 bytes left
uint8_t rawhex[16] = {0};
int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen);
if (res != 0)
errors = true;
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
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;
}
}
if (errors || cmdp == 0) return usage_lf_pac_clone();
// 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;
@ -299,7 +376,7 @@ 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"},
{"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}

View file

@ -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,12 +9,10 @@
// 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 "cmdparser.h" // command_t
#include "comms.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,
@ -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
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);
return demodParadox(true);
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': {
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);
int raw_len = 0;
// 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;
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 (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(rawhex + ((i - 1) * 4), sizeof(uint32_t));
}
cmdp += 2;
break;
}
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
}
if (errors || cmdp == 0) return usage_lf_paradox_clone();
//Securakey - compat mode, ASK/Man, data rate 40, 3 data blocks
// 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;
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"
);
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;
}
/*
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;
PrintAndLogEx(SUCCESS, "Simulating Paradox - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
uint8_t bs[96];
memset(bs, 0x00, sizeof(bs));
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,14 +337,29 @@ 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"},
{"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}
};

View file

@ -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"
);
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");
}
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;
}
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();
do {
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_LF_PCF7931_READ, NULL, 0);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
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}

View file

@ -8,12 +8,10 @@
//-----------------------------------------------------------------------------
#include "cmdlfpresco.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "comms.h"
@ -23,36 +21,51 @@
#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
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);
return demodPresco(true);
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,7 +346,7 @@ 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"},
{"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;
}

View file

@ -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

View file

@ -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
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);
return demodPyramid(true);
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));
@ -311,7 +362,7 @@ 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"},
{"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}

View file

@ -8,10 +8,8 @@
// 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 "comms.h"
@ -22,22 +20,11 @@
#include "parity.h" // for wiegand parity test
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "cliparser.h"
#include "cmdlfem4x05.h" // EM defines
static int CmdHelp(const char *Cmd);
static int usage_lf_securakey_clone(void) {
PrintAndLogEx(NORMAL, "clone a Securakey tag to a T55x7 tag.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf securakey clone [h] [b <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,77 +105,186 @@ int demodSecurakey(bool verbose) {
if (bitLen <= 32)
PrintAndLogEx(SUCCESS, "Wiegand: " _GREEN_("%08X") " parity (%s)", (lWiegand << (bitLen / 2)) | rWiegand, parity ? _GREEN_("ok") : _RED_("fail"));
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\n by sharing your tag on the pm3 forum or with forum members");
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
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);
return demodSecurakey(true);
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': {
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);
int raw_len = 0;
// 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;
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 (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(rawhex + ((i - 1) * 4), sizeof(uint32_t));
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
}
cmdp += 2;
break;
}
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (errors || cmdp == 0) return usage_lf_securakey_clone();
//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"},
{"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}

View file

@ -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,42 +272,98 @@ 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
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"},
{"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}
};

View file

@ -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,43 +54,108 @@ 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;
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);
return demodViking(true);
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))
);
@ -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

View file

@ -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
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);
return demodVisa2k(true);
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)
@ -259,7 +285,7 @@ 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"},
{"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}

View file

@ -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);

View file

@ -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);

View file

@ -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}
};

View file

@ -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) {

View file

@ -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 [i1] )
rk(key64, i, temp_output);
//y [i] = DES enc (rk(K cus , i), y [i1] )
@ -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};
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};
@ -318,12 +424,11 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
**/
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;
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,18 +436,141 @@ 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,
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
*/
//uint32_t brute = startvalue;
/*
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...
@ -350,16 +578,17 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
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();

View file

@ -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

View file

@ -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);
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...");

View file

@ -502,8 +502,7 @@ SWIG_TypePrettyName(const swig_type_info *type) {
for (s = type->str; *s; s++)
if (*s == '|') last_name = s + 1;
return last_name;
}
else
} else
return type->name;
}
@ -916,8 +915,7 @@ typedef struct swig_elua_entry {
prefixed with the location of the innermost Lua call-point
(as formatted by luaL_where). */
SWIGRUNTIME void
SWIG_Lua_pusherrstring (lua_State *L, const char *str)
{
SWIG_Lua_pusherrstring(lua_State *L, const char *str) {
luaL_where(L, 1);
lua_pushstring(L, str);
lua_concat(L, 2);
@ -927,8 +925,7 @@ SWIG_Lua_pusherrstring (lua_State *L, const char *str)
the Lua stack, like lua_pushfstring, but prefixed with the
location of the innermost Lua call-point (as formatted by luaL_where). */
SWIGRUNTIME void
SWIG_Lua_pushferrstring (lua_State *L, const char *fmt, ...)
{
SWIG_Lua_pushferrstring(lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
luaL_where(L, 1);
@ -1106,8 +1103,7 @@ SWIG_Lua_SetModule(lua_State *L, swig_module_info *module) {
/* this function is called when trying to set an immutable.
default action is to print an error.
This can removed with a compile flag SWIGLUA_IGNORE_SET_IMMUTABLE */
SWIGINTERN int SWIG_Lua_set_immutable(lua_State *L)
{
SWIGINTERN int SWIG_Lua_set_immutable(lua_State *L) {
/* there should be 1 param passed in: the new value */
#ifndef SWIGLUA_IGNORE_SET_IMMUTABLE
lua_pop(L, 1); /* remove it */
@ -1123,8 +1119,7 @@ SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State *L,void *ptr,size_t size,swig_t
static int swig_lua_elua_emulate_unique_key;
/* This function emulates eLua rotables behaviour. It loads a rotable definition into the usual lua table. */
SWIGINTERN void SWIG_Lua_elua_emulate_register(lua_State *L, const swig_elua_entry *table)
{
SWIGINTERN void SWIG_Lua_elua_emulate_register(lua_State *L, const swig_elua_entry *table) {
int i, table_parsed, parsed_tables_array, target_table;
assert(lua_istable(L, -1));
target_table = lua_gettop(L);
@ -1141,8 +1136,7 @@ SWIGINTERN void SWIG_Lua_elua_emulate_register(lua_State *L, const swig_elua_ent
lua_rawsetp(L, parsed_tables_array, table);
table_parsed = 0;
const int SWIGUNUSED pairs_start = lua_gettop(L);
for(i = 0;table[i].key.type != LUA_TNIL || table[i].value.type != LUA_TNIL;i++)
{
for (i = 0; table[i].key.type != LUA_TNIL || table[i].value.type != LUA_TNIL; i++) {
const swig_elua_entry *entry = table + i;
int is_metatable = 0;
switch (entry->key.type) {
@ -1207,16 +1201,14 @@ SWIGINTERN void SWIG_Lua_elua_emulate_register(lua_State *L, const swig_elua_ent
assert(lua_gettop(L) == target_table);
}
SWIGINTERN void SWIG_Lua_elua_emulate_register_clear(lua_State *L)
{
SWIGINTERN void SWIG_Lua_elua_emulate_register_clear(lua_State *L) {
lua_pushnil(L);
lua_rawsetp(L, LUA_REGISTRYINDEX, &swig_lua_elua_emulate_unique_key);
}
SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L);
SWIGINTERN int SWIG_Lua_emulate_elua_getmetatable(lua_State *L)
{
SWIGINTERN int SWIG_Lua_emulate_elua_getmetatable(lua_State *L) {
SWIG_check_num_args("getmetatable(SWIG eLua emulation)", 1, 1);
SWIG_Lua_get_class_registry(L);
lua_getfield(L, -1, "lua_getmetatable");
@ -1241,8 +1233,7 @@ fail:
return 0;
}
SWIGINTERN void SWIG_Lua_emulate_elua_swap_getmetatable(lua_State *L)
{
SWIGINTERN void SWIG_Lua_emulate_elua_swap_getmetatable(lua_State *L) {
SWIG_Lua_get_class_registry(L);
lua_pushglobaltable(L);
lua_pushstring(L, "lua_getmetatable");
@ -1262,8 +1253,7 @@ SWIGINTERN void SWIG_Lua_emulate_elua_swap_getmetatable(lua_State *L)
* global variable support code: namespaces and modules (which are the same thing)
* ----------------------------------------------------------------------------- */
SWIGINTERN int SWIG_Lua_namespace_get(lua_State *L)
{
SWIGINTERN int SWIG_Lua_namespace_get(lua_State *L) {
/* there should be 2 params passed in
(1) table (not the meta table)
(2) string name of the attribute
@ -1277,8 +1267,8 @@ SWIGINTERN int SWIG_Lua_namespace_get(lua_State *L)
lua_pushvalue(L, 2); /* key */
lua_rawget(L, -2);
lua_remove(L, -2); /* stack tidy, remove .get table */
if (lua_iscfunction(L,-1))
{ /* found it so call the fn & return its value */
if (lua_iscfunction(L, -1)) {
/* found it so call the fn & return its value */
lua_call(L, 0, 1); /* 1 value in (userdata),1 out (result) */
lua_remove(L, -2); /* stack tidy, remove metatable */
return 1;
@ -1290,8 +1280,8 @@ SWIGINTERN int SWIG_Lua_namespace_get(lua_State *L)
lua_pushvalue(L, 2); /* key */
lua_rawget(L, -2); /* look for the fn */
lua_remove(L, -2); /* stack tidy, remove .fn table */
if (lua_isfunction(L,-1)) /* note: whether it's a C function or lua function */
{ /* found it so return the fn & let lua call it */
if (lua_isfunction(L, -1)) { /* note: whether it's a C function or lua function */
/* found it so return the fn & let lua call it */
lua_remove(L, -2); /* stack tidy, remove metatable */
return 1;
}
@ -1299,8 +1289,7 @@ SWIGINTERN int SWIG_Lua_namespace_get(lua_State *L)
return 0;
}
SWIGINTERN int SWIG_Lua_namespace_set(lua_State *L)
{
SWIGINTERN int SWIG_Lua_namespace_set(lua_State *L) {
/* there should be 3 params passed in
(1) table (not the meta table)
(2) string name of the attribute
@ -1312,13 +1301,12 @@ SWIGINTERN int SWIG_Lua_namespace_set(lua_State *L)
assert(lua_istable(L, -1));
SWIG_Lua_get_table(L, ".set"); /* find the .set table */
if (lua_istable(L,-1))
{
if (lua_istable(L, -1)) {
/* look for the key in the .set table */
lua_pushvalue(L, 2); /* key */
lua_rawget(L, -2);
if (lua_iscfunction(L,-1))
{ /* found it so call the fn & return its value */
if (lua_iscfunction(L, -1)) {
/* found it so call the fn & return its value */
lua_pushvalue(L, 3); /* value */
lua_call(L, 1, 0);
return 0;
@ -1337,8 +1325,7 @@ SWIGINTERN void SWIG_Lua_add_variable(lua_State *L,const char *name,lua_CFuncti
SWIGINTERN void SWIG_Lua_class_register(lua_State *L, swig_lua_class *clss);
/* helper function - register namespace methods and attributes into namespace */
SWIGINTERN int SWIG_Lua_add_namespace_details(lua_State *L, swig_lua_namespace *ns)
{
SWIGINTERN int SWIG_Lua_add_namespace_details(lua_State *L, swig_lua_namespace *ns) {
int i;
/* There must be namespace table (not metatable) at the top of the stack */
assert(lua_istable(L, -1));
@ -1361,8 +1348,7 @@ SWIGINTERN int SWIG_Lua_add_namespace_details(lua_State *L, swig_lua_namespace *
}
/* Register all classes in the namespace */
SWIGINTERN void SWIG_Lua_add_namespace_classes(lua_State *L, swig_lua_namespace *ns)
{
SWIGINTERN void SWIG_Lua_add_namespace_classes(lua_State *L, swig_lua_namespace *ns) {
swig_lua_class **classes;
/* There must be a module/namespace table at the top of the stack */
@ -1383,8 +1369,7 @@ SWIGINTERN void SWIG_Lua_add_namespace_classes(lua_State *L, swig_lua_namespace
when function is called).
Function always returns newly registered table on top of the stack.
*/
SWIGINTERN void SWIG_Lua_namespace_register(lua_State *L, swig_lua_namespace *ns, int reg)
{
SWIGINTERN void SWIG_Lua_namespace_register(lua_State *L, swig_lua_namespace *ns, int reg) {
swig_lua_namespace **sub_namespace;
/* 1 argument - table on the top of the stack */
const int SWIGUNUSED begin = lua_gettop(L);
@ -1444,8 +1429,7 @@ SWIGINTERN void SWIG_Lua_get_class_metatable(lua_State *L,const char *cname);
typedef int (*swig_lua_base_iterator_func)(lua_State *, swig_type_info *, int, int *ret);
SWIGINTERN int SWIG_Lua_iterate_bases(lua_State *L, swig_type_info *SWIGUNUSED swig_type,
int first_arg, swig_lua_base_iterator_func func, int *const ret)
{
int first_arg, swig_lua_base_iterator_func func, int *const ret) {
/* first_arg - position of the object in stack. Everything that is above are arguments
* and is passed to every evocation of the func */
int last_arg = lua_gettop(L);/* position of last argument */
@ -1476,8 +1460,7 @@ SWIGINTERN int SWIG_Lua_iterate_bases(lua_State *L, swig_type_info * SWIGUNUSED
if (ret)
*ret = 0;
if(bases_count>0)
{
if (bases_count > 0) {
int to_remove;
size_t i;
int j;
@ -1543,8 +1526,7 @@ SWIGINTERN int SWIG_Lua_iterate_bases(lua_State *L, swig_type_info * SWIGUNUSED
* It returns an error code. Number of function return values is passed inside 'ret'.
* first_arg is not used in this function because function always has 2 arguments.
*/
SWIGINTERN int SWIG_Lua_class_do_get_item(lua_State *L, swig_type_info *type, int SWIGUNUSED first_arg, int *ret)
{
SWIGINTERN int SWIG_Lua_class_do_get_item(lua_State *L, swig_type_info *type, int SWIGUNUSED first_arg, int *ret) {
/* there should be 2 params passed in
(1) userdata (not the meta table)
(2) string name of the attribute
@ -1559,8 +1541,8 @@ SWIGINTERN int SWIG_Lua_class_do_get_item(lua_State *L, swig_type_info *type, i
/* NEW: looks for the __getitem() fn
this is a user provided get fn */
SWIG_Lua_get_table(L, "__getitem"); /* find the __getitem fn */
if (lua_iscfunction(L,-1)) /* if its there */
{ /* found it so call the fn & return its value */
if (lua_iscfunction(L, -1)) { /* if its there */
/* found it so call the fn & return its value */
lua_pushvalue(L, substack_start + 1); /* the userdata */
lua_pushvalue(L, substack_start + 2); /* the parameter */
lua_call(L, 2, 1); /* 2 value in (userdata),1 out (result) */
@ -1581,8 +1563,7 @@ SWIGINTERN int SWIG_Lua_class_do_get_item(lua_State *L, swig_type_info *type, i
* It returns an error code. Number of function return values is passed inside 'ret'.
* first_arg is not used in this function because function always has 2 arguments.
*/
SWIGINTERN int SWIG_Lua_class_do_get(lua_State *L, swig_type_info *type, int SWIGUNUSED first_arg, int *ret)
{
SWIGINTERN int SWIG_Lua_class_do_get(lua_State *L, swig_type_info *type, int SWIGUNUSED first_arg, int *ret) {
/* there should be 2 params passed in
(1) userdata (not the meta table)
(2) string name of the attribute
@ -1600,8 +1581,8 @@ SWIGINTERN int SWIG_Lua_class_do_get(lua_State *L, swig_type_info *type, int SW
lua_pushvalue(L, substack_start + 2); /* key */
lua_rawget(L, -2);
lua_remove(L, -2); /* stack tidy, remove .get table */
if (lua_iscfunction(L,-1))
{ /* found it so call the fn & return its value */
if (lua_iscfunction(L, -1)) {
/* found it so call the fn & return its value */
lua_pushvalue(L, substack_start + 1); /* the userdata */
lua_call(L, 1, 1); /* 1 value in (userdata),1 out (result) */
lua_remove(L, -2); /* stack tidy, remove metatable */
@ -1616,8 +1597,8 @@ SWIGINTERN int SWIG_Lua_class_do_get(lua_State *L, swig_type_info *type, int SW
lua_pushvalue(L, substack_start + 2); /* key */
lua_rawget(L, -2); /* look for the fn */
lua_remove(L, -2); /* stack tidy, remove .fn table */
if (lua_isfunction(L,-1)) /* note: if its a C function or lua function */
{ /* found it so return the fn & let lua call it */
if (lua_isfunction(L, -1)) { /* note: if its a C function or lua function */
/* found it so return the fn & let lua call it */
lua_remove(L, -2); /* stack tidy, remove metatable */
if (ret)
*ret = 1;
@ -1633,8 +1614,7 @@ SWIGINTERN int SWIG_Lua_class_do_get(lua_State *L, swig_type_info *type, int SW
/* the class.get method, performs the lookup of class attributes
*/
SWIGINTERN int SWIG_Lua_class_get(lua_State *L)
{
SWIGINTERN int SWIG_Lua_class_get(lua_State *L) {
/* there should be 2 params passed in
(1) userdata (not the meta table)
(2) string name of the attribute
@ -1660,8 +1640,7 @@ SWIGINTERN int SWIG_Lua_class_get(lua_State *L)
/* helper for the class.set method, performs the lookup of class attributes
* It returns error code. Number of function return values is passed inside 'ret'
*/
SWIGINTERN int SWIG_Lua_class_do_set(lua_State *L, swig_type_info *type, int first_arg, int *ret)
{
SWIGINTERN int SWIG_Lua_class_do_set(lua_State *L, swig_type_info *type, int first_arg, int *ret) {
/* there should be 3 params passed in
(1) table (not the meta table)
(2) string name of the attribute
@ -1678,14 +1657,13 @@ SWIGINTERN int SWIG_Lua_class_do_set(lua_State *L, swig_type_info *type, int fi
*ret = 0; /* it is setter - number of return values is always 0 */
SWIG_Lua_get_table(L, ".set"); /* find the .set table */
if (lua_istable(L,-1))
{
if (lua_istable(L, -1)) {
/* look for the key in the .set table */
lua_pushvalue(L, substack_start + 2); /* key */
lua_rawget(L, -2);
lua_remove(L, -2); /* tidy stack, remove .set table */
if (lua_iscfunction(L,-1))
{ /* found it so call the fn & return its value */
if (lua_iscfunction(L, -1)) {
/* found it so call the fn & return its value */
lua_pushvalue(L, substack_start + 1); /* userdata */
lua_pushvalue(L, substack_start + 3); /* value */
lua_call(L, 2, 0);
@ -1699,8 +1677,8 @@ SWIGINTERN int SWIG_Lua_class_do_set(lua_State *L, swig_type_info *type, int fi
/* NEW: looks for the __setitem() fn
this is a user provided set fn */
SWIG_Lua_get_table(L, "__setitem"); /* find the fn */
if (lua_iscfunction(L,-1)) /* if its there */
{ /* found it so call the fn & return its value */
if (lua_iscfunction(L, -1)) { /* if its there */
/* found it so call the fn & return its value */
lua_pushvalue(L, substack_start + 1); /* the userdata */
lua_pushvalue(L, substack_start + 2); /* the parameter */
lua_pushvalue(L, substack_start + 3); /* the value */
@ -1722,8 +1700,7 @@ SWIGINTERN int SWIG_Lua_class_do_set(lua_State *L, swig_type_info *type, int fi
/* This is the actual method exported to Lua. It calls SWIG_Lua_class_do_set and correctly
* handles return values.
*/
SWIGINTERN int SWIG_Lua_class_set(lua_State *L)
{
SWIGINTERN int SWIG_Lua_class_set(lua_State *L) {
/* There should be 3 params passed in
(1) table (not the meta table)
(2) string name of the attribute
@ -1747,8 +1724,7 @@ SWIGINTERN int SWIG_Lua_class_set(lua_State *L)
}
/* the class.destruct method called by the interpreter */
SWIGINTERN int SWIG_Lua_class_destruct(lua_State *L)
{
SWIGINTERN int SWIG_Lua_class_destruct(lua_State *L) {
/* there should be 1 params passed in
(1) userdata (not the meta table) */
swig_lua_userdata *usr;
@ -1756,11 +1732,9 @@ SWIGINTERN int SWIG_Lua_class_destruct(lua_State *L)
assert(lua_isuserdata(L, -1)); /* just in case */
usr = (swig_lua_userdata *)lua_touserdata(L, -1); /* get it */
/* if must be destroyed & has a destructor */
if (usr->own) /* if must be destroyed */
{
if (usr->own) { /* if must be destroyed */
clss = (swig_lua_class *)usr->type->clientdata; /* get the class */
if (clss && clss->destructor) /* there is a destroy fn */
{
if (clss && clss->destructor) { /* there is a destroy fn */
clss->destructor(usr->ptr); /* bye bye */
}
}
@ -1768,8 +1742,7 @@ SWIGINTERN int SWIG_Lua_class_destruct(lua_State *L)
}
/* the class.__tostring method called by the interpreter and print */
SWIGINTERN int SWIG_Lua_class_tostring(lua_State *L)
{
SWIGINTERN int SWIG_Lua_class_tostring(lua_State *L) {
/* there should be 1 param passed in
(1) userdata (not the metatable) */
swig_lua_userdata *userData;
@ -1781,8 +1754,7 @@ SWIGINTERN int SWIG_Lua_class_tostring(lua_State *L)
}
/* to manually disown some userdata */
SWIGINTERN int SWIG_Lua_class_disown(lua_State *L)
{
SWIGINTERN int SWIG_Lua_class_disown(lua_State *L) {
/* there should be 1 params passed in
(1) userdata (not the meta table) */
swig_lua_userdata *usr;
@ -1796,8 +1768,7 @@ SWIGINTERN int SWIG_Lua_class_disown(lua_State *L)
/* lua callable function to compare userdata's value
the issue is that two userdata may point to the same thing
but to lua, they are different objects */
SWIGRUNTIME int SWIG_Lua_class_equal(lua_State *L)
{
SWIGRUNTIME int SWIG_Lua_class_equal(lua_State *L) {
int result;
swig_lua_userdata *usr1, *usr2;
if (!lua_isuserdata(L, 1) || !lua_isuserdata(L, 2)) /* just in case */
@ -1811,8 +1782,7 @@ SWIGRUNTIME int SWIG_Lua_class_equal(lua_State *L)
}
/* populate table at the top of the stack with metamethods that ought to be inherited */
SWIGINTERN void SWIG_Lua_populate_inheritable_metamethods(lua_State *L)
{
SWIGINTERN void SWIG_Lua_populate_inheritable_metamethods(lua_State *L) {
SWIG_Lua_add_boolean(L, "__add", 1);
SWIG_Lua_add_boolean(L, "__sub", 1);
SWIG_Lua_add_boolean(L, "__mul", 1);
@ -1831,8 +1801,7 @@ SWIGINTERN void SWIG_Lua_populate_inheritable_metamethods(lua_State *L)
}
/* creates the swig registry */
SWIGINTERN void SWIG_Lua_create_class_registry(lua_State *L)
{
SWIGINTERN void SWIG_Lua_create_class_registry(lua_State *L) {
/* create main SWIG registry table */
lua_pushstring(L, "SWIG");
lua_newtable(L);
@ -1855,13 +1824,12 @@ SWIGINTERN void SWIG_Lua_create_class_registry(lua_State *L)
}
/* gets the swig registry (or creates it) */
SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L)
{
SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L) {
/* add this all into the swig registry: */
lua_pushstring(L, "SWIG");
lua_rawget(L, LUA_REGISTRYINDEX); /* get the registry */
if (!lua_istable(L,-1)) /* not there */
{ /* must be first time, so add it */
if (!lua_istable(L, -1)) { /* not there */
/* must be first time, so add it */
lua_pop(L, 1); /* remove the result */
SWIG_Lua_create_class_registry(L);
/* then get it */
@ -1870,8 +1838,7 @@ SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L)
}
}
SWIGINTERN void SWIG_Lua_get_inheritable_metamethods(lua_State *L)
{
SWIGINTERN void SWIG_Lua_get_inheritable_metamethods(lua_State *L) {
SWIG_Lua_get_class_registry(L);
lua_pushstring(L, ".library");
lua_rawget(L, -2);
@ -1885,8 +1852,7 @@ SWIGINTERN void SWIG_Lua_get_inheritable_metamethods(lua_State *L)
}
/* Helper function to get the classes metatable from the register */
SWIGINTERN void SWIG_Lua_get_class_metatable(lua_State *L,const char *cname)
{
SWIGINTERN void SWIG_Lua_get_class_metatable(lua_State *L, const char *cname) {
SWIG_Lua_get_class_registry(L); /* get the registry */
lua_pushstring(L, cname); /* get the name */
lua_rawget(L, -2); /* get it */
@ -1900,14 +1866,11 @@ It cannot be done at compile time, as this will not work with hireachies
spread over more than one swig file.
Therefore it must be done at runtime, querying the SWIG type system.
*/
SWIGINTERN void SWIG_Lua_init_base_class(lua_State *L,swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_init_base_class(lua_State *L, swig_lua_class *clss) {
int i = 0;
swig_module_info *module = SWIG_GetModule(L);
for(i=0;clss->base_names[i];i++)
{
if (clss->bases[i]==0) /* not found yet */
{
for (i = 0; clss->base_names[i]; i++) {
if (clss->bases[i] == 0) { /* not found yet */
/* lookup and cache the base class */
swig_type_info *info = SWIG_TypeQueryModule(module, module, clss->base_names[i]);
if (info) clss->bases[i] = (swig_lua_class *) info->clientdata;
@ -1917,8 +1880,7 @@ SWIGINTERN void SWIG_Lua_init_base_class(lua_State *L,swig_lua_class *clss)
#if defined(SWIG_LUA_SQUASH_BASES) && (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA)
/* Merges two tables */
SWIGINTERN void SWIG_Lua_merge_tables_by_index(lua_State *L, int target, int source)
{
SWIGINTERN void SWIG_Lua_merge_tables_by_index(lua_State *L, int target, int source) {
/* iterating */
lua_pushnil(L);
while (lua_next(L, source) != 0) {
@ -1933,8 +1895,7 @@ SWIGINTERN void SWIG_Lua_merge_tables_by_index(lua_State *L, int target, int sou
}
/* Merges two tables with given name. original - index of target metatable, base - index of source metatable */
SWIGINTERN void SWIG_Lua_merge_tables(lua_State *L, const char* name, int original, int base)
{
SWIGINTERN void SWIG_Lua_merge_tables(lua_State *L, const char *name, int original, int base) {
/* push original[name], then base[name] */
lua_pushstring(L, name);
lua_rawget(L, original);
@ -1948,8 +1909,7 @@ SWIGINTERN void SWIG_Lua_merge_tables(lua_State *L, const char* name, int origin
}
/* Function takes all symbols from base and adds it to derived class. It's just a helper. */
SWIGINTERN void SWIG_Lua_class_squash_base(lua_State *L, swig_lua_class *base_cls)
{
SWIGINTERN void SWIG_Lua_class_squash_base(lua_State *L, swig_lua_class *base_cls) {
/* There is one parameter - original, i.e. 'derived' class metatable */
assert(lua_istable(L, -1));
int original = lua_gettop(L);
@ -1962,12 +1922,10 @@ SWIGINTERN void SWIG_Lua_class_squash_base(lua_State *L, swig_lua_class *base_cl
}
/* Function squashes all symbols from 'clss' bases into itself */
SWIGINTERN void SWIG_Lua_class_squash_bases(lua_State *L, swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_class_squash_bases(lua_State *L, swig_lua_class *clss) {
int i;
SWIG_Lua_get_class_metatable(L, clss->fqname);
for(i=0;clss->base_names[i];i++)
{
for (i = 0; clss->base_names[i]; i++) {
if (clss->bases[i] == 0) /* Somehow it's not found. Skip it */
continue;
/* Thing is: all bases are already registered. Thus they have already executed
@ -1982,15 +1940,13 @@ SWIGINTERN void SWIG_Lua_class_squash_bases(lua_State *L, swig_lua_class *clss)
#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA) /* In elua this is useless */
/* helper add a variable to a registered class */
SWIGINTERN void SWIG_Lua_add_variable(lua_State *L,const char *name,lua_CFunction getFn,lua_CFunction setFn)
{
SWIGINTERN void SWIG_Lua_add_variable(lua_State *L, const char *name, lua_CFunction getFn, lua_CFunction setFn) {
assert(lua_istable(L, -1)); /* just in case */
SWIG_Lua_get_table(L, ".get"); /* find the .get table */
assert(lua_istable(L, -1)); /* just in case */
SWIG_Lua_add_function(L, name, getFn);
lua_pop(L, 1); /* tidy stack (remove table) */
if (setFn)
{
if (setFn) {
SWIG_Lua_get_table(L, ".set"); /* find the .set table */
assert(lua_istable(L, -1)); /* just in case */
SWIG_Lua_add_function(L, name, setFn);
@ -1999,14 +1955,12 @@ SWIGINTERN void SWIG_Lua_add_variable(lua_State *L,const char *name,lua_CFuncti
}
/* helper to recursively add class static details (static attributes, operations and constants) */
SWIGINTERN void SWIG_Lua_add_class_static_details(lua_State *L, swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_add_class_static_details(lua_State *L, swig_lua_class *clss) {
int i = 0;
/* The class namespace table must be on the top of the stack */
assert(lua_istable(L, -1));
/* call all the base classes first: we can then override these later: */
for(i=0;clss->bases[i];i++)
{
for (i = 0; clss->bases[i]; i++) {
SWIG_Lua_add_class_static_details(L, clss->bases[i]);
}
@ -2016,15 +1970,13 @@ SWIGINTERN void SWIG_Lua_add_class_static_details(lua_State *L, swig_lua_class *
SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss); /* forward declaration */
/* helper to recursively add class details (attributes & operations) */
SWIGINTERN void SWIG_Lua_add_class_instance_details(lua_State *L, swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_add_class_instance_details(lua_State *L, swig_lua_class *clss) {
int i;
size_t bases_count = 0;
/* Add bases to .bases table */
SWIG_Lua_get_table(L, ".bases");
assert(lua_istable(L, -1)); /* just in case */
for(i=0;clss->bases[i];i++)
{
for (i = 0; clss->bases[i]; i++) {
SWIG_Lua_get_class_metatable(L, clss->bases[i]->fqname);
/* Base class must be already registered */
assert(lua_istable(L, -1));
@ -2088,8 +2040,7 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L); /*forward declaration
* SWIG_Lua_resolve_metamethod
* */
SWIGINTERN int SWIG_Lua_do_resolve_metamethod(lua_State *L, const swig_lua_class *clss, int metamethod_name_idx,
int skip_check)
{
int skip_check) {
/* This function is called recursively */
int result = 0;
int i = 0;
@ -2110,8 +2061,7 @@ SWIGINTERN int SWIG_Lua_do_resolve_metamethod(lua_State *L, const swig_lua_class
}
/* Forwarding calls to bases */
for(i=0;clss->bases[i];i++)
{
for (i = 0; clss->bases[i]; i++) {
result = SWIG_Lua_do_resolve_metamethod(L, clss->bases[i], metamethod_name_idx, 0);
if (result)
break;
@ -2122,8 +2072,7 @@ SWIGINTERN int SWIG_Lua_do_resolve_metamethod(lua_State *L, const swig_lua_class
/* The proxy function for metamethod. All parameters are passed as cclosure. Searches for actual method
* and calls it */
SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L)
{
SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L) {
int numargs;
int metamethod_name_idx;
const swig_lua_class *clss;
@ -2159,8 +2108,7 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L)
* Returns 1 if successfully added, 0 if not added because no base class has it, -1
* if method is defined in the class metatable itself
*/
SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss, const int metatable_index)
{
SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss, const int metatable_index) {
int key_index;
int success = 0;
int i = 0;
@ -2180,8 +2128,7 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *
lua_pop(L, 1);
/* Iterating over immediate bases */
for(i=0;clss->bases[i];i++)
{
for (i = 0; clss->bases[i]; i++) {
const swig_lua_class *base = clss->bases[i];
SWIG_Lua_get_class_metatable(L, base->fqname);
lua_pushvalue(L, key_index);
@ -2207,8 +2154,7 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *
return success;
}
SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss) {
int metatable_index;
int metamethods_info_index;
int tostring_undefined;
@ -2264,8 +2210,7 @@ SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class
}
/* Register class static methods,attributes etc as well as constructor proxy */
SWIGINTERN void SWIG_Lua_class_register_static(lua_State *L, swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_class_register_static(lua_State *L, swig_lua_class *clss) {
const int SWIGUNUSED begin = lua_gettop(L);
lua_checkstack(L, 5); /* just in case */
assert(lua_istable(L, -1)); /* just in case */
@ -2279,8 +2224,7 @@ SWIGINTERN void SWIG_Lua_class_register_static(lua_State *L, swig_lua_class *cls
so you can do MyClass(...) as well as new_MyClass(...)
BUT only if a constructor is defined
(this overcomes the problem of pure virtual classes without constructors)*/
if (clss->constructor)
{
if (clss->constructor) {
lua_getmetatable(L, -1);
assert(lua_istable(L, -1)); /* just in case */
SWIG_Lua_add_function(L, "__call", clss->constructor);
@ -2298,8 +2242,7 @@ SWIGINTERN void SWIG_Lua_class_register_static(lua_State *L, swig_lua_class *cls
/* Performs the instance (non-static) class registration process. Metatable for class is created
* and added to the class registry.
*/
SWIGINTERN void SWIG_Lua_class_register_instance(lua_State *L,swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_class_register_instance(lua_State *L, swig_lua_class *clss) {
const int SWIGUNUSED begin = lua_gettop(L);
int i;
/* if name already there (class is already registered) then do nothing */
@ -2313,8 +2256,7 @@ SWIGINTERN void SWIG_Lua_class_register_instance(lua_State *L,swig_lua_class *c
}
lua_pop(L, 2); /* tidy stack */
/* Recursively initialize all bases */
for(i=0;clss->bases[i];i++)
{
for (i = 0; clss->bases[i]; i++) {
SWIG_Lua_class_register_instance(L, clss->bases[i]);
}
/* Again, get registry and push name */
@ -2328,8 +2270,7 @@ SWIGINTERN void SWIG_Lua_class_register_instance(lua_State *L,swig_lua_class *c
*/
{
int new_metatable_index = lua_absindex(L, -1);
for(i=0;clss->bases[i];i++)
{
for (i = 0; clss->bases[i]; i++) {
int base_metatable;
SWIG_Lua_get_class_metatable(L, clss->bases[i]->fqname);
base_metatable = lua_absindex(L, -1);
@ -2380,8 +2321,7 @@ SWIGINTERN void SWIG_Lua_class_register_instance(lua_State *L,swig_lua_class *c
assert(lua_gettop(L) == begin);
}
SWIGINTERN void SWIG_Lua_class_register(lua_State *L,swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_class_register(lua_State *L, swig_lua_class *clss) {
int SWIGUNUSED begin;
assert(lua_istable(L, -1)); /* This is a table (module or namespace) where classes will be added */
SWIG_Lua_class_register_instance(L, clss);
@ -2418,8 +2358,7 @@ SWIGINTERN void SWIG_Lua_class_register(lua_State *L,swig_lua_class *clss)
#endif /* SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_LUA */
#if (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUA) || (SWIG_LUA_TARGET == SWIG_LUA_FLAVOR_ELUAC)
SWIGINTERN void SWIG_Lua_elua_class_register_instance(lua_State *L, swig_lua_class *clss)
{
SWIGINTERN void SWIG_Lua_elua_class_register_instance(lua_State *L, swig_lua_class *clss) {
const int SWIGUNUSED begin = lua_gettop(L);
int i;
/* if name already there (class is already registered) then do nothing */
@ -2433,8 +2372,7 @@ SWIGINTERN void SWIG_Lua_elua_class_register_instance(lua_State *L, swig_lua_cla
}
lua_pop(L, 2); /* tidy stack */
/* Recursively initialize all bases */
for(i=0;clss->bases[i];i++)
{
for (i = 0; clss->bases[i]; i++) {
SWIG_Lua_elua_class_register_instance(L, clss->bases[i]);
}
/* Again, get registry and push name */
@ -2453,25 +2391,19 @@ SWIGINTERN void SWIG_Lua_elua_class_register_instance(lua_State *L, swig_lua_cla
* ----------------------------------------------------------------------------- */
/* helper to add metatable to new lua object */
SWIGINTERN void SWIG_Lua_AddMetatable(lua_State *L,swig_type_info *type)
{
if (type->clientdata) /* there is clientdata: so add the metatable */
{
SWIGINTERN void SWIG_Lua_AddMetatable(lua_State *L, swig_type_info *type) {
if (type->clientdata) { /* there is clientdata: so add the metatable */
SWIG_Lua_get_class_metatable(L, ((swig_lua_class *)(type->clientdata))->fqname);
if (lua_istable(L,-1))
{
if (lua_istable(L, -1)) {
lua_setmetatable(L, -2);
}
else
{
} else {
lua_pop(L, 1);
}
}
}
/* pushes a new object into the lua stack */
SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State *L,void *ptr,swig_type_info *type, int own)
{
SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State *L, void *ptr, swig_type_info *type, int own) {
swig_lua_userdata *usr;
if (!ptr) {
lua_pushnil(L);
@ -2488,31 +2420,25 @@ SWIGRUNTIME void SWIG_Lua_NewPointerObj(lua_State *L,void *ptr,swig_type_info *t
/* takes a object from the lua stack & converts it into an object of the correct type
(if possible) */
SWIGRUNTIME int SWIG_Lua_ConvertPtr(lua_State *L,int index,void **ptr,swig_type_info *type,int flags)
{
SWIGRUNTIME int SWIG_Lua_ConvertPtr(lua_State *L, int index, void **ptr, swig_type_info *type, int flags) {
swig_lua_userdata *usr;
swig_cast_info *cast;
/* special case: lua nil => NULL pointer */
if (lua_isnil(L,index))
{
if (lua_isnil(L, index)) {
*ptr = 0;
return (flags & SWIG_POINTER_NO_NULL) ? SWIG_NullReferenceError : SWIG_OK;
}
usr = (swig_lua_userdata *)lua_touserdata(L, index); /* get data */
if (usr)
{
if (flags & SWIG_POINTER_DISOWN) /* must disown the object */
{
if (usr) {
if (flags & SWIG_POINTER_DISOWN) { /* must disown the object */
usr->own = 0;
}
if (!type) /* special cast void*, no casting fn */
{
if (!type) { /* special cast void*, no casting fn */
*ptr = usr->ptr;
return SWIG_OK; /* ok */
}
cast = SWIG_TypeCheckStruct(usr->type, type); /* performs normal type checking */
if (cast)
{
if (cast) {
int newmemory = 0;
*ptr = SWIG_TypeCast(cast, usr->ptr, &newmemory);
assert(!newmemory); /* newmemory handling not yet implemented */
@ -2533,8 +2459,7 @@ SWIGRUNTIME void* SWIG_Lua_MustGetPtr(lua_State *L,int index,swig_type_info *typ
}
/* pushes a packed userdata. user for member fn pointers only */
SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State *L,void *ptr,size_t size,swig_type_info *type)
{
SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State *L, void *ptr, size_t size, swig_type_info *type) {
swig_lua_rawdata *raw;
assert(ptr); /* not acceptable to pass in a NULL value */
raw = (swig_lua_rawdata *)lua_newuserdata(L, sizeof(swig_lua_rawdata) - 1 + size); /* alloc data */
@ -2545,13 +2470,11 @@ SWIGRUNTIME void SWIG_Lua_NewPackedObj(lua_State *L,void *ptr,size_t size,swig_t
}
/* converts a packed userdata. user for member fn pointers only */
SWIGRUNTIME int SWIG_Lua_ConvertPacked(lua_State *L,int index,void *ptr,size_t size,swig_type_info *type)
{
SWIGRUNTIME int SWIG_Lua_ConvertPacked(lua_State *L, int index, void *ptr, size_t size, swig_type_info *type) {
swig_lua_rawdata *raw;
raw = (swig_lua_rawdata *)lua_touserdata(L, index); /* get data */
if (!raw) return SWIG_ERROR; /* error */
if (type==0 || type==raw->type) /* void* or identical type */
{
if (type == 0 || type == raw->type) { /* void* or identical type */
memcpy(ptr, raw->data, size); /* copy it */
return SWIG_OK; /* ok */
}
@ -2559,11 +2482,9 @@ SWIGRUNTIME int SWIG_Lua_ConvertPacked(lua_State *L,int index,void *ptr,size_t
}
/* a function to get the typestring of a piece of data */
SWIGRUNTIME const char *SWIG_Lua_typename(lua_State *L, int tp)
{
SWIGRUNTIME const char *SWIG_Lua_typename(lua_State *L, int tp) {
swig_lua_userdata *usr;
if (lua_isuserdata(L,tp))
{
if (lua_isuserdata(L, tp)) {
usr = (swig_lua_userdata *)lua_touserdata(L, tp); /* get data */
if (usr && usr->type && usr->type->str)
return usr->type->str;
@ -2573,8 +2494,7 @@ SWIGRUNTIME const char *SWIG_Lua_typename(lua_State *L, int tp)
}
/* lua callable function to get the userdata's type */
SWIGRUNTIME int SWIG_Lua_type(lua_State *L)
{
SWIGRUNTIME int SWIG_Lua_type(lua_State *L) {
lua_pushstring(L, SWIG_Lua_typename(L, 1));
return 1;
}
@ -2723,7 +2643,8 @@ static int _wrap_new_pm3__SWIG_0(lua_State* L) {
SWIG_check_num_args("pm3::pm3", 0, 0)
result = (pm3 *)new_pm3__SWIG_0();
SWIG_NewPointerObj(L,result,SWIGTYPE_p_pm3,1); SWIG_arg++;
SWIG_NewPointerObj(L, result, SWIGTYPE_p_pm3, 1);
SWIG_arg++;
return SWIG_arg;
if (0) SWIG_fail;
@ -2743,7 +2664,8 @@ static int _wrap_new_pm3__SWIG_1(lua_State* L) {
if (!SWIG_lua_isnilstring(L, 1)) SWIG_fail_arg("pm3::pm3", 1, "char *");
arg1 = (char *)lua_tostring(L, 1);
result = (pm3 *)new_pm3__SWIG_1(arg1);
SWIG_NewPointerObj(L,result,SWIGTYPE_p_pm3,1); SWIG_arg++;
SWIG_NewPointerObj(L, result, SWIGTYPE_p_pm3, 1);
SWIG_arg++;
return SWIG_arg;
if (0) SWIG_fail;
@ -2778,7 +2700,8 @@ static int _wrap_new_pm3(lua_State* L) {
" Possible C/C++ prototypes are:\n"
" pm3::pm3()\n"
" pm3::pm3(char *)\n");
lua_error(L);return 0;
lua_error(L);
return 0;
}
@ -2798,7 +2721,8 @@ static int _wrap_pm3_console(lua_State* L) {
arg2 = (char *)lua_tostring(L, 2);
result = (int)pm3_console(arg1, arg2);
lua_pushnumber(L, (lua_Number) result); SWIG_arg++;
lua_pushnumber(L, (lua_Number) result);
SWIG_arg++;
return SWIG_arg;
if (0) SWIG_fail;
@ -2822,7 +2746,8 @@ static int _wrap_pm3_name_get(lua_State* L) {
}
result = (char *)pm3_name_get(arg1);
lua_pushstring(L,(const char *)result); SWIG_arg++;
lua_pushstring(L, (const char *)result);
SWIG_arg++;
return SWIG_arg;
if (0) SWIG_fail;
@ -3154,7 +3079,8 @@ SWIG_PropagateClientData(void) {
#ifdef __cplusplus
#if 0
{ /* c-mode */
{
/* c-mode */
#endif
}
#endif
@ -3251,8 +3177,7 @@ SWIGEXPORT int SWIG_init(lua_State* L) /* default Lua action */
const char *SWIG_LUACODE =
"";
void SWIG_init_user(lua_State* L)
{
void SWIG_init_user(lua_State *L) {
/* exec Lua code if applicable */
SWIG_Lua_dostring(L, SWIG_LUACODE);
}

View file

@ -516,8 +516,7 @@ SWIG_TypePrettyName(const swig_type_info *type) {
for (s = type->str; *s; s++)
if (*s == '|') last_name = s + 1;
return last_name;
}
else
} else
return type->name;
}
@ -782,8 +781,7 @@ SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
* so please call SWIG_Python_str_DelForPy3(x) to free the space.
*/
SWIGINTERN char *
SWIG_Python_str_AsChar(PyObject *str)
{
SWIG_Python_str_AsChar(PyObject *str) {
#if PY_VERSION_HEX >= 0x03000000
char *newstr = 0;
str = PyUnicode_AsUTF8String(str);
@ -809,8 +807,7 @@ SWIG_Python_str_AsChar(PyObject *str)
SWIGINTERN PyObject *
SWIG_Python_str_FromChar(const char *c)
{
SWIG_Python_str_FromChar(const char *c) {
#if PY_VERSION_HEX >= 0x03000000
return PyUnicode_FromString(c);
#else
@ -882,8 +879,7 @@ SWIG_Python_ErrorType(int code) {
SWIGRUNTIME void
SWIG_Python_AddErrorMsg(const char* mesg)
{
SWIG_Python_AddErrorMsg(const char *mesg) {
PyObject *type = 0;
PyObject *value = 0;
PyObject *traceback = 0;
@ -908,8 +904,7 @@ SWIG_Python_AddErrorMsg(const char* mesg)
}
SWIGRUNTIME int
SWIG_Python_TypeErrorOccurred(PyObject *obj)
{
SWIG_Python_TypeErrorOccurred(PyObject *obj) {
PyObject *error;
if (obj)
return 0;
@ -918,8 +913,7 @@ SWIG_Python_TypeErrorOccurred(PyObject *obj)
}
SWIGRUNTIME void
SWIG_Python_RaiseOrModifyTypeError(const char *message)
{
SWIG_Python_RaiseOrModifyTypeError(const char *message) {
if (SWIG_Python_TypeErrorOccurred(NULL)) {
/* Use existing TypeError to preserve stacktrace and enhance with given message */
PyObject *newvalue;
@ -1174,8 +1168,7 @@ SWIG_Python_AppendOutput(PyObject* result, PyObject* obj) {
/* Unpack the argument tuple */
SWIGINTERN Py_ssize_t
SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs)
{
SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, PyObject **objs) {
if (!args) {
if (!min && !max) {
return 1;
@ -1252,8 +1245,7 @@ extern "C" {
/* The python void return value */
SWIGRUNTIMEINLINE PyObject *
SWIG_Py_Void(void)
{
SWIG_Py_Void(void) {
PyObject *none = Py_None;
Py_INCREF(none);
return none;
@ -1272,8 +1264,7 @@ typedef struct {
} SwigPyClientData;
SWIGRUNTIMEINLINE int
SWIG_Python_CheckImplicit(swig_type_info *ty)
{
SWIG_Python_CheckImplicit(swig_type_info *ty) {
SwigPyClientData *data = (SwigPyClientData *)ty->clientdata;
int fail = data ? data->implicitconv : 0;
if (fail)
@ -1290,8 +1281,7 @@ SWIG_Python_ExceptionType(swig_type_info *desc) {
SWIGRUNTIME SwigPyClientData *
SwigPyClientData_New(PyObject* obj)
{
SwigPyClientData_New(PyObject *obj) {
if (!obj) {
return 0;
} else {
@ -1359,8 +1349,7 @@ typedef struct {
#ifdef SWIGPYTHON_BUILTIN
SWIGRUNTIME PyObject *
SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args))
{
SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) {
SwigPyObject *sobj = (SwigPyObject *)v;
if (!sobj->dict)
@ -1373,14 +1362,12 @@ SwigPyObject_get___dict__(PyObject *v, PyObject *SWIGUNUSEDPARM(args))
#endif
SWIGRUNTIME PyObject *
SwigPyObject_long(SwigPyObject *v)
{
SwigPyObject_long(SwigPyObject *v) {
return PyLong_FromVoidPtr(v->ptr);
}
SWIGRUNTIME PyObject *
SwigPyObject_format(const char* fmt, SwigPyObject *v)
{
SwigPyObject_format(const char *fmt, SwigPyObject *v) {
PyObject *res = NULL;
PyObject *args = PyTuple_New(1);
if (args) {
@ -1401,20 +1388,17 @@ SwigPyObject_format(const char* fmt, SwigPyObject *v)
}
SWIGRUNTIME PyObject *
SwigPyObject_oct(SwigPyObject *v)
{
SwigPyObject_oct(SwigPyObject *v) {
return SwigPyObject_format("%o", v);
}
SWIGRUNTIME PyObject *
SwigPyObject_hex(SwigPyObject *v)
{
SwigPyObject_hex(SwigPyObject *v) {
return SwigPyObject_format("%x", v);
}
SWIGRUNTIME PyObject *
SwigPyObject_repr(SwigPyObject *v)
{
SwigPyObject_repr(SwigPyObject *v) {
const char *name = SWIG_TypePrettyName(v->ty);
PyObject *repr = SWIG_Python_str_FromFormat("<Swig Object of type '%s' at %p>", (name ? name : "unknown"), (void *)v);
if (v->next) {
@ -1434,14 +1418,12 @@ SwigPyObject_repr(SwigPyObject *v)
/* We need a version taking two PyObject* parameters so it's a valid
* PyCFunction to use in swigobject_methods[]. */
SWIGRUNTIME PyObject *
SwigPyObject_repr2(PyObject *v, PyObject *SWIGUNUSEDPARM(args))
{
SwigPyObject_repr2(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) {
return SwigPyObject_repr((SwigPyObject *)v);
}
SWIGRUNTIME int
SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w)
{
SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w) {
void *i = v->ptr;
void *j = w->ptr;
return (i < j) ? -1 : ((i > j) ? 1 : 0);
@ -1449,8 +1431,7 @@ SwigPyObject_compare(SwigPyObject *v, SwigPyObject *w)
/* Added for Python 3.x, would it also be useful for Python 2.x? */
SWIGRUNTIME PyObject *
SwigPyObject_richcompare(SwigPyObject *v, SwigPyObject *w, int op)
{
SwigPyObject_richcompare(SwigPyObject *v, SwigPyObject *w, int op) {
PyObject *res;
if (op != Py_EQ && op != Py_NE) {
Py_INCREF(Py_NotImplemented);
@ -1499,8 +1480,7 @@ SWIGRUNTIME PyObject *
SwigPyObject_New(void *ptr, swig_type_info *ty, int own);
SWIGRUNTIME void
SwigPyObject_dealloc(PyObject *v)
{
SwigPyObject_dealloc(PyObject *v) {
SwigPyObject *sobj = (SwigPyObject *) v;
PyObject *next = sobj->next;
if (sobj->own == SWIG_POINTER_OWN) {
@ -1550,8 +1530,7 @@ SwigPyObject_dealloc(PyObject *v)
}
SWIGRUNTIME PyObject *
SwigPyObject_append(PyObject* v, PyObject* next)
{
SwigPyObject_append(PyObject *v, PyObject *next) {
SwigPyObject *sobj = (SwigPyObject *) v;
if (!SwigPyObject_Check(next)) {
PyErr_SetString(PyExc_TypeError, "Attempt to append a non SwigPyObject");
@ -1563,8 +1542,7 @@ SwigPyObject_append(PyObject* v, PyObject* next)
}
SWIGRUNTIME PyObject *
SwigPyObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
{
SwigPyObject_next(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) {
SwigPyObject *sobj = (SwigPyObject *) v;
if (sobj->next) {
Py_INCREF(sobj->next);
@ -1575,24 +1553,21 @@ SwigPyObject_next(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
}
SWIGINTERN PyObject *
SwigPyObject_disown(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
{
SwigPyObject_disown(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) {
SwigPyObject *sobj = (SwigPyObject *)v;
sobj->own = 0;
return SWIG_Py_Void();
}
SWIGINTERN PyObject *
SwigPyObject_acquire(PyObject* v, PyObject *SWIGUNUSEDPARM(args))
{
SwigPyObject_acquire(PyObject *v, PyObject *SWIGUNUSEDPARM(args)) {
SwigPyObject *sobj = (SwigPyObject *)v;
sobj->own = SWIG_POINTER_OWN;
return SWIG_Py_Void();
}
SWIGINTERN PyObject *
SwigPyObject_own(PyObject *v, PyObject *args)
{
SwigPyObject_own(PyObject *v, PyObject *args) {
PyObject *val = 0;
if (!PyArg_UnpackTuple(args, "own", 0, 1, &val)) {
return NULL;
@ -1749,8 +1724,7 @@ SwigPyObject_TypeOnce(void) {
}
SWIGRUNTIME PyObject *
SwigPyObject_New(void *ptr, swig_type_info *ty, int own)
{
SwigPyObject_New(void *ptr, swig_type_info *ty, int own) {
SwigPyObject *sobj = PyObject_NEW(SwigPyObject, SwigPyObject_type());
if (sobj) {
sobj->ptr = ptr;
@ -1773,8 +1747,7 @@ typedef struct {
} SwigPyPacked;
SWIGRUNTIME PyObject *
SwigPyPacked_repr(SwigPyPacked *v)
{
SwigPyPacked_repr(SwigPyPacked *v) {
char result[SWIG_BUFFER_SIZE];
if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) {
return SWIG_Python_str_FromFormat("<Swig Packed at %s%s>", result, v->ty->name);
@ -1784,8 +1757,7 @@ SwigPyPacked_repr(SwigPyPacked *v)
}
SWIGRUNTIME PyObject *
SwigPyPacked_str(SwigPyPacked *v)
{
SwigPyPacked_str(SwigPyPacked *v) {
char result[SWIG_BUFFER_SIZE];
if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) {
return SWIG_Python_str_FromFormat("%s%s", result, v->ty->name);
@ -1795,8 +1767,7 @@ SwigPyPacked_str(SwigPyPacked *v)
}
SWIGRUNTIME int
SwigPyPacked_compare(SwigPyPacked *v, SwigPyPacked *w)
{
SwigPyPacked_compare(SwigPyPacked *v, SwigPyPacked *w) {
size_t i = v->size;
size_t j = w->size;
int s = (i < j) ? -1 : ((i > j) ? 1 : 0);
@ -1818,8 +1789,7 @@ SwigPyPacked_Check(PyObject *op) {
}
SWIGRUNTIME void
SwigPyPacked_dealloc(PyObject *v)
{
SwigPyPacked_dealloc(PyObject *v) {
if (SwigPyPacked_Check(v)) {
SwigPyPacked *sobj = (SwigPyPacked *) v;
free(sobj->pack);
@ -1910,8 +1880,7 @@ SwigPyPacked_TypeOnce(void) {
}
SWIGRUNTIME PyObject *
SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty)
{
SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty) {
SwigPyPacked *sobj = PyObject_NEW(SwigPyPacked, SwigPyPacked_type());
if (sobj) {
void *pack = malloc(size);
@ -1929,8 +1898,7 @@ SwigPyPacked_New(void *ptr, size_t size, swig_type_info *ty)
}
SWIGRUNTIME swig_type_info *
SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size)
{
SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size) {
if (SwigPyPacked_Check(obj)) {
SwigPyPacked *sobj = (SwigPyPacked *)obj;
if (sobj->size != size) return 0;
@ -1948,8 +1916,7 @@ SwigPyPacked_UnpackData(PyObject *obj, void *ptr, size_t size)
static PyObject *Swig_This_global = NULL;
SWIGRUNTIME PyObject *
SWIG_This(void)
{
SWIG_This(void) {
if (Swig_This_global == NULL)
Swig_This_global = SWIG_Python_str_FromChar("this");
return Swig_This_global;
@ -1963,8 +1930,7 @@ SWIG_This(void)
#endif
SWIGRUNTIME SwigPyObject *
SWIG_Python_GetSwigThis(PyObject *pyobj)
{
SWIG_Python_GetSwigThis(PyObject *pyobj) {
PyObject *obj;
if (SwigPyObject_Check(pyobj))
@ -2201,8 +2167,7 @@ SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *t
*/
SWIGRUNTIME PyObject *
SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
{
SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this) {
PyObject *inst = 0;
PyObject *newraw = data->newraw;
if (newraw) {
@ -2251,8 +2216,7 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
}
SWIGRUNTIME void
SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this)
{
SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) {
PyObject *dict;
#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
PyObject **dictptr = _PyObject_GetDictPtr(inst);
@ -2376,8 +2340,7 @@ SWIG_Python_GetModule(void *SWIGUNUSEDPARM(clientdata)) {
}
SWIGRUNTIME void
SWIG_Python_DestroyModule(PyObject *obj)
{
SWIG_Python_DestroyModule(PyObject *obj) {
swig_module_info *swig_module = (swig_module_info *) PyCapsule_GetPointer(obj, SWIGPY_CAPSULE_NAME);
swig_type_info **types = swig_module->types;
size_t i;
@ -2417,8 +2380,7 @@ SWIG_Python_TypeCache(void) {
}
SWIGRUNTIME swig_type_info *
SWIG_Python_TypeQuery(const char *type)
{
SWIG_Python_TypeQuery(const char *type) {
PyObject *cache = SWIG_Python_TypeCache();
PyObject *key = SWIG_Python_str_FromChar(type);
PyObject *obj = PyDict_GetItem(cache, key);
@ -2446,8 +2408,7 @@ SWIG_Python_TypeQuery(const char *type)
#define SWIG_MustGetPtr(p, type, argnum, flags) SWIG_Python_MustGetPtr(p, type, argnum, flags)
SWIGRUNTIME int
SWIG_Python_AddErrMesg(const char* mesg, int infront)
{
SWIG_Python_AddErrMesg(const char *mesg, int infront) {
if (PyErr_Occurred()) {
PyObject *type = 0;
PyObject *value = 0;
@ -2474,8 +2435,7 @@ SWIG_Python_AddErrMesg(const char* mesg, int infront)
}
SWIGRUNTIME int
SWIG_Python_ArgFail(int argnum)
{
SWIG_Python_ArgFail(int argnum) {
if (PyErr_Occurred()) {
/* add information about failing argument */
char mesg[256];
@ -2487,16 +2447,14 @@ SWIG_Python_ArgFail(int argnum)
}
SWIGRUNTIMEINLINE const char *
SwigPyObject_GetDesc(PyObject *self)
{
SwigPyObject_GetDesc(PyObject *self) {
SwigPyObject *v = (SwigPyObject *)self;
swig_type_info *ty = v ? v->ty : 0;
return ty ? ty->str : "";
}
SWIGRUNTIME void
SWIG_Python_TypeError(const char *type, PyObject *obj)
{
SWIG_Python_TypeError(const char *type, PyObject *obj) {
if (type) {
#if defined(SWIG_COBJECT_TYPES)
if (obj && SwigPyObject_Check(obj)) {
@ -2679,8 +2637,7 @@ SWIGINTERN pm3 *new_pm3__SWIG_0(void){
}
SWIGINTERN swig_type_info *
SWIG_pchar_descriptor(void)
{
SWIG_pchar_descriptor(void) {
static int init = 0;
static swig_type_info *info = 0;
if (!init) {
@ -2692,8 +2649,7 @@ SWIG_pchar_descriptor(void)
SWIGINTERN int
SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
{
SWIG_AsCharPtrAndSize(PyObject *obj, char **cptr, size_t *psize, int *alloc) {
#if PY_VERSION_HEX>=0x03000000
#if defined(SWIG_PYTHON_STRICT_BYTE_CHAR)
if (PyBytes_Check(obj))
@ -2704,7 +2660,8 @@ SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
if (PyString_Check(obj))
#endif
{
char *cstr; Py_ssize_t len;
char *cstr;
Py_ssize_t len;
int ret = SWIG_OK;
#if PY_VERSION_HEX>=0x03000000
#if !defined(SWIG_PYTHON_STRICT_BYTE_CHAR)
@ -2760,7 +2717,8 @@ SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
#endif
#if PY_VERSION_HEX<0x03000000
if (PyUnicode_Check(obj)) {
char *cstr; Py_ssize_t len;
char *cstr;
Py_ssize_t len;
if (!alloc && cptr) {
return SWIG_RuntimeError;
}
@ -2816,15 +2774,13 @@ SWIGINTERN void delete_pm3(pm3 *self){
}
SWIGINTERNINLINE PyObject *
SWIG_From_int (int value)
{
SWIG_From_int(int value) {
return PyInt_FromLong((long) value);
}
SWIGINTERNINLINE PyObject *
SWIG_FromCharPtrAndSize(const char* carray, size_t size)
{
SWIG_FromCharPtrAndSize(const char *carray, size_t size) {
if (carray) {
if (size > INT_MAX) {
swig_type_info *pchar_descriptor = SWIG_pchar_descriptor();
@ -2848,8 +2804,7 @@ SWIG_FromCharPtrAndSize(const char* carray, size_t size)
SWIGINTERNINLINE PyObject *
SWIG_FromCharPtr(const char *cptr)
{
SWIG_FromCharPtr(const char *cptr) {
return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0));
}
@ -3049,7 +3004,8 @@ static swig_cast_info *swig_cast_initial[] = {
/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
static swig_const_info swig_const_table[] = {
{0, 0, 0, 0.0, 0, 0}};
{0, 0, 0, 0.0, 0, 0}
};
#ifdef __cplusplus
}

View file

@ -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();
}

View file

@ -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

View file

@ -56,6 +56,7 @@ void print_blocks(uint32_t *data, size_t len);
int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen);
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);

View file

@ -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
ifneq (,$(STANDALONE_PLATFORM_DEFS))
PLATFORM_DEFS+=$(STANDALONE_PLATFORM_DEFS)
endif
$(info $(findstring WITH_STANDALONE_*,$(PLATFORM_DEFS)))
# Misc
# Misc (LCD support)
ifneq (,$(findstring WITH_LCD,$(PLATFORM_DEFS)))
#PLATFORM_DEFS += -DWITH_LCD
endif
# Add flags dependencies :

694
doc/T5577_Guide.md Normal file
View file

@ -0,0 +1,694 @@
# T5577 Introduction Guide
### Based on RRG proxmark3 fork.
### Ver.1 8 Sep 2019
| Contents |
| ----------------------------------------------------------------------------------- |
| [Part 1](#part-1) |
| [Introduction](#introduction) |
| [T5577 Overview](#t5577-overview) |
| [What data is on my T5577](#what-data-is-on-my-t5577) |
| [Read and Write Blocks of Data](#read-and-write-blocks-of-data) |
| [Exercise 1](#exercise-1) |
| [How do I use a password](#how-do-i-use-a-password) |
| |
| [Part 2 Configuration Blocks](#part-2-configuration-blocks) |
| [The configuration Block Block 0 Page 0](#the-configuration-block-block-0-page-0) |
| [Exercise 2](#exercise-2) |
| [The configuration Block Block 3 Page 1](#the-configuration-block-block-3-page-1) |
# Part 1
## Introduction
The T5577 is a generic LF (Low Frequency) RFID card the is used in the
125 Khz frequency space. It is a good card to use to learn about RFID and
learn how to use the proxmark3.
It is highly recommend that when learning about RFID that learning how
to read the data sheets be near the top of the list. It can be very hard
as the data sheet will hold the information you need, but you dont yet
know what it means. As such, I will attempt to point to sections of the
data sheet and would highly advise that you look at the data sheet as
you go. Overtime the data sheet may change, as a result things may not
always be reference correctly.
As at writing this guide, the data sheet can be found at :
<http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-9187-RFID-ATA5577C_Datasheet.pdf>
This guide is not a how do I clone document. It is meant to help people
learn how to use the T5577 and in the process learn about rfid and the
proxmark3.
Throughout this guide I will give examples. It is recommended that you
try these as we go. To do so, have a blank T5577 card that you can use
for this purpose.
## T5577 Overview
The T5577 is a chip that can hold data and a configuration (Section
4.12).
In the diagram below, all white blocks can hold data. Some can be used
for a second purpose, such as the password and traceability data.
The Configuration Data and Analog front end option setup will tell
the chip how to behave.
![](./t55xx_mem_map.png)
## What data is on my T5577
Lets have a look and see what a card might look in the proxmark3
software. Since we can change the configuration of how the T5577 will
output data, the proxmark3 software need to work out how to interpreted
the data it receives, we do this with the following command.
It should be noted that the T5577 has many clones. As such the default
setup of each card may be different. If the tractability data is
present, then this will vary based on the batch of cards.
Always run this command when you place a t5577 on the proxmark3. In all
examples shown, it will be assumed you have run the detect command.
```
[usb] pm3 --> lf t55xx detect
```
You should see a results simular to the following:
```
Chip Type : T55x7
Modulation : ASK
Bit Rate : 2 - RF/32
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x000880E0
Downlink Mode : default/fixed bit length
```
Now that the proxmark3 has detected a T55x7 chip, and found some
information about it, we should be able to see all the data on the chip.
```
[usb] pm3 --> lf t55xx dump
```
Your results should look similar to the following:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] Reading Page 1:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
```
I will cover the meaning of this data as we go, but for now, lets keep
it simple.
## Read and Write Blocks of Data
The basic function of using the proxmark3 with rfid cards is to read and
write data. This reading and writing must be done in the correct way
needed for the chip (and its configuration). Lucky for us, the
developers have done a great job and gave us commands. What we need to
know is that with the T5577 data is read/written one complete block at a
time. Each block holds 32 bits of data (hence the binary output shown)
Since we know that the card has data and configuration blocks, lets say
away from those while we learn how to read and write. I suggest you
follow along and perform each command and check the results as we go.
We can store our own data in blocks 1-7 (remember that block 7 will be
needed if we want to set a password).
(Dont forget to run the detect command: lf t55xx detect, and ensure you
can see the card)
1) Check what is stored in block 1. The following command can be read
as, run a low frequency (lf) command for the T55xx chip (t55xx) and
read block (b) number 1.
```
[usb] pm3 --> lf t55xx read b 1
```
result:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
```
Note: Depending on the history of your card your data may vary, but
should match the dump data.
2) Write some new data into block 1 on the card.
We use the d option to supply the data 12345678
```
[usb] pm3 --> lf t55xx write b 1 d 12345678
```
result:
```
[=] Writing page 0 block: 01 data: 0x12345678
```
3) Now, lets check if the data was written.
```
[usb] pm3 --> lf t55xx read b 1
```
result:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 01 | 12345678 | 00010010001101000101011001111000 | .4Vx
```
4) The data is written in Hexadecimal. A single hex digit holds 4 bits
of data. So to store 32 bits in a block we need to supply 8 hex
digits (8 \* 4 = 32). If you are familiar with hex and binary do a
little bit of home work to learn. The following is a quick start.
| Hex | Binary | Decimal |
|:---:|:------:|:-------:|
| 0 | 0000 | 0 |
| 1 | 0001 | 1 |
| 2 | 0010 | 2 |
| 3 | 0011 | 3 |
| 4 | 0100 | 4 |
| 5 | 0101 | 5 |
| 6 | 0110 | 6 |
| 7 | 0111 | 7 |
| 8 | 1000 | 8 |
| 9 | 1001 | 9 |
| A | 1010 | 10 |
| B | 1011 | 11 |
| C | 1100 | 12 |
| D | 1101 | 13 |
| E | 1110 | 14 |
| F | 1111 | 15 |
To use all the bits we supply the data in Hex format and it will
always be 8 hex digits.
Lets try and write 89ABCDEF
```
[usb] pm3 --> lf t55xx write b 1 d 89abcdef
```
result:
```
[=] Writing page 0 block: 01 data: 0x89ABCDEF
```
and check
```
[usb] pm3 --> lf t55xx read b 1
```
result:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 01 | 89ABCDEF | 10001001101010111100110111101111 | ....
```
### Exercise 1
Using the read and write commands you have learnt see if you can make
the lf t55 dump command show the following data for blocks 1-7 (Page 0).
Do not write to block 0 or try and change the data on page 1.
```
[usb] pm3 --> lf t55 dump
```
result:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | 89ABCDEF | 10001001101010111100110111101111 | ....
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] Reading Page 1:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
```
Practice reading and writing to blocks 1 to 7 until you are happy you
can do it and get the results you wanted (i.e. the data you want stored
is written to the block you want it stored in).
## How do I use a password
This can be a little tricky for beginners.
***If you forget your password you will lose access to your card***.
To tell the T5577 to use a password we have to change the data in the
configuration block (0). To help learn this and make it as simple as I
can, please read and follow exactly. If your results DONT match 100% as
required, please do not proceed.
1) Lets start with a known card state and wipe the card. This will set
a default configuration to block 0 and set all the data in blocks
1-7 to a default.
```
[usb] pm3 --> lf t55xx wipe
```
Result:
```
[=] Begin wiping T55x7 tag
[=] Default configation block 000880E0
[=] Writing page 0 block: 00 data: 0x000880E0
[=] Writing page 0 block: 01 data: 0x00000000
[=] Writing page 0 block: 02 data: 0x00000000
[=] Writing page 0 block: 03 data: 0x00000000
[=] Writing page 0 block: 04 data: 0x00000000
[=] Writing page 0 block: 05 data: 0x00000000
[=] Writing page 0 block: 06 data: 0x00000000
[=] Writing page 0 block: 07 data: 0x00000000
```
2) Check that the card is in the desired state.
```
[usb] pm3 --> lf t55xx detect
```
result:
```
Chip Type : T55x7
Modulation : ASK
Bit Rate : 2 - RF/32
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x000880E0
Downlink Mode : default/fixed bit length
```
If block 0 does not hold the hex data **0x00088040 resolve this
first before proceeding.**
3) Set the password we want to use. For this example lets use the
password : ***12345678***
The password is saved in block 7 of page 0.
```
[usb] pm3 --> lf t55xx write b 7 d 12345678
```
result:
```
[=] Writing page 0 block: 07 data: 0x12345678
```
4) Lets verify both block 0 and block 7
```
[usb] pm3 --> lf t55xx dump
```
result:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 07 | 12345678 | 00010010001101000101011001111000 | .4Vx
[+] Reading Page 1:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
```
***Important : If block 0 and block 7 dont match exactly, do not continue.***
5) Now we have a known configuration block and a known password of
12345678, we are ready to tell the card to use the password.
To do this the datasheet tells us we need to set the 28<sup>th</sup>
bit “PWD”. Check your datasheet and see the entire table (remember
the data sheet is your friend).
![](./t55xx_block0.png)
We will cover other things in the configuration later. But the key
note here is we ONLY want to change bit 28 and nothing else.
Current Block 0 : ***00088040***
New Block 0 : ***00088050***
To understand what happened to get from 00088040 to 00088050 we need
to look at the binary data.
While this can be confusing it is important to understand this as we
do more advanced things.
Bit Location (28)
000000000011111111112222222 ***2*** 2233
123456789012345678901234567 ***8*** 9012
| Hex Data | Binary Data |
|:--------:|:---------------------------------------|
| 00088040 | 000000000000100010000000010***0***0000 |
| 00088050 | 000000000000100010000000010***1***0000 |
See how in the above we change the bit in location 28 from a 0 to 1
0 = No Password, 1 = Use Password
Note how we did NOT change any other part of the configuration, only bit 28.
To re-cap.
We put the card into a known configuration Block 0 : 00088040
We set the a known password Block 7 : 12345678
We altered the config data to tell the T5577 to use the password.
New Block 0 : 00088050
If you have completed all steps and have the exact same results, we are
ready to apply the new configuration.
```
[usb] pm3 --> lf t55xx write b 0 d 00088050
```
result:
```
[=] Writing page 0 block: 00 data: 0x00088050
```
6) Lets check what happens when the password is set.
```
[usb] pm3 --> lf t55 detect
```
result:
```
[!] Could not detect modulation automatically. Try setting it manually with 'lf t55xx config'
```
Note how the lf t55 detect no longer seems to work\!
In this case, this is due to needing a password to read/write to the
card.
Lets try again, but this time supply the password. We use the option
p followed by the password.
```
[usb] pm3 --> lf t55 detect p 12345678
```
result:
```
Chip Type : T55x7
Modulation : ASK
Bit Rate : 2 - RF/32
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x00088050
Downlink Mode : default/fixed bit length
```
7) Write a block of data with a password
```
[usb] pm3 --> lf t55xx write b 1 d 1234abcd p 12345678
```
result:
```
[=] Writing page 0 block: 01 data: 0x1234ABCD pwd: 0x12345678
```
8) Read a block of data with a password
***\*\*\*\* Important \*\*\*\****
***Reading a T5577 block with a password when a password is not
enabled can result in locking the card. Please only use read with a
password when it is known that a password is in use.***
The proxmark3 has a safety check\!
```
[usb] pm3 --> lf t55xx read b 1 p 12345678
```
result:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[!] Safety check: Could not detect if PWD bit is set in config block. Exits.
```
Note that the proxmark3 did not read the block, the safty kicked in
and wants us to confirm by supply the override option o.
Lets try again with the o option as we know the password is set.
```
[usb] pm3 --> lf t55xx read b 1 p 12345678 o
```
result:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[=] Safety check overridden - proceeding despite risk
[+] 01 | 1234ABCD | 00010010001101001010101111001101 | .4..
```
This time, we can see the data we wrote to block 1 is found with the
read command.
9) Remove the need to supply the password.
To do this we need to clear Bit 28 (set to 0) in the config. We have
this from above.
Remember if we dont know the config and write this config to the
card, it will over write all other settings. This can recoved the
card, but will lose any settings you may want. So its a good idea
to read the config, and set bit 28 to 0, rather than just overwrite
the config and change the way the card works.
In our examples we know what it should be : 00088040
```
[usb] pm3 --> lf t55xx write b 0 d 00088040 p 12345678
```
result:
```
[=] Writing page 0 block: 00 data: 0x00088040 pwd: 0x12345678
```
Now check if we can detect without a password
```
[usb] pm3 --> lf t55 detect
```
result:
```
Chip Type : T55x7
Modulation : ASK
Bit Rate : 2 - RF/32
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x00088040
Downlink Mode : default/fixed bit length
```
Yes we can and we can see Block 0 is the correct config 00088040
# Part 2 Configuration Blocks
One of the things a lot of people have trouble with or miss, is that the
T5577 has two different and separate communications protocols, each with
their own sub-protocols.
- Card to Reader
- Reader to Card
In Card to Reader, the T5577 will encode its data using the settings
from Block 0 in Page 0. It will use this in both default read mode
(where is sends out the blocks from 1 to x on power up), as well as when
it responds to commands.
In the Read To Card, the T5577 will encode the data using the settings
from Block 3 Page 1. If the command is not encoded correctly it will
ignore the command and revert back to default read mode.
## The configuration Block Block 0 Page 0
For this configuration the settings chosen will be for the purpose of
the card when used in production. E.G. If you want the card to act like
an EM4100, then we need to choose the settings that work like the
EM4100; same goes for others like HID. I am not going to cover these
here, rather use an example. Others have collect these and posted on the
forum.
To get started lets look back at the tech sheet.
![](./t55xx_clock0_cfg.png)
The non-password protect EM4100 could have a block 0 config of 00148040,
so what does it mean.
To decode this config, we need to look at it in binary
00000000000101001000000001000000. Note that it had 32 bits and the
config block 0 is 32 bits. Now we can break it down.
| Bits | Purpose | Value |
| ------- | ---------------------- | ----------- |
| 0000 | Master Key | Nothing Set |
| 0000000 | Not used in Basic Mode | |
| 101 | Data Bit Rate | RF/64 |
| 0 | Not used in Basic Mode | |
| 01000 | Modulation | Manchester |
| 00 | PSKCF | RF/2 |
| 0 | AOR | Not Set |
| 0 | Not used in Basic Mode | |
| 010 | Max Block | 2 |
| 0 | Password | Not Set |
| 0 | ST Sequence Terminator | Not Set |
| 00 | Not used in Basic Mode | |
| 0 | Init Delay | Not Set |
To get more detail on each item, read through the data sheet.
Lets see how the proxmark3 can help us learn. We will assume the T5577
is in the same state from Part 1, where we can write to the card with no
password set (if not, review and get you card back to this state).
1) Lets turn you T5577 into an EM4100 with ID 1122334455
```
[usb] pm3 --> lf em 410x_write 1122334455 1
```
result:
```
[+] Writing T55x7 tag with UID 0x1122334455 (clock rate: 64)
#db# Started writing T55x7 tag ...
#db# Clock rate: 64
#db# Tag T55x7 written with 0xff8c65298c94a940
```
2) Check this has work.
```
[usb] pm3 --> lf search
```
result:
```
[=] NOTE: some demods output possible binary
[=] if it finds something that looks like a tag
[=] False Positives ARE possible
[=]
[=] Checking for known tags...
[+] EM410x pattern found
EM TAG ID : 1122334455
Possible de-scramble patterns
Unique TAG ID : 8844CC22AA
HoneyWell IdentKey {
DEZ 8 : 03359829
DEZ 10 : 0573785173
DEZ 5.5 : 08755.17493
DEZ 3.5A : 017.17493
DEZ 3.5B : 034.17493
DEZ 3.5C : 051.17493
DEZ 14/IK2 : 00073588229205
DEZ 15/IK3 : 000585269781162
DEZ 20/ZK : 08080404121202021010
}
Other : 17493_051_03359829
Pattern Paxton : 289899093 [0x11478255]
Pattern 1 : 5931804 [0x5A831C]
Pattern Sebury : 17493 51 3359829 [0x4455 0x33 0x334455]
[+] Valid EM410x ID found!
[+] Chipset detection : T55xx found
[+] Try `lf t55xx` commands
```
Looks good.
3) Now lest see what the T5577 detect and info shows
```
[usb] pm3 --> lf t55 detect
```
result:
```
[usb] pm3 --> lf t55 detect
Chip Type : T55x7
Modulation : ASK
Bit Rate : 5 - RF/64
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x00148040
Downlink Mode : default/fixed bit length
```
```
[usb] pm3 --> lf t55xx info
```
result:
```
-- T55x7 Configuration & Tag Information --------------------
-------------------------------------------------------------
Safer key : 0
reserved : 0
Data bit rate : 5 - RF/64
eXtended mode : No
Modulation : 8 - Manchester
PSK clock frequency : 0 - RF/2
AOR - Answer on Request : No
OTP - One Time Pad : No
Max block : 2
Password mode : No
Sequence Terminator : No
Fast Write : No
Inverse data : No
POR-Delay : No
-------------------------------------------------------------
Raw Data - Page 0
Block 0 : 0x00148040 00000000000101001000000001000000
Config block match : EM unique, Paxton
-------------------------------------------------------------
```
We can see that the info gave us more information and confirmed what
we decoded by hand. But remember, the detect is still needed so the
proxmark3 software will know how to decode the info block.
We can see that for the EM4100 emulation we have two blocks of data
(Max Block = 2). On the T5577 these will be Blocks 1 and 2.
## Exercise 2
Using the skills form part 1, see if you can view the data in blocks 1 and 2.
Note: the EM4100 ID of 1122334455 is encoded, so dont expect to see
those bytes as such. To learn how to do that, you guessed it, find the
datasheet and review.
At this point we have an EM4100 card. If we wanted to password protect
it, we can follow the password section and update the config from
00148040 to 00148050.
***Important : Dont forget to set a valid password in block 7 and remember it.***
## The configuration Block Block 3 Page 1

View file

@ -62,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
View 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

View file

@ -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
|------- |------- |-----------

View file

@ -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.

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
doc/t55xx_clock0_cfg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
doc/t55xx_mem_map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View file

@ -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
View file

@ -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

View file

@ -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