mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
Merge branch 'master' into dev_4x50_standalone
update
This commit is contained in:
commit
ac0ef23d5e
79 changed files with 2201 additions and 1396 deletions
|
@ -4,6 +4,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
- Added `LF_THAREXDE` standalone mode which simulates and reads EM4x50 cards (@tharexde)
|
- Added `LF_THAREXDE` standalone mode which simulates and reads EM4x50 cards (@tharexde)
|
||||||
|
- Added `hf jooki` commands (@iceman1001)
|
||||||
- Changed `wiegand encode` - format param is now optional, w/o it will try encode all formats (@iceman1001)
|
- Changed `wiegand encode` - format param is now optional, w/o it will try encode all formats (@iceman1001)
|
||||||
- Fix cppchecker warnings (@iceman1001)
|
- Fix cppchecker warnings (@iceman1001)
|
||||||
- Added `trace list -t mf` - now can use external dictionary keys file
|
- Added `trace list -t mf` - now can use external dictionary keys file
|
||||||
|
@ -132,6 +133,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Change, use system Whereami library if available (@doegox)
|
- Change, use system Whereami library if available (@doegox)
|
||||||
- Change, use system Zlib library if available (@doegox)
|
- Change, use system Zlib library if available (@doegox)
|
||||||
- Fix release version information (@doegox)
|
- Fix release version information (@doegox)
|
||||||
|
- Fix `lf gallagher read` - now correctly decodes card data
|
||||||
|
- Add support to `lf gallagher clone` and `lf gallagher sim` for writing specific card region, facility, card & issue numbers (@DarkMatterMatt)
|
||||||
|
|
||||||
## [ice coffee.4.9237][2020-05-21]
|
## [ice coffee.4.9237][2020-05-21]
|
||||||
- Updated documentation (@doegox, @iceman1001)
|
- Updated documentation (@doegox, @iceman1001)
|
||||||
|
|
|
@ -191,7 +191,7 @@ void RunMod(void) {
|
||||||
read_successful = false;
|
read_successful = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on hf_mfu_dumptoemulator
|
// We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on data_mfu_bin2eml
|
||||||
// When converting a bin, it's almost all 0 other than one 0x0F byte, and functionality seems to be unaffected if that byte is set to 0x00.
|
// When converting a bin, it's almost all 0 other than one 0x0F byte, and functionality seems to be unaffected if that byte is set to 0x00.
|
||||||
emlSetMem_xt(dataout, 14 + i, 1, 4);
|
emlSetMem_xt(dataout, 14 + i, 1, 4);
|
||||||
Dbhexdump(4, dataout, 0);
|
Dbhexdump(4, dataout, 0);
|
||||||
|
|
|
@ -52,8 +52,8 @@ static void fill_buff(uint8_t bit) {
|
||||||
static void construct_EM410x_emul(uint64_t id) {
|
static void construct_EM410x_emul(uint64_t id) {
|
||||||
|
|
||||||
int i, j;
|
int i, j;
|
||||||
int binary[4] = {0,0,0,0};
|
int binary[4] = {0, 0, 0, 0};
|
||||||
int parity[4] = {0,0,0,0};
|
int parity[4] = {0, 0, 0, 0};
|
||||||
buflen = 0;
|
buflen = 0;
|
||||||
|
|
||||||
for (i = 0; i < 9; i++)
|
for (i = 0; i < 9; i++)
|
||||||
|
|
|
@ -100,8 +100,8 @@ static void fill_buff(uint8_t bit) {
|
||||||
|
|
||||||
static void construct_EM410x_emul(uint64_t id) {
|
static void construct_EM410x_emul(uint64_t id) {
|
||||||
int i, j;
|
int i, j;
|
||||||
int binary[4] = {0,0,0,0};
|
int binary[4] = {0, 0, 0, 0};
|
||||||
int parity[4] = {0,0,0,0};
|
int parity[4] = {0, 0, 0, 0};
|
||||||
buflen = 0;
|
buflen = 0;
|
||||||
|
|
||||||
for (i = 0; i < 9; i++)
|
for (i = 0; i < 9; i++)
|
||||||
|
|
|
@ -67,8 +67,8 @@ static void fill_buff(uint8_t bit) {
|
||||||
static void construct_EM410x_emul(uint64_t id) {
|
static void construct_EM410x_emul(uint64_t id) {
|
||||||
|
|
||||||
int i, j;
|
int i, j;
|
||||||
int binary[4] = {0,0,0,0};
|
int binary[4] = {0, 0, 0, 0};
|
||||||
int parity[4] = {0,0,0,0};
|
int parity[4] = {0, 0, 0, 0};
|
||||||
buflen = 0;
|
buflen = 0;
|
||||||
|
|
||||||
for (i = 0; i < 9; i++)
|
for (i = 0; i < 9; i++)
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
#include "crc16.h"
|
#include "crc16.h"
|
||||||
|
|
||||||
#ifdef WITH_LCD
|
#ifdef WITH_LCD
|
||||||
#include "LCD.h"
|
#include "LCD_disabled.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_SMARTCARD
|
#ifdef WITH_SMARTCARD
|
||||||
|
|
|
@ -1885,7 +1885,7 @@ void iClass_WriteBlock(uint8_t *msg) {
|
||||||
res = false;
|
res = false;
|
||||||
switch_off();
|
switch_off();
|
||||||
if (payload->req.send_reply)
|
if (payload->req.send_reply)
|
||||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t*)&res, sizeof(uint8_t));
|
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -1927,7 +1927,7 @@ out:
|
||||||
switch_off();
|
switch_off();
|
||||||
|
|
||||||
if (payload->req.send_reply)
|
if (payload->req.send_reply)
|
||||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t*)&res, sizeof(uint8_t));
|
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
void iClass_Restore(iclass_restore_req_t *msg) {
|
void iClass_Restore(iclass_restore_req_t *msg) {
|
||||||
|
|
|
@ -916,18 +916,25 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) {
|
||||||
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||||
(void)b;
|
(void)b;
|
||||||
|
|
||||||
uint16_t check = 0;
|
uint8_t flip = 0;
|
||||||
|
uint16_t checker = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (check == 4000) {
|
WDT_HIT();
|
||||||
// if (BUTTON_PRESS() || data_available())
|
if (flip == 2) {
|
||||||
|
if (data_available())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
flip = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checker >= 4000) {
|
||||||
if (BUTTON_PRESS())
|
if (BUTTON_PRESS())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
check = 0;
|
flip++;
|
||||||
WDT_HIT();
|
checker = 0;
|
||||||
}
|
}
|
||||||
++check;
|
++checker;
|
||||||
|
|
||||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||||
b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||||
|
@ -1335,7 +1342,6 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data, uint8_t
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
//for (;;) {
|
|
||||||
bool finished = false;
|
bool finished = false;
|
||||||
bool button_pushed = BUTTON_PRESS();
|
bool button_pushed = BUTTON_PRESS();
|
||||||
while (!button_pushed && !finished) {
|
while (!button_pushed && !finished) {
|
||||||
|
|
|
@ -1009,7 +1009,7 @@ void CmdFSKsimTAGEx(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t cl
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
Dbprintf("Simulating with fcHigh: %d, fcLow: %d, clk: %d, STT: %d, n: %d", fchigh, fclow, clk, separator, n);
|
Dbprintf("FSK simulating with rf/%d, fc high %d, fc low %d, STT %d, n %d", clk, fchigh, fclow, separator, n);
|
||||||
|
|
||||||
if (ledcontrol) LED_A_ON();
|
if (ledcontrol) LED_A_ON();
|
||||||
SimulateTagLowFrequencyEx(n, 0, ledcontrol, numcycles);
|
SimulateTagLowFrequencyEx(n, 0, ledcontrol, numcycles);
|
||||||
|
@ -1122,10 +1122,10 @@ void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t c
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
Dbprintf("Simulating with clk: %d, invert: %d, encoding: %s (%d), separator: %d, n: %d"
|
Dbprintf("ASK simulating with rf/%d, invert %d, encoding %s (%d), separator %d, n %d"
|
||||||
, clk
|
, clk
|
||||||
, invert
|
, invert
|
||||||
, (encoding == 2) ? "BI" : (encoding == 1) ? "ASK" : "RAW"
|
, (encoding == 2) ? "ASK/BI" : (encoding == 1) ? "ASK/MAN" : "RAW/MAN"
|
||||||
, encoding
|
, encoding
|
||||||
, separator
|
, separator
|
||||||
, n
|
, n
|
||||||
|
@ -1176,7 +1176,7 @@ void CmdPSKsimTAG(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, u
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
Dbprintf("Simulating with Carrier: %d, clk: %d, invert: %d, n: %d", carrier, clk, invert, n);
|
Dbprintf("PSK simulating with rf/%d, fc/%d, invert %d, n %d", clk, carrier, invert, n);
|
||||||
|
|
||||||
if (ledcontrol) LED_A_ON();
|
if (ledcontrol) LED_A_ON();
|
||||||
SimulateTagLowFrequency(n, 0, ledcontrol);
|
SimulateTagLowFrequency(n, 0, ledcontrol);
|
||||||
|
@ -1220,7 +1220,7 @@ void CmdNRZsimTAG(uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size,
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
Dbprintf("Simulating with clk: %d, invert: %d, separator: %d, n: %d"
|
Dbprintf("NRZ simulating with rf/%d, invert %d, separator %d, n %d"
|
||||||
, clk
|
, clk
|
||||||
, invert
|
, invert
|
||||||
, separator
|
, separator
|
||||||
|
@ -1251,21 +1251,14 @@ int lf_hid_watch(int findone, uint32_t *high, uint32_t *low) {
|
||||||
BigBuf_Clear_keep_EM();
|
BigBuf_Clear_keep_EM();
|
||||||
|
|
||||||
int res = PM3_SUCCESS;
|
int res = PM3_SUCCESS;
|
||||||
uint16_t interval = 0;
|
for (;;) {
|
||||||
while (BUTTON_PRESS() == false) {
|
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
// cancel w usb command.
|
if (data_available() || BUTTON_PRESS()) {
|
||||||
if (interval == 4000) {
|
|
||||||
if (data_available()) {
|
|
||||||
res = PM3_EOPABORTED;
|
res = PM3_EOPABORTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
interval = 0;
|
|
||||||
} else {
|
|
||||||
interval++;
|
|
||||||
}
|
|
||||||
|
|
||||||
DoAcquisition_default(-1, false);
|
DoAcquisition_default(-1, false);
|
||||||
|
|
||||||
|
@ -1360,21 +1353,14 @@ int lf_awid_watch(int findone, uint32_t *high, uint32_t *low) {
|
||||||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||||
|
|
||||||
int res = PM3_SUCCESS;
|
int res = PM3_SUCCESS;
|
||||||
uint16_t interval = 0;
|
for (;;) {
|
||||||
while (BUTTON_PRESS() == false) {
|
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
// cancel w usb command.
|
if (data_available() || BUTTON_PRESS()) {
|
||||||
if (interval == 4000) {
|
|
||||||
if (data_available()) {
|
|
||||||
res = PM3_EOPABORTED;
|
res = PM3_EOPABORTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
interval = 0;
|
|
||||||
} else {
|
|
||||||
interval++;
|
|
||||||
}
|
|
||||||
|
|
||||||
DoAcquisition_default(-1, false);
|
DoAcquisition_default(-1, false);
|
||||||
// FSK demodulator
|
// FSK demodulator
|
||||||
|
@ -1465,20 +1451,13 @@ int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low) {
|
||||||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||||
|
|
||||||
int res = PM3_SUCCESS;
|
int res = PM3_SUCCESS;
|
||||||
uint16_t interval = 0;
|
for (;;) {
|
||||||
while (BUTTON_PRESS() == false) {
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
// cancel w usb command.
|
if (data_available() || BUTTON_PRESS()) {
|
||||||
if (interval == 4000) {
|
|
||||||
if (data_available()) {
|
|
||||||
res = PM3_EOPABORTED;
|
res = PM3_EOPABORTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
interval = 0;
|
|
||||||
} else {
|
|
||||||
interval++;
|
|
||||||
}
|
|
||||||
|
|
||||||
DoAcquisition_default(-1, false);
|
DoAcquisition_default(-1, false);
|
||||||
|
|
||||||
|
@ -1541,21 +1520,14 @@ int lf_io_watch(int findone, uint32_t *high, uint32_t *low) {
|
||||||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||||
|
|
||||||
int res = PM3_SUCCESS;
|
int res = PM3_SUCCESS;
|
||||||
uint16_t interval = 0;
|
for (;;) {
|
||||||
while (BUTTON_PRESS() == false) {
|
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
// cancel w usb command.
|
if (data_available() || BUTTON_PRESS()) {
|
||||||
if (interval == 4000) {
|
|
||||||
if (data_available()) {
|
|
||||||
res = PM3_EOPABORTED;
|
res = PM3_EOPABORTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
interval = 0;
|
|
||||||
} else {
|
|
||||||
interval++;
|
|
||||||
}
|
|
||||||
|
|
||||||
DoAcquisition_default(-1, false);
|
DoAcquisition_default(-1, false);
|
||||||
|
|
||||||
|
|
|
@ -73,11 +73,11 @@ void printSamples(void) {
|
||||||
void setSamplingConfig(sample_config *sc) {
|
void setSamplingConfig(sample_config *sc) {
|
||||||
|
|
||||||
// decimation (1-8) how many bits of adc sample value to save
|
// decimation (1-8) how many bits of adc sample value to save
|
||||||
if (sc->decimation > 0 && sc->decimation < 8)
|
if (sc->decimation > 0 && sc->decimation < 9)
|
||||||
config.decimation = sc->decimation;
|
config.decimation = sc->decimation;
|
||||||
|
|
||||||
// bits per sample (1-8)
|
// bits per sample (1-8)
|
||||||
if (sc->bits_per_sample > 0 && sc->bits_per_sample < 8)
|
if (sc->bits_per_sample > 0 && sc->bits_per_sample < 9)
|
||||||
config.bits_per_sample = sc->bits_per_sample;
|
config.bits_per_sample = sc->bits_per_sample;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -242,6 +242,7 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/cmdhffelica.c
|
${PM3_ROOT}/client/src/cmdhffelica.c
|
||||||
${PM3_ROOT}/client/src/cmdhffido.c
|
${PM3_ROOT}/client/src/cmdhffido.c
|
||||||
${PM3_ROOT}/client/src/cmdhficlass.c
|
${PM3_ROOT}/client/src/cmdhficlass.c
|
||||||
|
${PM3_ROOT}/client/src/cmdhfjooki.c
|
||||||
${PM3_ROOT}/client/src/cmdhflegic.c
|
${PM3_ROOT}/client/src/cmdhflegic.c
|
||||||
${PM3_ROOT}/client/src/cmdhflist.c
|
${PM3_ROOT}/client/src/cmdhflist.c
|
||||||
${PM3_ROOT}/client/src/cmdhflto.c
|
${PM3_ROOT}/client/src/cmdhflto.c
|
||||||
|
|
|
@ -474,6 +474,7 @@ SRCS = aiddesfire.c \
|
||||||
cmdhffido.c \
|
cmdhffido.c \
|
||||||
cmdhficlass.c \
|
cmdhficlass.c \
|
||||||
cmdhflegic.c \
|
cmdhflegic.c \
|
||||||
|
cmdhfjooki.c \
|
||||||
cmdhflist.c \
|
cmdhflist.c \
|
||||||
cmdhflto.c \
|
cmdhflto.c \
|
||||||
cmdhfmf.c \
|
cmdhfmf.c \
|
||||||
|
|
|
@ -1284,3 +1284,12 @@ AABAFFCC7612
|
||||||
#
|
#
|
||||||
534F4C415249
|
534F4C415249
|
||||||
534f4c303232
|
534f4c303232
|
||||||
|
#
|
||||||
|
# Nespresso, smart card
|
||||||
|
# key-gen algo, these keys are for one card
|
||||||
|
ff9a84635bd2
|
||||||
|
6f30126ee7e4
|
||||||
|
6039abb101bb
|
||||||
|
f1a1239a4487
|
||||||
|
#
|
||||||
|
b882fd4a9f78
|
||||||
|
|
|
@ -6,7 +6,7 @@ local ansicolors = require('ansicolors')
|
||||||
|
|
||||||
copyright = ''
|
copyright = ''
|
||||||
author = 'Martin Holst Swende'
|
author = 'Martin Holst Swende'
|
||||||
version = 'v1.0.2'
|
version = 'v1.0.3'
|
||||||
desc = [[
|
desc = [[
|
||||||
This script takes a dumpfile from 'hf mf dump' and converts it to a format that can be used
|
This script takes a dumpfile from 'hf mf dump' and converts it to a format that can be used
|
||||||
by the emulator
|
by the emulator
|
||||||
|
@ -46,7 +46,7 @@ end
|
||||||
---
|
---
|
||||||
-- This is only meant to be used when errors occur
|
-- This is only meant to be used when errors occur
|
||||||
local function oops(err)
|
local function oops(err)
|
||||||
print('ERROR:', err)
|
print('[!!] ERROR:', err)
|
||||||
core.clearCommandBuffer()
|
core.clearCommandBuffer()
|
||||||
return nil, err
|
return nil, err
|
||||||
end
|
end
|
||||||
|
@ -134,7 +134,7 @@ local function main(args)
|
||||||
|
|
||||||
outfile:write(dumpdata:lower())
|
outfile:write(dumpdata:lower())
|
||||||
io.close(outfile)
|
io.close(outfile)
|
||||||
print(('Wrote an emulator-dump to the file %s'):format(output))
|
print(('[+] Wrote an emulator-dump to the file %s'):format(output))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ local ansicolors = require('ansicolors')
|
||||||
|
|
||||||
copyright = ''
|
copyright = ''
|
||||||
author = 'Martin Holst Swende'
|
author = 'Martin Holst Swende'
|
||||||
version = 'v1.0.2'
|
version = 'v1.0.3'
|
||||||
desc =[[
|
desc =[[
|
||||||
This script takes a dumpfile and produces a html based dump, which is a
|
This script takes a dumpfile and produces a html based dump, which is a
|
||||||
bit more easily analyzed.
|
bit more easily analyzed.
|
||||||
|
@ -45,7 +45,7 @@ end
|
||||||
---
|
---
|
||||||
-- This is only meant to be used when errors occur
|
-- This is only meant to be used when errors occur
|
||||||
local function oops(err)
|
local function oops(err)
|
||||||
print('ERROR:', err)
|
print('[!!] ERROR:', err)
|
||||||
core.clearCommandBuffer()
|
core.clearCommandBuffer()
|
||||||
return nil, err
|
return nil, err
|
||||||
end
|
end
|
||||||
|
@ -76,7 +76,7 @@ local function main(args)
|
||||||
local filename, err = dumplib.convert_bin_to_html(input,output, 16)
|
local filename, err = dumplib.convert_bin_to_html(input,output, 16)
|
||||||
if err then return oops(err) end
|
if err then return oops(err) end
|
||||||
|
|
||||||
print(('Wrote a HTML dump to the file %s'):format(filename))
|
print(('[+] Wrote a HTML dump to the file %s'):format(filename))
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|
|
@ -5,7 +5,7 @@ local ansicolors = require('ansicolors')
|
||||||
|
|
||||||
copyright = ''
|
copyright = ''
|
||||||
author = 'Iceman'
|
author = 'Iceman'
|
||||||
version = 'v1.0.2'
|
version = 'v1.0.3'
|
||||||
desc =[[
|
desc =[[
|
||||||
This script takes an dumpfile in EML (ASCII) format and converts it to the PM3 dumpbin file to be used with `hf mf restore`
|
This script takes an dumpfile in EML (ASCII) format and converts it to the PM3 dumpbin file to be used with `hf mf restore`
|
||||||
]]
|
]]
|
||||||
|
@ -40,7 +40,7 @@ end
|
||||||
---
|
---
|
||||||
-- This is only meant to be used when errors occur
|
-- This is only meant to be used when errors occur
|
||||||
local function oops(err)
|
local function oops(err)
|
||||||
print('ERROR:', err)
|
print('[!!] ERROR:', err)
|
||||||
core.clearCommandBuffer()
|
core.clearCommandBuffer()
|
||||||
return nil, err
|
return nil, err
|
||||||
end
|
end
|
||||||
|
@ -82,7 +82,7 @@ local function main(args)
|
||||||
local filename, err = dumplib.convert_eml_to_bin(input,output)
|
local filename, err = dumplib.convert_eml_to_bin(input,output)
|
||||||
if err then return oops(err) end
|
if err then return oops(err) end
|
||||||
|
|
||||||
ExitMsg(('Wrote a BIN dump to the file %s'):format(filename))
|
ExitMsg(('[+] Wrote a BIN dump to the file %s'):format(filename))
|
||||||
end
|
end
|
||||||
|
|
||||||
main(args)
|
main(args)
|
||||||
|
|
|
@ -7,7 +7,7 @@ local ansicolors = require('ansicolors')
|
||||||
|
|
||||||
copyright = ''
|
copyright = ''
|
||||||
author = 'Martin Holst Swende'
|
author = 'Martin Holst Swende'
|
||||||
version = 'v1.0.2'
|
version = 'v1.0.3'
|
||||||
desc = [[
|
desc = [[
|
||||||
This script takes a dumpfile on EML (ASCII) format and produces a html based dump, which is a
|
This script takes a dumpfile on EML (ASCII) format and produces a html based dump, which is a
|
||||||
bit more easily analyzed.
|
bit more easily analyzed.
|
||||||
|
@ -44,7 +44,7 @@ end
|
||||||
---
|
---
|
||||||
-- This is only meant to be used when errors occur
|
-- This is only meant to be used when errors occur
|
||||||
local function oops(err)
|
local function oops(err)
|
||||||
print('ERROR:', err)
|
print('[!!] ERROR:', err)
|
||||||
core.clearCommandBuffer()
|
core.clearCommandBuffer()
|
||||||
return nil, err
|
return nil, err
|
||||||
end
|
end
|
||||||
|
@ -75,7 +75,7 @@ local function main(args)
|
||||||
local filename, err = dumplib.convert_eml_to_html(input,output)
|
local filename, err = dumplib.convert_eml_to_html(input,output)
|
||||||
if err then return oops(err) end
|
if err then return oops(err) end
|
||||||
|
|
||||||
print(('Wrote a HTML dump to the file %s'):format(filename))
|
print(('[+] Wrote a HTML dump to the file %s'):format(filename))
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|
|
@ -6,16 +6,16 @@ local ansicolors = require('ansicolors')
|
||||||
|
|
||||||
copyright = ''
|
copyright = ''
|
||||||
author = "Martin Holst Swende \n @Marshmellow \n @iceman"
|
author = "Martin Holst Swende \n @Marshmellow \n @iceman"
|
||||||
version = 'v1.0.2'
|
version = 'v1.0.4'
|
||||||
desc =[[
|
desc =[[
|
||||||
This script takes a dumpfile from 'hf mfu dump' and converts it to a format that can be used
|
This script takes a dumpfile from 'hf mfu dump' and converts it to a format that can be used
|
||||||
by the emulator
|
by the emulator
|
||||||
]]
|
]]
|
||||||
example = [[
|
example = [[
|
||||||
script run hf_mfu_dumptoemulator -i dumpdata-foobar.bin
|
script run data_mfu_bin2eml -i dumpdata-foobar.bin
|
||||||
]]
|
]]
|
||||||
usage = [[
|
usage = [[
|
||||||
script run hf_mfu_dumptoemulator [-i <file>] [-o <file>]
|
script run data_mfu_bin2eml [-i <file>] [-o <file>]
|
||||||
]]
|
]]
|
||||||
arguments = [[
|
arguments = [[
|
||||||
-h This help
|
-h This help
|
||||||
|
@ -43,7 +43,7 @@ end
|
||||||
---
|
---
|
||||||
-- This is only meant to be used when errors occur
|
-- This is only meant to be used when errors occur
|
||||||
local function oops(err)
|
local function oops(err)
|
||||||
print('ERROR:', err)
|
print('[!!] ERROR:', err)
|
||||||
core.clearCommandBuffer()
|
core.clearCommandBuffer()
|
||||||
return nil, err
|
return nil, err
|
||||||
end
|
end
|
||||||
|
@ -133,7 +133,7 @@ local function main(args)
|
||||||
|
|
||||||
outfile:write(dumpdata:lower())
|
outfile:write(dumpdata:lower())
|
||||||
io.close(outfile)
|
io.close(outfile)
|
||||||
print(('Wrote an emulator-dump to the file %s'):format(output))
|
print(('[+] Wrote an emulator-dump to the file %s'):format(output))
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
|
@ -4749,14 +4749,14 @@
|
||||||
"application": "Security and Access Control",
|
"application": "Security and Access Control",
|
||||||
"company": "PEC (New Zealand) Ltd.",
|
"company": "PEC (New Zealand) Ltd.",
|
||||||
"mad": "0x4811",
|
"mad": "0x4811",
|
||||||
"service_provider": "Cardax",
|
"service_provider": "Cardax / Gallagher",
|
||||||
"system_integrator": ""
|
"system_integrator": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"application": "Security and Access Control",
|
"application": "Security and Access Control",
|
||||||
"company": "PEC (New Zealand) Ltd.",
|
"company": "PEC (New Zealand) Ltd.",
|
||||||
"mad": "0x4812",
|
"mad": "0x4812",
|
||||||
"service_provider": "Cardax",
|
"service_provider": "Cardax / Gallagher",
|
||||||
"system_integrator": ""
|
"system_integrator": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h> // tolower
|
#include <ctype.h> // tolower
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <inttypes.h> // PRIx64 macro
|
||||||
#include "commonutil.h" // reflect...
|
#include "commonutil.h" // reflect...
|
||||||
#include "comms.h" // clearCommandBuffer
|
#include "comms.h" // clearCommandBuffer
|
||||||
#include "cmdparser.h" // command_t
|
#include "cmdparser.h" // command_t
|
||||||
|
@ -550,6 +551,13 @@ static int CmdAnalyseA(const char *Cmd) {
|
||||||
PrintAndLogEx(FAILED, "Error parsing bytes");
|
PrintAndLogEx(FAILED, "Error parsing bytes");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t key = 0;
|
||||||
|
res = mfc_algo_touch_one(data, 0, 0, &key);
|
||||||
|
if (res == PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(SUCCESS, "KEY A | %012" PRIx64, key);
|
||||||
|
}
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "cmdhfemrtd.h" // eMRTD
|
#include "cmdhfemrtd.h" // eMRTD
|
||||||
#include "cmdhflegic.h" // LEGIC
|
#include "cmdhflegic.h" // LEGIC
|
||||||
#include "cmdhficlass.h" // ICLASS
|
#include "cmdhficlass.h" // ICLASS
|
||||||
|
#include "cmdhfjooki.h" // MFU based Jooki
|
||||||
#include "cmdhfmf.h" // CLASSIC
|
#include "cmdhfmf.h" // CLASSIC
|
||||||
#include "cmdhfmfu.h" // ULTRALIGHT/NTAG etc
|
#include "cmdhfmfu.h" // ULTRALIGHT/NTAG etc
|
||||||
#include "cmdhfmfp.h" // Mifare Plus
|
#include "cmdhfmfp.h" // Mifare Plus
|
||||||
|
@ -397,6 +398,7 @@ static command_t CommandTable[] = {
|
||||||
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
|
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
|
||||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
||||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||||
|
{"jooki", CmdHF_Jooki, AlwaysAvailable, "{ Jooki RFIDs... }"},
|
||||||
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
|
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
|
||||||
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
|
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
|
||||||
{"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"},
|
{"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"},
|
||||||
|
|
|
@ -1422,7 +1422,8 @@ typedef enum {
|
||||||
MTDESFIRE = 4,
|
MTDESFIRE = 4,
|
||||||
MTPLUS = 8,
|
MTPLUS = 8,
|
||||||
MTULTRALIGHT = 16,
|
MTULTRALIGHT = 16,
|
||||||
MTOTHER = 32
|
HID_SEOS = 32,
|
||||||
|
MTOTHER = 64
|
||||||
} nxp_mifare_type_t;
|
} nxp_mifare_type_t;
|
||||||
|
|
||||||
// Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1
|
// Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1
|
||||||
|
@ -1525,12 +1526,18 @@ static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) {
|
||||||
type |= MTPLUS;
|
type |= MTPLUS;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
if ((atqa & 0x0001) == 0x0001) {
|
||||||
|
printTag("HID SEOS (smartmx / javacard)");
|
||||||
|
type |= HID_SEOS;
|
||||||
|
} else {
|
||||||
printTag("MIFARE Plus EV1 2K/4K in SL3");
|
printTag("MIFARE Plus EV1 2K/4K in SL3");
|
||||||
printTag("MIFARE Plus S 2K/4K in SL3");
|
printTag("MIFARE Plus S 2K/4K in SL3");
|
||||||
printTag("MIFARE Plus X 2K/4K in SL3");
|
printTag("MIFARE Plus X 2K/4K in SL3");
|
||||||
printTag("MIFARE Plus SE 1K");
|
printTag("MIFARE Plus SE 1K");
|
||||||
type |= MTPLUS;
|
type |= MTPLUS;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
printTag("NTAG 4xx");
|
printTag("NTAG 4xx");
|
||||||
type |= MTDESFIRE;
|
type |= MTDESFIRE;
|
||||||
|
@ -1634,6 +1641,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
bool isMifarePlus = false;
|
bool isMifarePlus = false;
|
||||||
bool isMifareUltralight = false;
|
bool isMifareUltralight = false;
|
||||||
bool isST = false;
|
bool isST = false;
|
||||||
|
bool isEMV = false;
|
||||||
int nxptype = MTNONE;
|
int nxptype = MTNONE;
|
||||||
|
|
||||||
if (card.uidlen <= 4) {
|
if (card.uidlen <= 4) {
|
||||||
|
@ -2048,6 +2056,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
|
|
||||||
if (verbose) PrintAndLogEx(SUCCESS, "----------------------------------------------------");
|
if (verbose) PrintAndLogEx(SUCCESS, "----------------------------------------------------");
|
||||||
found = true;
|
found = true;
|
||||||
|
isEMV = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2097,15 +2106,18 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
if (isMifareUltralight)
|
if (isMifareUltralight)
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu info`"));
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu info`"));
|
||||||
|
|
||||||
if (isMifarePlus && isMagic == 0)
|
if (isMifarePlus && isMagic == 0 && isEMV == false)
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfp info`"));
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfp info`"));
|
||||||
|
|
||||||
if (isMifareDESFire && isMagic == 0)
|
if (isMifareDESFire && isMagic == 0 && isEMV == false)
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`"));
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`"));
|
||||||
|
|
||||||
if (isST)
|
if (isST)
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf st info`"));
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf st info`"));
|
||||||
|
|
||||||
|
if (isEMV)
|
||||||
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`emv search -s`"));
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
DropField();
|
DropField();
|
||||||
return select_status;
|
return select_status;
|
||||||
|
@ -2309,7 +2321,7 @@ static command_t CommandTable[] = {
|
||||||
{"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
|
{"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
|
||||||
{"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"},
|
{"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"},
|
||||||
{"config", CmdHf14AConfig, IfPm3Iso14443a, "Configure 14a settings (use with caution)"},
|
{"config", CmdHf14AConfig, IfPm3Iso14443a, "Configure 14a settings (use with caution)"},
|
||||||
{"apdufind", CmdHf14AFindapdu, IfPm3Iso14443a, "Enuerate APDUs - CLA/INS/P1P2"},
|
{"apdufind", CmdHf14AFindapdu, IfPm3Iso14443a, "Enumerate APDUs - CLA/INS/P1P2"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1338,19 +1338,26 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) {
|
||||||
|
|
||||||
// Determine and print the document type
|
// Determine and print the document type
|
||||||
if (mrz[0] == 'I' && mrz[1] == 'P') {
|
if (mrz[0] == 'I' && mrz[1] == 'P') {
|
||||||
td_variant = 1;
|
|
||||||
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport Card"));
|
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport Card"));
|
||||||
} else if (mrz[0] == 'I') {
|
} else if (mrz[0] == 'I') {
|
||||||
td_variant = 1;
|
|
||||||
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("ID Card"));
|
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("ID Card"));
|
||||||
} else if (mrz[0] == 'P') {
|
} else if (mrz[0] == 'P') {
|
||||||
td_variant = 3;
|
|
||||||
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport"));
|
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport"));
|
||||||
|
} else if (mrz[0] == 'A') {
|
||||||
|
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("German Residency Permit"));
|
||||||
} else {
|
} else {
|
||||||
td_variant = 1;
|
|
||||||
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Unknown"));
|
PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Unknown"));
|
||||||
PrintAndLogEx(INFO, "Assuming ID-style MRZ.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mrzlen == 90) {
|
||||||
|
td_variant = 1;
|
||||||
|
} else if (mrzlen == 88) {
|
||||||
|
td_variant = 3;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(ERR, "MRZ length (%zu) is wrong.", mrzlen);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant);
|
PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant);
|
||||||
|
|
||||||
// Print the MRZ
|
// Print the MRZ
|
||||||
|
|
518
client/src/cmdhfjooki.c
Normal file
518
client/src/cmdhfjooki.c
Normal file
|
@ -0,0 +1,518 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Ultralight Code (c) 2021 Iceman
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// High frequency MIFARE ULTRALIGHT / Jooki commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#include "cmdhfjooki.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h> // memset
|
||||||
|
#include "commonutil.h" // ARRAYLEN
|
||||||
|
#include "ui.h" // PrintAndLog
|
||||||
|
#include "cmdparser.h"
|
||||||
|
#include "generator.h"
|
||||||
|
#include "base64.h"
|
||||||
|
#include "mifare/ndef.h" // print decode ndef
|
||||||
|
#include "mifare/mifarehost.h" // mfemlsetmem_xt
|
||||||
|
#include "cliparser.h"
|
||||||
|
#include "cmdhfmfu.h"
|
||||||
|
#include "cmdmain.h"
|
||||||
|
#include "fileutils.h" // convert_mfu..
|
||||||
|
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t uid[7];
|
||||||
|
const char b64[17];
|
||||||
|
uint8_t tagtype;
|
||||||
|
} PACKED jooki_t;
|
||||||
|
|
||||||
|
// sample set for selftest.
|
||||||
|
jooki_t jooks[] = {
|
||||||
|
{ {0x04, 0xDA, 0xB7, 0x6A, 0xE7, 0x4C, 0x80}, "ruxow8lnn88uyeX+", 0x00},
|
||||||
|
{ {0x04, 0xf0, 0x22, 0xc2, 0x33, 0x5e, 0x80}, "\0" , 0x00},
|
||||||
|
{ {0x04, 0x8C, 0xEC, 0xDA, 0xF0, 0x4A, 0x80}, "ONrsVf7jX6IaSNV6", 0x01},
|
||||||
|
{ {0x04, 0x92, 0xA7, 0x6A, 0xE7, 0x4C, 0x81}, "Hjjpcx/mZwuveTF+", 0x02},
|
||||||
|
{ {0x04, 0xD0, 0xB0, 0x3A, 0xD3, 0x63, 0x80}, "\0", 0x02},
|
||||||
|
{ {0x04, 0x96, 0x42, 0xDA, 0xF0, 0x4A, 0x80}, "vEWy0WO9wZNEzEok", 0x03},
|
||||||
|
{ {0x04, 0x33, 0xb5, 0x62, 0x39, 0x4d, 0x80}, "\0", 0x03},
|
||||||
|
{ {0x04, 0x17, 0xB7, 0x3A, 0xD3, 0x63, 0x81}, "f0axEma+g2WnLGAm", 0x05},
|
||||||
|
{ {0x04, 0x84, 0x27, 0x6A, 0xE7, 0x4C, 0x80}, "VZB/OLBwOiM5Mpnp", 0x05},
|
||||||
|
{ {0x04, 0x28, 0xF4, 0xDA, 0xF0, 0x4A, 0x81}, "7WzlgEzqLgwTnWNy", 0x05},
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *jooks_figures[] = {"Dragon", "Fox", "Ghost", "Knight", "?", "Whale"};
|
||||||
|
const uint8_t jooki_secret[] = {0x20, 0x20, 0x20, 0x6D, 0x24, 0x0B, 0xEB, 0x94, 0x2C, 0x80, 0x45, 0x16};
|
||||||
|
const uint8_t NFC_SECRET[] = { 0x03, 0x9c, 0x25, 0x6f, 0xb9, 0x2e, 0xe8, 0x08, 0x09, 0x83, 0xd9, 0x33, 0x56};
|
||||||
|
|
||||||
|
#define JOOKI_UID_LEN 7
|
||||||
|
#define JOOKI_IV_LEN 4
|
||||||
|
#define JOOKI_B64_LEN (16 + 1)
|
||||||
|
#define JOOKI_PLAIN_LEN 12
|
||||||
|
|
||||||
|
static int jooki_encode(uint8_t *iv, uint8_t tagtype, uint8_t *uid, uint8_t *out) {
|
||||||
|
if (out == NULL) {
|
||||||
|
PrintAndLogEx(ERR, "(encode jooki) base64ndef param is NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
out[0] = 0x00;
|
||||||
|
if (iv == NULL || uid == NULL) {
|
||||||
|
PrintAndLogEx(ERR, "(encode jooki) iv or uid param is NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t d[JOOKI_PLAIN_LEN] = {iv[0], iv[1],iv[2], iv[3], tagtype, uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]};
|
||||||
|
uint8_t enc[JOOKI_PLAIN_LEN] = {0};
|
||||||
|
for (uint8_t i = 0; i < JOOKI_PLAIN_LEN; i++) {
|
||||||
|
|
||||||
|
if (i < 3)
|
||||||
|
enc[i] = d[i] ^ NFC_SECRET[i];
|
||||||
|
else
|
||||||
|
enc[i] = d[i] ^ NFC_SECRET[i] ^ d[i % 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(DEBUG, "encoded result.... %s", sprint_hex(enc, sizeof(enc)));
|
||||||
|
|
||||||
|
size_t b64len = 0;
|
||||||
|
uint8_t b64[20];
|
||||||
|
memset(b64, 0, 20);
|
||||||
|
mbedtls_base64_encode(b64, sizeof(b64), &b64len, (const unsigned char*)enc, sizeof(enc));
|
||||||
|
memcpy(out, b64, b64len);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jooki_decode(uint8_t *b64, uint8_t *result) {
|
||||||
|
uint8_t ndef[JOOKI_PLAIN_LEN] = {0};
|
||||||
|
size_t outputlen = 0;
|
||||||
|
mbedtls_base64_decode(ndef, sizeof(ndef), &outputlen, (const unsigned char*)b64, 16);
|
||||||
|
|
||||||
|
PrintAndLogEx(DEBUG, "(decode_jooki) raw encoded... " _GREEN_("%s"), sprint_hex(ndef, sizeof(ndef)));
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < JOOKI_PLAIN_LEN; i++) {
|
||||||
|
if (i < 3)
|
||||||
|
result[i] = ndef[i] ^ NFC_SECRET[i];
|
||||||
|
else
|
||||||
|
result[i] = ndef[i] ^ NFC_SECRET[i] ^ ndef[i % 3] ^ NFC_SECRET[i % 3];
|
||||||
|
}
|
||||||
|
PrintAndLogEx(DEBUG, "(decode_jooki) plain......... %s", sprint_hex(result, sizeof(ndef)));
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jooki_create_ndef(uint8_t *b64ndef, uint8_t *ndefrecord) {
|
||||||
|
// sample of url: https://s.jooki.rocks/s/?s=ONrsVf7jX6IaSNV6
|
||||||
|
if (ndefrecord == NULL) {
|
||||||
|
PrintAndLogEx(ERR, "(jooki_create_ndef) ndefrecord param is NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
memcpy(ndefrecord,
|
||||||
|
"\x01\x03\xa0\x0c\x34\x03\x29\xd1"
|
||||||
|
"\x01\x25\x55\x04\x73\x2e\x6a\x6f"
|
||||||
|
"\x6f\x6b\x69\x2e\x72\x6f\x63\x6b"
|
||||||
|
"\x73\x2f\x73\x2f\x3f\x73\x3d", 31);
|
||||||
|
memcpy(ndefrecord + 31, b64ndef, 16);
|
||||||
|
memcpy(ndefrecord + 47, "\x0a\xFE\x00\x00\x00", 5);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jooki_printEx(uint8_t *b64, uint8_t *iv, uint8_t tt, uint8_t *uid, bool verbose) {
|
||||||
|
PrintAndLogEx(INFO, "Encoded URL.. %s ( %s )", sprint_hex(b64, 12), b64);
|
||||||
|
PrintAndLogEx(INFO, "Figurine..... %02x - " _GREEN_("%s"), tt, jooks_figures[tt]);
|
||||||
|
PrintAndLogEx(INFO, "iv........... %s", sprint_hex(iv, JOOKI_IV_LEN));
|
||||||
|
PrintAndLogEx(INFO, "uid.......... %s", sprint_hex(uid, JOOKI_UID_LEN));
|
||||||
|
|
||||||
|
uint8_t ndefmsg[52] = {0};
|
||||||
|
jooki_create_ndef(b64, ndefmsg);
|
||||||
|
PrintAndLogEx(INFO, "NDEF raw..... %s", sprint_hex_inrow(ndefmsg, sizeof(ndefmsg)));
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
int res = NDEFRecordsDecodeAndPrint(ndefmsg, sizeof(ndefmsg));
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
NDEFDecodeAndPrint(ndefmsg, sizeof(ndefmsg), verbose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jooki_print(uint8_t *b64, uint8_t *result, bool verbose) {
|
||||||
|
if (b64 == NULL || result == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t iv[JOOKI_IV_LEN] = {0};
|
||||||
|
uint8_t uid[JOOKI_UID_LEN] = {0};
|
||||||
|
memcpy(iv, result, sizeof(iv));
|
||||||
|
uint8_t tt = result[4];
|
||||||
|
memcpy(uid, result + 5, sizeof(uid));
|
||||||
|
|
||||||
|
jooki_printEx(b64, iv, tt, uid, verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jooki_selftest(void) {
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "======== " _CYAN_("selftest") " ===========================================");
|
||||||
|
for (int i = 0; i < ARRAYLEN(jooks); i++) {
|
||||||
|
if (strlen(jooks[i].b64) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t iv[JOOKI_IV_LEN] = {0};
|
||||||
|
uint8_t uid[JOOKI_UID_LEN] = {0};
|
||||||
|
uint8_t result[JOOKI_PLAIN_LEN] = {0};
|
||||||
|
jooki_decode((uint8_t*)jooks[i].b64, result);
|
||||||
|
|
||||||
|
memcpy(iv, result, 4);
|
||||||
|
uint8_t tt = result[4];
|
||||||
|
memcpy(uid, result + 5, sizeof(uid));
|
||||||
|
|
||||||
|
bool tt_ok = (tt == jooks[i].tagtype);
|
||||||
|
bool uid_ok = (memcmp(uid, jooks[i].uid, sizeof(uid)) == 0);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Encoded URL.. %s ( %s )", sprint_hex((const uint8_t*)jooks[i].b64, 12), jooks[i].b64);
|
||||||
|
PrintAndLogEx(INFO, "Figurine..... %02x - " _GREEN_("%s") " ( %s )", tt, jooks_figures[tt], tt_ok ? _GREEN_("ok") : _RED_("fail"));
|
||||||
|
PrintAndLogEx(INFO, "iv........... %s", sprint_hex(iv, sizeof(iv)));
|
||||||
|
PrintAndLogEx(INFO, "uid.......... %s ( %s )", sprint_hex(uid, sizeof(uid)), uid_ok ? _GREEN_("ok") : _RED_("fail"));
|
||||||
|
|
||||||
|
uint8_t b64[JOOKI_B64_LEN] = {0};
|
||||||
|
memset(b64, 0, sizeof(b64));
|
||||||
|
jooki_encode(iv, tt, uid, b64);
|
||||||
|
|
||||||
|
uint8_t ndefmsg[52] = {0};
|
||||||
|
jooki_create_ndef(b64, ndefmsg);
|
||||||
|
PrintAndLogEx(INFO, "NDEF raw .... %s", sprint_hex(ndefmsg, sizeof(ndefmsg)));
|
||||||
|
|
||||||
|
int status = NDEFRecordsDecodeAndPrint(ndefmsg, sizeof(ndefmsg));
|
||||||
|
if ( status != PM3_SUCCESS) {
|
||||||
|
status = NDEFDecodeAndPrint(ndefmsg, sizeof(ndefmsg), true);
|
||||||
|
}
|
||||||
|
PrintAndLogEx(INFO, "==================================================================");
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHF14AJookiEncode(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf jooki encode",
|
||||||
|
"Encode a Jooki token to base64 NDEF URI format",
|
||||||
|
"hf jooki encode -t --> selftest\n"
|
||||||
|
"hf jooki encode -r --dragon --> read uid from tag and use for encoding\n"
|
||||||
|
"hf jooki encode --uid 04010203040506 --dragon"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("u", "uid", "<hex>", "uid bytes"),
|
||||||
|
arg_lit0("r", NULL, "read uid from tag instead"),
|
||||||
|
arg_lit0("t", NULL, "selftest"),
|
||||||
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
arg_lit0(NULL, "dragon", "tag type"),
|
||||||
|
arg_lit0(NULL, "fox", "tag type"),
|
||||||
|
arg_lit0(NULL, "ghost", "tag type"),
|
||||||
|
arg_lit0(NULL, "knight", "tag type"),
|
||||||
|
arg_lit0(NULL, "whale", "tag type"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
int ulen = 0;
|
||||||
|
uint8_t uid[JOOKI_UID_LEN] = {0x00};
|
||||||
|
memset(uid, 0x0, sizeof(uid));
|
||||||
|
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), uid, sizeof(uid), &ulen);
|
||||||
|
if (res) {
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool use_tag = arg_get_lit(ctx, 2);
|
||||||
|
bool selftest = arg_get_lit(ctx, 3);
|
||||||
|
bool verbose = arg_get_lit(ctx, 4);
|
||||||
|
bool tt_dragon = arg_get_lit(ctx, 5);
|
||||||
|
bool tt_fox = arg_get_lit(ctx, 6);
|
||||||
|
bool tt_ghost = arg_get_lit(ctx, 7);
|
||||||
|
bool tt_knight = arg_get_lit(ctx, 8);
|
||||||
|
bool tt_whale = arg_get_lit(ctx, 9);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (selftest) {
|
||||||
|
return jooki_selftest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tt_dragon + tt_fox + tt_ghost + tt_knight + tt_whale) > 1) {
|
||||||
|
PrintAndLogEx(ERR, "Select one tag type");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
uint8_t tt = 0;
|
||||||
|
if (tt_fox)
|
||||||
|
tt = 1;
|
||||||
|
if (tt_ghost)
|
||||||
|
tt = 2;
|
||||||
|
if (tt_knight)
|
||||||
|
tt = 3;
|
||||||
|
if (tt_whale)
|
||||||
|
tt = 5;
|
||||||
|
|
||||||
|
uint8_t iv[JOOKI_IV_LEN] = {0x80, 0x77, 0x51, 1};
|
||||||
|
if (use_tag) {
|
||||||
|
res = ul_read_uid(uid);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ulen != JOOKI_UID_LEN) {
|
||||||
|
PrintAndLogEx(ERR, "Wrong length of UID, expect %u, got %d", JOOKI_UID_LEN, ulen);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t b64[JOOKI_B64_LEN] = {0};
|
||||||
|
memset(b64, 0, sizeof(b64));
|
||||||
|
jooki_encode(iv, tt, uid, b64);
|
||||||
|
jooki_printEx(b64, iv, tt, uid, verbose);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHF14AJookiDecode(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf jooki decode",
|
||||||
|
"Decode a base64-encode Jooki token in NDEF URI format",
|
||||||
|
"hf jooki decode -d 7WzlgEzqLgwTnWNy"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1("d", "data", "<base64>", "base64 url parameter"),
|
||||||
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
int dlen = 16;
|
||||||
|
uint8_t b64[JOOKI_B64_LEN] = {0x00};
|
||||||
|
memset(b64, 0x0, sizeof(b64));
|
||||||
|
CLIGetStrWithReturn(ctx, 1, b64, &dlen);
|
||||||
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
uint8_t result[JOOKI_PLAIN_LEN] = {0};
|
||||||
|
int res = jooki_decode(b64, result);
|
||||||
|
if (res == PM3_SUCCESS) {
|
||||||
|
jooki_print(b64, result, verbose);
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHF14AJookiSim(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf jooki sim",
|
||||||
|
"Simulate a Jooki token. Either `hf mfu eload` before or use `-d` param",
|
||||||
|
"hf jooki sim --> using eload before\n"
|
||||||
|
"hf jooki sim -d 7WzlgEzqLgwTnWNy"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("d", "data", "<base64>", "base64 url parameter"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
int dlen = 16;
|
||||||
|
uint8_t b64[JOOKI_B64_LEN] = {0x00};
|
||||||
|
memset(b64, 0x0, sizeof(b64));
|
||||||
|
CLIGetStrWithReturn(ctx, 1, b64, &dlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
uint8_t result[JOOKI_PLAIN_LEN] = {0};
|
||||||
|
int res = jooki_decode(b64, result);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
jooki_print(b64, result, false);
|
||||||
|
|
||||||
|
// hf mfu sim...
|
||||||
|
uint8_t *data = calloc(144, sizeof(uint8_t));
|
||||||
|
|
||||||
|
// copy UID from base64 url parameter
|
||||||
|
memcpy(data, result + 5, 3);
|
||||||
|
// bbc0
|
||||||
|
data[3] = 0x88 ^ data[0] ^ data[1] ^ data[2];
|
||||||
|
|
||||||
|
memcpy(data + (1*4), result + 8, 4);
|
||||||
|
// bbc1
|
||||||
|
data[8] = data[4] ^ data[5] ^ data[6] ^ data[7];
|
||||||
|
|
||||||
|
// copy NDEF magic firs, skip BBC1
|
||||||
|
memcpy(data + (2*4) + 1, "\x48\x00\x00\xE1\x10\x12\x00", 7);
|
||||||
|
|
||||||
|
// copy raw NDEF
|
||||||
|
jooki_create_ndef(b64, data + (4 * 4));
|
||||||
|
|
||||||
|
// convert plain or old mfu format to new format
|
||||||
|
size_t datalen = 144;
|
||||||
|
res = convert_mfu_dump_format(&data, &datalen, true);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(FAILED, "Failed convert on load to new Ultralight/NTAG format");
|
||||||
|
free(data);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
mfu_dump_t *mfu_dump = (mfu_dump_t *)data;
|
||||||
|
|
||||||
|
|
||||||
|
memcpy(mfu_dump->version, "\x00\x04\x04\x02\x01\x00\x0F\x03", 8);
|
||||||
|
mfu_dump->counter_tearing[2][3] = 0xBD;
|
||||||
|
mfu_dump->pages = 0x2c;
|
||||||
|
|
||||||
|
printMFUdumpEx(mfu_dump, mfu_dump->pages + 1, 0);
|
||||||
|
|
||||||
|
// upload to emulator memory
|
||||||
|
PrintAndLogEx(INFO, "Uploading to emulator memory");
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "." NOLF);
|
||||||
|
// fast push mode
|
||||||
|
conn.block_after_ACK = true;
|
||||||
|
uint8_t blockwidth = 4, counter = 0, blockno = 0;
|
||||||
|
while (datalen) {
|
||||||
|
if (datalen == blockwidth) {
|
||||||
|
// Disable fast mode on last packet
|
||||||
|
conn.block_after_ACK = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mfEmlSetMem_xt(data + counter, blockno, 1, blockwidth) != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(FAILED, "Cant set emul block: %3d", blockno);
|
||||||
|
free(data);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "." NOLF);
|
||||||
|
fflush(stdout);
|
||||||
|
blockno++;
|
||||||
|
counter += blockwidth;
|
||||||
|
datalen -= blockwidth;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "\n");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t tagtype;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t uid[10];
|
||||||
|
uint8_t exitAfter;
|
||||||
|
} PACKED payload;
|
||||||
|
|
||||||
|
// NTAG, 7 byte UID in eloaded data.
|
||||||
|
payload.tagtype = 7;
|
||||||
|
payload.flags = FLAG_7B_UID_IN_DATA;
|
||||||
|
payload.exitAfter = 0;
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
PacketResponseNG resp;
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " or pm3-button to abort simulation");
|
||||||
|
for (;;) {
|
||||||
|
if (kbd_enter_pressed()) {
|
||||||
|
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||||
|
PrintAndLogEx(DEBUG, "User aborted");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (resp.status != PM3_SUCCESS)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
PrintAndLogEx(INFO, "Done");
|
||||||
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14a list") "` to view trace log" );
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHF14AJookiWrite(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf jooki write",
|
||||||
|
"Write a Jooki token to a Ultralight or NTAG tag",
|
||||||
|
"hf jooki write -d xxxxxxxx -> where x is raw NDEF from encode command"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1("d", "data", "<hex>", "bytes"),
|
||||||
|
arg_str0("p", "pwd", "<hex>", "password for authentication (EV1/NTAG 4 bytes)"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
int dlen = 0;
|
||||||
|
uint8_t data[52] = {0x00};
|
||||||
|
memset(data, 0x0, sizeof(data));
|
||||||
|
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), data, sizeof(data), &dlen);
|
||||||
|
if (res) {
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
PrintAndLogEx(FAILED, "Error parsing bytes");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int plen = 0;
|
||||||
|
uint8_t pwd[4] = {0x00};
|
||||||
|
CLIGetHexWithReturn(ctx, 2, pwd, &plen);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (dlen != 52) {
|
||||||
|
PrintAndLogEx(ERR, "Wrong data length. Expected 52 got %d", dlen);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_pwd = false;
|
||||||
|
if (plen == 4) {
|
||||||
|
has_pwd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 - no authentication
|
||||||
|
// 2 - pwd (4 bytes)
|
||||||
|
uint8_t keytype = 0, blockno = 4, i = 0;
|
||||||
|
|
||||||
|
while ((i * 4) < dlen) {
|
||||||
|
|
||||||
|
uint8_t cmddata[8] = {0};
|
||||||
|
memcpy(cmddata, data + (i * 4), 4);
|
||||||
|
if (has_pwd) {
|
||||||
|
memcpy(cmddata + 4, pwd, 4);
|
||||||
|
keytype = 2;
|
||||||
|
}
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, blockno, keytype, 0, cmddata, sizeof(cmddata));
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
|
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||||
|
PrintAndLogEx(SUCCESS, "Write block %d ( %s )", blockno, isOK ? _GREEN_("ok") : _RED_("fail"));
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
blockno++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static command_t CommandTable[] = {
|
||||||
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
{"encode", CmdHF14AJookiEncode, AlwaysAvailable, "Encode Jooki token"},
|
||||||
|
{"decode", CmdHF14AJookiDecode, AlwaysAvailable, "Decode Jooki token"},
|
||||||
|
{"sim", CmdHF14AJookiSim, IfPm3Iso14443a, "Simulate Jooki token"},
|
||||||
|
{"write", CmdHF14AJookiWrite, IfPm3Iso14443a, "Write a Jooki token"},
|
||||||
|
|
||||||
|
{NULL, NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd) {
|
||||||
|
(void)Cmd; // Cmd is not used so far
|
||||||
|
CmdsHelp(CommandTable);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdHF_Jooki(const char *Cmd) {
|
||||||
|
clearCommandBuffer();
|
||||||
|
return CmdsParse(CommandTable, Cmd);
|
||||||
|
}
|
16
client/src/cmdhfjooki.h
Normal file
16
client/src/cmdhfjooki.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2021 iceman1001
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// High frequency ISO14443A / MFU / Jooki commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CMDHFJOOKI_H__
|
||||||
|
#define CMDHFJOOKI_H__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
int CmdHF_Jooki(const char *Cmd);
|
||||||
|
#endif
|
|
@ -3983,6 +3983,63 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CmdHF14ADesBruteApps(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf mfdes bruteaid",
|
||||||
|
"Recover AIDs by bruteforce.\n"
|
||||||
|
"WARNING: This command takes a long time",
|
||||||
|
"hf mfdes bruteaid -> Search all apps\n"
|
||||||
|
"hf mfdes bruteaid -s F0000F -i 16 -> Search MAD range manually");
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_strx0("s", "start", "<hex>", "Starting App ID as hex bytes (3 bytes,big endian)"),
|
||||||
|
arg_strx0("e", "end", "<hex>", "Last App ID as hex bytes (3 bytes,big endian)"),
|
||||||
|
arg_int0("i", "step", "<dec>", "Increment step when bruteforcing (decimal integer)"),
|
||||||
|
arg_lit0("m", "mad", "Only bruteforce the MAD range"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
uint8_t startAid[3] = {0};
|
||||||
|
uint8_t endAid[3] = {0xFF, 0xFF, 0xFF};
|
||||||
|
int startLen = 0;
|
||||||
|
int endLen = 0;
|
||||||
|
CLIGetHexWithReturn(ctx, 1, startAid, &startLen);
|
||||||
|
CLIGetHexWithReturn(ctx, 2, endAid, &endLen);
|
||||||
|
uint32_t idIncrement = arg_get_int_def(ctx, 3, 1);
|
||||||
|
bool mad = arg_get_lit(ctx, 4);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
// TODO: We need to check the tag version, EV1 should stop after 26 apps are found
|
||||||
|
if (mad) {
|
||||||
|
idIncrement = 0x10;
|
||||||
|
startAid[0] = 0xF0;
|
||||||
|
startAid[1] = 0x00;
|
||||||
|
startAid[2] = 0x0F;
|
||||||
|
}
|
||||||
|
uint32_t idStart = le24toh(startAid);
|
||||||
|
uint32_t idEnd = le24toh(endAid);
|
||||||
|
PrintAndLogEx(INFO, "Enumerating through all AIDs manually, this will take a while!");
|
||||||
|
for (uint32_t id = idStart; id <= idEnd && id >= idStart; id += idIncrement) {
|
||||||
|
if (kbd_enter_pressed()) break;
|
||||||
|
int progress = ((id - idStart) * 100) / ((idEnd - idStart));
|
||||||
|
PrintAndLogEx(INPLACE, "Progress: %d %%, current AID: %06X", progress, id);
|
||||||
|
uint8_t appId[3] = {0};
|
||||||
|
htole24(id, appId);
|
||||||
|
sAPDU apdu = {0x90, MFDES_SELECT_APPLICATION, 0x00, 0x00, 0x03, appId}; //0x5a
|
||||||
|
uint16_t sw = 0;
|
||||||
|
uint8_t data[255 * 5] = {0x00};
|
||||||
|
uint32_t resplen = 0;
|
||||||
|
DESFIRESendApdu(!tag->rf_field_on, true, apdu, data, sizeof(data), &resplen, &sw);
|
||||||
|
if (sw == status(MFDES_S_OPERATION_OK)) {
|
||||||
|
printf("\33[2K\r"); // clear current line before printing
|
||||||
|
PrintAndLogEx(SUCCESS, "Got new APPID %06X", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrintAndLogEx(SUCCESS, "Done");
|
||||||
|
DropFieldDesfire();
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdHF14ADesChangeKey(const char *Cmd) {
|
static int CmdHF14ADesChangeKey(const char *Cmd) {
|
||||||
//DropFieldDesfire();
|
//DropFieldDesfire();
|
||||||
// NR DESC KEYLENGHT
|
// NR DESC KEYLENGHT
|
||||||
|
@ -4924,6 +4981,7 @@ static command_t CommandTable[] = {
|
||||||
// {"ndef", CmdHF14aDesNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
// {"ndef", CmdHF14aDesNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||||
// {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"},
|
// {"mad", CmdHF14aDesMAD, IfPm3Iso14443a, "Prints MAD records from card"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("AID") " -----------------------"},
|
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("AID") " -----------------------"},
|
||||||
|
{"bruteaid", CmdHF14ADesBruteApps, IfPm3Iso14443a, "Recover AIDs by bruteforce"},
|
||||||
{"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},
|
{"createaid", CmdHF14ADesCreateApp, IfPm3Iso14443a, "Create Application ID"},
|
||||||
{"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"},
|
{"deleteaid", CmdHF14ADesDeleteApp, IfPm3Iso14443a, "Delete Application ID"},
|
||||||
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
|
{"selectaid", CmdHF14ADesSelectApp, IfPm3Iso14443a, "Select Application ID"},
|
||||||
|
|
|
@ -115,6 +115,36 @@ static char *getUlev1CardSizeStr(uint8_t fsize) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ul_read_uid(uint8_t *uid) {
|
||||||
|
if (uid == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "NUll parameter UID");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
// read uid from tag
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0);
|
||||||
|
PacketResponseNG resp;
|
||||||
|
WaitForResponse(CMD_ACK, &resp);
|
||||||
|
iso14a_card_select_t card;
|
||||||
|
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||||
|
|
||||||
|
uint64_t select_status = resp.oldarg[0];
|
||||||
|
// 0: couldn't read
|
||||||
|
// 1: OK with ATS
|
||||||
|
// 2: OK, no ATS
|
||||||
|
// 3: proprietary Anticollision
|
||||||
|
if (select_status == 0) {
|
||||||
|
PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
if (card.uidlen != 7) {
|
||||||
|
PrintAndLogEx(WARNING, "Wrong sized UID, expected 7bytes got %d", card.uidlen);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
memcpy(uid, card.uid, 7);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static void ul_switch_on_field(void) {
|
static void ul_switch_on_field(void) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0);
|
||||||
|
@ -1102,7 +1132,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (ak_len) {
|
if (ak_len) {
|
||||||
if (ak_len != 16 && ak_len != 8) {
|
if (ak_len != 16 && ak_len != 4) {
|
||||||
PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n");
|
PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
@ -2253,7 +2283,7 @@ static int CmdHF14AMfUeLoad(const char *Cmd) {
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
PrintAndLogEx(HINT, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to .eml");
|
PrintAndLogEx(HINT, "Hint: See " _YELLOW_("`script run data_mfu_bin2eml`") " to convert the .bin to .eml");
|
||||||
return CmdHF14AMfELoad(Cmd);
|
return CmdHF14AMfELoad(Cmd);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
@ -2264,7 +2294,8 @@ static int CmdHF14AMfUSim(const char *Cmd) {
|
||||||
CLIParserInit(&ctx, "hf mfu sim",
|
CLIParserInit(&ctx, "hf mfu sim",
|
||||||
"Simulate MIFARE Ultralight family type based upon\n"
|
"Simulate MIFARE Ultralight family type based upon\n"
|
||||||
"ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"
|
"ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"
|
||||||
"from emulator memory. See `hf mfu eload` first",
|
"from emulator memory. See `hf mfu eload` first. \n"
|
||||||
|
"See `hf 14a sim -h` to see available types. You want 2 or 7 usually.",
|
||||||
"hf mfu sim -t 2 --uid 1122344556677 -> MIFARE Ultralight\n"
|
"hf mfu sim -t 2 --uid 1122344556677 -> MIFARE Ultralight\n"
|
||||||
"hf mfu sim -t 7 --uid 1122344556677 -n 5 -> AMIIBO (NTAG 215), pack 0x8080"
|
"hf mfu sim -t 7 --uid 1122344556677 -n 5 -> AMIIBO (NTAG 215), pack 0x8080"
|
||||||
);
|
);
|
||||||
|
@ -2598,7 +2629,7 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str0("u", "uid", "<hex>", "4|7 hex byte UID"),
|
arg_str0("u", "uid", "<hex>", "<4|7> hex byte UID"),
|
||||||
arg_lit0("r", NULL, "read UID from tag"),
|
arg_lit0("r", NULL, "read UID from tag"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
|
@ -2636,6 +2667,11 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
|
||||||
}
|
}
|
||||||
ulen = card.uidlen;
|
ulen = card.uidlen;
|
||||||
memcpy(uid, card.uid, card.uidlen);
|
memcpy(uid, card.uid, card.uidlen);
|
||||||
|
} else {
|
||||||
|
if (ulen != 4 && ulen != 7) {
|
||||||
|
PrintAndLogEx(ERR, "Must supply 4 or 7 hex byte uid");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t iv[8] = { 0x00 };
|
uint8_t iv[8] = { 0x00 };
|
||||||
|
@ -2757,34 +2793,18 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
|
||||||
if (selftest)
|
if (selftest)
|
||||||
return generator_selftest();
|
return generator_selftest();
|
||||||
|
|
||||||
|
if (use_tag) {
|
||||||
|
// read uid from tag
|
||||||
|
int res = ul_read_uid(uid);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
if (u_len != 7) {
|
if (u_len != 7) {
|
||||||
PrintAndLogEx(WARNING, "Key must be 7 hex bytes");
|
PrintAndLogEx(WARNING, "Key must be 7 hex bytes");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_tag) {
|
|
||||||
// read uid from tag
|
|
||||||
clearCommandBuffer();
|
|
||||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0);
|
|
||||||
PacketResponseNG resp;
|
|
||||||
WaitForResponse(CMD_ACK, &resp);
|
|
||||||
iso14a_card_select_t card;
|
|
||||||
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
|
||||||
|
|
||||||
uint64_t select_status = resp.oldarg[0];
|
|
||||||
// 0: couldn't read
|
|
||||||
// 1: OK with ATS
|
|
||||||
// 2: OK, no ATS
|
|
||||||
// 3: proprietary Anticollision
|
|
||||||
if (select_status == 0) {
|
|
||||||
PrintAndLogEx(WARNING, "iso14443a card select failed");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
if (card.uidlen != 7) {
|
|
||||||
PrintAndLogEx(WARNING, "Wrong sized UID, expected 7bytes got %d", card.uidlen);
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
memcpy(uid, card.uid, sizeof(uid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "---------------------------------");
|
PrintAndLogEx(INFO, "---------------------------------");
|
||||||
|
@ -3539,7 +3559,27 @@ static int CmdHF14MfuNDEF(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
|
status = NDEFRecordsDecodeAndPrint(records, (size_t)maxsize);
|
||||||
|
if ( status != PM3_SUCCESS) {
|
||||||
status = NDEFDecodeAndPrint(records, (size_t)maxsize, true);
|
status = NDEFDecodeAndPrint(records, (size_t)maxsize, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *jooki = strstr((char*)records, "s.jooki.rocks/s/?s=");
|
||||||
|
if (jooki) {
|
||||||
|
jooki += 17;
|
||||||
|
while(jooki) {
|
||||||
|
if ((*jooki) != '=')
|
||||||
|
jooki++;
|
||||||
|
else {
|
||||||
|
jooki++;
|
||||||
|
char s[17] = {0};
|
||||||
|
strncpy(s, jooki, 16);
|
||||||
|
PrintAndLogEx(HINT, "Use `" _YELLOW_("hf jooki decode -d %s") "` to decode", s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(records);
|
free(records);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ typedef struct {
|
||||||
uint32_t GetHF14AMfU_Type(void);
|
uint32_t GetHF14AMfU_Type(void);
|
||||||
int ul_print_type(uint32_t tagtype, uint8_t spaces);
|
int ul_print_type(uint32_t tagtype, uint8_t spaces);
|
||||||
void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage);
|
void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage);
|
||||||
|
int ul_read_uid(uint8_t *uid);
|
||||||
|
|
||||||
int CmdHFMFUltra(const char *Cmd);
|
int CmdHFMFUltra(const char *Cmd);
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,8 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
|
||||||
sprintf(asBuff, "AT91SAM7S16 Rev A");
|
sprintf(asBuff, "AT91SAM7S16 Rev A");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " --= uC: %s", asBuff);
|
PrintAndLogEx(NORMAL, " --= uC: " _YELLOW_("%s"), asBuff);
|
||||||
|
|
||||||
switch ((iChipID & 0xE0) >> 5) {
|
switch ((iChipID & 0xE0) >> 5) {
|
||||||
case 1:
|
case 1:
|
||||||
sprintf(asBuff, "ARM946ES");
|
sprintf(asBuff, "ARM946ES");
|
||||||
|
@ -104,84 +105,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " --= Embedded Processor: %s", asBuff);
|
PrintAndLogEx(NORMAL, " --= Embedded Processor: %s", asBuff);
|
||||||
switch ((iChipID & 0xF00) >> 8) {
|
|
||||||
case 0:
|
|
||||||
mem_avail = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
mem_avail = 8;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
mem_avail = 16;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
mem_avail = 32;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
mem_avail = 64;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
mem_avail = 128;
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
mem_avail = 256;
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
mem_avail = 512;
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
mem_avail = 1024;
|
|
||||||
break;
|
|
||||||
case 14:
|
|
||||||
mem_avail = 2048;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t mem_left = 0;
|
|
||||||
if (mem_avail > 0)
|
|
||||||
mem_left = (mem_avail * 1024) - mem_used;
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " --= Nonvolatile Program Memory Size: %uK bytes, Used: %u bytes (%2.0f%%) Free: %u bytes (%2.0f%%)",
|
|
||||||
mem_avail,
|
|
||||||
mem_used,
|
|
||||||
mem_avail == 0 ? 0.0f : (float)mem_used / (mem_avail * 1024) * 100,
|
|
||||||
mem_left,
|
|
||||||
mem_avail == 0 ? 0.0f : (float)mem_left / (mem_avail * 1024) * 100
|
|
||||||
);
|
|
||||||
|
|
||||||
switch ((iChipID & 0xF000) >> 12) {
|
|
||||||
case 0:
|
|
||||||
sprintf(asBuff, "None");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
sprintf(asBuff, "8K bytes");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
sprintf(asBuff, "16K bytes");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
sprintf(asBuff, "32K bytes");
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
sprintf(asBuff, "64K bytes");
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
sprintf(asBuff, "128K bytes");
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
sprintf(asBuff, "256K bytes");
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
sprintf(asBuff, "512K bytes");
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
sprintf(asBuff, "1024K bytes");
|
|
||||||
break;
|
|
||||||
case 14:
|
|
||||||
sprintf(asBuff, "2048K bytes");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(NORMAL, " --= Second Nonvolatile Program Memory Size: %s", asBuff);
|
|
||||||
switch ((iChipID & 0xF0000) >> 16) {
|
switch ((iChipID & 0xF0000) >> 16) {
|
||||||
case 1:
|
case 1:
|
||||||
sprintf(asBuff, "1K bytes");
|
sprintf(asBuff, "1K bytes");
|
||||||
|
@ -229,7 +153,8 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
|
||||||
sprintf(asBuff, "512K bytes");
|
sprintf(asBuff, "512K bytes");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " --= Internal SRAM Size: %s", asBuff);
|
PrintAndLogEx(NORMAL, " --= Internal SRAM size: %s", asBuff);
|
||||||
|
|
||||||
switch ((iChipID & 0xFF00000) >> 20) {
|
switch ((iChipID & 0xFF00000) >> 20) {
|
||||||
case 0x19:
|
case 0x19:
|
||||||
sprintf(asBuff, "AT91SAM9xx Series");
|
sprintf(asBuff, "AT91SAM9xx Series");
|
||||||
|
@ -289,7 +214,8 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
|
||||||
sprintf(asBuff, "AT75Cxx Series");
|
sprintf(asBuff, "AT75Cxx Series");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " --= Architecture Identifier: %s", asBuff);
|
PrintAndLogEx(NORMAL, " --= Architecture identifier: %s", asBuff);
|
||||||
|
|
||||||
switch ((iChipID & 0x70000000) >> 28) {
|
switch ((iChipID & 0x70000000) >> 28) {
|
||||||
case 0:
|
case 0:
|
||||||
sprintf(asBuff, "ROM");
|
sprintf(asBuff, "ROM");
|
||||||
|
@ -307,7 +233,78 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
|
||||||
sprintf(asBuff, "SRAM emulating ROM");
|
sprintf(asBuff, "SRAM emulating ROM");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, " --= Nonvolatile Program Memory Type: %s", asBuff);
|
switch ((iChipID & 0xF00) >> 8) {
|
||||||
|
case 0:
|
||||||
|
mem_avail = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mem_avail = 8;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mem_avail = 16;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mem_avail = 32;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
mem_avail = 64;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
mem_avail = 128;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
mem_avail = 256;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
mem_avail = 512;
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
mem_avail = 1024;
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
mem_avail = 2048;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, " --= Nonvolatile program memory: " _YELLOW_("%uK") " bytes %s ( " _YELLOW_("%2.0f%%") " used )"
|
||||||
|
, mem_avail
|
||||||
|
, asBuff
|
||||||
|
, mem_avail == 0 ? 0.0f : (float)mem_used / (mem_avail * 1024) * 100
|
||||||
|
);
|
||||||
|
|
||||||
|
switch ((iChipID & 0xF000) >> 12) {
|
||||||
|
case 0:
|
||||||
|
sprintf(asBuff, "None");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
sprintf(asBuff, "8K bytes");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sprintf(asBuff, "16K bytes");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sprintf(asBuff, "32K bytes");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
sprintf(asBuff, "64K bytes");
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
sprintf(asBuff, "128K bytes");
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
sprintf(asBuff, "256K bytes");
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
sprintf(asBuff, "512K bytes");
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
sprintf(asBuff, "1024K bytes");
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
sprintf(asBuff, "2048K bytes");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, " --= Second nonvolatile program memory size: %s", asBuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdDbg(const char *Cmd) {
|
static int CmdDbg(const char *Cmd) {
|
||||||
|
|
1171
client/src/cmdlf.c
1171
client/src/cmdlf.c
File diff suppressed because it is too large
Load diff
|
@ -36,5 +36,6 @@ int lf_read(bool verbose, uint32_t samples);
|
||||||
int lf_sniff(bool verbose, uint32_t samples);
|
int lf_sniff(bool verbose, uint32_t samples);
|
||||||
int lf_config(sample_config *config);
|
int lf_config(sample_config *config);
|
||||||
int lf_getconfig(sample_config *config);
|
int lf_getconfig(sample_config *config);
|
||||||
|
int lfsim_upload_gb(void);
|
||||||
|
int lfsim_wait_check(uint32_t cmd);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -129,10 +129,7 @@ static int CmdAWIDWatch(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_AWID_WATCH, NULL, 0);
|
SendCommandNG(CMD_LF_AWID_WATCH, NULL, 0);
|
||||||
PacketResponseNG resp;
|
return lfsim_wait_check(CMD_LF_AWID_WATCH);
|
||||||
WaitForResponse(CMD_LF_AWID_WATCH, &resp);
|
|
||||||
PrintAndLogEx(INFO, "Done");
|
|
||||||
return resp.status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//by marshmellow
|
//by marshmellow
|
||||||
|
@ -438,8 +435,7 @@ static int CmdAWIDSim(const char *Cmd) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Simulating AWID %u -- FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fmtlen, fc, cn);
|
PrintAndLogEx(SUCCESS, "Simulating "_YELLOW_("AWID %u") " -- FC: " _YELLOW_("%u") " CN: " _YELLOW_("%u"), fmtlen, fc, cn);
|
||||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command");
|
|
||||||
|
|
||||||
// AWID uses: FSK2a fcHigh: 10, fcLow: 8, clk: 50, invert: 1
|
// AWID uses: FSK2a fcHigh: 10, fcLow: 8, clk: 50, invert: 1
|
||||||
// arg1 --- fcHigh<<8 + fcLow
|
// arg1 --- fcHigh<<8 + fcLow
|
||||||
|
@ -456,13 +452,7 @@ static int CmdAWIDSim(const char *Cmd) {
|
||||||
SendCommandNG(CMD_LF_FSK_SIMULATE, (uint8_t *)payload, sizeof(lf_fsksim_t) + sizeof(bs));
|
SendCommandNG(CMD_LF_FSK_SIMULATE, (uint8_t *)payload, sizeof(lf_fsksim_t) + sizeof(bs));
|
||||||
free(payload);
|
free(payload);
|
||||||
|
|
||||||
PacketResponseNG resp;
|
return lfsim_wait_check(CMD_LF_FSK_SIMULATE);
|
||||||
WaitForResponse(CMD_LF_FSK_SIMULATE, &resp);
|
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Done");
|
|
||||||
if (resp.status != PM3_EOPABORTED)
|
|
||||||
return resp.status;
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdAWIDBrute(const char *Cmd) {
|
static int CmdAWIDBrute(const char *Cmd) {
|
||||||
|
@ -630,7 +620,7 @@ int getAWIDBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *bits) {
|
||||||
if (bitLen != 88)
|
if (bitLen != 88)
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "awid raw bits:\n %s \n", sprint_bin(bits, bitLen));
|
PrintAndLogEx(DEBUG, "awid raw bits:\n %s \n", sprint_bin(bits, bitLen));
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,14 +286,10 @@ static int CmdEM410xWatch(const char *Cmd) {
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Watching for EM410x cards - place tag on antenna");
|
PrintAndLogEx(SUCCESS, "Watching for EM410x cards - place tag on Proxmark3 antenna");
|
||||||
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_EM410X_WATCH, NULL, 0);
|
SendCommandNG(CMD_LF_EM410X_WATCH, NULL, 0);
|
||||||
PacketResponseNG resp;
|
return lfsim_wait_check(CMD_LF_EM410X_WATCH);
|
||||||
WaitForResponse(CMD_LF_EM410X_WATCH, &resp);
|
|
||||||
PrintAndLogEx(INFO, "Done");
|
|
||||||
return resp.status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//by marshmellow
|
//by marshmellow
|
||||||
|
@ -320,11 +316,11 @@ static int CmdEM410xDemod(const char *Cmd) {
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_u64_0(NULL, "clk", "<dec>", "optional - clock (default autodetect)"),
|
arg_u64_0(NULL, "clk", "<dec>", "clock (default autodetect)"),
|
||||||
arg_u64_0(NULL, "err", "<dec>", "optional - maximum allowed errors (default 100)"),
|
arg_u64_0(NULL, "err", "<dec>", "maximum allowed errors (default 100)"),
|
||||||
arg_u64_0(NULL, "len", "<dec>", "optional - maximum length"),
|
arg_u64_0(NULL, "len", "<dec>", "maximum length"),
|
||||||
arg_lit0("i", "invert", "optional - invert output"),
|
arg_lit0("i", "invert", "invert output"),
|
||||||
arg_lit0("a", "amp", "optional - amplify signal"),
|
arg_lit0("a", "amp", "amplify signal"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
@ -359,12 +355,13 @@ static int CmdEM410xReader(const char *Cmd) {
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_u64_0(NULL, "clk", "<dec>", "optional - clock (default autodetect)"),
|
arg_u64_0(NULL, "clk", "<dec>", "clock (default autodetect)"),
|
||||||
arg_u64_0(NULL, "err", "<dec>", "optional - maximum allowed errors (default 100)"),
|
arg_u64_0(NULL, "err", "<dec>", "maximum allowed errors (default 100)"),
|
||||||
arg_u64_0(NULL, "len", "<dec>", "optional - maximum length"),
|
arg_u64_0(NULL, "len", "<dec>", "maximum length"),
|
||||||
arg_lit0("i", "invert", "optional - invert output"),
|
arg_lit0("i", "invert", "invert output"),
|
||||||
arg_lit0("a", "amp", "optional - amplify signal"),
|
arg_lit0("a", "amp", "amplify signal"),
|
||||||
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
arg_lit0("b", NULL, "break on first found"),
|
||||||
|
arg_lit0("@", NULL, "continuous reader mode"),
|
||||||
arg_lit0("v", "verbose", "verbose output"),
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
|
@ -375,8 +372,9 @@ static int CmdEM410xReader(const char *Cmd) {
|
||||||
size_t max_len = arg_get_u32_def(ctx, 3, 0);
|
size_t max_len = arg_get_u32_def(ctx, 3, 0);
|
||||||
bool invert = arg_get_lit(ctx, 4);
|
bool invert = arg_get_lit(ctx, 4);
|
||||||
bool amplify = arg_get_lit(ctx, 5);
|
bool amplify = arg_get_lit(ctx, 5);
|
||||||
bool cm = arg_get_lit(ctx, 6);
|
bool break_first = arg_get_lit(ctx, 6);
|
||||||
bool verbose = arg_get_lit(ctx, 7);
|
bool cm = arg_get_lit(ctx, 7);
|
||||||
|
bool verbose = arg_get_lit(ctx, 8);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (cm) {
|
if (cm) {
|
||||||
|
@ -388,6 +386,10 @@ static int CmdEM410xReader(const char *Cmd) {
|
||||||
uint64_t lo = 0;
|
uint64_t lo = 0;
|
||||||
lf_read(false, 12288);
|
lf_read(false, 12288);
|
||||||
AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, verbose);
|
AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, verbose);
|
||||||
|
|
||||||
|
if (break_first && g_em410xid != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
} while (cm && !kbd_enter_pressed());
|
} while (cm && !kbd_enter_pressed());
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -406,8 +408,8 @@ static int CmdEM410xSim(const char *Cmd) {
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_u64_0(NULL, "clk", "<dec>", "optional - clock [32|64] (default 64)"),
|
arg_u64_0(NULL, "clk", "<dec>", "<32|64> clock (default 64)"),
|
||||||
arg_str1("i", "id", "<hex>", "ID number (5 hex bytes)"),
|
arg_str1(NULL, "id", "<hex>", "ID number (5 hex bytes)"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
@ -425,11 +427,8 @@ static int CmdEM410xSim(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%s")" clock: "_YELLOW_("%d"), sprint_hex_inrow(uid, sizeof(uid)), clk);
|
PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%s")" clock: "_YELLOW_("%d"), sprint_hex_inrow(uid, sizeof(uid)), clk);
|
||||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation");
|
|
||||||
|
|
||||||
em410x_construct_emul_graph(uid, clk);
|
em410x_construct_emul_graph(uid, clk);
|
||||||
|
CmdLFSim("");
|
||||||
CmdLFSim("0"); // 240 start_gap.
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,8 +444,8 @@ static int CmdEM410xBrute(const char *Cmd) {
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_u64_1(NULL, "clk", "<dec>", "optional - clock [32|64] (default 64)"),
|
arg_u64_0(NULL, "clk", "<dec>", "<32|64> clock (default 64)"),
|
||||||
arg_u64_1(NULL, "delay", "<dec>", "optional - pause delay in milliseconds between UIDs simulation (default 1000ms)"),
|
arg_u64_0(NULL, "delay", "<dec>", "pause delay in milliseconds between UIDs simulation (default 1000ms)"),
|
||||||
arg_str1("f", "file", "<hex>", "file with UIDs in HEX format, one per line"),
|
arg_str1("f", "file", "<hex>", "file with UIDs in HEX format, one per line"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
|
@ -536,13 +535,14 @@ static int CmdEM410xBrute(const char *Cmd) {
|
||||||
uint8_t testuid[5];
|
uint8_t testuid[5];
|
||||||
for (uint32_t c = 0; c < uidcnt; ++c) {
|
for (uint32_t c = 0; c < uidcnt; ++c) {
|
||||||
if (kbd_enter_pressed()) {
|
if (kbd_enter_pressed()) {
|
||||||
PrintAndLogEx(WARNING, "\nAborted via keyboard!\n");
|
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||||
|
PrintAndLogEx(INFO, "Aborted via keyboard!\n");
|
||||||
free(uidblock);
|
free(uidblock);
|
||||||
return PM3_EOPABORTED;
|
return PM3_EOPABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(testuid, uidblock + 5 * c, 5);
|
memcpy(testuid, uidblock + 5 * c, 5);
|
||||||
PrintAndLogEx(INFO, "Bruteforce %d / %d: simulating UID " _YELLOW_("%s")
|
PrintAndLogEx(INFO, "Bruteforce %d / %u: simulating UID " _YELLOW_("%s")
|
||||||
, c + 1
|
, c + 1
|
||||||
, uidcnt
|
, uidcnt
|
||||||
, sprint_hex_inrow(testuid, sizeof(testuid))
|
, sprint_hex_inrow(testuid, sizeof(testuid))
|
||||||
|
@ -550,9 +550,25 @@ static int CmdEM410xBrute(const char *Cmd) {
|
||||||
|
|
||||||
em410x_construct_emul_graph(testuid, clk);
|
em410x_construct_emul_graph(testuid, clk);
|
||||||
|
|
||||||
CmdLFSim("0"); //240 start_gap.
|
lfsim_upload_gb();
|
||||||
|
|
||||||
msleep(delay);
|
struct p {
|
||||||
|
uint16_t len;
|
||||||
|
uint16_t gap;
|
||||||
|
} PACKED payload;
|
||||||
|
payload.len = GraphTraceLen;
|
||||||
|
payload.gap = 0;
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
if (WaitForResponseTimeout(CMD_LF_SIMULATE, &resp, delay)) {
|
||||||
|
if (resp.status == PM3_EOPABORTED) {
|
||||||
|
PrintAndLogEx(INFO, "Button pressed, user aborted");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(uidblock);
|
free(uidblock);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -575,9 +591,10 @@ static int CmdEM410xSpoof(const char *Cmd) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
// loops if the captured ID was in XL-format.
|
// loops if the captured ID was in XL-format.
|
||||||
CmdEM410xReader("-@");
|
g_em410xid = 0;
|
||||||
PrintAndLogEx(SUCCESS, "# Replaying captured ID: "_YELLOW_("%010" PRIx64), g_em410xid);
|
CmdEM410xReader("-b@");
|
||||||
CmdLFaskSim("");
|
PrintAndLogEx(SUCCESS, "Replaying captured ID "_YELLOW_("%010" PRIx64), g_em410xid);
|
||||||
|
CmdLFSim("");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,15 +602,15 @@ static int CmdEM410xClone(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "lf em 410x clone",
|
CLIParserInit(&ctx, "lf em 410x clone",
|
||||||
"Writes EM410x ID to a T55x7 or Q5/T5555 tag",
|
"Writes EM410x ID to a T55x7 or Q5/T5555 tag",
|
||||||
"lf em 410x clone --uid 0F0368568B -> write id to T55x7 tag\n"
|
"lf em 410x clone --id 0F0368568B -> write id to T55x7 tag\n"
|
||||||
"lf em 410x clone --uid 0F0368568B --q5 -> write id to Q5/T5555 tag"
|
"lf em 410x clone --id 0F0368568B --q5 -> write id to Q5/T5555 tag"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_u64_0(NULL, "clk", "<dec>", "optional - clock <16|32|40|64> (default 64)"),
|
arg_u64_0(NULL, "clk", "<dec>", "<16|32|40|64> clock (default 64)"),
|
||||||
arg_str1("u", "uid", "<hex>", "ID number (5 hex bytes)"),
|
arg_str1(NULL, "id", "<hex>", "ID number (5 hex bytes)"),
|
||||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
arg_lit0(NULL, "q5", "specify writing to Q5/T5555 tag"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
|
@ -29,8 +29,7 @@
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
static void descramble(uint8_t *arr, uint8_t len) {
|
static void scramble(uint8_t *arr, uint8_t len) {
|
||||||
|
|
||||||
uint8_t lut[] = {
|
uint8_t lut[] = {
|
||||||
0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c, 0x05,
|
0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c, 0x05,
|
||||||
0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04, 0x51, 0x2e,
|
0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04, 0x51, 0x2e,
|
||||||
|
@ -55,6 +54,31 @@ static void descramble(uint8_t *arr, uint8_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void descramble(uint8_t *arr, uint8_t len) {
|
||||||
|
uint8_t lut[] = {
|
||||||
|
0x2f, 0x6e, 0xdd, 0xdf, 0x1d, 0x0f, 0xb0, 0x76, 0xad, 0xaf, 0x7f, 0xbb, 0x77, 0x85, 0x11, 0x6d,
|
||||||
|
0xf4, 0xd2, 0x84, 0x42, 0xeb, 0xf7, 0x34, 0x55, 0x4a, 0x3a, 0x10, 0x71, 0xe7, 0xa1, 0x62, 0x1a,
|
||||||
|
0x3e, 0x4c, 0x14, 0xd3, 0x5e, 0xb2, 0x7d, 0x56, 0xbc, 0x27, 0x82, 0x60, 0xe3, 0xae, 0x1f, 0x9b,
|
||||||
|
0xaa, 0x2b, 0x95, 0x49, 0x73, 0xe1, 0x92, 0x79, 0x91, 0x38, 0x6c, 0x19, 0x0e, 0xa9, 0xe2, 0x8d,
|
||||||
|
0x66, 0xc7, 0x5a, 0xf5, 0x1c, 0x80, 0x99, 0xbe, 0x4e, 0x41, 0xf0, 0xe8, 0xa6, 0x20, 0xab, 0x87,
|
||||||
|
0xc8, 0x1e, 0xa0, 0x59, 0x7b, 0x0c, 0xc3, 0x3c, 0x61, 0xcc, 0x40, 0x9e, 0x06, 0x52, 0x1b, 0x32,
|
||||||
|
0x8c, 0x12, 0x93, 0xbf, 0xef, 0x3b, 0x25, 0x0d, 0xc2, 0x88, 0xd1, 0xe0, 0x07, 0x2d, 0x70, 0xc6,
|
||||||
|
0x29, 0x6a, 0x4d, 0x47, 0x26, 0xa3, 0xe4, 0x8b, 0xf6, 0x97, 0x2c, 0x5d, 0x3d, 0xd7, 0x96, 0x28,
|
||||||
|
0x02, 0x08, 0x30, 0xa7, 0x22, 0xc9, 0x65, 0xf8, 0xb7, 0xb4, 0x8a, 0xca, 0xb9, 0xf2, 0xd0, 0x17,
|
||||||
|
0xff, 0x46, 0xfb, 0x9a, 0xba, 0x8f, 0xb6, 0x69, 0x68, 0x8e, 0x21, 0x6f, 0xc4, 0xcb, 0xb3, 0xce,
|
||||||
|
0x51, 0xd4, 0x81, 0x00, 0x2e, 0x9c, 0x74, 0x63, 0x45, 0xd9, 0x16, 0x35, 0x5f, 0xed, 0x78, 0x9f,
|
||||||
|
0x01, 0x48, 0x04, 0xc1, 0x33, 0xd6, 0x4f, 0x94, 0xde, 0x31, 0x9d, 0x0a, 0xac, 0x18, 0x4b, 0xcd,
|
||||||
|
0x98, 0xb8, 0x37, 0xa2, 0x83, 0xec, 0x03, 0xd8, 0xda, 0xe5, 0x7a, 0x6b, 0x53, 0xd5, 0x15, 0xa4,
|
||||||
|
0x43, 0xe9, 0x90, 0x67, 0x58, 0xc0, 0xa5, 0xfa, 0x2a, 0xb1, 0x75, 0x50, 0x39, 0x5c, 0xe6, 0xdc,
|
||||||
|
0x89, 0xfc, 0xcf, 0xfe, 0xf9, 0x57, 0x54, 0x64, 0xa8, 0xee, 0x23, 0x0b, 0xf1, 0xea, 0xfd, 0xdb,
|
||||||
|
0xbd, 0x09, 0xb5, 0x5b, 0x05, 0x86, 0x13, 0xf3, 0x24, 0xc5, 0x3f, 0x44, 0x72, 0x7c, 0x7e, 0x36
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
arr[i] = lut[arr[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//see ASK/MAN Demod for what args are accepted
|
//see ASK/MAN Demod for what args are accepted
|
||||||
int demodGallagher(bool verbose) {
|
int demodGallagher(bool verbose) {
|
||||||
(void) verbose; // unused so far
|
(void) verbose; // unused so far
|
||||||
|
@ -81,7 +105,7 @@ int demodGallagher(bool verbose) {
|
||||||
setDemodBuff(DemodBuffer, 96, ans);
|
setDemodBuff(DemodBuffer, 96, ans);
|
||||||
setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
|
setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
|
||||||
|
|
||||||
//got a good demod
|
// got a good demod
|
||||||
uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
|
uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
|
||||||
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
||||||
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
|
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
|
||||||
|
@ -89,34 +113,30 @@ int demodGallagher(bool verbose) {
|
||||||
// bytes
|
// bytes
|
||||||
uint8_t arr[8] = {0};
|
uint8_t arr[8] = {0};
|
||||||
for (int i = 0, pos = 0; i < ARRAYLEN(arr); i++) {
|
for (int i = 0, pos = 0; i < ARRAYLEN(arr); i++) {
|
||||||
pos = (i * 8) + i;
|
pos = 16 + (9 * i);
|
||||||
arr[i] = bytebits_to_byte(DemodBuffer + pos, 8);
|
arr[i] = bytebits_to_byte(DemodBuffer + pos, 8);
|
||||||
PrintAndLogEx(NORMAL, "%d -" NOLF, pos);
|
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
|
|
||||||
// crc
|
// crc
|
||||||
uint8_t crc = bytebits_to_byte(DemodBuffer + 72, 8);
|
uint8_t crc = bytebits_to_byte(DemodBuffer + 16 + (9 * 8), 8);
|
||||||
uint8_t calc_crc = CRC8Cardx(arr, ARRAYLEN(arr));
|
uint8_t calc_crc = CRC8Cardx(arr, ARRAYLEN(arr));
|
||||||
|
|
||||||
PrintAndLogEx(INFO, " Before: %s", sprint_hex(arr, 8));
|
|
||||||
descramble(arr, ARRAYLEN(arr));
|
descramble(arr, ARRAYLEN(arr));
|
||||||
PrintAndLogEx(INFO, " After : %s", sprint_hex(arr, 8));
|
|
||||||
|
|
||||||
// 4bit region code
|
// 4bit region code
|
||||||
uint8_t rc = (arr[3] & 0x0E) >> 1;
|
uint8_t rc = (arr[3] & 0x1E) >> 1;
|
||||||
|
|
||||||
// 16bit FC
|
// 16bit FC
|
||||||
uint16_t fc = (arr[5] & 0x0F) << 12 | arr[1] << 4 | ((arr[7] >> 4) & 0x0F);
|
uint16_t fc = (arr[5] & 0x0F) << 12 | arr[1] << 4 | ((arr[7] >> 4) & 0x0F);
|
||||||
|
|
||||||
// 24bit CN
|
// 24bit CN
|
||||||
uint32_t cn = arr[0] << 16 | (arr[4] & 0x1F) << 11 | arr[2] << 3 | (arr[3] & 0xE0) >> 4;
|
uint32_t cn = arr[0] << 16 | (arr[4] & 0x1F) << 11 | arr[2] << 3 | (arr[3] & 0xE0) >> 5;
|
||||||
|
|
||||||
// 4bit issue level
|
// 4bit issue level
|
||||||
uint8_t il = arr[7] & 0x0F;
|
uint8_t il = arr[7] & 0x0F;
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "GALLAGHER - Region: " _GREEN_("%u") " FC: " _GREEN_("%u") " CN: " _GREEN_("%u") " Issue Level: " _GREEN_("%u"), rc, fc, cn, il);
|
PrintAndLogEx(SUCCESS, "GALLAGHER - Region: " _GREEN_("%u") " FC: " _GREEN_("%u") " CN: " _GREEN_("%u") " Issue Level: " _GREEN_("%u"), rc, fc, cn, il);
|
||||||
PrintAndLogEx(SUCCESS, " Printed: " _GREEN_("%C%u"), rc + 0x40, fc);
|
PrintAndLogEx(SUCCESS, " Displayed: " _GREEN_("%C%u"), rc + 'A', fc);
|
||||||
PrintAndLogEx(SUCCESS, " Raw: %08X%08X%08X", raw1, raw2, raw3);
|
PrintAndLogEx(SUCCESS, " Raw: %08X%08X%08X", raw1, raw2, raw3);
|
||||||
PrintAndLogEx(SUCCESS, " CRC: %02X - %02X (%s)", crc, calc_crc, (crc == calc_crc) ? "ok" : "fail");
|
PrintAndLogEx(SUCCESS, " CRC: %02X - %02X (%s)", crc, calc_crc, (crc == calc_crc) ? "ok" : "fail");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -165,6 +185,78 @@ static int CmdGallagherReader(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isValidGallagherParams(int8_t rc, int32_t fc, int32_t cn, int8_t il) {
|
||||||
|
bool isValid = true;
|
||||||
|
|
||||||
|
// if one is set, all must be set
|
||||||
|
if (rc < 0 || fc < 0 || cn < 0 || il < 0) {
|
||||||
|
PrintAndLogEx(FAILED, "If rc/fc/cn/il is specified, all must be set");
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
// validate input
|
||||||
|
if (rc > 0x0f) {
|
||||||
|
PrintAndLogEx(FAILED, "Region code must be less than 16 (4 bits)");
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
if (fc > 0xffff) {
|
||||||
|
PrintAndLogEx(FAILED, "Facility code must be less than 65536 (2 bytes)");
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
if (cn > 0xffffff) {
|
||||||
|
PrintAndLogEx(FAILED, "Card number must be less than 16777216 (3 bytes)");
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
if (il > 0x0f) {
|
||||||
|
PrintAndLogEx(FAILED, "Issue level must be less than 16 (4 bits)");
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setBitsInBlocks(uint32_t *blocks, uint8_t *pos, uint32_t data, uint8_t data_len) {
|
||||||
|
for (int i = data_len - 1; i >= 0; i--) {
|
||||||
|
uint8_t blk = *pos / 32;
|
||||||
|
uint8_t bitPos = 31 - *pos % 32; // fill from left
|
||||||
|
uint8_t bit = (data >> i) & 1;
|
||||||
|
blocks[blk] |= bit << bitPos;
|
||||||
|
(*pos)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void createBlocks(uint32_t *blocks, uint8_t rc, uint16_t fc, uint32_t cn, uint8_t il) {
|
||||||
|
// put data into the correct places (Gallagher obfuscation)
|
||||||
|
uint8_t arr[8] = {0};
|
||||||
|
arr[0] = (cn & 0xffffff) >> 16;
|
||||||
|
arr[1] = (fc & 0xfff) >> 4;
|
||||||
|
arr[2] = (cn & 0x7ff) >> 3;
|
||||||
|
arr[3] = (cn & 0x7) << 5 | (rc & 0xf) << 1;
|
||||||
|
arr[4] = (cn & 0xffff) >> 11;
|
||||||
|
arr[5] = (fc & 0xffff) >> 12;
|
||||||
|
arr[6] = 0;
|
||||||
|
arr[7] = (fc & 0xf) << 4 | (il & 0xf);
|
||||||
|
|
||||||
|
// more obfuscation
|
||||||
|
scramble(arr, ARRAYLEN(arr));
|
||||||
|
|
||||||
|
blocks[0] = blocks[1] = blocks[2] = 0;
|
||||||
|
uint8_t pos = 0;
|
||||||
|
|
||||||
|
// magic prefix
|
||||||
|
setBitsInBlocks(blocks, &pos, 0x7fea, 16);
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAYLEN(arr); i++) {
|
||||||
|
// data byte
|
||||||
|
setBitsInBlocks(blocks, &pos, arr[i], 8);
|
||||||
|
|
||||||
|
// every byte is followed by a bit which is the inverse of the last bit
|
||||||
|
setBitsInBlocks(blocks, &pos, !(arr[i] & 0x1), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// checksum
|
||||||
|
uint8_t crc = CRC8Cardx(arr, ARRAYLEN(arr));
|
||||||
|
setBitsInBlocks(blocks, &pos, crc, 8);
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdGallagherClone(const char *Cmd) {
|
static int CmdGallagherClone(const char *Cmd) {
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
|
@ -172,14 +264,19 @@ static int CmdGallagherClone(const char *Cmd) {
|
||||||
"clone a GALLAGHER tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
"clone a GALLAGHER tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
|
||||||
"lf gallagher clone --raw 0FFD5461A9DA1346B2D1AC32\n"
|
"lf gallagher clone --raw 0FFD5461A9DA1346B2D1AC32\n"
|
||||||
"lf gallagher clone --q5 --raw 0FFD5461A9DA1346B2D1AC32 -> encode for Q5/T5555 tag\n"
|
"lf gallagher clone --q5 --raw 0FFD5461A9DA1346B2D1AC32 -> encode for Q5/T5555 tag\n"
|
||||||
"lf gallagher clone --em --raw 0FFD5461A9DA1346B2D1AC32 -> encode for EM4305/4469"
|
"lf gallagher clone --em --raw 0FFD5461A9DA1346B2D1AC32 -> encode for EM4305/4469\n"
|
||||||
|
"lf gallagher clone --rc 0 --fc 9876 --cn 1234 --il 1"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
||||||
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
|
||||||
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
|
||||||
|
arg_int0(NULL, "rc", "<decimal>", "Region code. 4 bits max"),
|
||||||
|
arg_int0(NULL, "fc", "<decimal>", "Facility code. 2 bytes max"),
|
||||||
|
arg_int0(NULL, "cn", "<decimal>", "Card number. 3 bytes max"),
|
||||||
|
arg_int0(NULL, "il", "<decimal>", "Issue level. 4 bits max"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
@ -187,20 +284,52 @@ static int CmdGallagherClone(const char *Cmd) {
|
||||||
int raw_len = 0;
|
int raw_len = 0;
|
||||||
// skip first block, 3*4 = 12 bytes left
|
// skip first block, 3*4 = 12 bytes left
|
||||||
uint8_t raw[12] = {0};
|
uint8_t raw[12] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), raw, sizeof raw, &raw_len);
|
||||||
|
if (res) {
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
bool q5 = arg_get_lit(ctx, 2);
|
bool q5 = arg_get_lit(ctx, 2);
|
||||||
bool em = arg_get_lit(ctx, 3);
|
bool em = arg_get_lit(ctx, 3);
|
||||||
|
int16_t region_code = arg_get_int_def(ctx, 4, -1);
|
||||||
|
int32_t facility_code = arg_get_int_def(ctx, 5, -1);
|
||||||
|
uint64_t card_number = arg_get_int_def(ctx, 6, -1);
|
||||||
|
uint32_t issue_level = arg_get_int_def(ctx, 7, -1);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
bool use_raw = raw_len > 0;
|
||||||
|
|
||||||
if (q5 && em) {
|
if (q5 && em) {
|
||||||
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (region_code == -1 && facility_code == -1 && card_number == -1 && issue_level == -1) {
|
||||||
|
if (!use_raw) {
|
||||||
|
PrintAndLogEx(FAILED, "Must specify either raw data to clone, or rc/fc/cn/il");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// --raw and --rc/fc/cn/il are mutually exclusive
|
||||||
|
if (use_raw) {
|
||||||
|
PrintAndLogEx(FAILED, "Can't specify both raw and rc/fc/cn/il at the same time");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (!isValidGallagherParams(region_code, facility_code, card_number, issue_level)) {
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t blocks[4];
|
uint32_t blocks[4];
|
||||||
|
if (use_raw) {
|
||||||
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
|
||||||
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// fill blocks 1 to 3 with Gallagher data
|
||||||
|
createBlocks(blocks + 1, region_code, facility_code, card_number, issue_level);
|
||||||
|
}
|
||||||
|
|
||||||
//Pac - compat mode, NRZ, data rate 40, 3 data blocks
|
//Pac - compat mode, NRZ, data rate 40, 3 data blocks
|
||||||
blocks[0] = T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT;
|
blocks[0] = T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||||
|
@ -217,10 +346,10 @@ static int CmdGallagherClone(const char *Cmd) {
|
||||||
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Preparing to clone Gallagher to " _YELLOW_("%s") " with raw hex", cardtype);
|
PrintAndLogEx(INFO, "Preparing to clone Gallagher to " _YELLOW_("%s") " from %s.",
|
||||||
|
cardtype, use_raw ? "raw hex" : "specified data");
|
||||||
print_blocks(blocks, ARRAYLEN(blocks));
|
print_blocks(blocks, ARRAYLEN(blocks));
|
||||||
|
|
||||||
int res;
|
|
||||||
if (em) {
|
if (em) {
|
||||||
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -237,20 +366,68 @@ static int CmdGallagherSim(const char *Cmd) {
|
||||||
CLIParserInit(&ctx, "lf gallagher sim",
|
CLIParserInit(&ctx, "lf gallagher sim",
|
||||||
"Enables simulation of GALLAGHER card with specified card number.\n"
|
"Enables simulation of GALLAGHER card with specified card number.\n"
|
||||||
"Simulation runs until the button is pressed or another USB command is issued.\n",
|
"Simulation runs until the button is pressed or another USB command is issued.\n",
|
||||||
"lf gallagher sim --raw 0FFD5461A9DA1346B2D1AC32"
|
"lf gallagher sim --raw 0FFD5461A9DA1346B2D1AC32\n"
|
||||||
|
"lf gallagher sim --rc 0 --fc 9876 --cn 1234 --il 1"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes max"),
|
||||||
|
arg_int0(NULL, "rc", "<decimal>", "Region code. 4 bits max"),
|
||||||
|
arg_int0(NULL, "fc", "<decimal>", "Facility code. 2 bytes max"),
|
||||||
|
arg_int0(NULL, "cn", "<decimal>", "Card number. 3 bytes max"),
|
||||||
|
arg_int0(NULL, "il", "<decimal>", "Issue level. 4 bits max"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
int raw_len = 0;
|
int raw_len = 0;
|
||||||
// skip first block, 3*4 = 12 bytes left
|
// skip first block, 3*4 = 12 bytes left
|
||||||
uint8_t raw[12] = {0};
|
uint8_t raw[12] = {0};
|
||||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||||
|
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), raw, sizeof raw, &raw_len);
|
||||||
|
if (res) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t region_code = arg_get_int_def(ctx, 2, -1);
|
||||||
|
int32_t facility_code = arg_get_int_def(ctx, 3, -1);
|
||||||
|
uint64_t card_number = arg_get_int_def(ctx, 4, -1);
|
||||||
|
uint32_t issue_level = arg_get_int_def(ctx, 5, -1);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
bool use_raw = raw_len > 0;
|
||||||
|
|
||||||
|
if (region_code == -1 && facility_code == -1 && card_number == -1 && issue_level == -1) {
|
||||||
|
if (!use_raw) {
|
||||||
|
PrintAndLogEx(FAILED, "Must specify either raw data to clone, or rc/fc/cn/il");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// --raw and --rc/fc/cn/il are mutually exclusive
|
||||||
|
if (use_raw) {
|
||||||
|
PrintAndLogEx(FAILED, "Can't specify both raw and rc/fc/cn/il at the same time");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (!isValidGallagherParams(region_code, facility_code, card_number, issue_level)) {
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!use_raw) {
|
||||||
|
// generate Gallagher data
|
||||||
|
uint32_t blocks[3];
|
||||||
|
createBlocks(blocks, region_code, facility_code, card_number, issue_level);
|
||||||
|
|
||||||
|
// convert to the normal 'raw' format
|
||||||
|
for (int i = 0; i < ARRAYLEN(blocks); i++) {
|
||||||
|
raw[(4 * i) + 0] = (blocks[i] >> 24) & 0xff;
|
||||||
|
raw[(4 * i) + 1] = (blocks[i] >> 16) & 0xff;
|
||||||
|
raw[(4 * i) + 2] = (blocks[i] >> 8) & 0xff;
|
||||||
|
raw[(4 * i) + 3] = (blocks[i]) & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ASK/MAN sim.
|
// ASK/MAN sim.
|
||||||
PrintAndLogEx(SUCCESS, "Simulating Gallagher - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
|
PrintAndLogEx(SUCCESS, "Simulating Gallagher - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
|
||||||
|
@ -269,14 +446,7 @@ static int CmdGallagherSim(const char *Cmd) {
|
||||||
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs));
|
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs));
|
||||||
free(payload);
|
free(payload);
|
||||||
|
|
||||||
PacketResponseNG resp;
|
return lfsim_wait_check(CMD_LF_ASK_SIMULATE);
|
||||||
WaitForResponse(CMD_LF_ASK_SIMULATE, &resp);
|
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Done");
|
|
||||||
if (resp.status != PM3_EOPABORTED)
|
|
||||||
return resp.status;
|
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
#include "cliparser.h"
|
#include "cliparser.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "graph.h"
|
#include "graph.h"
|
||||||
#include "cmddata.h" //for g_debugMode, demodbuff cmds
|
#include "cmddata.h" // g_debugMode, demodbuff cmds
|
||||||
#include "cmdlf.h" // lf_read
|
#include "cmdlf.h" // lf_read, lfsim_wait_check
|
||||||
#include "util_posix.h"
|
#include "util_posix.h"
|
||||||
#include "lfdemod.h"
|
#include "lfdemod.h"
|
||||||
#include "wiegand_formats.h"
|
#include "wiegand_formats.h"
|
||||||
|
@ -58,7 +58,7 @@ static int sendTry(uint8_t format_idx, wiegand_card_t *card, uint32_t delay, boo
|
||||||
wiegand_message_t packed;
|
wiegand_message_t packed;
|
||||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (HIDPack(format_idx, card, &packed) == false) {
|
if (HIDPack(format_idx, card, &packed, true) == false) {
|
||||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
@ -223,10 +223,7 @@ static int CmdHIDWatch(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_HID_WATCH, NULL, 0);
|
SendCommandNG(CMD_LF_HID_WATCH, NULL, 0);
|
||||||
PacketResponseNG resp;
|
return lfsim_wait_check(CMD_LF_HID_WATCH);
|
||||||
WaitForResponse(CMD_LF_HID_WATCH, &resp);
|
|
||||||
PrintAndLogEx(INFO, "Done");
|
|
||||||
return resp.status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHIDSim(const char *Cmd) {
|
static int CmdHIDSim(const char *Cmd) {
|
||||||
|
@ -287,7 +284,7 @@ static int CmdHIDSim(const char *Cmd) {
|
||||||
packed.Mid = mid;
|
packed.Mid = mid;
|
||||||
packed.Bot = bot;
|
packed.Bot = bot;
|
||||||
} else {
|
} else {
|
||||||
if (HIDPack(format_idx, &card, &packed) == false) {
|
if (HIDPack(format_idx, &card, &packed, true) == false) {
|
||||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
@ -300,8 +297,6 @@ static int CmdHIDSim(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Simulating HID tag using raw " _GREEN_("%s"), raw);
|
PrintAndLogEx(INFO, "Simulating HID tag using raw " _GREEN_("%s"), raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
|
|
||||||
|
|
||||||
lf_hidsim_t payload;
|
lf_hidsim_t payload;
|
||||||
payload.hi2 = packed.Top;
|
payload.hi2 = packed.Top;
|
||||||
payload.hi = packed.Mid;
|
payload.hi = packed.Mid;
|
||||||
|
@ -310,13 +305,7 @@ static int CmdHIDSim(const char *Cmd) {
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||||
PacketResponseNG resp;
|
return lfsim_wait_check(CMD_LF_HID_SIMULATE);
|
||||||
WaitForResponse(CMD_LF_HID_SIMULATE, &resp);
|
|
||||||
PrintAndLogEx(INFO, "Done");
|
|
||||||
if (resp.status != PM3_EOPABORTED)
|
|
||||||
return resp.status;
|
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHIDClone(const char *Cmd) {
|
static int CmdHIDClone(const char *Cmd) {
|
||||||
|
@ -401,7 +390,7 @@ static int CmdHIDClone(const char *Cmd) {
|
||||||
packed.Mid = mid;
|
packed.Mid = mid;
|
||||||
packed.Bot = bot;
|
packed.Bot = bot;
|
||||||
} else {
|
} else {
|
||||||
if (HIDPack(format_idx, &card, &packed) == false) {
|
if (HIDPack(format_idx, &card, &packed, true) == false) {
|
||||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -544,7 +544,8 @@ static int CmdIndalaSim(const char *Cmd) {
|
||||||
|
|
||||||
// raw param
|
// raw param
|
||||||
int raw_len = 0;
|
int raw_len = 0;
|
||||||
uint8_t raw[(7 * 4) + 1 ];
|
uint8_t raw[(7 * 4) + 1];
|
||||||
|
memset(raw, 0, sizeof(raw));
|
||||||
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
|
||||||
|
|
||||||
bool is_long_uid = (raw_len == 28);
|
bool is_long_uid = (raw_len == 28);
|
||||||
|
@ -569,15 +570,21 @@ static int CmdIndalaSim(const char *Cmd) {
|
||||||
uint8_t bs[224];
|
uint8_t bs[224];
|
||||||
memset(bs, 0x00, sizeof(bs));
|
memset(bs, 0x00, sizeof(bs));
|
||||||
|
|
||||||
uint8_t counter = 223;
|
uint8_t counter = 0;
|
||||||
for (uint8_t i = 0; i < raw_len; i++) {
|
for (int8_t i = 0; i < raw_len; i++) {
|
||||||
uint8_t tmp = raw[i];
|
uint8_t tmp = raw[i];
|
||||||
for (uint8_t j = 0; j < 8; j++) {
|
bs[counter++] = (tmp >> 7) & 1;
|
||||||
bs[counter--] = tmp & 1;
|
bs[counter++] = (tmp >> 6) & 1;
|
||||||
tmp >>= 1;
|
bs[counter++] = (tmp >> 5) & 1;
|
||||||
}
|
bs[counter++] = (tmp >> 4) & 1;
|
||||||
|
bs[counter++] = (tmp >> 3) & 1;
|
||||||
|
bs[counter++] = (tmp >> 2) & 1;
|
||||||
|
bs[counter++] = (tmp >> 1) & 1;
|
||||||
|
bs[counter++] = tmp & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a0 00 00 00 bd 98 9a 11
|
||||||
|
|
||||||
// indala PSK
|
// indala PSK
|
||||||
// It has to send either 64bits (8bytes) or 224bits (28bytes). Zero padding needed if not.
|
// It has to send either 64bits (8bytes) or 224bits (28bytes). Zero padding needed if not.
|
||||||
// lf simpsk 1 c 32 r 2 d 0102030405060708
|
// lf simpsk 1 c 32 r 2 d 0102030405060708
|
||||||
|
@ -593,10 +600,10 @@ static int CmdIndalaSim(const char *Cmd) {
|
||||||
payload->carrier = 2;
|
payload->carrier = 2;
|
||||||
payload->invert = 0;
|
payload->invert = 0;
|
||||||
payload->clock = 32;
|
payload->clock = 32;
|
||||||
memcpy(payload->data, bs, sizeof(bs));
|
memcpy(payload->data, bs, raw_len * 8);
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs));
|
SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + (raw_len * 8));
|
||||||
free(payload);
|
free(payload);
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
|
|
@ -50,10 +50,7 @@ static int CmdIOProxWatch(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_IO_WATCH, NULL, 0);
|
SendCommandNG(CMD_LF_IO_WATCH, NULL, 0);
|
||||||
PacketResponseNG resp;
|
return lfsim_wait_check(CMD_LF_IO_WATCH);
|
||||||
WaitForResponse(CMD_LF_IO_WATCH, &resp);
|
|
||||||
PrintAndLogEx(INFO, "Done");
|
|
||||||
return resp.status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//IO-Prox demod - FSK RF/64 with preamble of 000000001
|
//IO-Prox demod - FSK RF/64 with preamble of 000000001
|
||||||
|
|
|
@ -98,7 +98,7 @@ static void arg_add_t55xx_downloadlink(void *at[], uint8_t *idx, uint8_t show, u
|
||||||
at[n++] = arg_lit0(NULL, "r3", r3);
|
at[n++] = arg_lit0(NULL, "r3", r3);
|
||||||
|
|
||||||
if (show == T55XX_DLMODE_ALL) {
|
if (show == T55XX_DLMODE_ALL) {
|
||||||
char *r4 = (char *)calloc(50, sizeof(uint8_t));
|
char *r4 = (char *)calloc(56, sizeof(uint8_t));
|
||||||
sprintf(r4, "try all downlink modes %s", (dl_mode_def == 4) ? "(def)" : "");
|
sprintf(r4, "try all downlink modes %s", (dl_mode_def == 4) ? "(def)" : "");
|
||||||
at[n++] = arg_lit0(NULL, "all", r4);
|
at[n++] = arg_lit0(NULL, "all", r4);
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,6 @@ static void arg_add_t55xx_downloadlink(void *at[], uint8_t *idx, uint8_t show, u
|
||||||
*idx = n;
|
*idx = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int usage_t55xx_config(void) {
|
static int usage_t55xx_config(void) {
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx config [c <blk0>] [d <demodulation>] [i [0/1]] [o <offset>] [Q5 [0/1]] [ST [0/1]]");
|
PrintAndLogEx(NORMAL, "Usage: lf t55xx config [c <blk0>] [d <demodulation>] [i [0/1]] [o <offset>] [Q5 [0/1]] [ST [0/1]]");
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
PrintAndLogEx(NORMAL, "Options:");
|
||||||
|
@ -236,48 +235,6 @@ static int usage_t55xx_restore(void) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
static int usage_t55xx_detect(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx detect [1] [r <mode>] [p <password>]");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " 1 - if set, use Graphbuffer otherwise read data from tag.");
|
|
||||||
PrintAndLogEx(NORMAL, " p <password - OPTIONAL password (8 hex characters)");
|
|
||||||
print_usage_t55xx_downloadlink(T55XX_DLMODE_ALL, T55XX_DLMODE_ALL);
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx detect"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx detect 1"));
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx detect p 11223344"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
static int usage_t55xx_wakup(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx wakeup [h] [r <mode>] p <password>");
|
|
||||||
PrintAndLogEx(NORMAL, "This commands sends the Answer-On-Request command and leaves the readerfield ON afterwards.");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h - this help");
|
|
||||||
PrintAndLogEx(NORMAL, " p <password> - password 4bytes (8 hex symbols)");
|
|
||||||
print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode);
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx wakeup p 11223344") " - send wakeup password");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usage_t55xx_dangerraw(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "This command allows to emit arbitrary raw commands on T5577 and cut the field after arbitrary duration.");
|
|
||||||
PrintAndLogEx(NORMAL, _RED_("WARNING:") " this may lock definitively the tag in an unusable state!");
|
|
||||||
PrintAndLogEx(NORMAL, "Uncontrolled usage can easily write an invalid configuration, activate lock bits,");
|
|
||||||
PrintAndLogEx(NORMAL, "OTP bit, password protection bit, deactivate test-mode, lock your card forever.");
|
|
||||||
PrintAndLogEx(NORMAL, "Uncontrolled usage is known to the State of California to cause cancer.");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf t55xx dangerraw [h] [b <bitstream> t <timing>]");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h - This help");
|
|
||||||
PrintAndLogEx(NORMAL, " b <bitstream> - raw bitstream");
|
|
||||||
PrintAndLogEx(NORMAL, " t <timing> - time in microseconds before dropping the field");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usage_t55xx_clonehelp(void) {
|
static int usage_t55xx_clonehelp(void) {
|
||||||
PrintAndLogEx(NORMAL, "For cloning specific techs on T55xx tags, see commands available in corresponding LF sub-menus, e.g.:");
|
PrintAndLogEx(NORMAL, "For cloning specific techs on T55xx tags, see commands available in corresponding LF sub-menus, e.g.:");
|
||||||
|
@ -915,66 +872,156 @@ static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
|
||||||
PrintAndLogEx(NORMAL, msg);
|
PrintAndLogEx(NORMAL, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define prototype to call from within detect.
|
static int CmdT55xxWakeUp(const char *Cmd) {
|
||||||
static int CmdT55xxWakeUp(const char *Cmd);
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "lf t55xx wakeup",
|
||||||
|
"This commands sends the Answer-On-Request command and leaves the readerfield ON afterwards",
|
||||||
|
"lf t55xx wakeup -p 11223344 --> send wakeup with password\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1 (help) + 2 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
|
||||||
|
void *argtable[3 + 5] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
|
||||||
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
};
|
||||||
|
uint8_t idx = 3;
|
||||||
|
arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, config.downlink_mode);
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
|
uint32_t password = 0;
|
||||||
|
int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &password, 4, true);
|
||||||
|
if (res == 0 || res == 2) {
|
||||||
|
PrintAndLogEx(ERR, "Password should be 4 hex bytes");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
|
bool r0 = arg_get_lit(ctx, 3);
|
||||||
|
bool r1 = arg_get_lit(ctx, 4);
|
||||||
|
bool r2 = arg_get_lit(ctx, 5);
|
||||||
|
bool r3 = arg_get_lit(ctx, 6);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if ((r0 + r1 + r2 + r3) > 1) {
|
||||||
|
PrintAndLogEx(FAILED, "Error multiple downlink encoding");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t downlink_mode = config.downlink_mode;
|
||||||
|
if (r0)
|
||||||
|
downlink_mode = refFixedBit;
|
||||||
|
else if (r1)
|
||||||
|
downlink_mode = refLongLeading;
|
||||||
|
else if (r2)
|
||||||
|
downlink_mode = refLeading0;
|
||||||
|
else if (r3)
|
||||||
|
downlink_mode = ref1of4;
|
||||||
|
|
||||||
|
struct p {
|
||||||
|
uint32_t password;
|
||||||
|
uint8_t flags;
|
||||||
|
} PACKED payload;
|
||||||
|
|
||||||
|
payload.password = password;
|
||||||
|
payload.flags = (downlink_mode << 3);
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_LF_T55XX_WAKEUP, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
if (WaitForResponseTimeout(CMD_LF_T55XX_WAKEUP, NULL, 1000) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "command execution time out");
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now");
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdT55xxDetect(const char *Cmd) {
|
static int CmdT55xxDetect(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "lf t55xx detect",
|
||||||
|
"Try detecting the tag modulation from reading the configuration block",
|
||||||
|
"lf t55xx detect\n"
|
||||||
|
"lf t55xx detect -1\n"
|
||||||
|
"lf t55xx detect -p 11223344\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1 (help) + 2 (two user specified params) + (6 T55XX_DLMODE_ALL)
|
||||||
|
void *argtable[3 + 6] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0("1", NULL, "extract using data from graphbuffer"),
|
||||||
|
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
|
||||||
|
};
|
||||||
|
uint8_t idx = 3;
|
||||||
|
arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_ALL, config.downlink_mode);
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
|
bool use_gb = arg_get_lit(ctx, 1);
|
||||||
|
|
||||||
bool errors = false;
|
|
||||||
bool useGB = false;
|
|
||||||
bool usepwd = false;
|
bool usepwd = false;
|
||||||
|
uint64_t password = -1;
|
||||||
|
uint32_t tmp_pwd = 0;
|
||||||
|
int res = arg_get_u32_hexstr_def_nlen(ctx, 2, 0, &tmp_pwd, 4, true);
|
||||||
|
if (res == 0 || res == 2) {
|
||||||
|
PrintAndLogEx(ERR, "Password should be 4 hex bytes");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (res == 1) {
|
||||||
|
usepwd = true;
|
||||||
|
password = tmp_pwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool r0 = arg_get_lit(ctx, 3);
|
||||||
|
bool r1 = arg_get_lit(ctx, 4);
|
||||||
|
bool r2 = arg_get_lit(ctx, 5);
|
||||||
|
bool r3 = arg_get_lit(ctx, 6);
|
||||||
|
bool ra = arg_get_lit(ctx, 7);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if ((r0 + r1 + r2 + r3 + ra) > 1) {
|
||||||
|
PrintAndLogEx(FAILED, "Error multiple downlink encoding");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_all_dl_modes = false;
|
||||||
|
uint8_t downlink_mode = config.downlink_mode;
|
||||||
|
if (r0)
|
||||||
|
downlink_mode = refFixedBit;
|
||||||
|
else if (r1)
|
||||||
|
downlink_mode = refLongLeading;
|
||||||
|
else if (r2)
|
||||||
|
downlink_mode = refLeading0;
|
||||||
|
else if (r3)
|
||||||
|
downlink_mode = ref1of4;
|
||||||
|
|
||||||
|
if (ra)
|
||||||
|
try_all_dl_modes = true;
|
||||||
|
|
||||||
bool try_with_pwd = false;
|
bool try_with_pwd = false;
|
||||||
bool try_all_dl_modes = true;
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
bool usewake = false;
|
bool usewake = false;
|
||||||
uint64_t password = -1;
|
|
||||||
uint8_t cmdp = 0;
|
|
||||||
uint8_t downlink_mode = 0;
|
|
||||||
char wakecmd[20] = { 0x00 };
|
|
||||||
struct timespec sleepperiod;
|
|
||||||
|
|
||||||
// Setup the 90ms time value to sleep for after the wake, to allow delay init to complete (~70ms)
|
// Setup the 90ms time value to sleep for after the wake, to allow delay init to complete (~70ms)
|
||||||
|
struct timespec sleepperiod;
|
||||||
sleepperiod.tv_sec = 0;
|
sleepperiod.tv_sec = 0;
|
||||||
sleepperiod.tv_nsec = 90000000;
|
sleepperiod.tv_nsec = 90000000;
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
|
||||||
case 'h':
|
|
||||||
return usage_t55xx_detect();
|
|
||||||
case 'p':
|
|
||||||
password = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
|
||||||
sprintf(wakecmd, "p %08x q", (uint32_t)(password & 0xFFFFFFFF));
|
|
||||||
usepwd = true;
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
useGB = true;
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10);
|
|
||||||
if (downlink_mode <= 3) try_all_dl_modes = false; // User selected ONLY 1 so honor.
|
|
||||||
if (downlink_mode == 4) try_all_dl_modes = true;
|
|
||||||
if (downlink_mode > 3) downlink_mode = 0;
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (errors) return usage_t55xx_detect();
|
|
||||||
|
|
||||||
|
|
||||||
// detect called so clear data blocks
|
// detect called so clear data blocks
|
||||||
T55x7_ClearAllBlockData();
|
T55x7_ClearAllBlockData();
|
||||||
|
|
||||||
// sanity check.
|
// sanity check.
|
||||||
if (SanityOfflineCheck(useGB) != PM3_SUCCESS)
|
if (SanityOfflineCheck(use_gb) != PM3_SUCCESS)
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
|
||||||
if (useGB == false) {
|
if (use_gb == false) {
|
||||||
|
|
||||||
|
char wakecmd[20] = { 0x00 };
|
||||||
|
sprintf(wakecmd, "-p %08" PRIx64, password);
|
||||||
|
|
||||||
// do ... while not found and not yet tried with wake (for AOR or Init Delay)
|
// do ... while not found and not yet tried with wake (for AOR or Init Delay)
|
||||||
do {
|
do {
|
||||||
// do ... while to check without password then loop back if password supplied
|
// do ... while to check without password then loop back if password supplied
|
||||||
|
@ -987,7 +1034,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
if (try_with_pwd)
|
if (try_with_pwd)
|
||||||
CmdT55xxWakeUp(wakecmd);
|
CmdT55xxWakeUp(wakecmd);
|
||||||
else
|
else
|
||||||
CmdT55xxWakeUp("q");
|
CmdT55xxWakeUp("");
|
||||||
// sleep 90 ms
|
// sleep 90 ms
|
||||||
nanosleep(&sleepperiod, &sleepperiod);
|
nanosleep(&sleepperiod, &sleepperiod);
|
||||||
}
|
}
|
||||||
|
@ -999,7 +1046,6 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1008,7 +1054,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
if (try_with_pwd)
|
if (try_with_pwd)
|
||||||
CmdT55xxWakeUp(wakecmd);
|
CmdT55xxWakeUp(wakecmd);
|
||||||
else
|
else
|
||||||
CmdT55xxWakeUp("q");
|
CmdT55xxWakeUp("");
|
||||||
// sleep 90 ms
|
// sleep 90 ms
|
||||||
nanosleep(&sleepperiod, &sleepperiod);
|
nanosleep(&sleepperiod, &sleepperiod);
|
||||||
}
|
}
|
||||||
|
@ -1019,7 +1065,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle so we loop back if not found and try with pwd
|
// toggle so we loop back if not found and try with pwd
|
||||||
if (!found && usepwd)
|
if (found == false && usepwd)
|
||||||
try_with_pwd = !try_with_pwd;
|
try_with_pwd = !try_with_pwd;
|
||||||
|
|
||||||
// force exit as detect block has been found
|
// force exit as detect block has been found
|
||||||
|
@ -1029,7 +1075,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
||||||
} while (try_with_pwd);
|
} while (try_with_pwd);
|
||||||
// Toggle so we loop back and try with wakeup.
|
// Toggle so we loop back and try with wakeup.
|
||||||
usewake = !usewake;
|
usewake = !usewake;
|
||||||
} while (!found && usewake);
|
} while (found == false && usewake);
|
||||||
} else {
|
} else {
|
||||||
found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig);
|
found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig);
|
||||||
}
|
}
|
||||||
|
@ -1553,63 +1599,6 @@ int printConfiguration(t55xx_conf_block_t b) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdT55xxWakeUp(const char *Cmd) {
|
|
||||||
|
|
||||||
uint32_t password = 0;
|
|
||||||
uint8_t cmdp = 0;
|
|
||||||
bool errors = false;
|
|
||||||
uint8_t downlink_mode = config.downlink_mode;
|
|
||||||
bool quiet = false;
|
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
|
||||||
case 'h':
|
|
||||||
return usage_t55xx_wakup();
|
|
||||||
case 'p':
|
|
||||||
password = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
downlink_mode = param_get8ex(Cmd, cmdp + 1, 0, 10);
|
|
||||||
if (downlink_mode > 3)
|
|
||||||
downlink_mode = 0;
|
|
||||||
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
quiet = true;
|
|
||||||
cmdp++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errors) return usage_t55xx_wakup();
|
|
||||||
|
|
||||||
struct p {
|
|
||||||
uint32_t password;
|
|
||||||
uint8_t flags;
|
|
||||||
} PACKED payload;
|
|
||||||
|
|
||||||
payload.password = password;
|
|
||||||
payload.flags = (downlink_mode & 3) << 3;
|
|
||||||
|
|
||||||
clearCommandBuffer();
|
|
||||||
SendCommandNG(CMD_LF_T55XX_WAKEUP, (uint8_t *)&payload, sizeof(payload));
|
|
||||||
if (!WaitForResponseTimeout(CMD_LF_T55XX_WAKEUP, NULL, 1000)) {
|
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
|
||||||
return PM3_ETIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!quiet)
|
|
||||||
PrintAndLogEx(SUCCESS, "Wake up command sent. Try read now");
|
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdT55xxWriteBlock(const char *Cmd) {
|
static int CmdT55xxWriteBlock(const char *Cmd) {
|
||||||
uint8_t block = 0xFF; // default to invalid block
|
uint8_t block = 0xFF; // default to invalid block
|
||||||
uint32_t data = 0; // default to blank Block
|
uint32_t data = 0; // default to blank Block
|
||||||
|
@ -1695,59 +1684,48 @@ static int CmdT55xxWriteBlock(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdT55xxDangerousRaw(const char *Cmd) {
|
static int CmdT55xxDangerousRaw(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "lf t55xx dangerraw",
|
||||||
|
"This command allows to emit arbitrary raw commands on T5577 and cut the field after arbitrary duration.\n"
|
||||||
|
"Uncontrolled usage can easily write an invalid configuration, activate lock bits,\n"
|
||||||
|
"OTP bit, password protection bit, deactivate test-mode, lock your card forever.\n"
|
||||||
|
_RED_("WARNING:") _CYAN_(" this may lock definitively the tag in an unusable state!"),
|
||||||
|
"lf t55xx dangerraw -d 01000000000000010000100000000100000000 -t 3200\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1("d", "data", NULL, "raw bit string"),
|
||||||
|
arg_int1("t", "time", "<us>", "<0 - 200000> time in microseconds before dropping the field"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
// supports only default downlink mode
|
// supports only default downlink mode
|
||||||
t55xx_test_block_t ng;
|
t55xx_test_block_t ng;
|
||||||
ng.time = 0;
|
ng.time = 0;
|
||||||
ng.bitlen = 0;
|
ng.bitlen = 0;
|
||||||
memset(ng.data, 0x00, sizeof(ng.data));
|
memset(ng.data, 0x00, sizeof(ng.data));
|
||||||
bool errors = false;
|
|
||||||
uint8_t cmdp = 0;
|
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
int bin_len = 127;
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
uint8_t bin[128] = {0};
|
||||||
case 'h':
|
CLIGetStrWithReturn(ctx, 1, bin, &bin_len);
|
||||||
return usage_t55xx_dangerraw();
|
|
||||||
case 't':
|
ng.time = arg_get_int_def(ctx, 2, 0);
|
||||||
ng.time = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (ng.time == 0 || ng.time > 200000) {
|
if (ng.time == 0 || ng.time > 200000) {
|
||||||
PrintAndLogEx(ERR, "Timing off 1..200000 limits, got %i", ng.time);
|
PrintAndLogEx(ERR, "Timing off 1..200000 limits, got %i", ng.time);
|
||||||
errors = true;
|
return PM3_EINVARG;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
cmdp += 2;
|
|
||||||
break;
|
int bs_len = binstring2binarray(ng.data, (char *)bin, bin_len);
|
||||||
case 'b': {
|
if (bs_len == 0) {
|
||||||
uint32_t n = param_getlength(Cmd, cmdp + 1);
|
return PM3_EINVARG;
|
||||||
if (n > 128) {
|
|
||||||
PrintAndLogEx(ERR, "Bitstream too long, max 128 bits, got %i", n);
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (uint8_t i = 0; i < n; i++) {
|
|
||||||
char c = param_getchar_indx(Cmd, i, cmdp + 1);
|
|
||||||
if (c == '0')
|
|
||||||
ng.data[i] = 0;
|
|
||||||
else if (c == '1')
|
|
||||||
ng.data[i] = 1;
|
|
||||||
else {
|
|
||||||
PrintAndLogEx(ERR, "Unknown bit char '%c'", c);
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ng.bitlen = n;
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (errors || ng.bitlen == 0 || ng.time == 0) {
|
|
||||||
return usage_t55xx_dangerraw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ng.bitlen = bs_len;
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_T55XX_DANGERRAW, (uint8_t *)&ng, sizeof(ng));
|
SendCommandNG(CMD_LF_T55XX_DANGERRAW, (uint8_t *)&ng, sizeof(ng));
|
||||||
|
@ -2868,8 +2846,8 @@ static int CmdT55xxWipe(const char *Cmd) {
|
||||||
"lf t55xx wipe -p 11223344 -> wipes a T55x7 tag, config block 0x000880E0, using pwd"
|
"lf t55xx wipe -p 11223344 -> wipes a T55x7 tag, config block 0x000880E0, using pwd"
|
||||||
);
|
);
|
||||||
|
|
||||||
// 4 + (5 or 6)
|
// 1 (help) + 3 (three user specified params) + (5 T55XX_DLMODE_SINGLE)
|
||||||
void *argtable[9] = {
|
void *argtable[4 + 5] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str0("c", "cfg", "<hex>", "configuration block0 (4 hex bytes)"),
|
arg_str0("c", "cfg", "<hex>", "configuration block0 (4 hex bytes)"),
|
||||||
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
|
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
|
||||||
|
@ -2895,8 +2873,9 @@ static int CmdT55xxWipe(const char *Cmd) {
|
||||||
res = arg_get_u32_hexstr_def(ctx, 2, 0x51243648, &password);
|
res = arg_get_u32_hexstr_def(ctx, 2, 0x51243648, &password);
|
||||||
if (res) {
|
if (res) {
|
||||||
usepwd = true;
|
usepwd = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (usepwd && res == 2)
|
if (res == 2) {
|
||||||
PrintAndLogEx(WARNING, "Password should be 4 bytes, using default pwd");
|
PrintAndLogEx(WARNING, "Password should be 4 bytes, using default pwd");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2978,11 +2957,14 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
||||||
"lf t55xx chk --em aa11223344 -> try known pwdgen algo from some cloners based on EM4100 ID"
|
"lf t55xx chk --em aa11223344 -> try known pwdgen algo from some cloners based on EM4100 ID"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Calculate size of argtable accordingly:
|
/*
|
||||||
// 1 (help) + 3 (three user specified params) + ( 5 or 6 T55XX_DLMODE)
|
Calculate size of argtable accordingly:
|
||||||
// 4 + (T55XX_DLMODE_xxx 5)
|
1 (help) + 3 (three user specified params) + ( 5 or 6 T55XX_DLMODE)
|
||||||
// 4 + (T55XX_DLMODE_ALL 6) == 10
|
start index to call arg_add_t55xx_downloadlink() is 4 (1 + 3) given the above sample
|
||||||
void *argtable[10] = {
|
*/
|
||||||
|
|
||||||
|
// 1 (help) + 3 (three user specified params) + (6 T55XX_DLMODE_ALL)
|
||||||
|
void *argtable[4 + 6] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("m", "fm", "use dictionary from flash memory (RDV4)"),
|
arg_lit0("m", "fm", "use dictionary from flash memory (RDV4)"),
|
||||||
arg_str0("f", "file", "<filename>", "file name"),
|
arg_str0("f", "file", "<filename>", "file name"),
|
||||||
|
@ -3198,6 +3180,7 @@ static int CmdT55xxBruteForce(const char *Cmd) {
|
||||||
"lf t55xx bruteforce --r2 -s aaaaaa77 -e aaaaaa99\n"
|
"lf t55xx bruteforce --r2 -s aaaaaa77 -e aaaaaa99\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 1 (help) + 2 (two user specified params) + (6 T55XX_DLMODE_ALL)
|
||||||
void *argtable[3 + 6] = {
|
void *argtable[3 + 6] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1("s", "start", "<hex>", "search start password (4 hex bytes)"),
|
arg_str1("s", "start", "<hex>", "search start password (4 hex bytes)"),
|
||||||
|
@ -3324,8 +3307,8 @@ static int CmdT55xxRecoverPW(const char *Cmd) {
|
||||||
"lf t55xx recoverpw -p 11223344 --r3\n"
|
"lf t55xx recoverpw -p 11223344 --r3\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2 + (5 or 6)
|
// 1 (help) + 1 (one user specified params) + (6 T55XX_DLMODE_ALL)
|
||||||
void *argtable[8] = {
|
void *argtable[2 + 6] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
|
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
|
||||||
};
|
};
|
||||||
|
@ -3564,8 +3547,8 @@ static int CmdT55xxDetectPage1(const char *Cmd) {
|
||||||
"lf t55xx p1detect -p 11223344 --r3\n"
|
"lf t55xx p1detect -p 11223344 --r3\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2 + (5 or 6)
|
// 1 (help) + 2 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
|
||||||
void *argtable[7] = {
|
void *argtable[3 + 5] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("1", NULL, "extract using data from graphbuffer"),
|
arg_lit0("1", NULL, "extract using data from graphbuffer"),
|
||||||
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
|
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
|
||||||
|
@ -3662,6 +3645,7 @@ static int CmdT55xxSetDeviceConfig(const char *Cmd) {
|
||||||
"lf t55xx deviceconfig -a 55 -b 14 -c 21 -d 30 -> default EM4305"
|
"lf t55xx deviceconfig -a 55 -b 14 -c 21 -d 30 -> default EM4305"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 1 (help) + 9 (nine user specified params) + (5 T55XX_DLMODE_SINGLE)
|
||||||
void *argtable[10 + 5] = {
|
void *argtable[10 + 5] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_int0("a", NULL, "<8..255>", "Set start gap"),
|
arg_int0("a", NULL, "<8..255>", "Set start gap"),
|
||||||
|
@ -3772,7 +3756,7 @@ static int CmdT55xxProtect(const char *Cmd) {
|
||||||
"lf t55xx protect -p 11223344 -n 00000000 -> use pwd 11223344, sets new pwd 00000000"
|
"lf t55xx protect -p 11223344 -n 00000000 -> use pwd 11223344, sets new pwd 00000000"
|
||||||
);
|
);
|
||||||
|
|
||||||
// 4 + (5 or 6)
|
// 1 (help) + 3 (three user specified params) + (5 T55XX_DLMODE_SINGLE)
|
||||||
void *argtable[4 + 5] = {
|
void *argtable[4 + 5] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("o", "override", "override safety check"),
|
arg_lit0("o", "override", "override safety check"),
|
||||||
|
|
|
@ -60,6 +60,7 @@ int CmdWiegandEncode(const char *Cmd) {
|
||||||
arg_u64_0(NULL, "issue", "<dec>", "issue level"),
|
arg_u64_0(NULL, "issue", "<dec>", "issue level"),
|
||||||
arg_u64_0(NULL, "oem", "<dec>", "OEM code"),
|
arg_u64_0(NULL, "oem", "<dec>", "OEM code"),
|
||||||
arg_str0("w", "wiegand", "<format>", "see `wiegand list` for available formats"),
|
arg_str0("w", "wiegand", "<format>", "see `wiegand list` for available formats"),
|
||||||
|
arg_lit0(NULL, "pre", "add HID preamble to wiegand"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
@ -75,6 +76,7 @@ int CmdWiegandEncode(const char *Cmd) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
char format[16] = {0};
|
char format[16] = {0};
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)format, sizeof(format), &len);
|
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)format, sizeof(format), &len);
|
||||||
|
bool preamble = arg_get_lit(ctx, 6);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
|
@ -89,14 +91,14 @@ int CmdWiegandEncode(const char *Cmd) {
|
||||||
if (idx != -1) {
|
if (idx != -1) {
|
||||||
wiegand_message_t packed;
|
wiegand_message_t packed;
|
||||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||||
if (HIDPack(idx, &data, &packed) == false) {
|
if (HIDPack(idx, &data, &packed, preamble) == false) {
|
||||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
print_wiegand_code(&packed);
|
print_wiegand_code(&packed);
|
||||||
} else {
|
} else {
|
||||||
// try all formats and print only the ones that work.
|
// try all formats and print only the ones that work.
|
||||||
HIDPackTryAll(&data);
|
HIDPackTryAll(&data, preamble);
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,44 @@ struct wave_info_t {
|
||||||
} PACKED audio_data;
|
} PACKED audio_data;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief detects if file is of a supported filetype based on extension
|
||||||
|
* @param filename
|
||||||
|
* @return o
|
||||||
|
*/
|
||||||
|
DumpFileType_t getfiletype(const char *filename) {
|
||||||
|
// assume unknown file is BINARY
|
||||||
|
DumpFileType_t o = BIN;
|
||||||
|
if (filename == NULL) {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(filename);
|
||||||
|
if (len > 4) {
|
||||||
|
// check if valid file extension and attempt to load data
|
||||||
|
char s[FILE_PATH_SIZE];
|
||||||
|
memset(s, 0, sizeof(s));
|
||||||
|
memcpy(s, filename, len);
|
||||||
|
str_lower(s);
|
||||||
|
|
||||||
|
if (str_endswith(s, "bin")) {
|
||||||
|
o = BIN;
|
||||||
|
} else if (str_endswith(s, "eml")) {
|
||||||
|
o = EML;
|
||||||
|
} else if (str_endswith(s, "json")) {
|
||||||
|
o = JSON;
|
||||||
|
} else if (str_endswith(s, "dic")) {
|
||||||
|
o = DICTIONARY;
|
||||||
|
} else {
|
||||||
|
// mfd, trc, trace is binary
|
||||||
|
o = BIN;
|
||||||
|
// log is text
|
||||||
|
// .pm3 is text values of signal data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief checks if a file exists
|
* @brief checks if a file exists
|
||||||
* @param filename
|
* @param filename
|
||||||
|
|
|
@ -272,4 +272,11 @@ mfu_df_e detect_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose);
|
||||||
int searchAndList(const char *pm3dir, const char *ext);
|
int searchAndList(const char *pm3dir, const char *ext);
|
||||||
int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent);
|
int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief detects if file is of a supported filetype based on extension
|
||||||
|
* @param filename
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
DumpFileType_t getfiletype(const char *filename);
|
||||||
#endif // FILEUTILS_H
|
#endif // FILEUTILS_H
|
||||||
|
|
|
@ -352,7 +352,6 @@ bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge) {
|
||||||
|
|
||||||
if (*rf1 == 0) {
|
if (*rf1 == 0) {
|
||||||
PrintAndLogEx(DEBUG, "DEBUG: Clock detect error");
|
PrintAndLogEx(DEBUG, "DEBUG: Clock detect error");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -806,13 +806,29 @@ int binarraytohex(char *target, const size_t targetlen, char *source, size_t src
|
||||||
|
|
||||||
// convert binary array to human readable binary
|
// convert binary array to human readable binary
|
||||||
void binarraytobinstring(char *target, char *source, int length) {
|
void binarraytobinstring(char *target, char *source, int length) {
|
||||||
int i;
|
for (int i = 0 ; i < length; ++i)
|
||||||
|
|
||||||
for (i = 0 ; i < length ; ++i)
|
|
||||||
*(target++) = *(source++) + '0';
|
*(target++) = *(source++) + '0';
|
||||||
*target = '\0';
|
*target = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int binstring2binarray(uint8_t *target, char *source, int length) {
|
||||||
|
int count = 0;
|
||||||
|
char *start = source;
|
||||||
|
while (length--) {
|
||||||
|
char x = *(source++);
|
||||||
|
// convert from binary value
|
||||||
|
if (x >= '0' && x <= '1')
|
||||||
|
x -= '0';
|
||||||
|
else {
|
||||||
|
PrintAndLogEx(WARNING, "(binstring2binarray) discovered unknown character %c %d at idx %d of %s", x, x, (int16_t)(source - start), start);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*(target++) = x;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
// return parity bit required to match type
|
// return parity bit required to match type
|
||||||
uint8_t GetParity(uint8_t *bits, uint8_t type, int length) {
|
uint8_t GetParity(uint8_t *bits, uint8_t type, int length) {
|
||||||
int x;
|
int x;
|
||||||
|
|
|
@ -83,6 +83,8 @@ int hextobinarray(char *target, char *source);
|
||||||
int hextobinstring(char *target, char *source);
|
int hextobinstring(char *target, char *source);
|
||||||
int binarraytohex(char *target, const size_t targetlen, char *source, size_t srclen);
|
int binarraytohex(char *target, const size_t targetlen, char *source, size_t srclen);
|
||||||
void binarraytobinstring(char *target, char *source, int length);
|
void binarraytobinstring(char *target, char *source, int length);
|
||||||
|
int binstring2binarray(uint8_t *target, char *source, int length);
|
||||||
|
|
||||||
uint8_t GetParity(uint8_t *bits, uint8_t type, int length);
|
uint8_t GetParity(uint8_t *bits, uint8_t type, int length);
|
||||||
void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length);
|
void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length);
|
||||||
void wiegand_add_parity_swapped(uint8_t *target, uint8_t *source, uint8_t length);
|
void wiegand_add_parity_swapped(uint8_t *target, uint8_t *source, uint8_t length);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
|
|
||||||
|
|
||||||
static bool Pack_H10301(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_H10301(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
||||||
|
@ -25,7 +25,9 @@ static bool Pack_H10301(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
packed->Bot |= (card->FacilityCode & 0xFF) << 17;
|
packed->Bot |= (card->FacilityCode & 0xFF) << 17;
|
||||||
packed->Bot |= oddparity32((packed->Bot >> 1) & 0xFFF) & 1;
|
packed->Bot |= oddparity32((packed->Bot >> 1) & 0xFFF) & 1;
|
||||||
packed->Bot |= (evenparity32((packed->Bot >> 13) & 0xFFF) & 1) << 25;
|
packed->Bot |= (evenparity32((packed->Bot >> 13) & 0xFFF) & 1) << 25;
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_H10301(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_H10301(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -40,7 +42,7 @@ static bool Unpack_H10301(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_Tecom27(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_Tecom27(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x7FF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x7FF) return false; // Can't encode FC.
|
||||||
|
@ -51,7 +53,9 @@ static bool Pack_Tecom27(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
packed->Length = 27;
|
packed->Length = 27;
|
||||||
set_nonlinear_field(packed, card->FacilityCode, 10, (uint8_t[]) {15, 19, 24, 23, 22, 18, 6, 10, 14, 3, 2});
|
set_nonlinear_field(packed, card->FacilityCode, 10, (uint8_t[]) {15, 19, 24, 23, 22, 18, 6, 10, 14, 3, 2});
|
||||||
set_nonlinear_field(packed, card->CardNumber, 16, (uint8_t[]) {0, 1, 13, 12, 9, 26, 20, 16, 17, 21, 25, 7, 8, 11, 4, 5});
|
set_nonlinear_field(packed, card->CardNumber, 16, (uint8_t[]) {0, 1, 13, 12, 9, 26, 20, 16, 17, 21, 25, 7, 8, 11, 4, 5});
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_Tecom27(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_Tecom27(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -64,7 +68,7 @@ static bool Unpack_Tecom27(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_2804W(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_2804W(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x0FF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x0FF) return false; // Can't encode FC.
|
||||||
|
@ -84,7 +88,9 @@ static bool Pack_2804W(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_bit_by_position(packed,
|
set_bit_by_position(packed,
|
||||||
oddparity32(get_linear_field(packed, 0, 27))
|
oddparity32(get_linear_field(packed, 0, 27))
|
||||||
, 27);
|
, 27);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_2804W(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_2804W(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -101,7 +107,7 @@ static bool Unpack_2804W(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_ATSW30(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_ATSW30(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
|
||||||
|
@ -118,7 +124,9 @@ static bool Pack_ATSW30(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_bit_by_position(packed,
|
set_bit_by_position(packed,
|
||||||
oddparity32(get_linear_field(packed, 13, 16))
|
oddparity32(get_linear_field(packed, 13, 16))
|
||||||
, 29);
|
, 29);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_ATSW30(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_ATSW30(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -134,7 +142,7 @@ static bool Unpack_ATSW30(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_ADT31(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_ADT31(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x0F) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x0F) return false; // Can't encode FC.
|
||||||
|
@ -146,7 +154,9 @@ static bool Pack_ADT31(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_linear_field(packed, card->FacilityCode, 1, 4);
|
set_linear_field(packed, card->FacilityCode, 1, 4);
|
||||||
set_linear_field(packed, card->CardNumber, 5, 23);
|
set_linear_field(packed, card->CardNumber, 5, 23);
|
||||||
// Parity not known, but 4 bits are unused.
|
// Parity not known, but 4 bits are unused.
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_ADT31(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_ADT31(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -158,7 +168,7 @@ static bool Unpack_ADT31(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_Kastle(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_Kastle(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x00FF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x00FF) return false; // Can't encode FC.
|
||||||
|
@ -173,7 +183,9 @@ static bool Pack_Kastle(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_linear_field(packed, card->CardNumber, 15, 16);
|
set_linear_field(packed, card->CardNumber, 15, 16);
|
||||||
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0);
|
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0);
|
||||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 14, 17)), 31);
|
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 14, 17)), 31);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_Kastle(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_Kastle(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -191,7 +203,7 @@ static bool Unpack_Kastle(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_Kantech(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_Kantech(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
||||||
|
@ -202,7 +214,9 @@ static bool Pack_Kantech(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
packed->Length = 32;
|
packed->Length = 32;
|
||||||
set_linear_field(packed, card->FacilityCode, 7, 8);
|
set_linear_field(packed, card->FacilityCode, 7, 8);
|
||||||
set_linear_field(packed, card->CardNumber, 15, 16);
|
set_linear_field(packed, card->CardNumber, 15, 16);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_Kantech(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_Kantech(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -214,7 +228,7 @@ static bool Unpack_Kantech(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x007F) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x007F) return false; // Can't encode FC.
|
||||||
|
@ -227,7 +241,9 @@ static bool Pack_D10202(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_linear_field(packed, card->CardNumber, 8, 24);
|
set_linear_field(packed, card->CardNumber, 8, 24);
|
||||||
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0);
|
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 16)), 0);
|
||||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 16, 16)), 32);
|
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 16, 16)), 32);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_D10202(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_D10202(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -243,7 +259,7 @@ static bool Unpack_D10202(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_H10306(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_H10306(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0xFFFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0xFFFF) return false; // Can't encode FC.
|
||||||
|
@ -257,7 +273,9 @@ static bool Pack_H10306(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
packed->Mid |= (card->FacilityCode & 0x8000) >> 15;
|
packed->Mid |= (card->FacilityCode & 0x8000) >> 15;
|
||||||
packed->Mid |= (evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xFFFE0000)) & 1) << 1;
|
packed->Mid |= (evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xFFFE0000)) & 1) << 1;
|
||||||
packed->Bot |= (oddparity32(packed->Bot & 0x0001FFFE) & 1);
|
packed->Bot |= (oddparity32(packed->Bot & 0x0001FFFE) & 1);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_H10306(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_H10306(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -275,7 +293,7 @@ static bool Unpack_H10306(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_N10002(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_N10002(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
||||||
|
@ -286,7 +304,9 @@ static bool Pack_N10002(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
packed->Length = 34; // Set number of bits
|
packed->Length = 34; // Set number of bits
|
||||||
set_linear_field(packed, card->FacilityCode, 9, 8);
|
set_linear_field(packed, card->FacilityCode, 9, 8);
|
||||||
set_linear_field(packed, card->CardNumber, 17, 16);
|
set_linear_field(packed, card->CardNumber, 17, 16);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_N10002(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_N10002(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -299,7 +319,7 @@ static bool Unpack_N10002(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_C1k35s(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_C1k35s(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0xFFF) return false; // Can't encode FC.
|
||||||
|
@ -314,7 +334,9 @@ static bool Pack_C1k35s(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
packed->Mid |= (evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xB6DB6DB6)) & 1) << 1;
|
packed->Mid |= (evenparity32((packed->Mid & 0x00000001) ^ (packed->Bot & 0xB6DB6DB6)) & 1) << 1;
|
||||||
packed->Bot |= (oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0x6DB6DB6C)) & 1);
|
packed->Bot |= (oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0x6DB6DB6C)) & 1);
|
||||||
packed->Mid |= (oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0xFFFFFFFF)) & 1) << 2;
|
packed->Mid |= (oddparity32((packed->Mid & 0x00000003) ^ (packed->Bot & 0xFFFFFFFF)) & 1) << 2;
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_C1k35s(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_C1k35s(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -331,7 +353,7 @@ static bool Unpack_C1k35s(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_H10320(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_H10320(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format)
|
if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format)
|
||||||
|
@ -356,7 +378,9 @@ static bool Pack_H10320(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_bit_by_position(packed, evenparity32(
|
set_bit_by_position(packed, evenparity32(
|
||||||
get_nonlinear_field(packed, 8, (uint8_t[]) {3, 7, 11, 15, 19, 23, 29, 31})
|
get_nonlinear_field(packed, 8, (uint8_t[]) {3, 7, 11, 15, 19, 23, 29, 31})
|
||||||
), 35);
|
), 35);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_H10320(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_H10320(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -383,7 +407,7 @@ static bool Unpack_H10320(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_S12906(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_S12906(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0xFF) return false; // Can't encode FC.
|
||||||
|
@ -397,7 +421,9 @@ static bool Pack_S12906(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_linear_field(packed, card->CardNumber, 11, 24);
|
set_linear_field(packed, card->CardNumber, 11, 24);
|
||||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 1, 17)), 0);
|
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 1, 17)), 0);
|
||||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 17, 18)), 35);
|
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 17, 18)), 35);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_S12906(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_S12906(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -414,7 +440,7 @@ static bool Unpack_S12906(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_Sie36(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_Sie36(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x0003FFFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x0003FFFF) return false; // Can't encode FC.
|
||||||
|
@ -431,7 +457,9 @@ static bool Pack_Sie36(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_bit_by_position(packed,
|
set_bit_by_position(packed,
|
||||||
evenparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34}))
|
evenparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34}))
|
||||||
, 35);
|
, 35);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_Sie36(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_Sie36(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -447,7 +475,7 @@ static bool Unpack_Sie36(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x000000FF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x000000FF) return false; // Can't encode FC.
|
||||||
|
@ -461,7 +489,9 @@ static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_linear_field(packed, card->CardNumber, 19, 16);
|
set_linear_field(packed, card->CardNumber, 19, 16);
|
||||||
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 17)), 0);
|
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 17)), 0);
|
||||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 17)), 35);
|
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 17)), 35);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -478,7 +508,7 @@ static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_H10302(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_H10302(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format)
|
if (card->FacilityCode > 0) return false; // Can't encode FC. (none in this format)
|
||||||
|
@ -490,7 +520,9 @@ static bool Pack_H10302(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_linear_field(packed, card->CardNumber, 1, 35);
|
set_linear_field(packed, card->CardNumber, 1, 35);
|
||||||
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
|
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
|
||||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
|
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_H10302(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_H10302(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -505,7 +537,7 @@ static bool Unpack_H10302(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x0000FFFF) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x0000FFFF) return false; // Can't encode FC.
|
||||||
|
@ -520,7 +552,9 @@ static bool Pack_H10304(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
|
|
||||||
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
|
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
|
||||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
|
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_H10304(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_H10304(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -536,7 +570,7 @@ static bool Unpack_H10304(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_HGeneric37(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_HGeneric37(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0) return false; // Not used in this format
|
if (card->FacilityCode > 0) return false; // Not used in this format
|
||||||
|
@ -553,25 +587,24 @@ static bool Pack_HGeneric37(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
// even1
|
// even1
|
||||||
set_bit_by_position(packed,
|
set_bit_by_position(packed,
|
||||||
evenparity32(
|
evenparity32(
|
||||||
get_nonlinear_field(packed, 8, (uint8_t[]) {4, 8, 12, 16, 20, 24, 28, 32})
|
get_nonlinear_field(packed, 8, (uint8_t[]) {4, 8, 12, 16, 20, 24, 28, 32}))
|
||||||
)
|
|
||||||
, 0
|
, 0
|
||||||
);
|
);
|
||||||
// odd1
|
// odd1
|
||||||
set_bit_by_position(packed,
|
set_bit_by_position(packed,
|
||||||
oddparity32(
|
oddparity32(
|
||||||
get_nonlinear_field(packed, 8, (uint8_t[]) {6, 10, 14, 18, 22, 26, 30, 34})
|
get_nonlinear_field(packed, 8, (uint8_t[]) {6, 10, 14, 18, 22, 26, 30, 34}))
|
||||||
)
|
|
||||||
, 2
|
, 2
|
||||||
);
|
);
|
||||||
// even2
|
// even2
|
||||||
set_bit_by_position(packed,
|
set_bit_by_position(packed,
|
||||||
evenparity32(
|
evenparity32(
|
||||||
get_nonlinear_field(packed, 8, (uint8_t[]) {7, 11, 15, 19, 23, 27, 31, 35})
|
get_nonlinear_field(packed, 8, (uint8_t[]) {7, 11, 15, 19, 23, 27, 31, 35}))
|
||||||
)
|
|
||||||
, 3
|
, 3
|
||||||
);
|
);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_HGeneric37(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_HGeneric37(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -589,7 +622,7 @@ static bool Unpack_HGeneric37(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_MDI37(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_MDI37(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (card->FacilityCode > 0x0000F) return false; // Can't encode FC.
|
if (card->FacilityCode > 0x0000F) return false; // Can't encode FC.
|
||||||
|
@ -604,7 +637,9 @@ static bool Pack_MDI37(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
|
|
||||||
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
|
set_bit_by_position(packed, evenparity32(get_linear_field(packed, 1, 18)), 0);
|
||||||
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
|
set_bit_by_position(packed, oddparity32(get_linear_field(packed, 18, 18)), 36);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_MDI37(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_MDI37(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -622,7 +657,7 @@ static bool Unpack_MDI37(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_P10001(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_P10001(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
|
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
|
@ -641,7 +676,9 @@ static bool Pack_P10001(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
get_linear_field(packed, 16, 8) ^
|
get_linear_field(packed, 16, 8) ^
|
||||||
get_linear_field(packed, 24, 8)
|
get_linear_field(packed, 24, 8)
|
||||||
, 32, 8);
|
, 32, 8);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_P10001(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_P10001(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -661,7 +698,7 @@ static bool Unpack_P10001(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
|
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
|
@ -677,7 +714,9 @@ static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
packed->Mid |= (evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6)) & 1) << 14;
|
packed->Mid |= (evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6)) & 1) << 14;
|
||||||
packed->Bot |= (oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C)) & 1);
|
packed->Bot |= (oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C)) & 1);
|
||||||
packed->Mid |= (oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF)) & 1) << 15;
|
packed->Mid |= (oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF)) & 1) << 15;
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_C1k48s(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_C1k48s(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -694,7 +733,7 @@ static bool Unpack_C1k48s(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_CasiRusco40(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_CasiRusco40(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
|
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
|
@ -706,7 +745,9 @@ static bool Pack_CasiRusco40(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
packed->Length = 40; // Set number of bits
|
packed->Length = 40; // Set number of bits
|
||||||
set_linear_field(packed, card->CardNumber, 1, 38);
|
set_linear_field(packed, card->CardNumber, 1, 38);
|
||||||
|
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_CasiRusco40(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_CasiRusco40(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -718,7 +759,7 @@ static bool Unpack_CasiRusco40(wiegand_message_t *packed, wiegand_card_t *card)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_Optus(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_Optus(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
|
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
|
@ -731,7 +772,9 @@ static bool Pack_Optus(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_linear_field(packed, card->CardNumber, 1, 16);
|
set_linear_field(packed, card->CardNumber, 1, 16);
|
||||||
set_linear_field(packed, card->FacilityCode, 22, 11);
|
set_linear_field(packed, card->FacilityCode, 22, 11);
|
||||||
|
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_Optus(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_Optus(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -744,7 +787,7 @@ static bool Unpack_Optus(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_Smartpass(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_Smartpass(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
|
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
|
@ -758,7 +801,9 @@ static bool Pack_Smartpass(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
set_linear_field(packed, card->FacilityCode, 1, 13);
|
set_linear_field(packed, card->FacilityCode, 1, 13);
|
||||||
set_linear_field(packed, card->IssueLevel, 14, 3);
|
set_linear_field(packed, card->IssueLevel, 14, 3);
|
||||||
set_linear_field(packed, card->CardNumber, 17, 16);
|
set_linear_field(packed, card->CardNumber, 17, 16);
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_Smartpass(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_Smartpass(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -772,7 +817,7 @@ static bool Unpack_Smartpass(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Pack_bqt(wiegand_card_t *card, wiegand_message_t *packed) {
|
static bool Pack_bqt(wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
|
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
|
@ -793,7 +838,9 @@ static bool Pack_bqt(wiegand_card_t *card, wiegand_message_t *packed) {
|
||||||
oddparity32(get_linear_field(packed, 17, 16))
|
oddparity32(get_linear_field(packed, 17, 16))
|
||||||
, 33);
|
, 33);
|
||||||
|
|
||||||
|
if (preamble)
|
||||||
return add_HID_header(packed);
|
return add_HID_header(packed);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Unpack_bqt(wiegand_message_t *packed, wiegand_card_t *card) {
|
static bool Unpack_bqt(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||||
|
@ -920,16 +967,16 @@ int HIDFindCardFormat(const char *format) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed) {
|
bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bool preamble) {
|
||||||
memset(packed, 0, sizeof(wiegand_message_t));
|
memset(packed, 0, sizeof(wiegand_message_t));
|
||||||
|
|
||||||
if (format_idx < 0 || format_idx >= ARRAYLEN(FormatTable))
|
if (format_idx < 0 || format_idx >= ARRAYLEN(FormatTable))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return FormatTable[format_idx].Pack(card, packed);
|
return FormatTable[format_idx].Pack(card, packed, preamble);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDPackTryAll(wiegand_card_t *card) {
|
void HIDPackTryAll(wiegand_card_t *card, bool preamble) {
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "%-10s %-30s --> Encoded wiegand", "Name", "Description");
|
PrintAndLogEx(INFO, "%-10s %-30s --> Encoded wiegand", "Name", "Description");
|
||||||
|
@ -939,7 +986,7 @@ void HIDPackTryAll(wiegand_card_t *card) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (FormatTable[i].Name) {
|
while (FormatTable[i].Name) {
|
||||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||||
bool res = FormatTable[i].Pack(card, &packed);
|
bool res = FormatTable[i].Pack(card, &packed, preamble);
|
||||||
if (res) {
|
if (res) {
|
||||||
cardformat_t fmt = HIDGetCardFormat(i);
|
cardformat_t fmt = HIDGetCardFormat(i);
|
||||||
print_desc_wiegand(&fmt, &packed);
|
print_desc_wiegand(&fmt, &packed);
|
||||||
|
|
|
@ -33,7 +33,7 @@ typedef struct {
|
||||||
// Structure for defined Wiegand card formats available for packing/unpacking
|
// Structure for defined Wiegand card formats available for packing/unpacking
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *Name;
|
const char *Name;
|
||||||
bool (*Pack)(wiegand_card_t *card, wiegand_message_t *packed);
|
bool (*Pack)(wiegand_card_t *card, wiegand_message_t *packed, bool preamble);
|
||||||
bool (*Unpack)(wiegand_message_t *packed, wiegand_card_t *card);
|
bool (*Unpack)(wiegand_message_t *packed, wiegand_card_t *card);
|
||||||
const char *Descrp;
|
const char *Descrp;
|
||||||
cardformatdescriptor_t Fields;
|
cardformatdescriptor_t Fields;
|
||||||
|
@ -42,9 +42,9 @@ typedef struct {
|
||||||
void HIDListFormats(void);
|
void HIDListFormats(void);
|
||||||
int HIDFindCardFormat(const char *format);
|
int HIDFindCardFormat(const char *format);
|
||||||
cardformat_t HIDGetCardFormat(int idx);
|
cardformat_t HIDGetCardFormat(int idx);
|
||||||
bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed);
|
bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed, bool preamble);
|
||||||
bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity);
|
bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity);
|
||||||
void HIDPackTryAll(wiegand_card_t *card);
|
void HIDPackTryAll(wiegand_card_t *card, bool preamble);
|
||||||
void print_wiegand_code(wiegand_message_t *packed);
|
void print_wiegand_code(wiegand_message_t *packed);
|
||||||
void print_desc_wiegand(cardformat_t *fmt, wiegand_message_t *packed);
|
void print_desc_wiegand(cardformat_t *fmt, wiegand_message_t *packed);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -121,7 +121,7 @@ bool set_nonlinear_field(wiegand_message_t *data, uint64_t value, uint8_t numBit
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t get_length_from_header(wiegand_message_t *data) {
|
static uint8_t get_length_from_header(wiegand_message_t *data) {
|
||||||
/**
|
/**
|
||||||
* detect if message has "preamble" / "sentinel bit"
|
* detect if message has "preamble" / "sentinel bit"
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -126,10 +126,10 @@ uint32_t CRC8Legic(uint8_t *buff, size_t size) {
|
||||||
crc_update2(&crc, buff[i], 8);
|
crc_update2(&crc, buff[i], 8);
|
||||||
return reflect8(crc_finish(&crc));
|
return reflect8(crc_finish(&crc));
|
||||||
}
|
}
|
||||||
// width=8 poly=0x107, init=0x2C refin=true refout=true xorout=0x0000 check=0 name="CRC-8/CARDX"
|
// width=8 poly=0x7, init=0x2C refin=false refout=false xorout=0x0000 check=0 name="CRC-8/CARDX"
|
||||||
uint32_t CRC8Cardx(uint8_t *buff, size_t size) {
|
uint32_t CRC8Cardx(uint8_t *buff, size_t size) {
|
||||||
crc_t crc;
|
crc_t crc;
|
||||||
crc_init_ref(&crc, 8, 0x107, 0x2C, 0, true, true);
|
crc_init_ref(&crc, 8, 0x7, 0x2C, 0, false, false);
|
||||||
for (size_t i = 0; i < size; ++i)
|
for (size_t i = 0; i < size; ++i)
|
||||||
crc_update2(&crc, buff[i], 8);
|
crc_update2(&crc, buff[i], 8);
|
||||||
return crc_finish(&crc);
|
return crc_finish(&crc);
|
||||||
|
|
|
@ -465,7 +465,6 @@ int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint3
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int mfc_generate4b_nuid(uint8_t *uid, uint8_t *nuid) {
|
int mfc_generate4b_nuid(uint8_t *uid, uint8_t *nuid) {
|
||||||
uint16_t crc;
|
uint16_t crc;
|
||||||
uint8_t b1, b2;
|
uint8_t b1, b2;
|
||||||
|
@ -481,6 +480,21 @@ int mfc_generate4b_nuid(uint8_t *uid, uint8_t *nuid) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mfc_algo_touch_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key) {
|
||||||
|
if (uid == NULL) return PM3_EINVARG;
|
||||||
|
if (key == NULL) return PM3_EINVARG;
|
||||||
|
|
||||||
|
*key = (
|
||||||
|
(uint64_t)(uid[1] ^ uid[2] ^ uid[3]) << 40 |
|
||||||
|
(uint64_t)uid[1] << 32 |
|
||||||
|
(uint64_t)uid[2] << 24 |
|
||||||
|
(uint64_t)(((uid[0] + uid[1] + uid[2] + uid[3]) % 0x100) ^ uid[3]) << 16 |
|
||||||
|
(uint64_t)0 << 8 |
|
||||||
|
(uint64_t)0
|
||||||
|
);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
// Self tests
|
// Self tests
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
|
|
@ -43,6 +43,8 @@ int mfc_algo_sky_all(uint8_t *uid, uint8_t *keys);
|
||||||
|
|
||||||
int mfc_generate4b_nuid(uint8_t *uid, uint8_t *nuid);
|
int mfc_generate4b_nuid(uint8_t *uid, uint8_t *nuid);
|
||||||
|
|
||||||
|
int mfc_algo_touch_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key);
|
||||||
|
|
||||||
uint32_t lf_t55xx_white_pwdgen(uint32_t id);
|
uint32_t lf_t55xx_white_pwdgen(uint32_t id);
|
||||||
|
|
||||||
int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint32_t aid, uint8_t *kdfInputOut, uint8_t *kdfInputLen);
|
int mfdes_kdf_input_gallagher(uint8_t *uid, uint8_t uidLen, uint8_t keyNo, uint32_t aid, uint8_t *kdfInputOut, uint8_t *kdfInputLen);
|
||||||
|
|
|
@ -332,9 +332,9 @@ pm3 --> hf mfu info
|
||||||
Clone MIFARE Ultralight EV1 Sequence
|
Clone MIFARE Ultralight EV1 Sequence
|
||||||
```
|
```
|
||||||
pm3 --> hf mfu dump -k FFFFFFFF
|
pm3 --> hf mfu dump -k FFFFFFFF
|
||||||
pm3 --> script run hf_mfu_dumptoemulator -i hf-mfu-XXXX-dump.bin -o hf-mfu-XXXX-dump.eml
|
pm3 --> script run data_mfu_bin2eml -i hf-mfu-XXXX-dump.bin -o hf-mfu-XXXX-dump.eml
|
||||||
pm3 --> hf mfu eload -u -f hf-mfu-XXXX-dump.eml
|
pm3 --> hf mfu eload -u -f hf-mfu-XXXX-dump.eml
|
||||||
pm3 --> hf mfu sim -t 7 -f hf-mfu-XXXX-dump.eml
|
pm3 --> hf mfu sim -t 7
|
||||||
```
|
```
|
||||||
|
|
||||||
Bruteforce MIFARE Classic card numbers from 11223344 to 11223346
|
Bruteforce MIFARE Classic card numbers from 11223344 to 11223346
|
||||||
|
|
|
@ -55,10 +55,14 @@ It will also add the `-h --help` option automatic.
|
||||||
-h --help : help
|
-h --help : help
|
||||||
--cn : card number
|
--cn : card number
|
||||||
--fn : facility number
|
--fn : facility number
|
||||||
--q5 : target is lf q5 card
|
--q5 : target is LF T5555/Q5 card
|
||||||
|
--em : target is LF EM4305/4469 card
|
||||||
--raw : raw data
|
--raw : raw data
|
||||||
|
-d --data : hex data supplied
|
||||||
|
-f --file : filename supplied
|
||||||
-k --key : key supplied
|
-k --key : key supplied
|
||||||
-n --keyno : key number to use
|
-n --keyno : key number to use
|
||||||
|
-p --pwd : password supplied
|
||||||
-v --verbose : flag when output should provide more information, not considered debug.
|
-v --verbose : flag when output should provide more information, not considered debug.
|
||||||
-1 --buffer : use the sample buffer
|
-1 --buffer : use the sample buffer
|
||||||
|
|
||||||
|
|
|
@ -93,14 +93,6 @@ hf mf gen3uid
|
||||||
hf mf gen3blk
|
hf mf gen3blk
|
||||||
hf mf gen3freeze
|
hf mf gen3freeze
|
||||||
hf mf ice
|
hf mf ice
|
||||||
lf config
|
|
||||||
lf cmdread
|
|
||||||
lf read
|
|
||||||
lf sim
|
|
||||||
lf simask
|
|
||||||
lf simfsk
|
|
||||||
lf simpsk
|
|
||||||
lf sniff
|
|
||||||
lf em 410x
|
lf em 410x
|
||||||
lf em 4x05
|
lf em 4x05
|
||||||
lf em 4x50
|
lf em 4x50
|
||||||
|
@ -111,15 +103,11 @@ lf hitag writer
|
||||||
lf hitag dump
|
lf hitag dump
|
||||||
lf hitag cc
|
lf hitag cc
|
||||||
lf t55xx config
|
lf t55xx config
|
||||||
lf t55xx dangerraw
|
|
||||||
lf t55xx detect
|
|
||||||
lf t55xx dump
|
lf t55xx dump
|
||||||
lf t55xx info
|
lf t55xx info
|
||||||
lf t55xx read
|
lf t55xx read
|
||||||
lf t55xx resetread
|
lf t55xx resetread
|
||||||
lf t55xx restore
|
lf t55xx restore
|
||||||
lf t55xx trace
|
lf t55xx trace
|
||||||
lf t55xx wakeup
|
|
||||||
lf t55xx write
|
lf t55xx write
|
||||||
lf t55xx special
|
|
||||||
script run
|
script run
|
||||||
|
|
|
@ -433,6 +433,7 @@ Check column "offline" for their availability.
|
||||||
|`hf mfdes getuid `|N |`Get random uid`
|
|`hf mfdes getuid `|N |`Get random uid`
|
||||||
|`hf mfdes info `|N |`Tag information`
|
|`hf mfdes info `|N |`Tag information`
|
||||||
|`hf mfdes list `|Y |`List DESFire (ISO 14443A) history`
|
|`hf mfdes list `|Y |`List DESFire (ISO 14443A) history`
|
||||||
|
|`hf mfdes bruteaid `|N |`Recover AIDs by bruteforce`
|
||||||
|`hf mfdes createaid `|N |`Create Application ID`
|
|`hf mfdes createaid `|N |`Create Application ID`
|
||||||
|`hf mfdes deleteaid `|N |`Delete Application ID`
|
|`hf mfdes deleteaid `|N |`Delete Application ID`
|
||||||
|`hf mfdes selectaid `|N |`Select Application ID`
|
|`hf mfdes selectaid `|N |`Select Application ID`
|
||||||
|
@ -534,13 +535,13 @@ Check column "offline" for their availability.
|
||||||
|------- |------- |-----------
|
|------- |------- |-----------
|
||||||
|`lf help `|Y |`This help`
|
|`lf help `|Y |`This help`
|
||||||
|`lf config `|N |`Get/Set config for LF sampling, bit/sample, decimation, frequency`
|
|`lf config `|N |`Get/Set config for LF sampling, bit/sample, decimation, frequency`
|
||||||
|`lf cmdread `|N |`Modulate LF reader field to send command before read (all periods in microseconds)`
|
|`lf cmdread `|N |`Modulate LF reader field to send command before read`
|
||||||
|`lf read `|N |`Read LF tag`
|
|`lf read `|N |`Read LF tag`
|
||||||
|`lf search `|Y |`Read and Search for valid known tag (in offline mode it you can load first then search)`
|
|`lf search `|Y |`Read and Search for valid known tag`
|
||||||
|`lf sim `|N |`Simulate LF tag from buffer with optional GAP (in microseconds)`
|
|`lf sim `|N |`Simulate LF tag from buffer`
|
||||||
|`lf simask `|N |`Simulate LF ASK tag from demodbuffer or input`
|
|`lf simask `|N |`Simulate ASK tag`
|
||||||
|`lf simfsk `|N |`Simulate LF FSK tag from demodbuffer or input`
|
|`lf simfsk `|N |`Simulate FSK tag`
|
||||||
|`lf simpsk `|N |`Simulate LF PSK tag from demodbuffer or input`
|
|`lf simpsk `|N |`Simulate PSK tag`
|
||||||
|`lf simbidir `|N |`Simulate LF tag (with bidirectional data transmission between reader and tag)`
|
|`lf simbidir `|N |`Simulate LF tag (with bidirectional data transmission between reader and tag)`
|
||||||
|`lf sniff `|N |`Sniff LF traffic between reader and tag`
|
|`lf sniff `|N |`Sniff LF traffic between reader and tag`
|
||||||
|`lf tune `|N |`Continuously measure LF antenna tuning`
|
|`lf tune `|N |`Continuously measure LF antenna tuning`
|
||||||
|
|
|
@ -8,7 +8,7 @@ The RDV4 repository contains helper scripts for JTAG flashing.
|
||||||
|
|
||||||
* Get OpenOCD, e.g.: `apt-get install openocd`
|
* Get OpenOCD, e.g.: `apt-get install openocd`
|
||||||
* Create `tools/jtag_openocd/openocd_configuration` by copying [`tools/jtag_openocd/openocd_configuration.sample`](/tools/jtag_openocd/openocd_configuration.sample)
|
* Create `tools/jtag_openocd/openocd_configuration` by copying [`tools/jtag_openocd/openocd_configuration.sample`](/tools/jtag_openocd/openocd_configuration.sample)
|
||||||
* Tune it to fit your JTAG tool: adapt `CONFIG_IF` to refer to the `interface-*.cfg` file corresponding to your JTAG tool. By default `openocd_configuration.sample` is set up to work with the J-Link.
|
* Tune it to fit your JTAG tool: adapt `CONFIG_IF` to refer to your JTAG tool. `openocd_configuration.sample` contains several examples and is set up by default to work with the J-Link.
|
||||||
* Wire the Proxmark3 to the JTAG tool. How to do it depends on the tool. See below for examples. **Warning:** don't plug the Proxmark3 on USB if the tool delivers already the voltage to the Proxmark3, which is most probably the case.
|
* Wire the Proxmark3 to the JTAG tool. How to do it depends on the tool. See below for examples. **Warning:** don't plug the Proxmark3 on USB if the tool delivers already the voltage to the Proxmark3, which is most probably the case.
|
||||||
* Then just run
|
* Then just run
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ For advanced usages there are also `openocd_flash_dump.sh` for dumping the conte
|
||||||
|
|
||||||
The RDV4 JTAG header is quite smaller compared to other Proxmark3 platforms.
|
The RDV4 JTAG header is quite smaller compared to other Proxmark3 platforms.
|
||||||
If you're using a J-Link, there is a [convenient adapter](https://github.com/RfidResearchGroup/proxmark3/wiki/Tools#jtag-adapter) made by Proxgrind.
|
If you're using a J-Link, there is a [convenient adapter](https://github.com/RfidResearchGroup/proxmark3/wiki/Tools#jtag-adapter) made by Proxgrind.
|
||||||
You can also make yours with some 1.27mm headers (look for `1.27mm header` on Aliexpress) or Pogo pins.
|
You can also make yours with some 1.27mm headers (look for `1.27mm header` on Aliexpress) or Pogo pins or buy an already made clip, e.g. search `dykb clamp` on Aliexpress and take a 1.27mm single-row 6P version.
|
||||||
|
|
||||||
## JLink pinout
|
## JLink pinout
|
||||||
|
|
||||||
|
|
4
pm3
4
pm3
|
@ -148,7 +148,7 @@ function get_pm3_list_Windows {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Normal SERIAL PORTS (COM)
|
# Normal SERIAL PORTS (COM)
|
||||||
for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
|
for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%' Or PNPDeviceID LIKE '%VID_2D2D&PID_504D%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
|
||||||
DEV=${DEV/ */}
|
DEV=${DEV/ */}
|
||||||
PM3LIST+=("$DEV")
|
PM3LIST+=("$DEV")
|
||||||
if [ ${#PM3LIST[*]} -ge "$N" ]; then
|
if [ ${#PM3LIST[*]} -ge "$N" ]; then
|
||||||
|
@ -192,7 +192,7 @@ function get_pm3_list_WSL {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Normal SERIAL PORTS (COM)
|
# Normal SERIAL PORTS (COM)
|
||||||
for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_9AC4&PID_4B8F*' | Select DeviceID" 2>/dev/null | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p'); do
|
for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.PNPDeviceID -like '*VID_9AC4&PID_4B8F*' -or \$_.PNPDeviceID -like '*VID_2D2D&PID_504D*'} | Select DeviceID" 2>/dev/null | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p'); do
|
||||||
# ttyS counterpart takes some more time to appear
|
# ttyS counterpart takes some more time to appear
|
||||||
if [ -e "$DEV" ]; then
|
if [ -e "$DEV" ]; then
|
||||||
PM3LIST+=("$DEV")
|
PM3LIST+=("$DEV")
|
||||||
|
|
|
@ -18,3 +18,13 @@ get_xorsearch:
|
||||||
# unzzip-big XORSearch_V1_11_2.zip
|
# unzzip-big XORSearch_V1_11_2.zip
|
||||||
# linux
|
# linux
|
||||||
# gunzip XORSearch_V1_11_2.zip
|
# gunzip XORSearch_V1_11_2.zip
|
||||||
|
|
||||||
|
# Python impl of NDEF FORUM 1-5 protocol
|
||||||
|
get_nfcpy:
|
||||||
|
$(MKDIR) nfcpy
|
||||||
|
$(GIT) https://github.com/nfcpy/nfcpy.git
|
||||||
|
|
||||||
|
# Python tool to create, modify and print NDEF records
|
||||||
|
get_ndeftool:
|
||||||
|
$(MKDIR) ndeftool
|
||||||
|
$(GIT) https://github.com/nfcpy/ndeftool.git
|
||||||
|
|
|
@ -254,7 +254,8 @@ int discoverDevices(unsigned int profile_selected, uint32_t device_types_selecte
|
||||||
|
|
||||||
if (verbose) printf("%14s: %s\n", "Device Type", (device_type & CL_DEVICE_TYPE_GPU) ? "GPU" : (device_type & CL_DEVICE_TYPE_CPU) ? "CPU" : "Other");
|
if (verbose) printf("%14s: %s\n", "Device Type", (device_type & CL_DEVICE_TYPE_GPU) ? "GPU" : (device_type & CL_DEVICE_TYPE_CPU) ? "CPU" : "Other");
|
||||||
|
|
||||||
(*cd_ctx)[platform_idx].device[device_idx].selected = plat_dev_enabled(global_device_id, dev_sel, dev_cnt, (unsigned int) device_type, device_types_selected);
|
if ((*cd_ctx)[platform_idx].selected == false)(*cd_ctx)[platform_idx].device[device_idx].selected = false;
|
||||||
|
else (*cd_ctx)[platform_idx].device[device_idx].selected = plat_dev_enabled(global_device_id, dev_sel, dev_cnt, (unsigned int) device_type, device_types_selected);
|
||||||
global_device_id++;
|
global_device_id++;
|
||||||
if ((*cd_ctx)[platform_idx].device[device_idx].selected)(*selected_devices_cnt)++;
|
if ((*cd_ctx)[platform_idx].device[device_idx].selected)(*selected_devices_cnt)++;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -28,3 +28,7 @@ gdb_memory_map enable
|
||||||
sam7x.cpu configure -work-area-virt 0 -work-area-phys 0x00200000 -work-area-size 0x10000 -work-area-backup 0
|
sam7x.cpu configure -work-area-virt 0 -work-area-phys 0x00200000 -work-area-size 0x10000 -work-area-backup 0
|
||||||
flash bank sam7x.flash.0 at91sam7 0 0 0 0 sam7x.cpu 0 0 0 0 0 0 0 18432
|
flash bank sam7x.flash.0 at91sam7 0 0 0 0 sam7x.cpu 0 0 0 0 0 0 0 18432
|
||||||
flash bank sam7x.flash.1 at91sam7 0 0 0 0 sam7x.cpu 1 0 0 0 0 0 0 18432
|
flash bank sam7x.flash.1 at91sam7 0 0 0 0 sam7x.cpu 1 0 0 0 0 0 0 18432
|
||||||
|
transport select jtag
|
||||||
|
# Since some 0.10.0 versions, "adapter_khz" is deprecated in favor of "adapter speed" but there are also some 0.10.0 not recognizing "adapter speed" so we'll stick to "adapter_khz" for now...
|
||||||
|
# adapter speed 1000
|
||||||
|
adapter_khz 1000
|
|
@ -1,8 +0,0 @@
|
||||||
# Commands specific to the Olimex ARM-USB-OCD Dongle
|
|
||||||
interface ft2232
|
|
||||||
ft2232_device_desc "Olimex OpenOCD JTAG"
|
|
||||||
ft2232_layout "olimex-jtag"
|
|
||||||
ft2232_vid_pid 0x15BA 0x0003
|
|
||||||
jtag_speed 2
|
|
||||||
jtag_nsrst_delay 200
|
|
||||||
jtag_ntrst_delay 200
|
|
|
@ -1,10 +0,0 @@
|
||||||
# Commands specific to the Bus Blaster
|
|
||||||
interface ftdi
|
|
||||||
ftdi_device_desc "Dual RS232-HS"
|
|
||||||
ftdi_vid_pid 0x0403 0x6010
|
|
||||||
|
|
||||||
ftdi_layout_init 0x0c08 0x0f1b
|
|
||||||
ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400
|
|
||||||
ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800
|
|
||||||
|
|
||||||
adapter_khz 1000
|
|
|
@ -1,10 +1,8 @@
|
||||||
# Commands specific to the BusPirate
|
# Commands specific to the BusPirate
|
||||||
interface buspirate
|
|
||||||
buspirate_port /dev/ttyUSB0
|
|
||||||
adapter_khz 1000
|
|
||||||
|
|
||||||
# Communication speed
|
source [find interface/buspirate.cfg]
|
||||||
buspirate_speed normal # or fast
|
|
||||||
|
buspirate_port /dev/ttyUSB0
|
||||||
|
|
||||||
# Voltage regulator: enabled = 1 or disabled = 0
|
# Voltage regulator: enabled = 1 or disabled = 0
|
||||||
buspirate_vreg 1
|
buspirate_vreg 1
|
||||||
|
|
|
@ -11,13 +11,4 @@
|
||||||
# Black <> GND
|
# Black <> GND
|
||||||
# Red <> 3.3 (don't connect if C232HM-EDSL-0! power via USB instead)
|
# Red <> 3.3 (don't connect if C232HM-EDSL-0! power via USB instead)
|
||||||
|
|
||||||
interface ftdi
|
source [find interface/ftdi/c232hm.cfg]
|
||||||
#ftdi_device_desc "C232HM-DDHSL-0"
|
|
||||||
#ftdi_device_desc "C232HM-EDHSL-0"
|
|
||||||
ftdi_vid_pid 0x0403 0x6014
|
|
||||||
|
|
||||||
ftdi_layout_init 0x0008 0x400b
|
|
||||||
ftdi_layout_signal LED -ndata 0x4000
|
|
||||||
|
|
||||||
transport select jtag
|
|
||||||
adapter_khz 1000
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
# Commands specific to the Segger J-Link
|
|
||||||
interface jlink
|
|
||||||
transport select jtag
|
|
||||||
adapter_khz 1000
|
|
|
@ -1,8 +0,0 @@
|
||||||
# Commands specific to the Amontec JTAGKey
|
|
||||||
interface ft2232
|
|
||||||
ft2232_device_desc "Amontec JTAGkey A"
|
|
||||||
ft2232_layout jtagkey
|
|
||||||
ft2232_vid_pid 0x0403 0xcff8
|
|
||||||
jtag_khz 200
|
|
||||||
jtag_nsrst_delay 200
|
|
||||||
jtag_ntrst_delay 200
|
|
|
@ -12,26 +12,7 @@
|
||||||
# 6 <> GND
|
# 6 <> GND
|
||||||
# 1 <> 3.3
|
# 1 <> 3.3
|
||||||
|
|
||||||
interface bcm2835gpio
|
source [find interface/raspberrypi-native.cfg]
|
||||||
|
|
||||||
# This file is meant for first versions of Raspberry Pi
|
|
||||||
# You can check yours with:
|
|
||||||
# dd if=/proc/device-tree/soc/ranges bs=4 skip=1 count=1 2>/dev/null|xxd -p
|
|
||||||
# if it returns 20000000, you're fine
|
|
||||||
# if it returns 3F000000, use interface-raspberrypi2.cfg
|
|
||||||
bcm2835gpio_peripheral_base 0x20000000
|
|
||||||
|
|
||||||
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
|
|
||||||
# These depend on system clock, calibrated for stock 700MHz
|
|
||||||
# bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET
|
|
||||||
bcm2835gpio_speed_coeffs 113714 28
|
|
||||||
|
|
||||||
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
|
|
||||||
# Header pin numbers: 23 22 19 21
|
|
||||||
bcm2835gpio_jtag_nums 11 25 10 9
|
|
||||||
|
|
||||||
bcm2835gpio_srst_num 18
|
bcm2835gpio_srst_num 18
|
||||||
reset_config srst_only srst_push_pull
|
reset_config srst_only srst_push_pull
|
||||||
|
|
||||||
transport select jtag
|
|
||||||
adapter_khz 1000
|
|
||||||
|
|
|
@ -12,26 +12,7 @@
|
||||||
# 6 <> GND
|
# 6 <> GND
|
||||||
# 1 <> 3.3
|
# 1 <> 3.3
|
||||||
|
|
||||||
interface bcm2835gpio
|
source [find interface/raspberrypi2-native.cfg]
|
||||||
|
|
||||||
# This file is meant for recent versions of Raspberry Pi
|
|
||||||
# You can check yours with:
|
|
||||||
# dd if=/proc/device-tree/soc/ranges bs=4 skip=1 count=1 2>/dev/null|xxd -p
|
|
||||||
# if it returns 20000000, use interface-raspberrypi.cfg
|
|
||||||
# if it returns 3F000000, you're fine
|
|
||||||
bcm2835gpio_peripheral_base 0x3F000000
|
|
||||||
|
|
||||||
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
|
|
||||||
# These depend on system clock, calibrated for stock 700MHz
|
|
||||||
# bcm2835gpio_speed SPEED_COEFF SPEED_OFFSET
|
|
||||||
bcm2835gpio_speed_coeffs 146203 36
|
|
||||||
|
|
||||||
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
|
|
||||||
# Header pin numbers: 23 22 19 21
|
|
||||||
bcm2835gpio_jtag_nums 11 25 10 9
|
|
||||||
|
|
||||||
bcm2835gpio_srst_num 18
|
bcm2835gpio_srst_num 18
|
||||||
reset_config srst_only srst_push_pull
|
reset_config srst_only srst_push_pull
|
||||||
|
|
||||||
transport select jtag
|
|
||||||
adapter_khz 1000
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
# Commands specific to the Shikra
|
|
||||||
interface ftdi
|
|
||||||
transport select jtag
|
|
||||||
ftdi_vid_pid 0x0403 0x6014
|
|
||||||
ftdi_layout_init 0x0c08 0x0f1b
|
|
||||||
adapter_khz 2000
|
|
|
@ -1,7 +0,0 @@
|
||||||
# Commands specific to the Wiggler
|
|
||||||
interface parport
|
|
||||||
parport_port 0x378
|
|
||||||
parport_cable wiggler
|
|
||||||
jtag_speed 0
|
|
||||||
jtag_nsrst_delay 200
|
|
||||||
jtag_ntrst_delay 200
|
|
|
@ -1,7 +1,34 @@
|
||||||
CONFIG_GEN=general.cfg
|
CONFIG_GEN=general.cfg
|
||||||
CONFIG_CHIP=chip-at91sam7s.cfg
|
CONFIG_BOARD=board-at91sam7s.cfg
|
||||||
IMAGE=../../recovery/proxmark3_recovery.bin
|
IMAGE=../../recovery/proxmark3_recovery.bin
|
||||||
DUMP="dump_$(date +'%Y%m%d-%H%M%S').bin"
|
DUMP="dump_$(date +'%Y%m%d-%H%M%S').bin"
|
||||||
|
|
||||||
# Example using Segger Jlink:
|
# One can use openocd-provided interfaces or local interface files
|
||||||
CONFIG_IF=interface-jlink.cfg
|
# Here are a few examples
|
||||||
|
|
||||||
|
# Segger Jlink:
|
||||||
|
CONFIG_IF=interface/jlink.cfg
|
||||||
|
|
||||||
|
# Raspberry Pi models Pi1, Pi2 and Pi Zero (read interface-raspberrypi.cfg for pinout)
|
||||||
|
#CONFIG_IF=interface-raspberrypi.cfg
|
||||||
|
|
||||||
|
# Raspberry Pi models 2+ and above (read interface-raspberrypi2.cfg for pinout)
|
||||||
|
#CONFIG_IF=interface-raspberrypi2.cfg
|
||||||
|
|
||||||
|
# DP BusBlaster:
|
||||||
|
#CONFIG_IF=interface/ftdi/dp_busblaster.cfg
|
||||||
|
|
||||||
|
# BusPirate:
|
||||||
|
#CONFIG_IF=interface-buspirate.cfg
|
||||||
|
|
||||||
|
# C232HM-DDHSL-0 and C232HM-EDSL-0 (beware! read interface-c232hm.cfg instructions)
|
||||||
|
#CONFIG_IF=interface-c232hm.cfg
|
||||||
|
|
||||||
|
# Olimex ARM-USB-OCD Dongle:
|
||||||
|
#CONFIG_IF=interface/ftdi/olimex-arm-usb-ocd.cfg
|
||||||
|
|
||||||
|
# Amontec JTAGKey:
|
||||||
|
#CONFIG_IF=interface/ftdi/jtagkey.cfg
|
||||||
|
|
||||||
|
# Wiggler:
|
||||||
|
#CONFIG_IF=interface/parport.cfg
|
||||||
|
|
|
@ -7,4 +7,4 @@ if [ -e "$DUMP" ]; then
|
||||||
echo "$DUMP exists already. Abort!"
|
echo "$DUMP exists already. Abort!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_CHIP -c "init;halt;dump_image $DUMP 0x100000 0x80000;exit"
|
openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_BOARD -c "init;halt;dump_image $DUMP 0x100000 0x80000;exit"
|
||||||
|
|
|
@ -7,4 +7,4 @@ if [ ! -e "$IMAGE" ]; then
|
||||||
echo "$IMAGE missing. Abort!"
|
echo "$IMAGE missing. Abort!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_CHIP -c "init;halt;flash erase_sector 0 0 15;flash erase_sector 1 0 15;flash write_image $IMAGE 0x100000;exit"
|
openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_BOARD -c "init;halt;flash erase_sector 0 0 15;flash erase_sector 1 0 15;flash write_image $IMAGE 0x100000;exit"
|
||||||
|
|
|
@ -6,4 +6,4 @@ cd $(dirname "$0")
|
||||||
echo "*********************************************"
|
echo "*********************************************"
|
||||||
echo "Connect to OpenOCD via: telnet localhost $(awk '/^telnet_port/{print$2}' $CONFIG_GEN)"
|
echo "Connect to OpenOCD via: telnet localhost $(awk '/^telnet_port/{print$2}' $CONFIG_GEN)"
|
||||||
echo "*********************************************"
|
echo "*********************************************"
|
||||||
openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_CHIP
|
openocd -f $CONFIG_GEN -f $CONFIG_IF -f $CONFIG_BOARD
|
||||||
|
|
|
@ -343,6 +343,8 @@ while true; do
|
||||||
if ! CheckExecute "reveng -g test" "$CLIENTBIN -c 'reveng -g abda202c'" "CRC-16/ISO-IEC-14443-3-A"; then break; fi
|
if ! CheckExecute "reveng -g test" "$CLIENTBIN -c 'reveng -g abda202c'" "CRC-16/ISO-IEC-14443-3-A"; then break; fi
|
||||||
if ! CheckExecute "reveng -w test" "$CLIENTBIN -c 'reveng -w 8 -s 01020304e3 010204039d'" "CRC-8/SMBUS"; then break; fi
|
if ! CheckExecute "reveng -w test" "$CLIENTBIN -c 'reveng -w 8 -s 01020304e3 010204039d'" "CRC-8/SMBUS"; then break; fi
|
||||||
if ! CheckExecute "mfu pwdgen test" "$CLIENTBIN -c 'hf mfu pwdgen -t'" "Selftest OK"; then break; fi
|
if ! CheckExecute "mfu pwdgen test" "$CLIENTBIN -c 'hf mfu pwdgen -t'" "Selftest OK"; then break; fi
|
||||||
|
if ! CheckExecute "mfu keygen test" "$CLIENTBIN -c 'hf mfu keygen --uid 11223344556677'" "80 B1 C2 71 D8 A0"; then break; fi
|
||||||
|
if ! CheckExecute "jooki encode test" "$CLIENTBIN -c 'hf jooki encode -t'" "04 28 F4 DA F0 4A 81 ( ok )"; then break; fi
|
||||||
if ! CheckExecute "trace load/list 14a" "$CLIENTBIN -c 'trace load -f traces/hf_14a_mfu.trace; trace list -1 -t 14a;'" "READBLOCK(8)"; then break; fi
|
if ! CheckExecute "trace load/list 14a" "$CLIENTBIN -c 'trace load -f traces/hf_14a_mfu.trace; trace list -1 -t 14a;'" "READBLOCK(8)"; then break; fi
|
||||||
if ! CheckExecute "trace load/list x" "$CLIENTBIN -c 'trace load -f traces/hf_14a_mfu.trace; trace list -x1 -t 14a;'" "0.0101840425"; then break; fi
|
if ! CheckExecute "trace load/list x" "$CLIENTBIN -c 'trace load -f traces/hf_14a_mfu.trace; trace list -x1 -t 14a;'" "0.0101840425"; then break; fi
|
||||||
|
|
||||||
|
@ -382,7 +384,7 @@ while true; do
|
||||||
"temperature 95.2 F / 35.1 C"; then break; fi
|
"temperature 95.2 F / 35.1 C"; then break; fi
|
||||||
if ! CheckExecute slow "lf T55 gallagher test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gallagher.pm3; lf search -1'" "GALLAGHER ID found"; then break; fi
|
if ! CheckExecute slow "lf T55 gallagher test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gallagher.pm3; lf search -1'" "GALLAGHER ID found"; then break; fi
|
||||||
if ! CheckExecute slow "lf T55 gallagher test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gallagher.pm3; lf gallagher demod'" \
|
if ! CheckExecute slow "lf T55 gallagher test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gallagher.pm3; lf gallagher demod'" \
|
||||||
"GALLAGHER - Region: 0 FC: 27865 CN: 682758 Issue Level: 13"; then break; fi
|
"GALLAGHER - Region: 1 FC: 16640 CN: 201 Issue Level: 1"; then break; fi
|
||||||
if ! CheckExecute slow "lf T55 gproxii test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gproxii.pm3; lf search -1'" "Guardall G-Prox II ID found"; then break; fi
|
if ! CheckExecute slow "lf T55 gproxii test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gproxii.pm3; lf search -1'" "Guardall G-Prox II ID found"; then break; fi
|
||||||
if ! CheckExecute slow "lf T55 gproxii test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gproxii.pm3; lf gproxii demod'" \
|
if ! CheckExecute slow "lf T55 gproxii test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_gproxii.pm3; lf gproxii demod'" \
|
||||||
"G-Prox-II - len: 26 FC: 123 Card: 11223, Raw: f98c7038c63356c7ac26398c"; then break; fi
|
"G-Prox-II - len: 26 FC: 123 Card: 11223, Raw: f98c7038c63356c7ac26398c"; then break; fi
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue