mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge pull request #825 from tharexde/dev-rplc-em4x50_read
replace em4x50 read
This commit is contained in:
commit
56ee5313b3
12 changed files with 335 additions and 623 deletions
|
@ -1019,8 +1019,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
em4x50_write_password((em4x50_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_SREAD: {
|
||||
em4x50_sread((em4x50_data_t *)packet->data.asBytes);
|
||||
case CMD_LF_EM4X50_READ: {
|
||||
em4x50_read((em4x50_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,9 +72,9 @@ static em4x50_tag_t tag = {
|
|||
#define EM4X50_T_TAG_HALF_PERIOD 32
|
||||
#define EM4X50_T_TAG_THREE_QUARTER_PERIOD 48
|
||||
#define EM4X50_T_TAG_FULL_PERIOD 64
|
||||
#define EM4X50_T_WAITING_FOR_LIW 500
|
||||
#define EM4X50_T_TAG_TPP 64
|
||||
#define EM4X50_T_TAG_TWA 64
|
||||
#define EM4X50_T_WAITING_FOR_DBLLIW 1550
|
||||
|
||||
#define EM4X50_TAG_TOLERANCE 8
|
||||
#define EM4X50_TAG_WORD 45
|
||||
|
@ -237,19 +237,34 @@ static void em4x50_setup_read(void) {
|
|||
|
||||
// functions for "reader" use case
|
||||
|
||||
static void get_signalproperties(void) {
|
||||
static bool get_signalproperties(void) {
|
||||
|
||||
// calculate signal properties (mean amplitudes) from measured data:
|
||||
// 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow
|
||||
|
||||
bool signal_found = false;
|
||||
int no_periods = 32, pct = 75, noise = 140;
|
||||
uint8_t sample = 0, sample_ref = 127;
|
||||
uint8_t sample_max_mean = 0;
|
||||
uint8_t sample_max[no_periods];
|
||||
uint32_t sample_max_sum = 0;
|
||||
|
||||
// wait until signal/noise > 1
|
||||
while (AT91C_BASE_SSC->SSC_RHR < noise);
|
||||
|
||||
// wait until signal/noise > 1 (max. 32 periods)
|
||||
for (int i = 0; i < T0 * no_periods; i++) {
|
||||
|
||||
// about 2 samples per bit period
|
||||
wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD);
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_RHR > noise) {
|
||||
signal_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!signal_found)
|
||||
return false;
|
||||
|
||||
// calculate mean maximum value of 32 periods, each period has a length of
|
||||
// 3 single "full periods" to eliminate the influence of a listen window
|
||||
|
@ -274,6 +289,7 @@ static void get_signalproperties(void) {
|
|||
gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100;
|
||||
gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int get_next_bit(void) {
|
||||
|
@ -408,9 +424,13 @@ static bool find_double_listen_window(bool bcommand) {
|
|||
|
||||
// find two successive listen windows that indicate the beginning of
|
||||
// data transmission
|
||||
// double listen window to be detected within 1600 pulses -> worst case
|
||||
// reason: first detectable double listen window after 34 words
|
||||
// -> 34 words + 34 single listen windows -> about 1600 pulses
|
||||
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_WAITING_FOR_LIW) {
|
||||
int cnt_pulses = 0;
|
||||
|
||||
while (cnt_pulses < EM4X50_T_WAITING_FOR_DBLLIW) {
|
||||
|
||||
// identification of listen window is done via evaluation of
|
||||
// pulse lengths
|
||||
|
@ -454,6 +474,8 @@ static bool find_double_listen_window(bool bcommand) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cnt_pulses++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,6 +535,10 @@ static bool check_ack(bool bliw) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// It's NAK -> stop searching
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -626,7 +652,7 @@ static bool login(uint8_t password[4]) {
|
|||
return true;
|
||||
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("error in command request");
|
||||
}
|
||||
|
||||
|
@ -650,7 +676,7 @@ static bool reset(void) {
|
|||
return true;
|
||||
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("error in command request");
|
||||
}
|
||||
|
||||
|
@ -682,7 +708,7 @@ static bool standard_read(int *now) {
|
|||
return true;
|
||||
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("didn't find a listen window");
|
||||
}
|
||||
|
||||
|
@ -716,7 +742,7 @@ static bool selective_read(uint8_t addresses[4]) {
|
|||
return true;
|
||||
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("error in command request");
|
||||
}
|
||||
|
||||
|
@ -738,7 +764,7 @@ void em4x50_info(em4x50_data_t *etd) {
|
|||
em4x50_setup_read();
|
||||
|
||||
// set gHigh and gLow
|
||||
get_signalproperties();
|
||||
if (get_signalproperties()) {
|
||||
|
||||
if (etd->pwd_given) {
|
||||
|
||||
|
@ -753,6 +779,7 @@ void em4x50_info(em4x50_data_t *etd) {
|
|||
}
|
||||
|
||||
bsuccess = selective_read(addresses);
|
||||
}
|
||||
|
||||
status = (bsuccess << 1) + blogin;
|
||||
|
||||
|
@ -760,7 +787,7 @@ void em4x50_info(em4x50_data_t *etd) {
|
|||
reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238);
|
||||
}
|
||||
|
||||
void em4x50_sread(em4x50_data_t *etd) {
|
||||
void em4x50_read(em4x50_data_t *etd) {
|
||||
|
||||
// reads in two different ways:
|
||||
// - using "selective read mode" -> bidirectional communication
|
||||
|
@ -776,7 +803,7 @@ void em4x50_sread(em4x50_data_t *etd) {
|
|||
em4x50_setup_read();
|
||||
|
||||
// set gHigh and gLow
|
||||
get_signalproperties();
|
||||
if (get_signalproperties()) {
|
||||
|
||||
if (etd->addr_given) {
|
||||
|
||||
|
@ -796,6 +823,7 @@ void em4x50_sread(em4x50_data_t *etd) {
|
|||
bsuccess = standard_read(&now);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
status = (now << 2) + (bsuccess << 1) + blogin;
|
||||
|
||||
|
@ -836,7 +864,7 @@ static bool write(uint8_t word[4], uint8_t address) {
|
|||
}
|
||||
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("error in command request");
|
||||
}
|
||||
|
||||
|
@ -875,7 +903,7 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) {
|
|||
}
|
||||
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("error in command request");
|
||||
}
|
||||
|
||||
|
@ -896,7 +924,7 @@ void em4x50_write(em4x50_data_t *etd) {
|
|||
em4x50_setup_read();
|
||||
|
||||
// set gHigh and gLow
|
||||
get_signalproperties();
|
||||
if (get_signalproperties()) {
|
||||
|
||||
// reorder word according to datasheet
|
||||
msb2lsb_word(etd->word);
|
||||
|
@ -933,6 +961,7 @@ void em4x50_write(em4x50_data_t *etd) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = (bsuccess << 1) + blogin;
|
||||
|
||||
|
@ -950,12 +979,13 @@ void em4x50_write_password(em4x50_data_t *etd) {
|
|||
em4x50_setup_read();
|
||||
|
||||
// set gHigh and gLow
|
||||
get_signalproperties();
|
||||
if (get_signalproperties()) {
|
||||
|
||||
// login and change password
|
||||
if (login(etd->password)) {
|
||||
bsuccess = write_password(etd->password, etd->new_password);
|
||||
}
|
||||
}
|
||||
|
||||
lf_finalize();
|
||||
reply_ng(CMD_ACK, bsuccess, 0, 0);
|
||||
|
|
|
@ -20,6 +20,6 @@ typedef struct {
|
|||
void em4x50_info(em4x50_data_t *etd);
|
||||
void em4x50_write(em4x50_data_t *etd);
|
||||
void em4x50_write_password(em4x50_data_t *etd);
|
||||
void em4x50_sread(em4x50_data_t *etd);
|
||||
void em4x50_read(em4x50_data_t *etd);
|
||||
|
||||
#endif /* EM4X50_H */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "cmddata.h" // for `lf search`
|
||||
#include "cmdlfawid.h" // for awid menu
|
||||
#include "cmdlfem4x.h" // for em4x menu
|
||||
#include "cmdlfem4x50.h" // for em4x50
|
||||
#include "cmdlfhid.h" // for hid menu
|
||||
#include "cmdlfhitag.h" // for hitag menu
|
||||
#include "cmdlfio.h" // for ioprox menu
|
||||
|
@ -1250,6 +1251,13 @@ int CmdLFfind(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
if (IfPm3EM4x50()) {
|
||||
if (EM4x50Read("", false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM4x50 ID") " found!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// only run if graphbuffer is just noise as it should be for hitag
|
||||
// The improved noise detection will find Cotag.
|
||||
if (getSignalProperties()->isnoise) {
|
||||
|
@ -1270,8 +1278,6 @@ int CmdLFfind(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
if (EM4x50Read("", false) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM4x50 ID") " found!"); return PM3_SUCCESS;}
|
||||
|
||||
if (demodHID() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("HID Prox ID") " found!"); goto out;}
|
||||
if (demodAWID() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("AWID ID") " found!"); goto out;}
|
||||
if (demodIOProx() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("IO Prox ID") " found!"); goto out;}
|
||||
|
|
|
@ -116,41 +116,6 @@ static int usage_lf_em410x_brute(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
//////////////// 4050 / 4450 commands
|
||||
static int usage_lf_em4x50_demod(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_demod [h]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_demod");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_em4x50_dump(void) {
|
||||
PrintAndLogEx(NORMAL, "Dump EM4x50/EM4x69. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_dump [h] <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_dump");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_dump 11223344");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_em4x50_read(void) {
|
||||
PrintAndLogEx(NORMAL, "Read EM 4x50/EM4x69. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] <address> <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " address - memory address to read. (0-15)");
|
||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_read 1");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_read 1 11223344");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
//////////////// 4205 / 4305 commands
|
||||
static int usage_lf_em4x05_dump(void) {
|
||||
PrintAndLogEx(NORMAL, "Dump EM4x05/EM4x69. Tag must be on antenna. ");
|
||||
|
@ -723,329 +688,6 @@ static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t col
|
|||
return true;
|
||||
}
|
||||
|
||||
// even parity ROW
|
||||
static bool EM_RowParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
|
||||
if (rows * cols > size) return false;
|
||||
uint8_t rowP = 0;
|
||||
|
||||
for (uint8_t r = 0; r < rows - 1; r++) {
|
||||
for (uint8_t c = 0; c < cols; c++) {
|
||||
rowP ^= bs[(r * cols) + c];
|
||||
}
|
||||
if (rowP != pType) return false;
|
||||
rowP = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// EM word parity test.
|
||||
// 9*5 = 45 bits in total
|
||||
// 012345678|r0
|
||||
// 012345678|r1
|
||||
// 012345678|r2
|
||||
// 012345678|r3
|
||||
// ------------
|
||||
//c012345678| 0
|
||||
// |- must be zero
|
||||
|
||||
/*
|
||||
static int EMwordparitytest(uint8_t *bits) {
|
||||
|
||||
// last row/col parity must be 0
|
||||
if (bits[44] != 0) return PM3_ESOFT;
|
||||
|
||||
// col parity check
|
||||
uint8_t c1 = bytebits_to_byte(bits, 8) ^ bytebits_to_byte(bits + 9, 8) ^ bytebits_to_byte(bits + 18, 8) ^ bytebits_to_byte(bits + 27, 8);
|
||||
uint8_t c2 = bytebits_to_byte(bits + 36, 8);
|
||||
if (c1 != c2) return PM3_ESOFT;
|
||||
|
||||
// row parity check
|
||||
uint8_t rowP = 0;
|
||||
for (uint8_t i = 0; i < 36; ++i) {
|
||||
|
||||
rowP ^= bits[i];
|
||||
if (i > 0 && (i % 9) == 0) {
|
||||
|
||||
if (rowP != EVEN)
|
||||
return PM3_ESOFT;
|
||||
|
||||
rowP = 0;
|
||||
}
|
||||
}
|
||||
// all checks ok.
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
//////////////// 4050 / 4450 commands
|
||||
|
||||
static uint32_t OutputEM4x50_Block(uint8_t *BitStream, size_t size, bool verbose, bool pTest) {
|
||||
if (size < 45) return 0;
|
||||
|
||||
uint32_t code = bytebits_to_byte(BitStream, 8);
|
||||
code = code << 8 | bytebits_to_byte(BitStream + 9, 8);
|
||||
code = code << 8 | bytebits_to_byte(BitStream + 18, 8);
|
||||
code = code << 8 | bytebits_to_byte(BitStream + 27, 8);
|
||||
|
||||
if (verbose || g_debugMode) {
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
if (i == 4) PrintAndLogEx(NORMAL, ""); //parity byte spacer
|
||||
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d -> 0x%02x",
|
||||
BitStream[i * 9],
|
||||
BitStream[i * 9 + 1],
|
||||
BitStream[i * 9 + 2],
|
||||
BitStream[i * 9 + 3],
|
||||
BitStream[i * 9 + 4],
|
||||
BitStream[i * 9 + 5],
|
||||
BitStream[i * 9 + 6],
|
||||
BitStream[i * 9 + 7],
|
||||
BitStream[i * 9 + 8],
|
||||
bytebits_to_byte(BitStream + i * 9, 8)
|
||||
);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Parity checks | %s", (pTest) ? _GREEN_("Passed") : _RED_("Fail"));
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
/* Read the transmitted data of an EM4x50 tag from the graphbuffer
|
||||
* Format:
|
||||
*
|
||||
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
|
||||
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
|
||||
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
|
||||
* XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
|
||||
* CCCCCCC0 <- column parity bits
|
||||
* 0 <- stop bit
|
||||
* LW <- Listen Window
|
||||
*
|
||||
* This pattern repeats for every block of data being transmitted.
|
||||
* Transmission starts with two Listen Windows (LW - a modulated
|
||||
* pattern of 320 cycles each (32/32/128/64/64)).
|
||||
*
|
||||
* Note that this data may or may not be the UID. It is whatever data
|
||||
* is stored in the blocks defined in the control word First and Last
|
||||
* Word Read values. UID is stored in block 32.
|
||||
*/
|
||||
//completed by Marshmellow
|
||||
int EM4x50Read(const char *Cmd, bool verbose) {
|
||||
int clk = 0, invert = 0, tol = 0, phaseoff;
|
||||
int i = 0, j = 0, startblock, skip, block, start, end, low = 0, high = 0;
|
||||
uint32_t Code[6];
|
||||
char tmp[6];
|
||||
char tmp2[20];
|
||||
bool complete = false;
|
||||
|
||||
int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
|
||||
memset(tmpbuff, 0, sizeof(tmpbuff));
|
||||
|
||||
// get user entry if any
|
||||
sscanf(Cmd, "%i %i", &clk, &invert);
|
||||
|
||||
uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0};
|
||||
size_t size = getFromGraphBuf(bits);
|
||||
|
||||
if (size < 4000) {
|
||||
if (verbose || g_debugMode) PrintAndLogEx(ERR, "Error: EM4x50 - Too little data in Graphbuffer");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
computeSignalProperties(bits, size);
|
||||
|
||||
// get fuzzed HI / LOW limits in signal
|
||||
getHiLo(&high, &low, 75, 75);
|
||||
|
||||
// get to first full low to prime loop and skip incomplete first pulse
|
||||
size_t offset = 0;
|
||||
getNextHigh(bits, size, high, &offset);
|
||||
getNextLow(bits, size, low, &offset);
|
||||
|
||||
i = (int)offset;
|
||||
skip = offset;
|
||||
|
||||
// set clock
|
||||
if (clk == 0) {
|
||||
DetectASKClock(bits, size, &clk, 0);
|
||||
if (clk == 0) {
|
||||
if (verbose || g_debugMode) PrintAndLogEx(ERR, "Error: EM4x50 - didn't find a clock");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
// tolerance
|
||||
tol = clk / 8;
|
||||
|
||||
// populate tmpbuff buffer with pulse lengths
|
||||
while (i < size) {
|
||||
// measure from low to low
|
||||
while ((i < size) && (bits[i] > low))
|
||||
++i;
|
||||
start = i;
|
||||
|
||||
while ((i < size) && (bits[i] < high))
|
||||
++i;
|
||||
|
||||
while ((i < size) && (bits[i] > low))
|
||||
++i;
|
||||
|
||||
if (j >= (MAX_GRAPH_TRACE_LEN / 64)) {
|
||||
break;
|
||||
}
|
||||
tmpbuff[j++] = i - start;
|
||||
}
|
||||
|
||||
// look for data start - should be 2 pairs of LW (pulses of clk*3,clk*2)
|
||||
start = -1;
|
||||
for (i = 0; i < j - 4 ; ++i) {
|
||||
skip += tmpbuff[i];
|
||||
if (tmpbuff[i] >= clk * 3 - tol && tmpbuff[i] <= clk * 3 + tol) //3 clocks
|
||||
if (tmpbuff[i + 1] >= clk * 2 - tol && tmpbuff[i + 1] <= clk * 2 + tol) //2 clocks
|
||||
if (tmpbuff[i + 2] >= clk * 3 - tol && tmpbuff[i + 2] <= clk * 3 + tol) //3 clocks
|
||||
if (tmpbuff[i + 3] >= clk - tol) { //1.5 to 2 clocks - depends on bit following
|
||||
start = i + 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
startblock = i + 4;
|
||||
|
||||
// skip over the remainder of LW
|
||||
skip += (tmpbuff[i + 1] + tmpbuff[i + 2] + clk);
|
||||
|
||||
if (tmpbuff[i + 3] > clk)
|
||||
phaseoff = tmpbuff[i + 3] - clk;
|
||||
else
|
||||
phaseoff = 0;
|
||||
|
||||
// now do it again to find the end
|
||||
for (i += 3; i < j - 4 ; ++i) {
|
||||
if (tmpbuff[i] >= clk * 3 - tol && tmpbuff[i] <= clk * 3 + tol) //3 clocks
|
||||
if (tmpbuff[i + 1] >= clk * 2 - tol && tmpbuff[i + 1] <= clk * 2 + tol) //2 clocks
|
||||
if (tmpbuff[i + 2] >= clk * 3 - tol && tmpbuff[i + 2] <= clk * 3 + tol) //3 clocks
|
||||
if (tmpbuff[i + 3] >= clk - tol) { //1.5 to 2 clocks - depends on bit following
|
||||
complete = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
end = i;
|
||||
|
||||
// report back
|
||||
if (verbose || g_debugMode) {
|
||||
if (start >= 0) {
|
||||
PrintAndLogEx(INFO, "\nNote: one block = 50 bits (32 data, 12 parity, 6 marker)");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "No data found!, clock tried: " _YELLOW_("%d"), clk);
|
||||
PrintAndLogEx(HINT, "Try again with more samples");
|
||||
PrintAndLogEx(HINT, " or after a " _YELLOW_("'data askedge'") " command to clean up the read");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else if (start < 0) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
start = skip;
|
||||
|
||||
snprintf(tmp2, sizeof(tmp2), "%d %d 1000 %d", clk, invert, clk * 47);
|
||||
|
||||
// save GraphBuffer - to restore it later
|
||||
save_restoreGB(GRAPH_SAVE);
|
||||
|
||||
// get rid of leading crap
|
||||
snprintf(tmp, sizeof(tmp), "%i", skip);
|
||||
CmdLtrim(tmp);
|
||||
|
||||
bool AllPTest = true;
|
||||
|
||||
// now work through remaining buffer printing out data blocks
|
||||
block = 0;
|
||||
i = startblock;
|
||||
while (block < 6) {
|
||||
if (verbose || g_debugMode) PrintAndLogEx(NORMAL, "\nBlock %i:", block);
|
||||
skip = phaseoff;
|
||||
|
||||
// look for LW before start of next block
|
||||
for (; i < j - 4 ; ++i) {
|
||||
skip += tmpbuff[i];
|
||||
if (tmpbuff[i] >= clk * 3 - tol && tmpbuff[i] <= clk * 3 + tol)
|
||||
if (tmpbuff[i + 1] >= clk - tol)
|
||||
break;
|
||||
}
|
||||
if (i >= j - 4) break; //next LW not found
|
||||
skip += clk;
|
||||
if (tmpbuff[i + 1] > clk)
|
||||
phaseoff = tmpbuff[i + 1] - clk;
|
||||
else
|
||||
phaseoff = 0;
|
||||
|
||||
i += 2;
|
||||
|
||||
if (ASKDemod(tmp2, false, false, 1) != PM3_SUCCESS) {
|
||||
save_restoreGB(GRAPH_RESTORE);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
//set DemodBufferLen to just one block
|
||||
DemodBufferLen = skip / clk;
|
||||
//test parities
|
||||
bool pTest = EM_RowParityTest(DemodBuffer, DemodBufferLen, 5, 9, 0);
|
||||
pTest &= EM_ColParityTest(DemodBuffer, DemodBufferLen, 5, 9, 0);
|
||||
AllPTest &= pTest;
|
||||
//get output
|
||||
Code[block] = OutputEM4x50_Block(DemodBuffer, DemodBufferLen, verbose, pTest);
|
||||
PrintAndLogEx(DEBUG, "\nskipping %d samples, bits:%d", skip, skip / clk);
|
||||
//skip to start of next block
|
||||
snprintf(tmp, sizeof(tmp), "%i", skip);
|
||||
CmdLtrim(tmp);
|
||||
block++;
|
||||
if (i >= end) break; //in case chip doesn't output 6 blocks
|
||||
}
|
||||
|
||||
//print full code:
|
||||
if (verbose || g_debugMode || AllPTest) {
|
||||
if (!complete) {
|
||||
PrintAndLogEx(WARNING, _RED_("* **Warning!"));
|
||||
PrintAndLogEx(INFO, "Partial data - no end found!");
|
||||
PrintAndLogEx(HINT, "Try again with more samples.");
|
||||
}
|
||||
PrintAndLogEx(INFO, "Found data at sample: %i - using clock: %i", start, clk);
|
||||
end = block;
|
||||
PrintAndLogEx(INFO, "blk | data");
|
||||
PrintAndLogEx(INFO, "----+--------------");
|
||||
for (block = 0; block < end; block++) {
|
||||
PrintAndLogEx(INFO, "%03d | %08x", block, Code[block]);
|
||||
}
|
||||
PrintAndLogEx(INFO, "----+--------------");
|
||||
PrintAndLogEx((AllPTest) ? SUCCESS : WARNING, "Parities checks | %s", (AllPTest) ? _GREEN_("Passed") : _RED_("Fail"));
|
||||
|
||||
if (AllPTest == false) {
|
||||
PrintAndLogEx(HINT, "Try cleaning the read samples with " _YELLOW_("'data askedge'"));
|
||||
}
|
||||
}
|
||||
|
||||
//restore GraphBuffer
|
||||
save_restoreGB(GRAPH_RESTORE);
|
||||
return AllPTest ? PM3_SUCCESS : PM3_ESOFT;
|
||||
}
|
||||
|
||||
static int CmdEM4x50Demod(const char *Cmd) {
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_lf_em4x50_demod();
|
||||
return EM4x50Read(Cmd, true);
|
||||
}
|
||||
|
||||
static int CmdEM4x50Read(const char *Cmd) {
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_lf_em4x50_read();
|
||||
lf_read(false, 24000);
|
||||
return EM4x50Read(Cmd, true);
|
||||
}
|
||||
|
||||
static int CmdEM4x50Dump(const char *Cmd) {
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_lf_em4x50_dump();
|
||||
PrintAndLogEx(NORMAL, "no implemented yet");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
#define EM_PREAMBLE_LEN 6
|
||||
// download samples from device and copy to Graphbuffer
|
||||
static bool downloadSamplesEM(void) {
|
||||
|
@ -1753,13 +1395,10 @@ static command_t CommandTable[] = {
|
|||
{"4x05_read", CmdEM4x05Read, IfPm3Lf, "read word data from EM4x05/EM4x69"},
|
||||
{"4x05_write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"},
|
||||
{"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 4x50") " -----------------------"},
|
||||
{"4x50_demod", CmdEM4x50Demod, AlwaysAvailable, "demodulate a EM4x50 tag from the GraphBuffer"},
|
||||
{"4x50_dump", CmdEM4x50Dump, IfPm3Lf, "dump EM4x50 tag"},
|
||||
{"4x50_read", CmdEM4x50Read, IfPm3Lf, "read word data from EM4x50"},
|
||||
{"4x50_info", CmdEM4x50Info, IfPm3Lf, "read complete data from EM4x50"},
|
||||
{"4x50_write", CmdEM4x50Write, IfPm3Lf, "write word data to EM4x50"},
|
||||
{"4x50_write_password", CmdEM4x50WritePassword, IfPm3Lf, "change passwword of EM4x50 tag"},
|
||||
{"4x50_sread", CmdEM4x50SRead, IfPm3Lf, "read word data from EM4x50 on device"},
|
||||
{"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "read complete data from EM4x50"},
|
||||
{"4x50_write", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"},
|
||||
{"4x50_write_password", CmdEM4x50WritePassword, IfPm3EM4x50, "change passwword of EM4x50 tag"},
|
||||
{"4x50_read", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
int CmdLFEM4X(const char *Cmd);
|
||||
|
||||
int demodEM410x(void);
|
||||
int EM4x50Read(const char *Cmd, bool verbose);
|
||||
bool EM4x05IsBlock0(uint32_t *word);
|
||||
|
||||
void printEM410x(uint32_t hi, uint64_t id);
|
||||
|
|
|
@ -54,17 +54,17 @@ int usage_lf_em4x50_write_password(void) {
|
|||
PrintAndLogEx(NORMAL, " lf em 4x50_write_password p 11223344 n 01020304");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
int usage_lf_em4x50_sread(void) {
|
||||
int usage_lf_em4x50_read(void) {
|
||||
PrintAndLogEx(NORMAL, "Read EM4x50 word(s). Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_sread [h] a <address> p <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] a <address> p <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " a <addr> - memory address to read (dec) (optional)");
|
||||
PrintAndLogEx(NORMAL, " p <pwd> - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_sread");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_sread a 2 p 00000000");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_read");
|
||||
PrintAndLogEx(NORMAL, " lf em 4x50_read a 2 p 00000000");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ static void print_bit_table(const em4x50_word_t word) {
|
|||
string[0] = '\0';
|
||||
}
|
||||
|
||||
static void print_result(const em4x50_word_t *words, int fwr, int lwr) {
|
||||
static void print_result(const em4x50_word_t *words, int fwr, int lwr, bool verbose) {
|
||||
|
||||
// print available information for given word from fwr to lwr, i.e.
|
||||
// bit table + summary lines with hex notation of word (msb + lsb)
|
||||
|
@ -199,6 +199,8 @@ static void print_result(const em4x50_word_t *words, int fwr, int lwr) {
|
|||
|
||||
for (int i = fwr; i <= lwr; i++) {
|
||||
|
||||
if (verbose) {
|
||||
|
||||
// blank line before each bit table
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
|
@ -222,6 +224,17 @@ static void print_result(const em4x50_word_t *words, int fwr, int lwr) {
|
|||
sprintf(pstring, "%02x", reflect8(words[i].byte[3-j]));
|
||||
strcat(string, pstring);
|
||||
}
|
||||
} else {
|
||||
|
||||
string[0] = '\0';
|
||||
sprintf(pstring, "[" _GREEN_("+") "] word[%i]: " _YELLOW_("0x"), i);
|
||||
strcat(string, pstring);
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
sprintf(pstring, _YELLOW_("%02x"), words[i].byte[j]);
|
||||
strcat(string, pstring);
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL,string);
|
||||
}
|
||||
|
@ -235,9 +248,8 @@ static void print_info_result(PacketResponseNG *resp, const em4x50_data_t *etd,
|
|||
em4x50_word_t words[EM4X50_NO_WORDS];
|
||||
char pstring[NO_CHARS_MAX] = {0}, string[NO_CHARS_MAX] = {0};
|
||||
|
||||
bool pwd_given = etd->pwd_given;
|
||||
bool success = (resp->status & STATUS_SUCCESS) >> 1;
|
||||
bool login = resp->status & STATUS_LOGIN;
|
||||
bool bpwd_given = etd->pwd_given;
|
||||
bool blogin = resp->status & STATUS_LOGIN;
|
||||
|
||||
prepare_result(data, 0, EM4X50_NO_WORDS - 1, words);
|
||||
|
||||
|
@ -256,7 +268,7 @@ static void print_info_result(PacketResponseNG *resp, const em4x50_data_t *etd,
|
|||
if (verbose) {
|
||||
|
||||
// detailed data section
|
||||
print_result(words, 0, EM4X50_NO_WORDS - 1);
|
||||
print_result(words, 0, EM4X50_NO_WORDS - 1, true);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -336,33 +348,37 @@ static void print_info_result(PacketResponseNG *resp, const em4x50_data_t *etd,
|
|||
sprintf(pstring, " reading ");
|
||||
strcat(string, pstring);
|
||||
|
||||
if (success == false) {
|
||||
sprintf(pstring, _RED_("failed"));
|
||||
strcat(string, pstring);
|
||||
} else {
|
||||
|
||||
sprintf(pstring, _GREEN_("ok "));
|
||||
strcat(string, pstring);
|
||||
|
||||
if (login) {
|
||||
if (pwd_given) {
|
||||
if (blogin) {
|
||||
|
||||
if (bpwd_given) {
|
||||
|
||||
sprintf(pstring, "(login with password 0x%02x%02x%02x%02x)",
|
||||
etd->password[0], etd->password[1],
|
||||
etd->password[2], etd->password[3]);
|
||||
strcat(string, pstring);
|
||||
|
||||
} else {
|
||||
|
||||
sprintf(pstring, "(login with default password 0x00000000)");
|
||||
strcat(string, pstring);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
if (pwd_given) {
|
||||
|
||||
if (bpwd_given) {
|
||||
|
||||
sprintf(pstring, "(login failed)");
|
||||
strcat(string, pstring);
|
||||
|
||||
} else {
|
||||
|
||||
sprintf(pstring, "(no login)");
|
||||
strcat(string, pstring);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,15 +435,19 @@ int CmdEM4x50Info(const char *Cmd) {
|
|||
|
||||
|
||||
// get result
|
||||
if (!WaitForResponse(CMD_ACK, &resp)) {
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// print result
|
||||
print_info_result(&resp, &etd, verbose);
|
||||
|
||||
success = (resp.status & STATUS_SUCCESS) >> 1;
|
||||
|
||||
// print result
|
||||
if (success)
|
||||
print_info_result(&resp, &etd, verbose);
|
||||
else
|
||||
PrintAndLogEx(NORMAL,"\nreading " _RED_("failed") "\n");
|
||||
|
||||
return (success) ? PM3_SUCCESS : PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -436,19 +456,13 @@ static void print_write_result(PacketResponseNG *resp, const em4x50_data_t *etd)
|
|||
// display result of writing operation in structured format
|
||||
|
||||
bool pwd_given = etd->pwd_given;
|
||||
bool success = (resp->status & STATUS_SUCCESS) >> 1;
|
||||
bool login = resp->status & STATUS_LOGIN;
|
||||
uint8_t *data = resp->data.asBytes;
|
||||
char string[NO_CHARS_MAX] = {0}, pstring[NO_CHARS_MAX] = {0};
|
||||
em4x50_word_t words[EM4X50_NO_WORDS];
|
||||
|
||||
if (success == false) {
|
||||
sprintf(pstring, "\n writing " _RED_("failed"));
|
||||
strcat(string, pstring);
|
||||
} else {
|
||||
|
||||
prepare_result(data, etd->address, etd->address, words);
|
||||
print_result(words, etd->address, etd->address);
|
||||
print_result(words, etd->address, etd->address, true);
|
||||
|
||||
sprintf(pstring, "\n writing " _GREEN_("ok "));
|
||||
strcat(string, pstring);
|
||||
|
@ -469,7 +483,6 @@ static void print_write_result(PacketResponseNG *resp, const em4x50_data_t *etd)
|
|||
sprintf(pstring, "(no login)");
|
||||
strcat(string, pstring);
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL,"%s\n", string);
|
||||
}
|
||||
|
@ -536,15 +549,19 @@ int CmdEM4x50Write(const char *Cmd) {
|
|||
SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd));
|
||||
|
||||
|
||||
if (!WaitForResponse(CMD_ACK, &resp)) {
|
||||
PrintAndLogEx(WARNING, "\n timeout while waiting for reply.\n");
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// get, prepare and print response
|
||||
print_write_result(&resp, &etd);
|
||||
|
||||
success = (resp.status & STATUS_SUCCESS) >> 1;
|
||||
|
||||
// get, prepare and print response
|
||||
if (success)
|
||||
print_write_result(&resp, &etd);
|
||||
else
|
||||
PrintAndLogEx(NORMAL,"\nwriting " _RED_("failed") "\n");
|
||||
|
||||
return (success) ? PM3_SUCCESS : PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -552,19 +569,10 @@ static void print_write_password_result(PacketResponseNG *resp, const em4x50_dat
|
|||
|
||||
// display result of password changing operation
|
||||
|
||||
bool success = resp->status;
|
||||
char string[NO_CHARS_MAX] = {0}, pstring[NO_CHARS_MAX] = {0};
|
||||
|
||||
if (!success) {
|
||||
|
||||
sprintf(pstring, "\n writing new password " _RED_("failed"));
|
||||
strcat(string, pstring);
|
||||
|
||||
} else {
|
||||
|
||||
sprintf(pstring, "\n writing new password " _GREEN_("ok"));
|
||||
strcat(string, pstring);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL,"%s\n", string);
|
||||
}
|
||||
|
@ -573,7 +581,7 @@ int CmdEM4x50WritePassword(const char *Cmd) {
|
|||
|
||||
// envokes changing the password of EM4x50 tag
|
||||
|
||||
bool errors = false, bpwd = false, bnpwd = false;
|
||||
bool errors = false, bpwd = false, bnpwd = false, success = false;
|
||||
uint8_t cmdp = 0;
|
||||
em4x50_data_t etd;
|
||||
PacketResponseNG resp;
|
||||
|
@ -621,44 +629,39 @@ int CmdEM4x50WritePassword(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X50_WRITE_PASSWORD, (uint8_t *)&etd, sizeof(etd));
|
||||
|
||||
if (!WaitForResponse(CMD_ACK, &resp)) {
|
||||
PrintAndLogEx(WARNING, "\n timeout while waiting for reply.\n");
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
success = (bool)resp.status;
|
||||
|
||||
// get, prepare and print response
|
||||
if (success)
|
||||
print_write_password_result(&resp, &etd);
|
||||
else
|
||||
PrintAndLogEx(NORMAL,"\nwriting password " _RED_("failed") "\n");
|
||||
|
||||
return ((bool)resp.status) ? PM3_SUCCESS : PM3_ESOFT;
|
||||
return (success) ? PM3_SUCCESS : PM3_ESOFT;
|
||||
}
|
||||
|
||||
static void print_sread_result(PacketResponseNG *resp, const em4x50_data_t *etd) {
|
||||
static void print_read_result(PacketResponseNG *resp, const em4x50_data_t *etd, bool verbose) {
|
||||
|
||||
// display result of writing operation in structured format
|
||||
|
||||
bool addr_given = etd->addr_given;
|
||||
bool pwd_given = etd->pwd_given;
|
||||
bool login = resp->status & STATUS_LOGIN;
|
||||
bool success = (resp->status & STATUS_SUCCESS) >> 1;
|
||||
int now = (resp->status & STATUS_NO_WORDS) >> 2;
|
||||
char string[NO_CHARS_MAX] = {0}, pstring[NO_CHARS_MAX] = {0};
|
||||
uint8_t *data = resp->data.asBytes;
|
||||
em4x50_word_t words[EM4X50_NO_WORDS];
|
||||
|
||||
if (success == false) {
|
||||
|
||||
sprintf(pstring, "\n reading " _RED_("failed"));
|
||||
strcat(string, pstring);
|
||||
PrintAndLogEx(NORMAL,"%s\n", string);
|
||||
|
||||
} else {
|
||||
|
||||
if (addr_given) {
|
||||
|
||||
// selective read mode
|
||||
|
||||
prepare_result(data, etd->address, etd->address, words);
|
||||
print_result(words, etd->address, etd->address);
|
||||
print_result(words, etd->address, etd->address, true);
|
||||
|
||||
string[0] = '\0';
|
||||
sprintf(pstring, "\n reading " _GREEN_("ok "));
|
||||
|
@ -679,12 +682,16 @@ static void print_sread_result(PacketResponseNG *resp, const em4x50_data_t *etd)
|
|||
strcat(string, pstring);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL,"%s\n", string);
|
||||
|
||||
} else {
|
||||
|
||||
//standard read mode
|
||||
|
||||
prepare_result(data, 0, now - 1, words);
|
||||
print_result(words, 0, now - 1);
|
||||
print_result(words, 0, now - 1, verbose);
|
||||
|
||||
if (verbose) {
|
||||
|
||||
string[0] = '\0';
|
||||
sprintf(pstring, "\n reading " _GREEN_("ok "));
|
||||
|
@ -697,13 +704,13 @@ static void print_sread_result(PacketResponseNG *resp, const em4x50_data_t *etd)
|
|||
sprintf(pstring, "(standard read mode)");
|
||||
strcat(string, pstring);
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL,"%s\n", string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CmdEM4x50SRead(const char *Cmd) {
|
||||
int EM4x50Read(const char *Cmd, bool verbose) {
|
||||
|
||||
// envoke reading
|
||||
// - without option -> standard read mode
|
||||
|
@ -719,11 +726,12 @@ int CmdEM4x50SRead(const char *Cmd) {
|
|||
etd.pwd_given = false;
|
||||
etd.addr_given = false;
|
||||
|
||||
if (verbose) {
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_em4x50_sread();
|
||||
return usage_lf_em4x50_read();
|
||||
|
||||
case 'p':
|
||||
if (param_gethex(Cmd, cmdp + 1, etd.password, 8)) {
|
||||
|
@ -754,20 +762,38 @@ int CmdEM4x50SRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (errors)
|
||||
return usage_lf_em4x50_sread();
|
||||
return usage_lf_em4x50_read();
|
||||
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X50_SREAD, (uint8_t *)&etd, sizeof(etd));
|
||||
SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&etd, sizeof(etd));
|
||||
|
||||
|
||||
if (!WaitForResponse(CMD_ACK, &resp)) {
|
||||
PrintAndLogEx(WARNING, "\n timeout while waiting for reply.\n");
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// get, prepare and print response
|
||||
print_sread_result(&resp, &etd);
|
||||
|
||||
success = (resp.status & STATUS_SUCCESS) >> 1;
|
||||
|
||||
// get, prepare and print response
|
||||
if (success)
|
||||
print_read_result(&resp, &etd, verbose);
|
||||
else if (verbose)
|
||||
PrintAndLogEx(NORMAL,"\nreading " _RED_("failed") "\n");
|
||||
|
||||
return (success) ? PM3_SUCCESS : PM3_ESOFT;
|
||||
|
||||
}
|
||||
|
||||
int CmdEM4x50Read(const char *Cmd) {
|
||||
|
||||
// envoke reading function
|
||||
// verbose = true for manual call
|
||||
// verbose = false for automatic call (e.g. lf search)
|
||||
|
||||
bool verbose = true;
|
||||
|
||||
return EM4x50Read(Cmd, verbose);
|
||||
}
|
||||
|
|
|
@ -11,14 +11,18 @@
|
|||
#ifndef CMDLFEM4X50_H__
|
||||
#define CMDLFEM4X50_H__
|
||||
|
||||
#include"common.h"
|
||||
|
||||
int usage_lf_em4x50_info(void);
|
||||
int usage_lf_em4x50_write(void);
|
||||
int usage_lf_em4x50_write_password(void);
|
||||
int usage_lf_em4x50_sread(void);
|
||||
int usage_lf_em4x50_read(void);
|
||||
|
||||
int EM4x50Read(const char *Cmd, bool verbose);
|
||||
|
||||
int CmdEM4x50Info(const char *Cmd);
|
||||
int CmdEM4x50Write(const char *Cmd);
|
||||
int CmdEM4x50WritePassword(const char *Cmd);
|
||||
int CmdEM4x50SRead(const char *Cmd);
|
||||
int CmdEM4x50Read(const char *Cmd);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -89,6 +89,12 @@ bool IfPm3Hitag(void) {
|
|||
return pm3_capabilities.compiled_with_hitag;
|
||||
}
|
||||
|
||||
bool IfPm3EM4x50(void) {
|
||||
if (!IfPm3Present())
|
||||
return false;
|
||||
return pm3_capabilities.compiled_with_em4x50;
|
||||
}
|
||||
|
||||
bool IfPm3Hfsniff(void) {
|
||||
if (!IfPm3Present())
|
||||
return false;
|
||||
|
|
|
@ -33,6 +33,7 @@ bool IfPm3FpcUsartDevFromUsb(void);
|
|||
bool IfPm3FpcUsartFromUsb(void);
|
||||
bool IfPm3Lf(void);
|
||||
bool IfPm3Hitag(void);
|
||||
bool IfPm3EM4x50(void);
|
||||
bool IfPm3Hfsniff(void);
|
||||
bool IfPm3Hfplot(void);
|
||||
bool IfPm3Iso14443a(void);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#define STATUS_SUCCESS 0x2
|
||||
#define STATUS_LOGIN 0x1
|
||||
#define NO_CHARS_MAX 400
|
||||
#define TIMEOUT 2000
|
||||
|
||||
typedef struct {
|
||||
bool addr_given;
|
||||
|
|
|
@ -405,7 +405,7 @@ typedef struct {
|
|||
#define CMD_LF_EM4X50_INFO 0x0240
|
||||
#define CMD_LF_EM4X50_WRITE 0x0241
|
||||
#define CMD_LF_EM4X50_WRITE_PASSWORD 0x0242
|
||||
#define CMD_LF_EM4X50_SREAD 0x0243
|
||||
#define CMD_LF_EM4X50_READ 0x0243
|
||||
// Sampling configuration for LF reader/sniffer
|
||||
#define CMD_LF_SAMPLING_SET_CONFIG 0x021D
|
||||
#define CMD_LF_FSK_SIMULATE 0x021E
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue