deleted nearly all EM4x50 code; new EM4x50 code is in 'cmdlfem4x50.c' (device side instead GraphBuffer)

This commit is contained in:
tharexde 2020-06-28 21:43:13 +02:00
parent 78511df9f2
commit 9aafc094b6

View file

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