mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 05:13:46 -07:00
commit
f1ed632a1c
47 changed files with 1265 additions and 571 deletions
55
.vscode/launch.json
vendored
Normal file
55
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
"program": "${cwd}/client/proxmark3",
|
||||
//"processId": "${command:pickProcess}",
|
||||
"processId": "${input:ProcessID}",
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},{
|
||||
"name": "(gdb) Build & Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${cwd}/client/proxmark3",
|
||||
"args": ["/dev/ttyACM0"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "client: Debug: clean & make",
|
||||
"miDebuggerPath": "/usr/bin/gdb"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
// Using Extension "Tasks Shell Input" https://marketplace.visualstudio.com/items?itemName=augustocdias.tasks-shell-input
|
||||
"id": "ProcessID",
|
||||
"type": "command",
|
||||
"command": "shellCommand.execute",
|
||||
"args": {
|
||||
"command": "pgrep -n proxmark3",
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
72
.vscode/tasks.json
vendored
72
.vscode/tasks.json
vendored
|
@ -4,24 +4,82 @@
|
|||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"label": "all: Make & run",
|
||||
"type": "shell",
|
||||
"command": "make clean && make all -j$(nproc --all)",
|
||||
"command": "make -j && ./pm3",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "flash fullimage",
|
||||
"label": "choose: Make",
|
||||
"type": "shell",
|
||||
"command": "sudo ./pm3-flash-fullimage",
|
||||
"command": "make ${input:componentType} -j",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": "build",
|
||||
},
|
||||
{
|
||||
"label": "client: Debug: make",
|
||||
"type": "shell",
|
||||
"command": "make client -j DEBUG=1",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": "build",
|
||||
},
|
||||
{
|
||||
"label": "client: Debug: clean & make",
|
||||
"type": "shell",
|
||||
"command": "make client/clean && make client -j DEBUG=1",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": "build",
|
||||
},
|
||||
{
|
||||
"label": "fullimage: Make & Flash",
|
||||
"type": "shell",
|
||||
"command": "make fullimage && ./pm3-flash-fullimage",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "FLASH BOOTROM",
|
||||
"label": "BOOTROM: Make & Flash",
|
||||
"type": "shell",
|
||||
"command": "sudo ./pm3-flash-bootrom",
|
||||
"command": "make bootrom && ./pm3-flash-bootrom",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Run client",
|
||||
"type": "shell",
|
||||
"command": "./pm3",
|
||||
"problemMatcher": []
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"type": "pickString",
|
||||
"id": "componentType",
|
||||
"description": "What Makefile target do you want to execute?",
|
||||
"options": [
|
||||
"all",
|
||||
"client",
|
||||
"bootrom",
|
||||
"fullimage",
|
||||
"recovery",
|
||||
"clean",
|
||||
"install",
|
||||
"uninstall",
|
||||
"style",
|
||||
"miscchecks",
|
||||
"check",
|
||||
],
|
||||
"default": "all"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -27,6 +27,9 @@ LD = g++
|
|||
SH = sh
|
||||
BASH = bash
|
||||
PERL = perl
|
||||
CCC =foo
|
||||
CC_VERSION = $(shell $(CC) -dumpversion 2>/dev/null|sed 's/\..*//')
|
||||
CC_VERSION := $(or $(strip $(CC_VERSION)),0)
|
||||
|
||||
PATHSEP=/
|
||||
PREFIX ?= /usr/local
|
||||
|
@ -48,9 +51,15 @@ else
|
|||
RANLIB= ranlib
|
||||
endif
|
||||
|
||||
DEFCXXFLAGS = -Wall -Werror -O3 -pipe
|
||||
DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe
|
||||
DEFLDFLAGS =
|
||||
ifeq ($(DEBUG),1)
|
||||
DEFCXXFLAGS = -g -O0 -pipe
|
||||
DEFCFLAGS = -g -O0 -fstrict-aliasing -pipe
|
||||
DEFLDFLAGS =
|
||||
else
|
||||
DEFCXXFLAGS = -Wall -Werror -O3 -pipe
|
||||
DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe
|
||||
DEFLDFLAGS =
|
||||
endif
|
||||
# Next ones are activated only if SANITIZE=1
|
||||
ifeq ($(SANITIZE),1)
|
||||
DEFCFLAGS += -g -fsanitize=address -fno-omit-frame-pointer
|
||||
|
@ -62,7 +71,11 @@ DEFCFLAGS += -Wbad-function-cast -Wredundant-decls -Wmissing-prototypes -Wchar-s
|
|||
# Some more warnings we need first to eliminate, so temporarely tolerated:
|
||||
DEFCFLAGS += -Wcast-align -Wno-error=cast-align
|
||||
DEFCFLAGS += -Wswitch-enum -Wno-error=switch-enum
|
||||
|
||||
# GCC 10 has issues with false positives on stringop-overflow, let's disable them for now (cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335)
|
||||
# beware these flags didn't exist for GCC < 7
|
||||
ifeq ($(shell expr $(CC_VERSION) \>= 10), 1)
|
||||
DEFCFLAGS += -Wno-stringop-overflow -Wno-error=stringop-overflow
|
||||
endif
|
||||
ifeq ($(platform),Darwin)
|
||||
# their readline has strict-prototype issues
|
||||
DEFCFLAGS += -Wno-strict-prototypes
|
||||
|
|
|
@ -978,6 +978,15 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
EM4xLogin(payload->password);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X_BF: {
|
||||
struct p {
|
||||
uint32_t start_pwd;
|
||||
uint32_t n;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
EM4xBruteforce(payload->start_pwd, payload->n);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X_READWORD: {
|
||||
struct p {
|
||||
uint32_t password;
|
||||
|
@ -1250,7 +1259,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443A_ANTIFUZZ: {
|
||||
iso14443a_antifuzz(packet->oldarg[0]);
|
||||
struct p {
|
||||
uint8_t flag;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
iso14443a_antifuzz(payload->flag);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_EPA_COLLECT_NONCE: {
|
||||
|
@ -1520,13 +1533,13 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_SIMULATE: {
|
||||
/*
|
||||
struct p {
|
||||
uint8_t reader[4];
|
||||
uint8_t mac[4];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
*/
|
||||
/*
|
||||
struct p {
|
||||
uint8_t reader[4];
|
||||
uint8_t mac[4];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
*/
|
||||
|
||||
SimulateIClass(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
||||
break;
|
||||
|
@ -1562,7 +1575,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_RESTORE: {
|
||||
iClass_Restore( (iclass_restore_req_t *)packet->data.asBytes);
|
||||
iClass_Restore((iclass_restore_req_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -1604,7 +1617,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_SMART_SETCLOCK: {
|
||||
SmartCardSetClock(packet->oldarg[0]);
|
||||
struct p {
|
||||
uint32_t new_clk;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
SmartCardSetClock(payload->new_clk);
|
||||
break;
|
||||
}
|
||||
case CMD_SMART_RAW: {
|
||||
|
|
|
@ -889,18 +889,18 @@ static int write(uint8_t word[4], uint8_t address) {
|
|||
return PM3_ETEAROFF;
|
||||
} else {
|
||||
|
||||
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
|
||||
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
|
||||
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
|
||||
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
|
||||
|
||||
// look for ACK sequence
|
||||
if (check_ack(false)) {
|
||||
// look for ACK sequence
|
||||
if (check_ack(false)) {
|
||||
|
||||
// now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time)
|
||||
// for saving data and should return with ACK
|
||||
if (check_ack(false))
|
||||
return PM3_SUCCESS;
|
||||
// now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time)
|
||||
// for saving data and should return with ACK
|
||||
if (check_ack(false))
|
||||
return PM3_SUCCESS;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
28
armsrc/i2c.c
28
armsrc/i2c.c
|
@ -47,12 +47,6 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
|
|||
#define I2C_DELAY_2CLK I2CSpinDelayClk(2)
|
||||
#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x))
|
||||
|
||||
#define I2C_DELAY_100us I2CSpinDelayClk( 100 / 3)
|
||||
#define I2C_DELAY_600us I2CSpinDelayClk( 600 / 3)
|
||||
#define I2C_DELAY_10ms I2CSpinDelayClk( 10 * 1000 / 3 )
|
||||
#define I2C_DELAY_30ms I2CSpinDelayClk( 30 * 1000 / 3 )
|
||||
#define I2C_DELAY_100ms I2CSpinDelayClk( 100 * 1000 / 3)
|
||||
|
||||
#define ISO7618_MAX_FRAME 255
|
||||
|
||||
// try i2c bus recovery at 100kHz = 5us high, 5us low
|
||||
|
@ -134,11 +128,11 @@ void I2C_Reset_EnterMainProgram(void) {
|
|||
StartTicks();
|
||||
I2C_init();
|
||||
I2C_SetResetStatus(0, 0, 0);
|
||||
I2C_DELAY_30ms;
|
||||
WaitMS(30);
|
||||
I2C_SetResetStatus(1, 0, 0);
|
||||
I2C_DELAY_30ms;
|
||||
WaitMS(30);
|
||||
I2C_SetResetStatus(1, 1, 1);
|
||||
I2C_DELAY_10ms;
|
||||
WaitMS(10);
|
||||
}
|
||||
|
||||
// Reset the SIM_Adapter, then enter the bootloader program
|
||||
|
@ -147,9 +141,9 @@ void I2C_Reset_EnterBootloader(void) {
|
|||
StartTicks();
|
||||
I2C_init();
|
||||
I2C_SetResetStatus(0, 1, 1);
|
||||
I2C_DELAY_100ms;
|
||||
WaitMS(100);
|
||||
I2C_SetResetStatus(1, 1, 1);
|
||||
I2C_DELAY_10ms;
|
||||
WaitMS(10);
|
||||
}
|
||||
|
||||
// Wait for the clock to go High.
|
||||
|
@ -193,7 +187,7 @@ static bool WaitSCL_L_timeout(void) {
|
|||
if (!SCL_read)
|
||||
return true;
|
||||
|
||||
I2C_DELAY_100us;
|
||||
WaitMS(1);
|
||||
}
|
||||
return (delay == 0);
|
||||
}
|
||||
|
@ -440,8 +434,7 @@ int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d
|
|||
|
||||
// extra wait 500us (514us measured)
|
||||
// 200us (xx measured)
|
||||
// WaitUS(600);
|
||||
I2C_DELAY_600us;
|
||||
WaitUS(600);
|
||||
|
||||
bool bBreak = true;
|
||||
uint16_t readcount = 0;
|
||||
|
@ -811,8 +804,7 @@ void SmartCardUpgrade(uint64_t arg0) {
|
|||
}
|
||||
|
||||
// writing takes time.
|
||||
// WaitMS(50);
|
||||
I2C_DELAY_100ms;
|
||||
WaitMS(100);
|
||||
|
||||
// read
|
||||
res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
|
||||
|
@ -844,12 +836,10 @@ void SmartCardSetClock(uint64_t arg0) {
|
|||
LED_D_ON();
|
||||
set_tracing(true);
|
||||
I2C_Reset_EnterMainProgram();
|
||||
|
||||
// Send SIM CLC
|
||||
// start [C0 05 xx] stop
|
||||
I2C_WriteByte(arg0, I2C_DEVICE_CMD_SIM_CLC, I2C_DEVICE_ADDRESS_MAIN);
|
||||
|
||||
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
|
||||
reply_ng(CMD_SMART_SETCLOCK, PM3_SUCCESS, NULL, 0);
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
}
|
||||
|
|
|
@ -1443,7 +1443,7 @@ void ReaderIClass(uint8_t flags) {
|
|||
// with 0xFF:s in block 3 and 4.
|
||||
|
||||
LED_B_ON();
|
||||
reply_mix(CMD_ACK, result_status, 0, 0, (uint8_t*)&hdr, sizeof(hdr));
|
||||
reply_mix(CMD_ACK, result_status, 0, 0, (uint8_t *)&hdr, sizeof(hdr));
|
||||
|
||||
//Send back to client, but don't bother if we already sent this -
|
||||
// only useful if looping in arm (not try_once && not abort_after_read)
|
||||
|
@ -1489,7 +1489,7 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint
|
|||
|
||||
memcpy(ccnr, hdr->epurse, sizeof(hdr->epurse));
|
||||
|
||||
if ( payload->use_replay) {
|
||||
if (payload->use_replay) {
|
||||
|
||||
memcpy(pmac, payload->key + 4, 4);
|
||||
memcpy(cmd_check + 1, payload->key, 8);
|
||||
|
@ -1872,11 +1872,11 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
iclass_send_as_reader(write, sizeof(write), &start_time, &eof_time);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
res = false;
|
||||
switch_off();
|
||||
if (payload->req.send_reply)
|
||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
|
||||
return;
|
||||
res = false;
|
||||
switch_off();
|
||||
if (payload->req.send_reply)
|
||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
|
||||
return;
|
||||
} else {
|
||||
|
||||
if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time) == 10) {
|
||||
|
|
|
@ -2390,7 +2390,7 @@ void iso14443a_antifuzz(uint32_t flags) {
|
|||
}
|
||||
}
|
||||
|
||||
reply_old(CMD_ACK, 1, 0, 0, 0, 0);
|
||||
reply_ng(CMD_HF_ISO14443A_ANTIFUZZ, PM3_SUCCESS, NULL, 0);
|
||||
switch_off();
|
||||
BigBuf_free_keep_EM();
|
||||
}
|
||||
|
|
|
@ -1869,7 +1869,7 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
|
|||
}
|
||||
|
||||
if (recv) {
|
||||
recvlen = MIN(recvlen,ISO15693_MAX_RESPONSE_LENGTH);
|
||||
recvlen = MIN(recvlen, ISO15693_MAX_RESPONSE_LENGTH);
|
||||
reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen);
|
||||
} else {
|
||||
reply_mix(CMD_ACK, 1, 0, 0, NULL, 0);
|
||||
|
|
|
@ -2467,7 +2467,7 @@ static uint8_t Prepare_Data(uint16_t data_low, uint16_t data_hi) {
|
|||
// Requires: forwarLink_data filled with valid bits (1 bit per byte)
|
||||
// fwd_bit_count set with number of bits to be sent
|
||||
//====================================================================
|
||||
static void SendForward(uint8_t fwd_bit_count) {
|
||||
static void SendForward(uint8_t fwd_bit_count, bool fast) {
|
||||
|
||||
// iceman, 21.3us increments for the USclock verification.
|
||||
// 55FC * 8us == 440us / 21.3 === 20.65 steps. could be too short. Go for 56FC instead
|
||||
|
@ -2480,9 +2480,10 @@ static void SendForward(uint8_t fwd_bit_count) {
|
|||
fwd_write_ptr = forwardLink_data;
|
||||
fwd_bit_sz = fwd_bit_count;
|
||||
|
||||
// Set up FPGA, 125kHz or 95 divisor
|
||||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||
|
||||
if (! fast) {
|
||||
// Set up FPGA, 125kHz or 95 divisor
|
||||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||
}
|
||||
// force 1st mod pulse (start gap must be longer for 4305)
|
||||
fwd_bit_sz--; //prepare next bit modulation
|
||||
fwd_write_ptr++;
|
||||
|
@ -2490,13 +2491,13 @@ static void SendForward(uint8_t fwd_bit_count) {
|
|||
TurnReadLF_off(EM_START_GAP);
|
||||
TurnReadLFOn(18 * 8);
|
||||
|
||||
// now start writting with bitbanging the antenna. (each bit should be 32*8 total length)
|
||||
// now start writing with bitbanging the antenna. (each bit should be 32*8 total length)
|
||||
while (fwd_bit_sz-- > 0) { //prepare next bit modulation
|
||||
if (((*fwd_write_ptr++) & 1) == 1) {
|
||||
WaitUS(32 * 8);
|
||||
} else {
|
||||
TurnReadLF_off(23 * 8);
|
||||
TurnReadLFOn((32 - 23) * 8);
|
||||
TurnReadLFOn(18 * 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2505,13 +2506,60 @@ static void EM4xLoginEx(uint32_t pwd) {
|
|||
forward_ptr = forwardLink_data;
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN);
|
||||
len += Prepare_Data(pwd & 0xFFFF, pwd >> 16);
|
||||
SendForward(len);
|
||||
SendForward(len, false);
|
||||
//WaitUS(20); // no wait for login command.
|
||||
// should receive
|
||||
// 0000 1010 ok
|
||||
// 0000 0001 fail
|
||||
}
|
||||
|
||||
void EM4xBruteforce(uint32_t start_pwd, uint32_t n) {
|
||||
// With current timing, 18.6 ms per test = 53.8 pwds/s
|
||||
reply_ng(CMD_LF_EM4X_BF, PM3_SUCCESS, NULL, 0);
|
||||
StartTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
WaitMS(20);
|
||||
LED_A_ON();
|
||||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||
uint32_t candidates_found = 0;
|
||||
for (uint32_t pwd = start_pwd; pwd < 0xFFFFFFFF; pwd++) {
|
||||
if (((pwd - start_pwd) & 0x3F) == 0x00) {
|
||||
WDT_HIT();
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
Dbprintf("EM4x05 Bruteforce Interrupted");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Report progress every 256 attempts
|
||||
if (((pwd - start_pwd) & 0xFF) == 0x00) {
|
||||
Dbprintf("Trying: %06Xxx", pwd >> 8);
|
||||
}
|
||||
clear_trace();
|
||||
|
||||
forward_ptr = forwardLink_data;
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN);
|
||||
len += Prepare_Data(pwd & 0xFFFF, pwd >> 16);
|
||||
SendForward(len, true);
|
||||
|
||||
WaitUS(400);
|
||||
DoPartialAcquisition(0, false, 350, 1000);
|
||||
uint8_t *mem = BigBuf_get_addr();
|
||||
if (mem[334] < 128) {
|
||||
candidates_found++;
|
||||
Dbprintf("Password candidate: " _GREEN_("%08X"), pwd);
|
||||
if ((n != 0) && (candidates_found == n)) {
|
||||
Dbprintf("EM4x05 Bruteforce Stopped. %i candidate%s found", candidates_found, candidates_found > 1 ? "s" : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Beware: if smaller, tag might not have time to be back in listening state yet
|
||||
WaitMS(1);
|
||||
}
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
void EM4xLogin(uint32_t pwd) {
|
||||
|
||||
StartTicks();
|
||||
|
@ -2558,7 +2606,7 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) {
|
|||
uint8_t len = Prepare_Cmd(FWD_CMD_READ);
|
||||
len += Prepare_Addr(addr);
|
||||
|
||||
SendForward(len);
|
||||
SendForward(len, false);
|
||||
|
||||
WaitUS(400);
|
||||
|
||||
|
@ -2594,7 +2642,7 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
|||
len += Prepare_Addr(addr);
|
||||
len += Prepare_Data(data & 0xFFFF, data >> 16);
|
||||
|
||||
SendForward(len);
|
||||
SendForward(len, false);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
StopTicks();
|
||||
|
@ -2636,7 +2684,7 @@ void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
|||
uint8_t len = Prepare_Cmd(FWD_CMD_PROTECT);
|
||||
len += Prepare_Data(data & 0xFFFF, data >> 16);
|
||||
|
||||
SendForward(len);
|
||||
SendForward(len, false);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
StopTicks();
|
||||
|
|
|
@ -57,6 +57,7 @@ void T55xxDangerousRawTest(uint8_t *data);
|
|||
void TurnReadLFOn(uint32_t delay);
|
||||
|
||||
void EM4xLogin(uint32_t pwd);
|
||||
void EM4xBruteforce(uint32_t start_pwd, uint32_t n);
|
||||
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd);
|
||||
|
|
|
@ -2752,15 +2752,15 @@ void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
|
|||
|
||||
// Send MFU counter increase cmd
|
||||
uint8_t cmd[] = {
|
||||
MIFARE_ULEV1_INCR_CNT,
|
||||
counter,
|
||||
0, // lsb
|
||||
0,
|
||||
0, // msb
|
||||
0, // rfu
|
||||
0,
|
||||
0,
|
||||
};
|
||||
MIFARE_ULEV1_INCR_CNT,
|
||||
counter,
|
||||
0, // lsb
|
||||
0,
|
||||
0, // msb
|
||||
0, // rfu
|
||||
0,
|
||||
0,
|
||||
};
|
||||
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||
|
||||
// anticollision / select card
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
# -DANDROID_NATIVE_API_LEVEL=android-19 \
|
||||
# -DSKIPBT=1 -DSKIPPYTHON=1 -DSKIPPTHREAD=1 ..
|
||||
|
||||
message(STATUS "CMake ${CMAKE_VERSION}")
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(proxmark3)
|
||||
SET (PM3_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
|
@ -496,20 +497,10 @@ if (NOT APPLE)
|
|||
set(ADDITIONAL_LNK ${ADDITIONAL_LNK} -Wl,--as-needed -latomic -Wl,--no-as-needed)
|
||||
endif (NOT APPLE)
|
||||
|
||||
|
||||
find_library(pm3rrg_rdv4_cliparser REQUIRED)
|
||||
find_library(pm3rrg_rdv4_tinycbor REQUIRED)
|
||||
find_library(pm3rrg_rdv4_lua REQUIRED)
|
||||
find_library(pm3rrg_rdv4_mbedtls REQUIRED)
|
||||
find_library(pm3rrg_rdv4_reveng REQUIRED)
|
||||
find_library(pm3rrg_rdv4_hardnested REQUIRED)
|
||||
|
||||
if (NOT JANSSON_FOUND)
|
||||
find_library(pm3rrg_rdv4_jansson REQUIRED)
|
||||
set(ADDITIONAL_LNK pm3rrg_rdv4_jansson ${ADDITIONAL_LNK})
|
||||
endif (NOT JANSSON_FOUND)
|
||||
if (NOT WHEREAMI_FOUND)
|
||||
find_library(pm3rrg_rdv4_whereami REQUIRED)
|
||||
set(ADDITIONAL_LNK pm3rrg_rdv4_whereami ${ADDITIONAL_LNK})
|
||||
endif (NOT WHEREAMI_FOUND)
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# version
|
||||
message(STATUS "CMake ${CMAKE_VERSION}")
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -fvisibility=hidden -w")
|
||||
|
@ -12,7 +13,6 @@ add_subdirectory(../deps deps)
|
|||
if (CMAKE_MAKE_PROGRAM MATCHES ".*ninja.*")
|
||||
set(BZIP2_INCLUDE_DIRS ${BZIP2_ROOT})
|
||||
set(BZIP2_LIBRARIES pm3rrg_rdv4_bzip2)
|
||||
find_library(pm3rrg_rdv4_bzip2 REQUIRED)
|
||||
elseif (UNIX) # Cross compile at Unix Makefile System.
|
||||
# bzip2 dep.
|
||||
include(ExternalProject)
|
||||
|
@ -190,15 +190,6 @@ target_include_directories(pm3rrg_rdv4 PRIVATE
|
|||
${PM3_ROOT}/common_fpga
|
||||
${PM3_ROOT}/client/src)
|
||||
|
||||
find_library(pm3rrg_rdv4_cliparser REQUIRED)
|
||||
find_library(pm3rrg_rdv4_jansson REQUIRED)
|
||||
find_library(pm3rrg_rdv4_tinycbor REQUIRED)
|
||||
find_library(pm3rrg_rdv4_lua REQUIRED)
|
||||
find_library(pm3rrg_rdv4_mbedtls REQUIRED)
|
||||
find_library(pm3rrg_rdv4_reveng REQUIRED)
|
||||
find_library(pm3rrg_rdv4_hardnested REQUIRED)
|
||||
find_library(pm3rrg_rdv4_whereami REQUIRED)
|
||||
|
||||
target_link_libraries(pm3rrg_rdv4
|
||||
${BZIP2_LIBRARIES}
|
||||
pm3rrg_rdv4_hardnested
|
||||
|
|
|
@ -14,7 +14,6 @@ add_library(pm3rrg_rdv4_amiibo STATIC
|
|||
if (NOT TARGET pm3rrg_rdv4_mbedtls)
|
||||
include(mbedtls.cmake)
|
||||
endif()
|
||||
find_library(pm3rrg_rdv4_mbedtls REQUIRED)
|
||||
target_link_libraries(pm3rrg_rdv4_amiibo PRIVATE
|
||||
m
|
||||
pm3rrg_rdv4_mbedtls)
|
||||
|
|
|
@ -3,6 +3,7 @@ add_library(pm3rrg_rdv4_cliparser STATIC
|
|||
cliparser/cliparser.c
|
||||
)
|
||||
|
||||
target_compile_definitions(pm3rrg_rdv4_cliparser PRIVATE _ISOC99_SOURCE)
|
||||
target_include_directories(pm3rrg_rdv4_cliparser PRIVATE
|
||||
../../common
|
||||
../../include
|
||||
|
|
|
@ -9,3 +9,12 @@ MYSRCS = \
|
|||
LIB_A = libcliparser.a
|
||||
|
||||
include ../../../Makefile.host
|
||||
|
||||
$(info PLATFORM $(platform))
|
||||
ifneq (,$(findstring MINGW,$(platform)))
|
||||
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
|
||||
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
|
||||
# FTR __USE_MINGW_ANSI_STDIO seems deprecated in Mingw32
|
||||
# but not Mingw64 https://fr.osdn.net/projects/mingw/lists/archive/users/2019-January/000199.html
|
||||
CFLAGS += -D_ISOC99_SOURCE
|
||||
endif
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
#include "cliparser.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <util.h> // Get color constants
|
||||
#include <ui.h> // get PrintAndLogEx
|
||||
#include <util.h> // Get color constants
|
||||
#include <ui.h> // get PrintAndLogEx
|
||||
#include <ctype.h> // tolower
|
||||
#include <inttypes.h> // PRIu64
|
||||
|
||||
#ifndef ARRAYLEN
|
||||
# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
@ -125,7 +127,6 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
enum ParserState {
|
||||
PS_FIRST,
|
||||
PS_ARGUMENT,
|
||||
|
@ -216,7 +217,7 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
return res;
|
||||
}
|
||||
|
||||
res = param_gethex_to_eol((char*)tmpstr, 0, data, maxdatalen, datalen);
|
||||
res = param_gethex_to_eol((char *)tmpstr, 0, data, maxdatalen, datalen);
|
||||
switch (res) {
|
||||
case 1:
|
||||
printf("Parameter error: Invalid HEX value\n");
|
||||
|
@ -244,7 +245,7 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
|
||||
int len = strlen(argstr->sval[i]);
|
||||
|
||||
if (len > ( (sizeof(tmpstr) / 2 ) - ibuf)) {
|
||||
if (len > ((sizeof(tmpstr) / 2) - ibuf)) {
|
||||
printf("Parameter error: string too long (%i chars), expect MAX %zu chars\n", len + ibuf, (sizeof(tmpstr) / 2));
|
||||
fflush(stdout);
|
||||
return 2;
|
||||
|
@ -272,4 +273,20 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def) {
|
||||
uint64_t rv = 0;
|
||||
uint8_t data[8];
|
||||
int datalen = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), &datalen);
|
||||
if (res == 0) {
|
||||
for (uint8_t i = 0; i < datalen; i++) {
|
||||
rv <<= 8;
|
||||
rv |= data[i];
|
||||
}
|
||||
} else {
|
||||
rv = def;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,4 +66,6 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
|||
|
||||
int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen);
|
||||
int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen);
|
||||
|
||||
uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def);
|
||||
#endif
|
||||
|
|
|
@ -1203,3 +1203,9 @@ FEE2A3FBC5B6
|
|||
# taurus avm
|
||||
#
|
||||
005078565703
|
||||
#
|
||||
# Ving?
|
||||
#
|
||||
0602721E8F06
|
||||
FC0B50AF8700
|
||||
F7BA51A9434E
|
|
@ -1338,7 +1338,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
|||
if (!res && datalen > 0)
|
||||
waitCmd(0, timeout);
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int waitCmd(uint8_t iSelect, uint32_t timeout) {
|
||||
|
@ -1398,16 +1398,20 @@ static int CmdHF14AAntiFuzz(const char *Cmd) {
|
|||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t arg0 = FLAG_4B_UID_IN_DATA;
|
||||
struct {
|
||||
uint8_t flag;
|
||||
} PACKED param;
|
||||
param.flag = FLAG_4B_UID_IN_DATA;
|
||||
|
||||
if (arg_get_lit(ctx, 2))
|
||||
arg0 = FLAG_7B_UID_IN_DATA;
|
||||
param.flag = FLAG_7B_UID_IN_DATA;
|
||||
if (arg_get_lit(ctx, 3))
|
||||
arg0 = FLAG_10B_UID_IN_DATA;
|
||||
param.flag = FLAG_10B_UID_IN_DATA;
|
||||
|
||||
CLIParserFree(ctx);
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443A_ANTIFUZZ, arg0, 0, 0, NULL, 0);
|
||||
return 0;
|
||||
SendCommandNG(CMD_HF_ISO14443A_ANTIFUZZ, (uint8_t*)¶m, sizeof(param));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14AChaining(const char *Cmd) {
|
||||
|
@ -1438,7 +1442,7 @@ static int CmdHF14AChaining(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", APDUInFramingEnable ? "enabled" : "disabled");
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void printTag(const char *tag) {
|
||||
|
@ -1681,10 +1685,16 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
}
|
||||
getTagLabel(card.uid[0], card.uid[1]);
|
||||
break;
|
||||
case 0x57: // Qualcomm
|
||||
case 0x46:
|
||||
if (memcmp(card.uid, "FSTN10m", 7) == 0) {
|
||||
isMifareClassic = false;
|
||||
printTag("Waveshare NFC-Powered e-Paper 1.54\" (please disregard MANUFACTURER mapping above)");
|
||||
}
|
||||
break;
|
||||
case 0x57:
|
||||
if (memcmp(card.uid, "WSDZ10m", 7) == 0) {
|
||||
isMifareClassic = false;
|
||||
printTag("Waveshare NFC-Powered e-Paper");
|
||||
printTag("Waveshare NFC-Powered e-Paper (please disregard MANUFACTURER mapping above)");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -734,7 +734,7 @@ static int CmdHF15Demod(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, " mask = %02x", mask);
|
||||
}
|
||||
|
||||
if ( k == 0 ) {
|
||||
if (k == 0) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -744,7 +744,7 @@ static int CmdHF15Demod(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " idx | data");
|
||||
PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------");
|
||||
if ( k / 16 > 0) {
|
||||
if (k / 16 > 0) {
|
||||
for (; i < k; i += 16) {
|
||||
PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, 16));
|
||||
}
|
||||
|
|
|
@ -427,52 +427,52 @@ static void fuse_config(const picopass_hdr *hdr) {
|
|||
|
||||
uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]);
|
||||
|
||||
PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t*)&hdr->conf, 8));
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "..................... App limit", hdr->conf.app_limit);
|
||||
PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8));
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "..................... app limit", hdr->conf.app_limit);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ Block write lock", hdr->conf.block_writelock);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... Chip", hdr->conf.chip_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... Mem", hdr->conf.mem_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " Fuses", hdr->conf.fuses);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses);
|
||||
|
||||
uint8_t fuses = hdr->conf.fuses;
|
||||
|
||||
PrintAndLogEx(INFO, " Fuses:");
|
||||
if (isset(fuses, FUSE_FPERS))
|
||||
PrintAndLogEx(SUCCESS, " mode..... " _GREEN_("Personalization (programmable)"));
|
||||
PrintAndLogEx(SUCCESS, " mode......... " _GREEN_("Personalization (programmable)"));
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, " mode..... " _YELLOW_("Application (locked)"));
|
||||
PrintAndLogEx(SUCCESS, " mode......... " _YELLOW_("Application (locked)"));
|
||||
|
||||
if (isset(fuses, FUSE_CODING1)) {
|
||||
PrintAndLogEx(SUCCESS, " coding.. RFU");
|
||||
PrintAndLogEx(SUCCESS, " coding...... RFU");
|
||||
} else {
|
||||
if (isset(fuses, FUSE_CODING0))
|
||||
PrintAndLogEx(SUCCESS, " coding... " _YELLOW_("ISO 14443-2 B / 15693"));
|
||||
PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-2 B / 15693"));
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, " coding... " _YELLOW_("ISO 14443-B only"));
|
||||
PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-B only"));
|
||||
}
|
||||
|
||||
uint8_t pagemap = get_pagemap(hdr);
|
||||
switch (pagemap) {
|
||||
case 0x0:
|
||||
PrintAndLogEx(INFO, " crypt.... No auth possible. Read only if RA is enabled");
|
||||
PrintAndLogEx(INFO, " crypt........ No auth possible. Read only if RA is enabled");
|
||||
break;
|
||||
case 0x1:
|
||||
PrintAndLogEx(SUCCESS, " crypt.... Non secured page");
|
||||
PrintAndLogEx(SUCCESS, " crypt........ Non secured page");
|
||||
break;
|
||||
case 0x2:
|
||||
PrintAndLogEx(INFO, " crypt.... Secured page, keys locked");
|
||||
PrintAndLogEx(INFO, " crypt........ Secured page, keys locked");
|
||||
break;
|
||||
case 0x03:
|
||||
PrintAndLogEx(SUCCESS, " crypt.... Secured page, " _GREEN_("keys not locked"));
|
||||
PrintAndLogEx(SUCCESS, " crypt........ Secured page, " _GREEN_("keys not locked"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset(fuses, FUSE_RA))
|
||||
PrintAndLogEx(SUCCESS, " RA....... Read access enabled (non-secure mode)");
|
||||
PrintAndLogEx(SUCCESS, " RA........... Read access enabled (non-secure mode)");
|
||||
else
|
||||
PrintAndLogEx(INFO, " RA....... Read access not enabled");
|
||||
PrintAndLogEx(INFO, " RA........... Read access not enabled");
|
||||
}
|
||||
|
||||
static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb) {
|
||||
|
@ -545,23 +545,23 @@ static void mem_app_config(const picopass_hdr *hdr) {
|
|||
PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit, app1_limit + 5, app1_limit + 5);
|
||||
PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit);
|
||||
|
||||
PrintAndLogEx(INFO, "------------------------ " _CYAN_("KeyAccess") " -------------------------");
|
||||
PrintAndLogEx(INFO, " Kd = Debit key (AA1), Kc = Credit key (AA2)");
|
||||
PrintAndLogEx(INFO, "------------------------- " _CYAN_("KeyAccess") " ------------------------");
|
||||
PrintAndLogEx(INFO, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *");
|
||||
uint8_t book = isset(mem, 0x20);
|
||||
if (book) {
|
||||
PrintAndLogEx(INFO, " Read A - Kd");
|
||||
PrintAndLogEx(INFO, " Read B - Kc");
|
||||
PrintAndLogEx(INFO, " Write A - Kd");
|
||||
PrintAndLogEx(INFO, " Write B - Kc");
|
||||
PrintAndLogEx(INFO, " Debit - Kd or Kc");
|
||||
PrintAndLogEx(INFO, " Credit - Kc");
|
||||
PrintAndLogEx(INFO, " Read A....... debit");
|
||||
PrintAndLogEx(INFO, " Read B....... credit");
|
||||
PrintAndLogEx(INFO, " Write A...... debit");
|
||||
PrintAndLogEx(INFO, " Write B...... credit");
|
||||
PrintAndLogEx(INFO, " Debit........ debit or credit");
|
||||
PrintAndLogEx(INFO, " Credit....... credit");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, " Read A - Kd or Kc");
|
||||
PrintAndLogEx(INFO, " Read B - Kd or Kc");
|
||||
PrintAndLogEx(INFO, " Write A - Kc");
|
||||
PrintAndLogEx(INFO, " Write B - Kc");
|
||||
PrintAndLogEx(INFO, " Debit - Kd or Kc");
|
||||
PrintAndLogEx(INFO, " Credit - Kc");
|
||||
PrintAndLogEx(INFO, " Read A....... debit or credit");
|
||||
PrintAndLogEx(INFO, " Read B....... debit or credit");
|
||||
PrintAndLogEx(INFO, " Write A...... credit");
|
||||
PrintAndLogEx(INFO, " Write B...... credit");
|
||||
PrintAndLogEx(INFO, " Debit........ debit or credit");
|
||||
PrintAndLogEx(INFO, " redit........ credit");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1882,13 +1882,13 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
|
|||
rawkey = true;
|
||||
cmdp++;
|
||||
break;
|
||||
/*
|
||||
case 'n':
|
||||
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode"));
|
||||
use_replay = true;
|
||||
cmdp++;
|
||||
break;
|
||||
*/
|
||||
/*
|
||||
case 'n':
|
||||
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode"));
|
||||
use_replay = true;
|
||||
cmdp++;
|
||||
break;
|
||||
*/
|
||||
case 'v':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
|
@ -1910,7 +1910,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
|
|||
if (errors || cmdp < 6) return usage_hf_iclass_writeblock();
|
||||
|
||||
int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, use_replay, verbose);
|
||||
switch(isok) {
|
||||
switch (isok) {
|
||||
case PM3_SUCCESS:
|
||||
PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno);
|
||||
break;
|
||||
|
@ -2043,22 +2043,22 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
|||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
if (bytes_read < ((endblock - startblock + 1) * 8 )) {
|
||||
if (bytes_read < ((endblock - startblock + 1) * 8)) {
|
||||
PrintAndLogEx(ERR, "file is smaller than your suggested block range ( " _RED_("0x%02x..0x%02x")" )",
|
||||
startblock, endblock
|
||||
);
|
||||
startblock, endblock
|
||||
);
|
||||
free(dump);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
iclass_restore_req_t *payload = calloc(1, payload_size);
|
||||
payload->req.use_raw = rawkey,
|
||||
payload->req.use_elite = elite,
|
||||
payload->req.use_credit_key = use_credit_key,
|
||||
payload->req.use_replay = false,
|
||||
payload->req.blockno = startblock,
|
||||
payload->req.send_reply = true,
|
||||
payload->req.do_auth = true,
|
||||
payload->req.use_raw = rawkey;
|
||||
payload->req.use_elite = elite;
|
||||
payload->req.use_credit_key = use_credit_key;
|
||||
payload->req.use_replay = false;
|
||||
payload->req.blockno = startblock;
|
||||
payload->req.send_reply = true;
|
||||
payload->req.do_auth = true;
|
||||
memcpy(payload->req.key, KEY, 8);
|
||||
|
||||
payload->item_cnt = (endblock - startblock + 1);
|
||||
|
@ -2070,7 +2070,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
|||
|
||||
for (uint8_t i = 0; i < payload->item_cnt; i++) {
|
||||
payload->blocks[i].blockno = startblock + i;
|
||||
memcpy(payload->blocks[i].data, dump + (startblock * 8) + (i * 8) , sizeof(payload->blocks[i].data));
|
||||
memcpy(payload->blocks[i].data, dump + (startblock * 8) + (i * 8), sizeof(payload->blocks[i].data));
|
||||
}
|
||||
|
||||
free(dump);
|
||||
|
@ -2979,7 +2979,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
// Get CSN / UID and CCNR
|
||||
// Get CSN / UID and CCNR
|
||||
PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR...");
|
||||
for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) {
|
||||
got_csn = select_only(CSN, CCNR, false);
|
||||
|
@ -3539,33 +3539,33 @@ int info_iclass(void) {
|
|||
picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)resp.data.asBytes;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " --------------------------");
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "--------------------- " _CYAN_("Tag Information") " ----------------------");
|
||||
PrintAndLogEx(INFO, "------------------------------------------------------------");
|
||||
|
||||
if (readStatus & FLAG_ICLASS_CSN) {
|
||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn)));
|
||||
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
|
||||
}
|
||||
|
||||
if (readStatus & FLAG_ICLASS_CONF) {
|
||||
PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
|
||||
PrintAndLogEx(SUCCESS, " Config: %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
|
||||
}
|
||||
|
||||
// page mapping. If fuse0|1 == 0x01, card is in non-secure mode, with CSN, CONF, AIA as top 3 blocks.
|
||||
// page9 in http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20iClass/DS%20Picopass%202KS%20V1-0.pdf
|
||||
uint8_t pagemap = get_pagemap(hdr);
|
||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
||||
PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area)));
|
||||
PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area)));
|
||||
} else {
|
||||
|
||||
if (readStatus & FLAG_ICLASS_CC) {
|
||||
PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
|
||||
PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
|
||||
PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
|
||||
PrintAndLogEx(SUCCESS, " Kd: %s debit key, hidden", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
|
||||
PrintAndLogEx(SUCCESS, " Kc: %s credit key, hidden", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
|
||||
|
||||
if (readStatus & FLAG_ICLASS_AIA) {
|
||||
PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
|
||||
PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3573,7 +3573,7 @@ int info_iclass(void) {
|
|||
print_picopass_info(hdr);
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "------ " _CYAN_("Fingerprint") " ------");
|
||||
PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------");
|
||||
|
||||
uint8_t aia[8];
|
||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE)
|
||||
|
@ -3588,18 +3588,17 @@ int info_iclass(void) {
|
|||
bool se_enabled = (memcmp(aia, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
|
||||
|
||||
if (isHidRange) {
|
||||
PrintAndLogEx(SUCCESS, "CSN is in HID range");
|
||||
PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("HID range"));
|
||||
if (legacy)
|
||||
PrintAndLogEx(SUCCESS, "Credential : " _GREEN_("iCLASS legacy"));
|
||||
PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS legacy"));
|
||||
if (se_enabled)
|
||||
PrintAndLogEx(SUCCESS, "Credential : " _GREEN_("iCLASS SE"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE"));
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, _YELLOW_("PicoPass")" (CSN is not in HID range)");
|
||||
PrintAndLogEx(SUCCESS, " CSN..-....... " _YELLOW_("outside HID range"));
|
||||
}
|
||||
|
||||
uint8_t cardtype = get_mem_config(hdr);
|
||||
PrintAndLogEx(SUCCESS, " Card type : " _GREEN_("%s"), card_types[cardtype]);
|
||||
PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]);
|
||||
}
|
||||
|
||||
DropField();
|
||||
|
|
|
@ -351,7 +351,7 @@ static void map8to1(uint8_t *colormap, uint16_t width, uint16_t height, uint8_t
|
|||
static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, uint8_t **black, uint8_t **red, char *filename, bool save_conversions) {
|
||||
BMP_HEADER *pbmpheader = (BMP_HEADER *)bmp;
|
||||
// check file is full color
|
||||
if (pbmpheader->bpp != 24) {
|
||||
if ((pbmpheader->bpp != 24) && (pbmpheader->bpp != 32)) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -400,6 +400,8 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui
|
|||
chanB[X + (height - Y - 1) * width] = bmp[offset++];
|
||||
chanG[X + (height - Y - 1) * width] = bmp[offset++];
|
||||
chanR[X + (height - Y - 1) * width] = bmp[offset++];
|
||||
if (pbmpheader->bpp == 32) // Skip Alpha chan
|
||||
offset++;
|
||||
}
|
||||
// Skip line padding
|
||||
offset += width % 4;
|
||||
|
@ -436,6 +438,8 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui
|
|||
bmp[offset++] = chanB[X + (height - Y - 1) * width] & 0xFF;
|
||||
bmp[offset++] = chanG[X + (height - Y - 1) * width] & 0xFF;
|
||||
bmp[offset++] = chanR[X + (height - Y - 1) * width] & 0xFF;
|
||||
if (pbmpheader->bpp == 32) // Fill Alpha chan
|
||||
bmp[offset++] = 0xFF;
|
||||
}
|
||||
// Skip line padding
|
||||
offset += width % 4;
|
||||
|
@ -500,6 +504,8 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui
|
|||
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
|
||||
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
|
||||
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
|
||||
if (pbmpheader->bpp == 32) // Fill Alpha chan
|
||||
bmp[offset++] = 0xFF;
|
||||
}
|
||||
// Skip line padding
|
||||
offset += width % 4;
|
||||
|
@ -536,7 +542,8 @@ static void read_black(uint32_t i, uint8_t *l, uint8_t model_nr, uint8_t *black)
|
|||
}
|
||||
}
|
||||
static void read_red(uint32_t i, uint8_t *l, uint8_t model_nr, uint8_t *red) {
|
||||
for (uint8_t j = 0; j < models[model_nr].len; j++) {
|
||||
// spurious warning with GCC10 (-Wstringop-overflow) when j is uint8_t, even if all len are < 128
|
||||
for (uint16_t j = 0; j < models[model_nr].len; j++) {
|
||||
if (model_nr == M1in54B) {
|
||||
//1.54B needs to flip the red picture data, other screens do not need to flip data
|
||||
l[3 + j] = ~red[i * models[model_nr].len + j];
|
||||
|
@ -693,11 +700,21 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if ((card.uidlen != 7) || (memcmp(card.uid, "WSDZ10m", 7) != 0)) {
|
||||
if ((card.uidlen != 7) || ((memcmp(card.uid, "FSTN10m", 7) != 0) && (memcmp(card.uid, "WSDZ10m", 7) != 0))) {
|
||||
PrintAndLogEx(WARNING, "Card doesn't look like Waveshare tag");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (((model_nr != M1in54B) && (memcmp(card.uid, "FSTN10m", 7) == 0))) {
|
||||
PrintAndLogEx(WARNING, "Card is a Waveshare tag 1.54\", not %s", models[model_nr].desc);
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (((model_nr == M1in54B) && (memcmp(card.uid, "FSTN10m", 7) != 0))) {
|
||||
PrintAndLogEx(WARNING, "Card is not a Waveshare tag 1.54\", check your model number");
|
||||
DropField();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
PrintAndLogEx(DEBUG, "model_nr = %d", model_nr);
|
||||
int ret;
|
||||
PrintAndLogEx(DEBUG, "Step0");
|
||||
|
@ -921,6 +938,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
msleep(200);
|
||||
}
|
||||
PrintAndLogEx(DEBUG, "Step11: Wait tag to be ready");
|
||||
PrintAndLogEx(INPLACE, "E-paper Reflashing, Waiting");
|
||||
if (model_nr == M2in13B || model_nr == M1in54B) { // Black, white and red screen refresh time is longer, wait first
|
||||
msleep(9000);
|
||||
} else if (model_nr == M7in5HD) {
|
||||
|
@ -950,7 +968,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
} else {
|
||||
fail_num++;
|
||||
PrintAndLogEx(INPLACE, "E-paper Reflashing, Waiting");
|
||||
msleep(100);
|
||||
msleep(400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1048,11 +1066,13 @@ static int CmdHF14AWSLoadBmp(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
} else if (depth == 32) {
|
||||
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported. Remove alpha channel.", depth);
|
||||
free(bmp);
|
||||
return PM3_ESOFT;
|
||||
PrintAndLogEx(DEBUG, "BMP file is a RGBA, we will ignore the Alpha channel");
|
||||
if (read_bmp_rgb(bmp, bytes_read, model_nr, &black, &red, filename, save_conversions) != PM3_SUCCESS) {
|
||||
free(bmp);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported. Must be 1 (BW) or 24 (RGB)", depth);
|
||||
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported. Must be 1 (BW), 24 (RGB) or 32 (RGBA)", depth);
|
||||
free(bmp);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
|
|
@ -792,18 +792,18 @@ void pm3_version(bool verbose, bool oneliner) {
|
|||
|
||||
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]");
|
||||
if (IfPm3Rdv4Fw() == false) {
|
||||
PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3OTHER"));
|
||||
PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("PM3OTHER"));
|
||||
if (IfPm3FpcUsartHost()) {
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", _GREEN_("present"));
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", _GREEN_("present"));
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3RDV4"));
|
||||
PrintAndLogEx(NORMAL, " external flash...................%s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " smartcard reader.................%s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("PM3RDV4"));
|
||||
PrintAndLogEx(NORMAL, " external flash............ %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " smartcard reader.......... %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
|
||||
}
|
||||
if (IfPm3FpcUsartDevFromUsb()) {
|
||||
PrintAndLogEx(NORMAL, " FPC USART for developer..........%s", _GREEN_("present"));
|
||||
PrintAndLogEx(NORMAL, " FPC USART for developer... %s", _GREEN_("present"));
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
|
|
@ -1348,7 +1348,7 @@ static bool CheckChipType(bool getDeviceData) {
|
|||
|
||||
//check for em4x05/em4x69 chips first
|
||||
uint32_t word = 0;
|
||||
if (EM4x05IsBlock0(&word)) {
|
||||
if (em4x05_isblock0(&word)) {
|
||||
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x05 / EM4x69"));
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05`") " commands");
|
||||
retval = true;
|
||||
|
|
|
@ -66,7 +66,7 @@ int demodDestron(bool verbose) {
|
|||
|
||||
uint8_t data[5] = {0};
|
||||
uint8_t parity_err = 0;
|
||||
for (int i=0; i < sizeof(data); i++) {
|
||||
for (int i = 0; i < sizeof(data); i++) {
|
||||
data[i] = bytebits_to_byte(bits + i * 8, 8);
|
||||
parity_err += oddparity8(data[i]);
|
||||
data[i] &= 0x7F;
|
||||
|
@ -113,11 +113,11 @@ static int CmdDestronClone(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t data_ex[12 + 24] = {0}; // ManchesterEncode need extra room
|
||||
for (int i=0; i < datalen; i++) {
|
||||
for (int i = 0; i < datalen; i++) {
|
||||
data_ex[i + 1] = ~data [i] | (evenparity8(data[i]) << 7);
|
||||
}
|
||||
for (int i=0; i < 3; i++) {
|
||||
blocks[i+1] = manchesterEncode2Bytes((data_ex[i*2]<<8)+data_ex[i*2+1]);
|
||||
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;
|
||||
|
|
|
@ -646,6 +646,8 @@ static command_t CommandTable[] = {
|
|||
{"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"},
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
//////////////// 4205 / 4305 commands
|
||||
|
||||
#define EM_PREAMBLE_LEN 8
|
||||
|
||||
static int usage_lf_em4x05_wipe(void) {
|
||||
PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -90,24 +92,11 @@ static int usage_lf_em4x05_info(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
#define EM_SERIAL_BLOCK 1
|
||||
#define EM_CONFIG_BLOCK 4
|
||||
#define EM4305_PROT1_BLOCK 14
|
||||
#define EM4305_PROT2_BLOCK 15
|
||||
#define EM4469_PROT_BLOCK 3
|
||||
|
||||
typedef enum {
|
||||
EM_UNKNOWN,
|
||||
EM_4205,
|
||||
EM_4305,
|
||||
EM_4X69,
|
||||
} em_tech_type_t;
|
||||
|
||||
// 1 = EM4x69
|
||||
// 2 = EM4x05
|
||||
static em_tech_type_t em_get_card_type(uint32_t config) {
|
||||
uint8_t t = (config >> 1) & 0xF;
|
||||
switch(t) {
|
||||
switch (t) {
|
||||
case 4:
|
||||
return EM_4X69;
|
||||
case 8:
|
||||
|
@ -118,7 +107,7 @@ static em_tech_type_t em_get_card_type(uint32_t config) {
|
|||
return EM_UNKNOWN;
|
||||
}
|
||||
|
||||
static const char* em_get_card_str(uint32_t config) {
|
||||
static const char *em_get_card_str(uint32_t config) {
|
||||
switch (em_get_card_type(config)) {
|
||||
case EM_4305:
|
||||
return "EM4305";
|
||||
|
@ -133,7 +122,7 @@ static const char* em_get_card_str(uint32_t config) {
|
|||
}
|
||||
|
||||
// even parity COLUMN
|
||||
static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
|
||||
static bool em4x05_col_parity_test(uint8_t *bs, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
|
||||
if (rows * cols > size) return false;
|
||||
uint8_t colP = 0;
|
||||
|
||||
|
@ -147,14 +136,14 @@ static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t col
|
|||
return true;
|
||||
}
|
||||
|
||||
#define EM_PREAMBLE_LEN 8
|
||||
|
||||
// download samples from device and copy to Graphbuffer
|
||||
static bool downloadSamplesEM(void) {
|
||||
static bool em4x05_download_samples(void) {
|
||||
|
||||
// 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
|
||||
uint8_t got[6000];
|
||||
if (!GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 0, NULL, 2500, false)) {
|
||||
PrintAndLogEx(WARNING, "(downloadSamplesEM) command execution time out");
|
||||
PrintAndLogEx(WARNING, "(em_download_samples) command execution time out");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -273,12 +262,12 @@ static bool detectNRZ(void) {
|
|||
}
|
||||
|
||||
// param: idx - start index in demoded data.
|
||||
static int setDemodBufferEM(uint32_t *word, size_t idx) {
|
||||
static int em4x05_setdemod_buffer(uint32_t *word, size_t idx) {
|
||||
|
||||
//test for even parity bits.
|
||||
uint8_t parity[45] = {0};
|
||||
memcpy(parity, DemodBuffer, 45);
|
||||
if (!EM_ColParityTest(DemodBuffer + idx + EM_PREAMBLE_LEN, 45, 5, 9, 0)) {
|
||||
if (!em4x05_col_parity_test(DemodBuffer + idx + EM_PREAMBLE_LEN, 45, 5, 9, 0)) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - End Parity check failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -296,7 +285,7 @@ static int setDemodBufferEM(uint32_t *word, size_t idx) {
|
|||
// FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE, NRZ
|
||||
// should cover 90% of known used configs
|
||||
// the rest will need to be manually demoded for now...
|
||||
static int demodEM4x05resp(uint32_t *word, bool onlyPreamble) {
|
||||
static int em4x05_demod_resp(uint32_t *word, bool onlyPreamble) {
|
||||
size_t idx = 0;
|
||||
*word = 0;
|
||||
bool found_err = false;
|
||||
|
@ -347,21 +336,77 @@ static int demodEM4x05resp(uint32_t *word, bool onlyPreamble) {
|
|||
}
|
||||
if (found_err)
|
||||
return PM3_EFAILED;
|
||||
|
||||
return PM3_ESOFT;
|
||||
} while (0);
|
||||
|
||||
if (onlyPreamble)
|
||||
return PM3_SUCCESS;
|
||||
res = setDemodBufferEM(word, idx);
|
||||
|
||||
res = em4x05_setdemod_buffer(word, idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
return res;
|
||||
|
||||
if (found_err)
|
||||
return PM3_EFAILED;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//////////////// 4205 / 4305 commands
|
||||
|
||||
static int EM4x05Login_ext(uint32_t pwd) {
|
||||
static bool em4x05_verify_write(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t data) {
|
||||
uint32_t r = 0;
|
||||
int res = em4x05_read_word_ext(addr, pwd, use_pwd, &r);
|
||||
if (res == PM3_SUCCESS) {
|
||||
return (r == data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int em4x05_clone_tag(uint32_t *blockdata, uint8_t numblocks, uint32_t pwd, bool use_pwd) {
|
||||
|
||||
if (blockdata == NULL)
|
||||
return PM3_EINVARG;
|
||||
|
||||
if (numblocks < 1 || numblocks > 8)
|
||||
return PM3_EINVARG;
|
||||
|
||||
// fast push mode
|
||||
conn.block_after_ACK = true;
|
||||
int res = 0;
|
||||
for (int8_t i = 0; i < numblocks; i++) {
|
||||
|
||||
// Disable fast mode on last packet
|
||||
if (i == numblocks - 1) {
|
||||
conn.block_after_ACK = false;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
blockdata[i] = reflect(blockdata[i], 32);
|
||||
}
|
||||
|
||||
res = em4x05_write_word_ext(4 + i, pwd, use_pwd, blockdata[i]);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "(em4x05_clone_tag) Time out writing to tag");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
res = 0;
|
||||
for (int8_t i = 0; i < numblocks; i++) {
|
||||
if (em4x05_verify_write(4 + i, use_pwd, pwd, blockdata[i]) == false) {
|
||||
res++;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == 0)
|
||||
PrintAndLogEx(SUCCESS, "Success writing to tag");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int em4x05_login_ext(uint32_t pwd) {
|
||||
|
||||
struct {
|
||||
uint32_t password;
|
||||
|
@ -373,18 +418,18 @@ static int EM4x05Login_ext(uint32_t pwd) {
|
|||
SendCommandNG(CMD_LF_EM4X_LOGIN, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_LOGIN, &resp, 10000)) {
|
||||
PrintAndLogEx(WARNING, "(EM4x05Login_ext) timeout while waiting for reply.");
|
||||
PrintAndLogEx(WARNING, "(em4x05_login_ext) timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (downloadSamplesEM() == false) {
|
||||
if (em4x05_download_samples() == false) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
uint32_t word;
|
||||
return demodEM4x05resp(&word, true);
|
||||
return em4x05_demod_resp(&word, true);
|
||||
}
|
||||
|
||||
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word) {
|
||||
int em4x05_read_word_ext(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t *word) {
|
||||
|
||||
struct {
|
||||
uint32_t password;
|
||||
|
@ -394,27 +439,48 @@ int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word)
|
|||
|
||||
payload.password = pwd;
|
||||
payload.address = addr;
|
||||
payload.usepwd = usePwd;
|
||||
payload.usepwd = use_pwd;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_READWORD, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_READWORD, &resp, 10000)) {
|
||||
PrintAndLogEx(WARNING, "(EM4x05ReadWord_ext) timeout while waiting for reply.");
|
||||
PrintAndLogEx(WARNING, "(em4x05_read_word_ext) timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (downloadSamplesEM() == false) {
|
||||
if (em4x05_download_samples() == false) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return demodEM4x05resp(word, false);
|
||||
return em4x05_demod_resp(word, false);
|
||||
}
|
||||
|
||||
int em4x05_write_word_ext(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t data) {
|
||||
struct {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t address;
|
||||
uint8_t usepwd;
|
||||
} PACKED payload;
|
||||
|
||||
payload.password = pwd;
|
||||
payload.data = data;
|
||||
payload.address = addr;
|
||||
payload.usepwd = use_pwd;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_WRITEWORD, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_WRITEWORD, &resp, 2000)) {
|
||||
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdEM4x05Demod(const char *Cmd) {
|
||||
// uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
// if (ctmp == 'h') return usage_lf_em4x05_demod();
|
||||
uint32_t dummy = 0;
|
||||
return demodEM4x05resp(&dummy, false);
|
||||
return em4x05_demod_resp(&dummy, false);
|
||||
}
|
||||
|
||||
int CmdEM4x05Dump(const char *Cmd) {
|
||||
|
@ -429,13 +495,13 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_0("p", "pwd", "<hex>", "password (0x00000000)"),
|
||||
arg_str0("f", "file", "<filename>", "overide filename prefix (optional). Default is based on UID"),
|
||||
arg_str0("p", "pwd", "<hex>", "password (00000000)"),
|
||||
arg_str0("f", "file", "<filename>", "override filename prefix (optional). Default is based on UID"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
uint64_t inputpwd = arg_get_u64_def(ctx, 1, 0xFFFFFFFFFFFFFFFF);
|
||||
uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 1, 0xFFFFFFFFFFFFFFFF);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
@ -458,7 +524,7 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
uint32_t block0 = 0;
|
||||
// read word 0 (chip info)
|
||||
// block 0 can be read even without a password.
|
||||
if (EM4x05IsBlock0(&block0) == false)
|
||||
if (em4x05_isblock0(&block0) == false)
|
||||
return PM3_ESOFT;
|
||||
|
||||
uint8_t bytes[4] = {0};
|
||||
|
@ -481,7 +547,7 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
|
||||
if (usePwd) {
|
||||
// Test first if the password is correct
|
||||
status = EM4x05Login_ext(pwd);
|
||||
status = em4x05_login_ext(pwd);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Password is " _GREEN_("correct"));
|
||||
} else if (status == PM3_EFAILED) {
|
||||
|
@ -497,12 +563,12 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Addr | data | ascii |lck| info");
|
||||
PrintAndLogEx(INFO, "-----+----------+-------+---+-----");
|
||||
|
||||
if ( card_type == EM_4205 || card_type == EM_4305 || card_type == EM_UNKNOWN) {
|
||||
if (card_type == EM_4205 || card_type == EM_4305 || card_type == EM_UNKNOWN) {
|
||||
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
status14 = EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word);
|
||||
status14 = em4x05_read_word_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
|
@ -512,7 +578,7 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
}
|
||||
status15 = EM4x05ReadWord_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word);
|
||||
status15 = em4x05_read_word_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word);
|
||||
if (status15 == PM3_SUCCESS) {
|
||||
if ((word & 0x00008000) != 0x00) { // assume block 15 is the current lock block
|
||||
lock_bits = word;
|
||||
|
@ -537,8 +603,8 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
}
|
||||
} else {
|
||||
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read
|
||||
// success &= em4x05_read_word_ext(addr, pwd, usePwd, &word);
|
||||
status = em4x05_read_word_ext(addr, pwd, usePwd, &word); // Get status for single read
|
||||
if (status != PM3_SUCCESS)
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
data[addr] = BSWAP_32(word);
|
||||
|
@ -573,7 +639,7 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
status14 = EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word);
|
||||
status14 = em4x05_read_word_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
|
@ -599,7 +665,7 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
}
|
||||
} else {
|
||||
|
||||
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||
status = em4x05_read_word_ext(addr, pwd, usePwd, &word);
|
||||
if (status != PM3_SUCCESS) {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
}
|
||||
|
@ -622,7 +688,7 @@ int CmdEM4x05Dump(const char *Cmd) {
|
|||
// saveFile (binary) passes in the .bin extension.
|
||||
if (strcmp(filename, "") == 0) {
|
||||
|
||||
if ( card_type == EM_4X69) {
|
||||
if (card_type == EM_4X69) {
|
||||
sprintf(filename, "lf-4x69-%08X-dump", BSWAP_32(data[1]));
|
||||
} else {
|
||||
sprintf(filename, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
|
||||
|
@ -662,7 +728,7 @@ int CmdEM4x05Read(const char *Cmd) {
|
|||
}
|
||||
|
||||
uint32_t word = 0;
|
||||
int status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||
int status = em4x05_read_word_ext(addr, pwd, usePwd, &word);
|
||||
if (status == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Address %02d | %08X - %s", addr, word, (addr > 13) ? "Lock" : "");
|
||||
else if (status == PM3_EFAILED)
|
||||
|
@ -721,31 +787,14 @@ int CmdEM4x05Write(const char *Cmd) {
|
|||
return PM3_ETIMEOUT;
|
||||
}
|
||||
} else {
|
||||
struct {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t address;
|
||||
uint8_t usepwd;
|
||||
} PACKED payload;
|
||||
|
||||
payload.password = pwd;
|
||||
payload.data = data;
|
||||
payload.address = addr;
|
||||
payload.usepwd = usePwd;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_WRITEWORD, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_WRITEWORD, &resp, 2000)) {
|
||||
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
em4x05_write_word_ext(addr, pwd, usePwd, data);
|
||||
}
|
||||
if (!downloadSamplesEM())
|
||||
|
||||
if (em4x05_download_samples() == false)
|
||||
return PM3_ENODATA;
|
||||
|
||||
uint32_t dummy = 0;
|
||||
int status = demodEM4x05resp(&dummy, true);
|
||||
int status = em4x05_demod_resp(&dummy, true);
|
||||
if (status == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Success writing to tag");
|
||||
else if (status == PM3_EFAILED)
|
||||
|
@ -1000,8 +1049,8 @@ static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) {
|
|||
}
|
||||
|
||||
//quick test for EM4x05/EM4x69 tag
|
||||
bool EM4x05IsBlock0(uint32_t *word) {
|
||||
return (EM4x05ReadWord_ext(0, 0, false, word) == PM3_SUCCESS);
|
||||
bool em4x05_isblock0(uint32_t *word) {
|
||||
return (em4x05_read_word_ext(0, 0, false, word) == PM3_SUCCESS);
|
||||
}
|
||||
|
||||
int CmdEM4x05Info(const char *Cmd) {
|
||||
|
@ -1019,7 +1068,7 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
|
||||
// read word 0 (chip info)
|
||||
// block 0 can be read even without a password.
|
||||
if (EM4x05IsBlock0(&block0) == false)
|
||||
if (em4x05_isblock0(&block0) == false)
|
||||
return PM3_ESOFT;
|
||||
|
||||
// based on Block0 , decide type.
|
||||
|
@ -1027,13 +1076,13 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
|
||||
// read word 1 (serial #) doesn't need pwd
|
||||
// continue if failed, .. non blocking fail.
|
||||
EM4x05ReadWord_ext(EM_SERIAL_BLOCK, 0, false, &serial);
|
||||
em4x05_read_word_ext(EM_SERIAL_BLOCK, 0, false, &serial);
|
||||
|
||||
printEM4x05info(block0, serial);
|
||||
|
||||
// read word 4 (config block)
|
||||
// needs password if one is set
|
||||
if (EM4x05ReadWord_ext(EM_CONFIG_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
if (em4x05_read_word_ext(EM_CONFIG_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
return PM3_ESOFT;
|
||||
|
||||
printEM4x05config(word);
|
||||
|
@ -1043,7 +1092,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 (EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
if (em4x05_read_word_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -1051,7 +1100,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 (EM4x05ReadWord_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
if (em4x05_read_word_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
return PM3_ESOFT;
|
||||
if (word & 0x8000) {
|
||||
printEM4x05ProtectionBits(word, EM4305_PROT2_BLOCK);
|
||||
|
@ -1059,8 +1108,8 @@ int CmdEM4x05Info(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
} else if (card_type == EM_4X69) {
|
||||
// read word 3 to see which is being used for the protection bits
|
||||
if (EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
// 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) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
printEM4x05ProtectionBits(word, EM4469_PROT_BLOCK);
|
||||
|
@ -1083,21 +1132,22 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
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 0x00000022B8 -> remember to use 0x for hex\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[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("f", "file", "<*.dic>", "loads a default keys dictionary file <*.dic>"),
|
||||
arg_u64_0("e", "em", "<EM4100>", "try the calculated password from some cloners based on EM4100 ID"),
|
||||
arg_str0("e", "em", "<EM4100>", "try the calculated password from some cloners based on EM4100 ID"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
uint64_t card_id = arg_get_u64_def(ctx, 2, 0);
|
||||
|
||||
uint64_t card_id = arg_get_u64_hexstr_def(ctx, 2, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (strlen(filename) == 0) {
|
||||
|
@ -1109,12 +1159,12 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
uint64_t t1 = msclock();
|
||||
|
||||
// White cloner password based on EM4100 ID
|
||||
if ( card_id > 0 ) {
|
||||
if (card_id > 0) {
|
||||
|
||||
uint32_t pwd = lf_t55xx_white_pwdgen(card_id & 0xFFFFFFFF);
|
||||
PrintAndLogEx(INFO, "testing %08"PRIX32" generated ", pwd);
|
||||
|
||||
int status = EM4x05Login_ext(pwd);
|
||||
int status = em4x05_login_ext(pwd);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", pwd);
|
||||
found = true;
|
||||
|
@ -1157,7 +1207,7 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(INFO, "testing %08"PRIX32, curr_password);
|
||||
|
||||
int status = EM4x05Login_ext(curr_password);
|
||||
int status = em4x05_login_ext(curr_password);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", curr_password);
|
||||
found = true;
|
||||
|
@ -1178,6 +1228,48 @@ int CmdEM4x05Chk(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdEM4x05Brute(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
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"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_0("s", "start", "<pwd>", "Start bruteforce enumeration from this password value"),
|
||||
arg_int0("n", "", "<digits>", "Stop after having found n candidates. Default: 0 => infinite"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
uint32_t start_pwd = arg_get_u64_hexstr_def(ctx, 1, 0);
|
||||
uint32_t n = arg_get_int_def(ctx, 2, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
struct {
|
||||
uint32_t start_pwd;
|
||||
uint32_t n;
|
||||
} PACKED payload;
|
||||
|
||||
payload.start_pwd = start_pwd;
|
||||
payload.n = n;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_BF, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_BF, &resp, 1000)) {
|
||||
PrintAndLogEx(WARNING, "(EM4x05 Bruteforce) timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Bruteforce is running on device side, press button to interrupt");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint16_t cnt;
|
||||
uint32_t value;
|
||||
|
@ -1203,11 +1295,11 @@ static int unlock_write_protect(bool use_pwd, uint32_t pwd, uint32_t data, bool
|
|||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (!downloadSamplesEM())
|
||||
if (em4x05_download_samples() == false)
|
||||
return PM3_ENODATA;
|
||||
|
||||
uint32_t dummy = 0;
|
||||
int status = demodEM4x05resp(&dummy, true);
|
||||
int status = em4x05_demod_resp(&dummy, true);
|
||||
if (status == PM3_SUCCESS && verbose)
|
||||
PrintAndLogEx(SUCCESS, "Success writing to tag");
|
||||
else if (status == PM3_EFAILED)
|
||||
|
@ -1227,11 +1319,11 @@ static void unlock_add_item(em4x05_unlock_item_t *array, uint8_t len, uint32_t v
|
|||
|
||||
uint8_t i = 0;
|
||||
for (; i < len; i++) {
|
||||
if ( array[i].value == value ) {
|
||||
if (array[i].value == value) {
|
||||
array[i].cnt++;
|
||||
break;
|
||||
}
|
||||
if ( array[i].cnt == 0 ) {
|
||||
if (array[i].cnt == 0) {
|
||||
array[i].cnt++;
|
||||
array[i].value = value;
|
||||
break;
|
||||
|
@ -1254,7 +1346,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
arg_int0("n", NULL, NULL, "steps to skip"),
|
||||
arg_int0("s", "start", "<us>", "start scan from delay (us)"),
|
||||
arg_int0("e", "end", "<us>", "end scan at delay (us)"),
|
||||
arg_u64_0("p", "pwd", "", "password (0x00000000)"),
|
||||
arg_str0("p", "pwd", "", "password (00000000)"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -1262,11 +1354,11 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
double n = (double)arg_get_int_def(ctx, 1, 0);
|
||||
double start = (double)arg_get_int_def(ctx, 2, 2000);
|
||||
double end = (double)arg_get_int_def(ctx, 3, 6000);
|
||||
uint64_t inputpwd = arg_get_u64_def(ctx, 4, 0xFFFFFFFFFFFFFFFF);
|
||||
uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 4, 0xFFFFFFFFFFFFFFFF);
|
||||
bool verbose = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ( start > end ) {
|
||||
if (start > end) {
|
||||
PrintAndLogEx(FAILED, "start delay can\'t be larger than end delay %.0lf vs %.0lf", start, end);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -1290,7 +1382,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
//
|
||||
// read word 14
|
||||
uint32_t init_14 = 0;
|
||||
int res = EM4x05ReadWord_ext(14, pwd, use_pwd, &init_14);
|
||||
int res = em4x05_read_word_ext(14, pwd, use_pwd, &init_14);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "failed to read word 14\n");
|
||||
return PM3_ENODATA;
|
||||
|
@ -1299,7 +1391,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
|
||||
// read 15
|
||||
uint32_t init_15 = 0;
|
||||
res = EM4x05ReadWord_ext(15, pwd, use_pwd, &init_15);
|
||||
res = em4x05_read_word_ext(15, pwd, use_pwd, &init_15);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "failed to read word 15\n");
|
||||
return PM3_ENODATA;
|
||||
|
@ -1357,7 +1449,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
uint32_t soon = 0;
|
||||
uint32_t late = 0;
|
||||
|
||||
em4x05_unlock_item_t flipped[64] ={{0,0}};
|
||||
em4x05_unlock_item_t flipped[64] = {{0, 0}};
|
||||
|
||||
//
|
||||
// main loop
|
||||
|
@ -1406,7 +1498,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
.off = false
|
||||
};
|
||||
res = handle_tearoff(¶ms, verbose);
|
||||
if ( res != PM3_SUCCESS ) {
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "failed to configure tear off");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -1415,14 +1507,14 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
res = unlock_write_protect(use_pwd, pwd, write_value, verbose);
|
||||
|
||||
// read after trigger
|
||||
res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14);
|
||||
res = em4x05_read_word_ext(14, pwd, use_pwd, &word14);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "failed to read 14");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// read after trigger
|
||||
res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15);
|
||||
res = em4x05_read_word_ext(15, pwd, use_pwd, &word15);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "failed to read 15");
|
||||
return PM3_ESOFT;
|
||||
|
@ -1431,7 +1523,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
if (verbose)
|
||||
PrintAndLogEx(INFO, "ref:%08X 14:%08X 15:%08X ", search_value, word14, word15);
|
||||
|
||||
if ( word14 == search_value && word15 == 0) {
|
||||
if (word14 == search_value && word15 == 0) {
|
||||
PrintAndLogEx(INFO, "Status: Nothing happened => " _GREEN_("tearing too soon"));
|
||||
|
||||
if (my_auto) {
|
||||
|
@ -1448,7 +1540,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
if (word14 == 0) {
|
||||
PrintAndLogEx(INFO, "Status: Protect succeeded => " _GREEN_("tearing too late"));
|
||||
} else {
|
||||
if ( word14 == search_value) {
|
||||
if (word14 == search_value) {
|
||||
PrintAndLogEx(INFO, "Status: 15 ok, 14 not yet erased => " _GREEN_("tearing too late"));
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Status: 15 ok, 14 partially erased => " _GREEN_("tearing too late"));
|
||||
|
@ -1458,7 +1550,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
unlock_reset(use_pwd, pwd, write_value, verbose);
|
||||
|
||||
// read after reset
|
||||
res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14b);
|
||||
res = em4x05_read_word_ext(14, pwd, use_pwd, &word14b);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "failed to read 14");
|
||||
return PM3_ESOFT;
|
||||
|
@ -1468,7 +1560,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
|
||||
unlock_reset(use_pwd, pwd, write_value, verbose);
|
||||
|
||||
res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14b);
|
||||
res = em4x05_read_word_ext(14, pwd, use_pwd, &word14b);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "failed to read 14");
|
||||
return PM3_ESOFT;
|
||||
|
@ -1477,7 +1569,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
|
||||
if (word14b != search_value) {
|
||||
|
||||
res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15b);
|
||||
res = em4x05_read_word_ext(15, pwd, use_pwd, &word15b);
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Status: new definitive value! => " _RED_("SUCCESS:") " 14: " _CYAN_("%08X") " 15: %08X", word14b, word15b);
|
||||
success = true;
|
||||
|
@ -1498,7 +1590,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
|
||||
} else {
|
||||
|
||||
if (( word15 & ACTIVE_MASK) == ACTIVE_MASK) {
|
||||
if ((word15 & ACTIVE_MASK) == ACTIVE_MASK) {
|
||||
|
||||
PrintAndLogEx(INFO, "Status: 15 bitflipped and active => " _RED_("SUCCESS?: ") "14: %08X 15: " _CYAN_("%08X"), word14, word15);
|
||||
PrintAndLogEx(INFO, "Committing results...");
|
||||
|
@ -1506,14 +1598,14 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
unlock_reset(use_pwd, pwd, write_value, verbose);
|
||||
|
||||
// read after reset
|
||||
res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14b);
|
||||
if ( res != PM3_SUCCESS ) {
|
||||
res = em4x05_read_word_ext(14, pwd, use_pwd, &word14b);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "failed to read 14");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15b);
|
||||
if ( res != PM3_SUCCESS ) {
|
||||
res = em4x05_read_word_ext(15, pwd, use_pwd, &word15b);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "failed to read 15");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -1524,7 +1616,7 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
if ((word14b & ACTIVE_MASK) == ACTIVE_MASK) {
|
||||
|
||||
if (word14b == word15) {
|
||||
PrintAndLogEx(INFO, "Status: confirmed => " _RED_("SUCCESS: ") "14: " _CYAN_("%08X") " 15: %08X", word14b, word15b);
|
||||
PrintAndLogEx(INFO, "Status: confirmed => " _GREEN_("SUCCESS: ") "14: " _GREEN_("%08X") " 15: %08X", word14b, word15b);
|
||||
|
||||
unlock_add_item(flipped, 64, word14b);
|
||||
success = true;
|
||||
|
@ -1571,8 +1663,8 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
uint32_t bitflips = search_value ^ word14b;
|
||||
PrintAndLogEx(INFO, "Old protection word => " _YELLOW_("%08X"), search_value);
|
||||
char bitstring[9] = {0};
|
||||
for (int i=0; i < 8; i++) {
|
||||
bitstring[i] = bitflips & (0xF << ((7-i) * 4)) ? 'x' : '.';
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bitstring[i] = bitflips & (0xF << ((7 - i) * 4)) ? 'x' : '.';
|
||||
}
|
||||
// compute number of bits flipped
|
||||
|
||||
|
@ -1597,3 +1689,262 @@ int CmdEM4x05Unlock(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
static size_t em4x05_Sniff_GetNextBitStart (size_t idx, size_t sc, int *data, size_t *pulsesamples) {
|
||||
while ((idx < sc) && (data[idx] <= 10)) // find a going high
|
||||
idx++;
|
||||
|
||||
while ((idx < sc) && (data[idx] > -10)) // find going low may need to add something here it SHOULD be a small clk around 0, but white seems to extend a bit.
|
||||
idx++;
|
||||
|
||||
(*pulsesamples) = 0;
|
||||
while ((idx < sc) && ((data[idx+1] - data[idx]) < 10 )) { // find "sharp rise"
|
||||
(*pulsesamples)++;
|
||||
idx++;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
uint32_t static em4x05_Sniff_GetBlock (char *bits, bool fwd) {
|
||||
uint32_t value = 0;
|
||||
uint8_t idx;
|
||||
bool parityerror = false;
|
||||
uint8_t parity;
|
||||
|
||||
parity = 0;
|
||||
for (idx = 0; idx < 8; idx++) {
|
||||
value <<= 1;
|
||||
value += (bits[idx] - '0');
|
||||
parity += (bits[idx] - '0');
|
||||
}
|
||||
parity = parity % 2;
|
||||
if (parity != (bits[8] - '0'))
|
||||
parityerror = true;
|
||||
|
||||
parity = 0;
|
||||
for (idx = 9; idx < 17; idx++) {
|
||||
value <<= 1;
|
||||
value += (bits[idx] - '0');
|
||||
parity += (bits[idx] - '0');
|
||||
}
|
||||
parity = parity % 2;
|
||||
if (parity != (bits[17] - '0'))
|
||||
parityerror = true;
|
||||
|
||||
parity = 0;
|
||||
for (idx = 18; idx < 26; idx++) {
|
||||
value <<= 1;
|
||||
value += (bits[idx] - '0');
|
||||
parity += (bits[idx] - '0');
|
||||
}
|
||||
parity = parity % 2;
|
||||
if (parity != (bits[26] - '0'))
|
||||
parityerror = true;
|
||||
|
||||
parity = 0;
|
||||
for (idx = 27; idx < 35; idx++) {
|
||||
value <<= 1;
|
||||
value += (bits[idx] - '0');
|
||||
parity += (bits[idx] - '0');
|
||||
}
|
||||
parity = parity % 2;
|
||||
if (parity != (bits[35] - '0'))
|
||||
parityerror = true;
|
||||
|
||||
if (parityerror) printf ("parity error : ");
|
||||
|
||||
if (!fwd) {
|
||||
uint32_t t1 = value;
|
||||
value = 0;
|
||||
for (idx = 0; idx < 32; idx++)
|
||||
value |= (((t1 >> idx) & 1) << (31 - idx));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
int CmdEM4x05Sniff(const char *Cmd) {
|
||||
|
||||
bool sampleData = true;
|
||||
bool haveData = false;
|
||||
size_t idx = 0;
|
||||
char cmdText [100];
|
||||
char dataText [100];
|
||||
char blkAddr[4];
|
||||
char bits[80];
|
||||
int bitidx;
|
||||
int ZeroWidth; // 32-42 "1" is 32
|
||||
int CycleWidth;
|
||||
size_t pulseSamples;
|
||||
size_t pktOffset;
|
||||
int i;
|
||||
bool eop = false;
|
||||
uint32_t tmpValue;
|
||||
bool pwd = false;
|
||||
bool fwd = false;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05_sniff",
|
||||
"Sniff EM4x05 commands sent from a programmer",
|
||||
"lf em 4x05_sniff -> sniff via lf sniff\n"
|
||||
"lf em 4x05_sniff -1 -> sniff from data loaded into the buffer\n"
|
||||
"lf em 4x05_sniff -r -> reverse the bit order when showing block data"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("1", "buf","Use the data in the buffer"),
|
||||
arg_lit0("r", "rev", "Reverse the bit order for data blocks"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
sampleData = !arg_get_lit(ctx,1);
|
||||
fwd = arg_get_lit(ctx,2);
|
||||
|
||||
// setup and sample data from Proxmark
|
||||
// if not directed to existing sample/graphbuffer
|
||||
if (sampleData) {
|
||||
if (!IfPm3Lf()) {
|
||||
PrintAndLogEx(WARNING, "Only offline mode is available");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
CmdLFSniff("");
|
||||
}
|
||||
|
||||
// Headings
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, _CYAN_("EM4x05 command detection"));
|
||||
PrintAndLogEx(SUCCESS, "offset | Command | Data | blk | raw");
|
||||
PrintAndLogEx(SUCCESS, "-------+-------------+----------+-----+------------------------------------------------------------");
|
||||
|
||||
idx = 0;
|
||||
// loop though sample buffer
|
||||
while (idx < GraphTraceLen) {
|
||||
eop = false;
|
||||
haveData = false;
|
||||
pwd = false;
|
||||
|
||||
idx = em4x05_Sniff_GetNextBitStart (idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
pktOffset = idx;
|
||||
if (pulseSamples >= 10) { // Should be 18 so a bit less to allow for processing
|
||||
|
||||
// Use first bit to get "0" bit samples as a reference
|
||||
ZeroWidth = idx;
|
||||
idx = em4x05_Sniff_GetNextBitStart (idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
ZeroWidth = idx - ZeroWidth;
|
||||
|
||||
if (ZeroWidth <= 50) {
|
||||
pktOffset -= ZeroWidth;
|
||||
memset(bits,0x00,sizeof(bits));
|
||||
bitidx = 0;
|
||||
|
||||
while ((idx < GraphTraceLen) && !eop) {
|
||||
CycleWidth = idx;
|
||||
idx = em4x05_Sniff_GetNextBitStart (idx, GraphTraceLen, GraphBuffer, &pulseSamples);
|
||||
|
||||
CycleWidth = idx - CycleWidth;
|
||||
if ((CycleWidth > 300) || (CycleWidth < (ZeroWidth-5))) { // to long or too short
|
||||
eop = true;
|
||||
bits[bitidx++] = '0'; // Append last zero from the last bit find
|
||||
cmdText[0] = 0;
|
||||
|
||||
// EM4305 command lengths
|
||||
// Login 0011 <pwd> => 4 + 45 => 49
|
||||
// Write Word 0101 <adr> <data> => 4 + 7 + 45 => 56
|
||||
// Read Word 1001 <adr> => 4 + 7 => 11
|
||||
// Protect 1100 <data> => 4 + 45 => 49
|
||||
// Disable 1010 <data> => 4 + 45 => 49
|
||||
// -> disaable 1010 11111111 0 11111111 0 11111111 0 11111111 0 00000000 0
|
||||
|
||||
// Check to see if we got the leading 0
|
||||
if (((strncmp (bits,"00011",5) == 0)&& (bitidx == 50)) ||
|
||||
((strncmp (bits,"00101",5) == 0)&& (bitidx == 57)) ||
|
||||
((strncmp (bits,"01001",5) == 0)&& (bitidx == 12)) ||
|
||||
((strncmp (bits,"01100",5) == 0)&& (bitidx == 50)) ||
|
||||
((strncmp (bits,"01010",5) == 0)&& (bitidx == 50))) {
|
||||
memcpy (bits,&bits[1],bitidx-1);
|
||||
bitidx--;
|
||||
printf ("Trim leading 0\n");
|
||||
}
|
||||
bits[bitidx] = 0;
|
||||
// printf ("==> %s\n",bits);
|
||||
// logon
|
||||
if ((strncmp (bits,"0011",4) == 0) && (bitidx == 49)) {
|
||||
haveData = true;
|
||||
pwd = true;
|
||||
sprintf (cmdText,"Logon");
|
||||
sprintf (blkAddr," ");
|
||||
tmpValue = em4x05_Sniff_GetBlock (&bits[4], fwd);
|
||||
sprintf (dataText,"%08X",tmpValue);
|
||||
}
|
||||
|
||||
// write
|
||||
if ((strncmp (bits,"0101",4) == 0) && (bitidx == 56)) {
|
||||
haveData = true;
|
||||
sprintf (cmdText,"Write");
|
||||
tmpValue = (bits[4] - '0') + ((bits[5] - '0') << 1) + ((bits[6] - '0') << 2) + ((bits[7] - '0') << 3);
|
||||
sprintf (blkAddr,"%d",tmpValue);
|
||||
if (tmpValue == 2)
|
||||
pwd = true;
|
||||
tmpValue = em4x05_Sniff_GetBlock (&bits[11], fwd);
|
||||
sprintf (dataText,"%08X",tmpValue);
|
||||
}
|
||||
|
||||
// read
|
||||
if ((strncmp (bits,"1001",4) == 0) && (bitidx == 11)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
sprintf (cmdText,"Read");
|
||||
tmpValue = (bits[4] - '0') + ((bits[5] - '0') << 1) + ((bits[6] - '0') << 2) + ((bits[7] - '0') << 3);
|
||||
sprintf (blkAddr,"%d",tmpValue);
|
||||
sprintf (dataText," ");
|
||||
}
|
||||
|
||||
// protect
|
||||
if ((strncmp (bits,"1100",4) == 0) && (bitidx == 49)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
sprintf (cmdText,"Protect");
|
||||
sprintf (blkAddr," ");
|
||||
tmpValue = em4x05_Sniff_GetBlock (&bits[11], fwd);
|
||||
sprintf (dataText,"%08X",tmpValue);
|
||||
}
|
||||
|
||||
// disable
|
||||
if ((strncmp (bits,"1010",4) == 0) && (bitidx == 49)) {
|
||||
haveData = true;
|
||||
pwd = false;
|
||||
sprintf (cmdText,"Disable");
|
||||
sprintf (blkAddr," ");
|
||||
tmpValue = em4x05_Sniff_GetBlock (&bits[11], fwd);
|
||||
sprintf (dataText,"%08X",tmpValue);
|
||||
}
|
||||
|
||||
// bits[bitidx] = 0;
|
||||
} else {
|
||||
i = (CycleWidth - ZeroWidth) / 28;
|
||||
bits[bitidx++] = '0';
|
||||
for (int ii = 0; ii < i; ii++)
|
||||
bits[bitidx++] = '1';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
|
||||
// Print results
|
||||
if (haveData) { //&& (minWidth > 1) && (maxWidth > minWidth)){
|
||||
if (pwd)
|
||||
PrintAndLogEx(SUCCESS, "%6llu | %-10s | "_YELLOW_("%8s")" | "_YELLOW_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits);
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "%6llu | %-10s | "_GREEN_("%8s")" | "_GREEN_("%3s")" | %s", pktOffset, cmdText, dataText, blkAddr, bits);
|
||||
}
|
||||
}
|
||||
|
||||
// footer
|
||||
PrintAndLogEx(SUCCESS, "---------------------------------------------------------------------------------------------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -13,11 +13,57 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#define EM_SERIAL_BLOCK 1
|
||||
#define EM_CONFIG_BLOCK 4
|
||||
#define EM4305_PROT1_BLOCK 14
|
||||
#define EM4305_PROT2_BLOCK 15
|
||||
#define EM4469_PROT_BLOCK 3
|
||||
|
||||
// config blocks
|
||||
#define EM4305_DEFAULT_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/MAN , data rate 32, 4 data blocks
|
||||
//#define EM4305_DEFAULT_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/BIPHASE , data rate 32, 4 data blocks
|
||||
|
||||
#define EM4305_EM_UNIQUE_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(2) ) // ASK/MAN, EM4x02/unique - data rate 64, 2 data blocks
|
||||
#define EM4305_PAXTON_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(2) ) // ASK/MAN, EM4x02/paxton - data rate 64, 2 data blocks
|
||||
#define EM4305_VISA2000_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK, data rate 64, 3 data blocks
|
||||
#define EM4305_VIKING_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(2) ) // ASK/MAN, data rate 32, 2 data blocks
|
||||
#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_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
|
||||
#define EM4305_PYRAMID_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(4) ) // FSK2a, Pyramid 26 bit, data rate 50, 4 data blocks
|
||||
#define EM4305_IOPROX_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(2) ) // FSK2a, data rate 64, 2 data blocks
|
||||
|
||||
#define EM4305_INDALA_64_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(2) ) // PSK1, indala 64 bit, psk carrier FC * 2, data rate 32, maxblock 2
|
||||
#define EM4305_INDALA_224_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(7) ) // PSK1, indala 224 bit, psk carrier FC * 2, data rate 32, maxblock 7
|
||||
#define EM4305_MOTOROLA_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(2) ) // PSK1, data rate 32, 2 data blocks
|
||||
#define EM4305_NEXWATCH_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(3) ) // PSK1 data rate 16, psk carrier FC * 2, 3 data blocks
|
||||
#define EM4305_KERI_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(2) ) // PSK1, 2 data blocks
|
||||
|
||||
#define EM4305_JABLOTRON_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(2) ) // Biphase, data rate 64, 2 data blocks
|
||||
#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_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
|
||||
|
||||
typedef enum {
|
||||
EM_UNKNOWN,
|
||||
EM_4205,
|
||||
EM_4305,
|
||||
EM_4X69,
|
||||
} em_tech_type_t;
|
||||
|
||||
int CmdLFEM4X05(const char *Cmd);
|
||||
|
||||
bool EM4x05IsBlock0(uint32_t *word);
|
||||
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word);
|
||||
|
||||
bool em4x05_isblock0(uint32_t *word);
|
||||
int em4x05_read_word_ext(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t *word);
|
||||
int em4x05_write_word_ext(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t data);
|
||||
int em4x05_clone_tag(uint32_t *blockdata, uint8_t numblocks, uint32_t pwd, bool use_pwd);
|
||||
|
||||
int CmdEM4x05Demod(const char *Cmd);
|
||||
int CmdEM4x05Dump(const char *Cmd);
|
||||
|
@ -27,5 +73,7 @@ int CmdEM4x05Wipe(const char *Cmd);
|
|||
int CmdEM4x05Info(const char *Cmd);
|
||||
int CmdEM4x05Chk(const char *Cmd);
|
||||
int CmdEM4x05Unlock(const char *Cmd);
|
||||
int CmdEM4x05Sniff(const char *Cmd);
|
||||
int CmdEM4x05Brute(const char *Cmd);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -77,7 +77,7 @@ static int usage_lf_em4x50_dump(void) {
|
|||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_dump [h] [f <filename prefix>] [p <pwd>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " f <filename prefix> - overide filename prefix (optional). Default is based on UID");
|
||||
PrintAndLogEx(NORMAL, " f <filename prefix> - override filename prefix (optional). Default is based on UID");
|
||||
PrintAndLogEx(NORMAL, " p <pwd> - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_dump"));
|
||||
|
|
|
@ -470,7 +470,7 @@ const fdxbCountryMapping_t fdxbCountryMapping[] = {
|
|||
{ 0, "N/A" } // must be the last entry
|
||||
};
|
||||
|
||||
static const char* mapFDBX(uint16_t countryCode) {
|
||||
static const char *mapFDBX(uint16_t countryCode) {
|
||||
uint16_t i = 0;
|
||||
while (fdxbCountryMapping[i].code > 0) {
|
||||
if (countryCode == fdxbCountryMapping[i].code) {
|
||||
|
@ -572,8 +572,8 @@ int demodFDXB(bool verbose) {
|
|||
PrintAndLogEx(SUCCESS, " Animal bit set? %s", animalBit ? _YELLOW_("True") : "False");
|
||||
PrintAndLogEx(SUCCESS, " Data block? %s [value 0x%X]", dataBlockBit ? _YELLOW_("True") : "False", extended);
|
||||
PrintAndLogEx(SUCCESS, " RUDI bit? %s", rudiBit ? _YELLOW_("True") " (advanced transponder)" : "False");
|
||||
PrintAndLogEx(SUCCESS, " User Info? %u %s", userInfo, userInfo == 0 ? "(RFU)":"");
|
||||
PrintAndLogEx(SUCCESS, " Replacement No? %u %s", replacementNr, replacementNr == 0 ? "(RFU)":"");
|
||||
PrintAndLogEx(SUCCESS, " User Info? %u %s", userInfo, userInfo == 0 ? "(RFU)" : "");
|
||||
PrintAndLogEx(SUCCESS, " Replacement No? %u %s", replacementNr, replacementNr == 0 ? "(RFU)" : "");
|
||||
|
||||
uint8_t c[] = {0, 0};
|
||||
compute_crc(CRC_11784, raw, sizeof(raw), &c[0], &c[1]);
|
||||
|
|
|
@ -8,23 +8,21 @@
|
|||
// PSK1, RF/128, RF/2, 64 bits long
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdlfkeri.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cliparser.h"
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // preamble test
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
#include "cmdlfem4x05.h" //
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
typedef enum {Scramble = 0, Descramble = 1} KeriMSScramble_t;
|
||||
|
@ -125,17 +123,6 @@ int demodKeri(bool verbose) {
|
|||
setDemodBuff(DemodBuffer, size, idx);
|
||||
setClockGrid(g_DemodClock, g_DemodStartIdx + (idx * g_DemodClock));
|
||||
|
||||
//got a good demod
|
||||
uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
|
||||
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
||||
|
||||
//get internal id
|
||||
// uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32);
|
||||
// Due to the 3 sync bits being at the start of the capture
|
||||
// We can take the last 32bits as the internal ID.
|
||||
uint32_t ID = raw2;
|
||||
ID &= 0x7FFFFFFF;
|
||||
|
||||
/*
|
||||
000000000000000000000000000001XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX111
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1###############################^^^
|
||||
|
@ -150,25 +137,40 @@ int demodKeri(bool verbose) {
|
|||
Might be a hash of FC & CN to generate Internal ID
|
||||
*/
|
||||
|
||||
PrintAndLogEx(SUCCESS, "KERI - Internal ID: " _GREEN_("%u") ", Raw: %08X%08X", ID, raw1, raw2);
|
||||
|
||||
/*
|
||||
Descramble Data.
|
||||
*/
|
||||
uint32_t fc = 0;
|
||||
uint32_t cardid = 0;
|
||||
|
||||
// Just need to the low 32 bits without the 111 trailer
|
||||
CmdKeriMSScramble(Descramble, &fc, &cardid, &raw2);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Descrambled MS - FC: " _GREEN_("%d") " Card: " _GREEN_("%d"), fc, cardid);
|
||||
//got a good demod
|
||||
uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
|
||||
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
||||
|
||||
if (invert) {
|
||||
PrintAndLogEx(INFO, "Had to Invert - probably KERI");
|
||||
for (size_t i = 0; i < size; i++)
|
||||
DemodBuffer[i] ^= 1;
|
||||
|
||||
raw1 = bytebits_to_byte(DemodBuffer, 32);
|
||||
raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
||||
|
||||
CmdPrintDemodBuff("x");
|
||||
}
|
||||
|
||||
//get internal id
|
||||
// uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32);
|
||||
// Due to the 3 sync bits being at the start of the capture
|
||||
// We can take the last 32bits as the internal ID.
|
||||
uint32_t ID = raw2;
|
||||
ID &= 0x7FFFFFFF;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "KERI - Internal ID: " _GREEN_("%u") ", Raw: %08X%08X", ID, raw1, raw2);
|
||||
|
||||
// Just need to the low 32 bits without the 111 trailer
|
||||
CmdKeriMSScramble(Descramble, &fc, &cardid, &raw2);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Descrambled MS - FC: " _GREEN_("%d") " Card: " _GREEN_("%d"), fc, cardid);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -185,7 +187,7 @@ static int CmdKeriRead(const char *Cmd) {
|
|||
|
||||
static int CmdKeriClone(const char *Cmd) {
|
||||
|
||||
bool q5 = false;
|
||||
bool q5 = false, em4305 = false;
|
||||
|
||||
uint8_t keritype[2] = {'i'}; // default to internalid
|
||||
int typeLen = 0;
|
||||
|
@ -207,7 +209,7 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf keri clone",
|
||||
"clone a KERI tag to a T55x7 or Q5/T5555 tag",
|
||||
"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");
|
||||
|
||||
|
@ -217,14 +219,23 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
arg_str0("t", "type", "<m|i>", "Type m - MS, i - Internal ID"),
|
||||
arg_int0(NULL, "fc", "<dec>", "Facility Code"),
|
||||
arg_int1(NULL, "id", "<dec>", "Keri ID"),
|
||||
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"),
|
||||
arg_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");
|
||||
em4305 = true;
|
||||
}
|
||||
|
||||
typeLen = sizeof(keritype);
|
||||
CLIGetStrWithReturn(ctx, 2, keritype, &typeLen);
|
||||
|
||||
|
@ -232,6 +243,11 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
cid = arg_get_int_def(ctx, 4, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (q5 && em4305) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// Setup card data/build internal id
|
||||
switch (keritype[0]) {
|
||||
case 'i' : // Internal ID
|
||||
|
@ -249,14 +265,20 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
// Prepare and write to card
|
||||
// 3 LSB is ONE
|
||||
uint64_t data = ((uint64_t)internalid << 3) + 7;
|
||||
PrintAndLogEx(INFO, "Preparing to clone KERI to " _YELLOW_("%s") " with Internal Id " _YELLOW_("%" PRIx32), (q5) ? "Q5/T5555" : "T55x7", internalid);
|
||||
PrintAndLogEx(INFO, "Preparing to clone KERI to " _YELLOW_("%s") " with Internal Id " _YELLOW_("%" PRIx32), cardtype, internalid);
|
||||
|
||||
blocks[1] = data >> 32;
|
||||
blocks[2] = data & 0xFFFFFFFF;
|
||||
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em4305) {
|
||||
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 keri read`") " to verify");
|
||||
return res;
|
||||
|
|
|
@ -186,7 +186,7 @@ static int usage_t55xx_dump(void) {
|
|||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " p <password> - OPTIONAL password 4bytes (8 hex symbols)");
|
||||
PrintAndLogEx(NORMAL, " o - OPTIONAL override, force pwd read despite danger to card");
|
||||
PrintAndLogEx(NORMAL, " f <prefix> - overide filename prefix (optional). Default is based on blk 0");
|
||||
PrintAndLogEx(NORMAL, " f <prefix> - override filename prefix (optional). Default is based on blk 0");
|
||||
print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
|
|
|
@ -10,23 +10,23 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlfvisa2000.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include <stdio.h>
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "common.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "ui.h"
|
||||
#include "graph.h"
|
||||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "protocols.h" // for T55xx config register definitions
|
||||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // write verify
|
||||
#include "cmdlfem4x05.h" //
|
||||
|
||||
#define BL0CK1 0x56495332
|
||||
|
||||
|
@ -39,10 +39,12 @@ static int usage_lf_visa2k_clone(void) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -180,18 +182,38 @@ static int CmdVisa2kClone(const char *Cmd) {
|
|||
|
||||
id = param_get32ex(Cmd, 0, 0, 10);
|
||||
|
||||
//Q5
|
||||
char cardtype[16] = {"T55x7"};
|
||||
// Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 1)) == 'q';
|
||||
if (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
|
||||
bool em4305 = tolower(param_getchar(Cmd, 1)) == 'e';
|
||||
if (em4305) {
|
||||
blocks[0] = EM4305_VISA2000_CONFIG_BLOCK;
|
||||
snprintf(cardtype, sizeof(cardtype) ,"EM4305/4469");
|
||||
}
|
||||
|
||||
if (q5 && em4305) {
|
||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
blocks[2] = id;
|
||||
blocks[3] = (visa_parity(id) << 4) | visa_chksum(id);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, (q5) ? "Q5/T5555" : "T55x7", id);
|
||||
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, cardtype, id);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res;
|
||||
if (em4305) {
|
||||
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 visa2000 read`") " to verify");
|
||||
return res;
|
||||
|
|
|
@ -791,14 +791,14 @@ static int CmdSmartReader(const char *Cmd) {
|
|||
static int CmdSmartSetClock(const char *Cmd) {
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
uint8_t clock1 = 0;
|
||||
uint8_t new_clk = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_sm_setclock();
|
||||
case 'c':
|
||||
clock1 = param_get8ex(Cmd, cmdp + 1, 2, 10);
|
||||
if (clock1 > 2)
|
||||
new_clk = param_get8ex(Cmd, cmdp + 1, 2, 10);
|
||||
if (new_clk > 2)
|
||||
errors = true;
|
||||
|
||||
cmdp += 2;
|
||||
|
@ -813,21 +813,26 @@ static int CmdSmartSetClock(const char *Cmd) {
|
|||
//Validations
|
||||
if (errors || cmdp == 0) return usage_sm_setclock();
|
||||
|
||||
struct {
|
||||
uint32_t new_clk;
|
||||
} PACKED payload;
|
||||
|
||||
payload.new_clk = new_clk;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_SMART_SETCLOCK, clock1, 0, 0, NULL, 0);
|
||||
SendCommandNG(CMD_SMART_SETCLOCK, (uint8_t*)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
if (!WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500)) {
|
||||
PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "smart card set clock failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
switch (clock1) {
|
||||
switch (new_clk) {
|
||||
case 0:
|
||||
PrintAndLogEx(SUCCESS, "Clock changed to 16MHz giving 10800 baudrate");
|
||||
break;
|
||||
|
|
|
@ -1106,7 +1106,7 @@ static int l_em4x05_read(lua_State *L) {
|
|||
|
||||
// get password
|
||||
const char *p_pwd = luaL_checkstring(L, 2);
|
||||
if (p_pwd == NULL || strlen(p_pwd) == 0 ) {
|
||||
if (p_pwd == NULL || strlen(p_pwd) == 0) {
|
||||
use_pwd = false;
|
||||
} else {
|
||||
if (strlen(p_pwd) != 8)
|
||||
|
@ -1121,7 +1121,7 @@ static int l_em4x05_read(lua_State *L) {
|
|||
PrintAndLogEx(DEBUG, " Pwd %08X", password);
|
||||
|
||||
uint32_t word = 0;
|
||||
int res = EM4x05ReadWord_ext(addr, password, use_pwd, &word);
|
||||
int res = em4x05_read_word_ext(addr, password, use_pwd, &word);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return returnToLuaWithError(L, "Failed to read EM4x05 data");
|
||||
}
|
||||
|
@ -1181,11 +1181,11 @@ static int l_em4x50_read(lua_State *L) {
|
|||
}
|
||||
|
||||
uint32_t word = (
|
||||
words[etd.address].byte[0] << 24 |
|
||||
words[etd.address].byte[1] << 16 |
|
||||
words[etd.address].byte[2] << 8 |
|
||||
words[etd.address].byte[3]
|
||||
);
|
||||
words[etd.address].byte[0] << 24 |
|
||||
words[etd.address].byte[1] << 16 |
|
||||
words[etd.address].byte[2] << 8 |
|
||||
words[etd.address].byte[3]
|
||||
);
|
||||
lua_pushinteger(L, word);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -177,13 +177,13 @@ Check column "offline" for their availability.
|
|||
|`hf 15 info `|N |`Tag information`
|
||||
|`hf 15 sniff `|N |`Sniff ISO15693 traffic`
|
||||
|`hf 15 raw `|N |`Send raw hex data to tag`
|
||||
|`hf 15 read `|N |`Read a block`
|
||||
|`hf 15 rdbl `|N |`Read a block`
|
||||
|`hf 15 reader `|N |`Act like an ISO15693 reader`
|
||||
|`hf 15 readmulti `|N |`Reads multiple Blocks`
|
||||
|`hf 15 restore `|N |`Restore from file to all memory pages of an ISO15693 tag`
|
||||
|`hf 15 samples `|N |`Acquire Samples as Reader (enables carrier, sends inquiry)`
|
||||
|`hf 15 sim `|N |`Fake an ISO15693 tag`
|
||||
|`hf 15 write `|N |`Write a block`
|
||||
|`hf 15 wrbl `|N |`Write a block`
|
||||
|`hf 15 findafi `|N |`Brute force AFI of an ISO15693 tag`
|
||||
|`hf 15 writeafi `|N |`Writes the AFI on an ISO15693 tag`
|
||||
|`hf 15 writedsfid `|N |`Writes the DSFID on an ISO15693 tag`
|
||||
|
@ -233,7 +233,7 @@ Check column "offline" for their availability.
|
|||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`hf fido help `|Y |`This help.`
|
||||
|`hf fido info `|N |`List ISO 14443A history`
|
||||
|`hf fido list `|N |`List ISO 14443A history`
|
||||
|`hf fido info `|N |`Info about FIDO tag.`
|
||||
|`hf fido reg `|N |`FIDO U2F Registration Message.`
|
||||
|`hf fido auth `|N |`FIDO U2F Authentication Message.`
|
||||
|
@ -256,10 +256,10 @@ 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 chk `|Y |`[options..] Check keys`
|
||||
|`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`
|
||||
|`hf iclass replay `|N |`<mac> Read Picopass / iCLASS tag via replay attack`
|
||||
|`hf iclass sim `|N |`[options..] Simulate iCLASS tag`
|
||||
|`hf iclass eload `|N |`[f <fn> ] Load Picopass / iCLASS dump file into emulator memory`
|
||||
|`hf iclass esave `|N |`[f <fn> ] Save emulator memory to file`
|
||||
|
@ -556,6 +556,19 @@ Check column "offline" for their availability.
|
|||
|`lf cotag read `|N |`Attempt to read and extract tag data`
|
||||
|
||||
|
||||
### lf destron
|
||||
|
||||
{ FDX-A Destron RFIDs... }
|
||||
|
||||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`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 clone `|N |`Clone Destron tag to T55x7`
|
||||
|`lf destron sim `|N |`Simulate Destron tag`
|
||||
|
||||
|
||||
### lf em
|
||||
|
||||
{ EM4X CHIPs & RFIDs... }
|
||||
|
@ -570,12 +583,14 @@ Check column "offline" for their availability.
|
|||
|`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 4x50_dump `|N |`dump EM4x50 tag`
|
||||
|`lf em 4x50_info `|N |`tag information EM4x50`
|
||||
|`lf em 4x50_write `|N |`write word data to EM4x50`
|
||||
|
|
|
@ -13,7 +13,8 @@ At the moment both are maintained because they don't perfectly overlap yet.
|
|||
|
||||
| Feature | Makefile | CMake | Remarks |
|
||||
|-----|---|---|---|
|
||||
| verbose | V=1 | VERBOSE=1 | |
|
||||
| verbose | `V=1` | `VERBOSE=1` | |
|
||||
| debug build | `DEBUG=1` | `-DCMAKE_BUILD_TYPE=Debug` | client only |
|
||||
| warnings management | yes (1) | **no** | (1) cf Makefile.defs |
|
||||
| extra GCC warnings | GCCEXTRA=1 | **no** | |
|
||||
| extra Clang warnings | CLANGEXTRA=1 | **no** | only on host |
|
||||
|
@ -32,7 +33,7 @@ At the moment both are maintained because they don't perfectly overlap yet.
|
|||
| bzip2 detection | **none** | find_package, Cross:gitclone | |
|
||||
| dep cliparser | in_deps | in_deps | |
|
||||
| dep hardnested | in_deps | in_deps | |
|
||||
| hardn arch autodetect | `uname -m` =? 86 or amd64; `$(CC) -E -mavx512f`? +AVX512` | `CMAKE_SYSTEM_PROCESSOR` =? x86 or x86_64 or i686 or AMD64 (1) | (1) currently it always includes AVX512 on Intel arch |
|
||||
| hardn arch autodetect | `uname -m` =? 86 or amd64; `$(CC) -E -mavx512f`? +`AVX512` | `CMAKE_SYSTEM_PROCESSOR` =? x86 or x86_64 or i686 or AMD64 (1) | (1) currently it always includes AVX512 on Intel arch |
|
||||
| `cpu_arch` | yes | **no/auto?** | e.g. `cpu_arch=generic` for cross-compilation
|
||||
| dep jansson | sys / in_deps | sys / in_deps | |
|
||||
| jansson detection | pc | pc/find* | |
|
||||
|
|
|
@ -500,6 +500,7 @@ typedef struct {
|
|||
#define CMD_LF_EM4X_READWORD 0x0218
|
||||
#define CMD_LF_EM4X_WRITEWORD 0x0219
|
||||
#define CMD_LF_EM4X_PROTECTWORD 0x021B
|
||||
#define CMD_LF_EM4X_BF 0x022A
|
||||
#define CMD_LF_IO_WATCH 0x021A
|
||||
#define CMD_LF_EM410X_WATCH 0x021C
|
||||
#define CMD_LF_EM4X50_INFO 0x0240
|
||||
|
|
|
@ -541,8 +541,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define T55XX_WRITE_TIMEOUT 1500
|
||||
|
||||
// em4x05 & em4x69 chip configuration register definitions
|
||||
#define EM4x05_GET_BITRATE(x) (((x & 0x3F)*2)+2)
|
||||
#define EM4x05_SET_BITRATE(x) ((x-2)/2)
|
||||
#define EM4x05_GET_BITRATE(x) ((((x) & 0x3F) * 2) + 2)
|
||||
#define EM4x05_SET_BITRATE(x) (((x) - 2) / 2)
|
||||
#define EM4x05_MODULATION_NRZ 0x00000000
|
||||
#define EM4x05_MODULATION_MANCHESTER 0x00000040
|
||||
#define EM4x05_MODULATION_BIPHASE 0x00000080
|
||||
|
@ -557,15 +557,15 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define EM4x05_PSK_RF_8 0x00000800
|
||||
#define EM4x05_MAXBLOCK_SHIFT 14
|
||||
#define EM4x05_FIRST_USER_BLOCK 5
|
||||
#define EM4x05_SET_NUM_BLOCKS(x) ((x+5-1)<<14) //# of blocks sent during default read mode
|
||||
#define EM4x05_GET_NUM_BLOCKS(x) (((x>>14) & 0xF)-5+1)
|
||||
#define EM4x05_READ_LOGIN_REQ 1<<18
|
||||
#define EM4x05_READ_HK_LOGIN_REQ 1<<19
|
||||
#define EM4x05_WRITE_LOGIN_REQ 1<<20
|
||||
#define EM4x05_WRITE_HK_LOGIN_REQ 1<<21
|
||||
#define EM4x05_READ_AFTER_WRITE 1<<22
|
||||
#define EM4x05_DISABLE_ALLOWED 1<<23
|
||||
#define EM4x05_READER_TALK_FIRST 1<<24
|
||||
#define EM4x05_SET_NUM_BLOCKS(x) (( (x) + 4) << 14) //# of blocks sent during default read mode
|
||||
#define EM4x05_GET_NUM_BLOCKS(x) ((( (x) >> 14) & 0xF) - 4)
|
||||
#define EM4x05_READ_LOGIN_REQ (1 << 18)
|
||||
#define EM4x05_READ_HK_LOGIN_REQ (1 << 19)
|
||||
#define EM4x05_WRITE_LOGIN_REQ (1 << 20)
|
||||
#define EM4x05_WRITE_HK_LOGIN_REQ (1 << 21)
|
||||
#define EM4x05_READ_AFTER_WRITE (1 << 22)
|
||||
#define EM4x05_DISABLE_ALLOWED (1 << 23)
|
||||
#define EM4x05_READER_TALK_FIRST (1 << 24)
|
||||
|
||||
|
||||
// FeliCa protocol
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue