X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/35aa230ee467d8d603aa49415f43239fe014d9ac..50acfd37e2671110116c29cdc96af3f018b5495c:/client/cmdlfem4x.c diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 12300955..da6c3094 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -11,6 +11,7 @@ #include #include #include +#include "cmdlfem4x.h" #include "proxmark3.h" #include "ui.h" #include "util.h" @@ -21,6 +22,8 @@ #include "cmdlf.h" #include "cmdmain.h" #include "lfdemod.h" +#include "protocols.h" +#include "util_posix.h" uint64_t g_em410xId=0; @@ -144,17 +147,20 @@ void printEM410x(uint32_t hi, uint64_t id) int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo ) { size_t idx = 0; - size_t BitLen = DemodBufferLen; - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - memcpy(BitStream, DemodBuffer, BitLen); - if (Em410xDecode(BitStream, &BitLen, &idx, hi, lo)){ + uint8_t BitStream[512]={0}; + size_t BitLen = sizeof(BitStream); + if ( !getDemodBuf(BitStream, &BitLen) ) return 0; + + if (Em410xDecode(BitStream, &BitLen, &idx, hi, lo)) { //set GraphBuffer for clone or sim command - setDemodBuf(BitStream, BitLen, idx); - if (g_debugMode){ + setDemodBuf(DemodBuffer, (BitLen==40) ? 64 : 128, idx+1); + setClockGrid(g_DemodClock, g_DemodStartIdx + ((idx+1)*g_DemodClock)); + + if (g_debugMode) { PrintAndLog("DEBUG: idx: %d, Len: %d, Printing Demod Buffer:", idx, BitLen); printDemodBuff(); } - if (verbose){ + if (verbose) { PrintAndLog("EM410x pattern found: "); printEM410x(*hi, *lo); g_em410xId = *lo; @@ -230,7 +236,7 @@ int CmdEM410xSim(const char *Cmd) param_getdec(Cmd,1, &clock); PrintAndLog("Starting simulating UID %02X%02X%02X%02X%02X clock: %d", uid[0],uid[1],uid[2],uid[3],uid[4],clock); - PrintAndLog("Press pm3-button to about simulation"); + PrintAndLog("Press pm3-button to abort simulation"); /* clear our graph */ @@ -278,6 +284,120 @@ int CmdEM410xSim(const char *Cmd) return 0; } +int usage_lf_em410x_brute(void) { + PrintAndLog("Bruteforcing by emulating EM410x tag"); + PrintAndLog(""); + PrintAndLog("Usage: lf em 410xbrute [h] ids.txt"); + PrintAndLog("Options:"); + PrintAndLog(" h - this help"); + PrintAndLog(" ids.txt - file with id in HEX format one per line"); + PrintAndLog(" clock - clock (32|64) (optional)"); + PrintAndLog("samples:"); + PrintAndLog(" lf em 410xbrute ids.txt"); + PrintAndLog(" lf em 410xbrute ids.txt 32"); + return 0; +} + +int CmdEM410xBrute(const char *Cmd) +{ + char filename[FILE_PATH_SIZE]={0}; + char buf[11]; + int i, n, j, binary[4], parity[4]; + + char cmdp = param_getchar(Cmd, 0); + uint8_t uid[5] = {0x00}; + + if (cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_sim(); + /* clock is 64 in EM410x tags */ + uint8_t clock = 64; + + param_getdec(Cmd,1, &clock); + + param_getstr(Cmd, 0, filename); + PrintAndLog("Filename: %s", filename); + + FILE *f = fopen(filename, "r"); + + if(!f) { + PrintAndLog("Couldn't open '%s'", Cmd); + return 0; + } + + while( fgets(buf, sizeof(buf), f) ) { + msleep(1000); + if (strlen(buf) < 10 || buf[9] == '\n') continue; + while (fgetc(f) != '\n' && !feof(f)); //goto next line + + //The line start with # is comment, skip + if( buf[0]=='#' ) continue; + + buf[10] = 0; + //PrintAndLog("ID: %s", buf); + + if (param_gethex(buf, 0, uid, 10)) { + PrintAndLog("UID must include 10 HEX symbols"); + return 0; + } + + PrintAndLog("Starting simulating UID %02X%02X%02X%02X%02X clock: %d", uid[0],uid[1],uid[2],uid[3],uid[4],clock); + + + /* clear our graph */ + ClearGraph(0); + + /* write 9 start bits */ + for (i = 0; i < 9; i++) + AppendGraph(0, clock, 1); + + /* for each hex char */ + parity[0] = parity[1] = parity[2] = parity[3] = 0; + for (i = 0; i < 10; i++) + { + /* read each hex char */ + sscanf(&buf[i], "%1x", &n); + for (j = 3; j >= 0; j--, n/= 2) + binary[j] = n % 2; + + /* append each bit */ + AppendGraph(0, clock, binary[0]); + AppendGraph(0, clock, binary[1]); + AppendGraph(0, clock, binary[2]); + AppendGraph(0, clock, binary[3]); + + /* append parity bit */ + AppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]); + + /* keep track of column parity */ + parity[0] ^= binary[0]; + parity[1] ^= binary[1]; + parity[2] ^= binary[2]; + parity[3] ^= binary[3]; + } + + /* parity columns */ + AppendGraph(0, clock, parity[0]); + AppendGraph(0, clock, parity[1]); + AppendGraph(0, clock, parity[2]); + AppendGraph(0, clock, parity[3]); + + /* stop bit */ + AppendGraph(1, clock, 0); + + CmdLFSim("0"); //240 start_gap. + + + memset(buf, 0, sizeof(buf)); + + } + + fclose(f); + + + + return 0; +} + + /* Function is equivalent of lf read + data samples + em410xread * looped until an EM410x tag is detected * @@ -296,9 +416,7 @@ int CmdEM410xWatch(const char *Cmd) printf("\naborted via keyboard!\n"); break; } - - CmdLFRead("s"); - getSamples("8201",true); + lf_read(true, 8201); } while (!CmdAskEM410xDemod("")); return 0; @@ -471,9 +589,6 @@ int EM4x50Read(const char *Cmd, bool verbose) // get user entry if any sscanf(Cmd, "%i %i", &clk, &invert); - // save GraphBuffer - to restore it later - save_restoreGB(1); - // first get high and low values for (i = 0; i < GraphTraceLen; i++) { if (GraphBuffer[i] > high) @@ -570,6 +685,8 @@ int EM4x50Read(const char *Cmd, bool verbose) } else if (start < 0) return 0; 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); @@ -597,7 +714,7 @@ int EM4x50Read(const char *Cmd, bool verbose) phaseoff = 0; i += 2; if (ASKDemod(tmp2, false, false, 1) < 1) { - save_restoreGB(0); + save_restoreGB(GRAPH_RESTORE); return 0; } //set DemodBufferLen to just one block @@ -636,7 +753,7 @@ int EM4x50Read(const char *Cmd, bool verbose) } //restore GraphBuffer - save_restoreGB(0); + save_restoreGB(GRAPH_RESTORE); return (int)AllPTest; } @@ -702,6 +819,8 @@ bool EM4x05testDemodReadData(uint32_t *word, bool readCmd) { } setDemodBuf(DemodBuffer, 32, 0); + //setClockGrid(0,0); + *word = bytebits_to_byteLSBF(DemodBuffer, 32); } return true; @@ -898,47 +1017,35 @@ int CmdEM4x05dump(const char *Cmd) { int usage_lf_em_write(void) { PrintAndLog("Write EM4x05/EM4x69. Tag must be on antenna. "); PrintAndLog(""); - PrintAndLog("Usage: lf em 4x05writeword [h] [s]
"); + PrintAndLog("Usage: lf em 4x05writeword [h] a
d p [s] [i]"); PrintAndLog("Options:"); - PrintAndLog(" h - this help"); - PrintAndLog(" s - swap data bit order before write"); - PrintAndLog(" address - memory address to write to. (0-15)"); - PrintAndLog(" data - data to write (hex)"); - PrintAndLog(" pwd - password (hex) (optional)"); + PrintAndLog(" h - this help"); + PrintAndLog(" a
- memory address to write to. (0-15)"); + PrintAndLog(" d - data to write (hex)"); + PrintAndLog(" p - password (hex) (optional)"); + PrintAndLog(" s - swap the data bit order before write"); + PrintAndLog(" i - invert the data bits before write"); PrintAndLog("samples:"); - PrintAndLog(" lf em 4x05writeword 1"); - PrintAndLog(" lf em 4x05writeword 1 deadc0de 11223344"); + PrintAndLog(" lf em 4x05writeword a 5 d 11223344"); + PrintAndLog(" lf em 4x05writeword a 5 p deadc0de d 11223344 s i"); return 0; } -int CmdEM4x05WriteWord(const char *Cmd) { - uint8_t ctmp = param_getchar(Cmd, 0); - if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_write(); +// note: em4x05 doesn't have a way to invert data output so we must invert the data prior to writing +// it if invertion is needed. (example FSK2a vs FSK) +// also em4x05 requires swapping word data when compared to the data used for t55xx chips. +int EM4x05WriteWord(uint8_t addr, uint32_t data, uint32_t pwd, bool usePwd, bool swap, bool invert) { + if (swap) data = SwapBits(data, 32); - bool usePwd = false; - - uint8_t addr = 16; // default to invalid address - uint32_t data = 0xFFFFFFFF; // default to blank data - uint32_t pwd = 0xFFFFFFFF; // default to blank password - char swap = 0; - - int p = 0; - swap = param_getchar(Cmd, 0); - if (swap == 's' || swap=='S') p++; - addr = param_get8ex(Cmd, p++, 16, 10); - data = param_get32ex(Cmd, p++, 0, 16); - pwd = param_get32ex(Cmd, p++, 1, 16); - - if (swap == 's' || swap=='S') data = SwapBits(data, 32); + if (invert) data ^= 0xFFFFFFFF; if ( (addr > 15) ) { PrintAndLog("Address must be between 0 and 15"); - return 1; + return -1; } - if ( pwd == 1 ) - PrintAndLog("Writing address %d data %08X", addr, data); - else { - usePwd = true; + if ( !usePwd ) { + PrintAndLog("Writing address %d data %08X", addr, data); + } else { PrintAndLog("Writing address %d data %08X using password %08X", addr, data, pwd); } @@ -967,8 +1074,75 @@ int CmdEM4x05WriteWord(const char *Cmd) { return result; } +int CmdEM4x05WriteWord(const char *Cmd) { + bool errors = false; + bool usePwd = false; + uint32_t data = 0xFFFFFFFF; + uint32_t pwd = 0xFFFFFFFF; + bool swap = false; + bool invert = false; + uint8_t addr = 16; // default to invalid address + bool gotData = false; + char cmdp = 0; + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_lf_em_write(); + case 'a': + case 'A': + addr = param_get8ex(Cmd, cmdp+1, 16, 10); + cmdp += 2; + break; + case 'd': + case 'D': + data = param_get32ex(Cmd, cmdp+1, 0, 16); + gotData = true; + cmdp += 2; + break; + case 'i': + case 'I': + invert = true; + cmdp++; + break; + case 'p': + case 'P': + pwd = param_get32ex(Cmd, cmdp+1, 1, 16); + if (pwd == 1) { + PrintAndLog("invalid pwd"); + errors = true; + } + usePwd = true; + cmdp += 2; + break; + case 's': + case 'S': + swap = true; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) break; + } + //Validations + if(errors) return usage_lf_em_write(); + + if ( strlen(Cmd) == 0 ) return usage_lf_em_write(); + + if (!gotData) { + PrintAndLog("You must enter the data you want to write"); + return usage_lf_em_write(); + } + return EM4x05WriteWord(addr, data, pwd, usePwd, swap, invert); +} + void printEM4x05config(uint32_t wordData) { - uint16_t datarate = (((wordData & 0x3F)+1)*2); + uint16_t datarate = EM4x05_GET_BITRATE(wordData); uint8_t encoder = ((wordData >> 6) & 0xF); char enc[14]; memset(enc,0,sizeof(enc)); @@ -979,8 +1153,8 @@ void printEM4x05config(uint32_t wordData) { uint8_t delay = (wordData >> 12) & 0x3; char cdelay[33]; memset(cdelay,0,sizeof(cdelay)); - uint8_t LWR = (wordData >> 14) & 0xF; //last word read - + uint8_t numblks = EM4x05_GET_NUM_BLOCKS(wordData); + uint8_t LWR = numblks+5-1; //last word read switch (encoder) { case 0: snprintf(enc,sizeof(enc),"NRZ"); break; case 1: snprintf(enc,sizeof(enc),"Manchester"); break; @@ -1008,21 +1182,29 @@ void printEM4x05config(uint32_t wordData) { case 2: snprintf(cdelay, sizeof(cdelay),"BP/4 or 1/4th bit period delay"); break; case 3: snprintf(cdelay, sizeof(cdelay),"no delay"); break; } + uint8_t readLogin = (wordData & EM4x05_READ_LOGIN_REQ)>>18; + uint8_t readHKL = (wordData & EM4x05_READ_HK_LOGIN_REQ)>>19; + uint8_t writeLogin = (wordData & EM4x05_WRITE_LOGIN_REQ)>>20; + uint8_t writeHKL = (wordData & EM4x05_WRITE_HK_LOGIN_REQ)>>21; + uint8_t raw = (wordData & EM4x05_READ_AFTER_WRITE)>>22; + uint8_t disable = (wordData & EM4x05_DISABLE_ALLOWED)>>23; + uint8_t rtf = (wordData & EM4x05_READER_TALK_FIRST)>>24; + uint8_t pigeon = (wordData & (1<<26))>>26; PrintAndLog("ConfigWord: %08X (Word 4)\n", wordData); - PrintAndLog("Config Breakdown:", wordData); + PrintAndLog("Config Breakdown:"); PrintAndLog(" Data Rate: %02u | RF/%u", wordData & 0x3F, datarate); PrintAndLog(" Encoder: %u | %s", encoder, enc); PrintAndLog(" PSK CF: %u | %s", PSKcf, cf); PrintAndLog(" Delay: %u | %s", delay, cdelay); - PrintAndLog(" LastWordR: %02u | Address of last word for default read", LWR); - PrintAndLog(" ReadLogin: %u | Read Login is %s", (wordData & 0x40000)>>18, (wordData & 0x40000) ? "Required" : "Not Required"); - PrintAndLog(" ReadHKL: %u | Read Housekeeping Words Login is %s", (wordData & 0x80000)>>19, (wordData & 0x80000) ? "Required" : "Not Required"); - PrintAndLog("WriteLogin: %u | Write Login is %s", (wordData & 0x100000)>>20, (wordData & 0x100000) ? "Required" : "Not Required"); - PrintAndLog(" WriteHKL: %u | Write Housekeeping Words Login is %s", (wordData & 0x200000)>>21, (wordData & 0x200000) ? "Required" : "Not Required"); - PrintAndLog(" R.A.W.: %u | Read After Write is %s", (wordData & 0x400000)>>22, (wordData & 0x400000) ? "On" : "Off"); - PrintAndLog(" Disable: %u | Disable Command is %s", (wordData & 0x800000)>>23, (wordData & 0x800000) ? "Accepted" : "Not Accepted"); - PrintAndLog(" R.T.F.: %u | Reader Talk First is %s", (wordData & 0x1000000)>>24, (wordData & 0x1000000) ? "Enabled" : "Disabled"); - PrintAndLog(" Pigeon: %u | Pigeon Mode is %s\n", (wordData & 0x4000000)>>26, (wordData & 0x4000000) ? "Enabled" : "Disabled"); + PrintAndLog(" LastWordR: %02u | Address of last word for default read - meaning %u blocks are output", LWR, numblks); + PrintAndLog(" ReadLogin: %u | Read Login is %s", readLogin, readLogin ? "Required" : "Not Required"); + PrintAndLog(" ReadHKL: %u | Read Housekeeping Words Login is %s", readHKL, readHKL ? "Required" : "Not Required"); + PrintAndLog("WriteLogin: %u | Write Login is %s", writeLogin, writeLogin ? "Required" : "Not Required"); + PrintAndLog(" WriteHKL: %u | Write Housekeeping Words Login is %s", writeHKL, writeHKL ? "Required" : "Not Required"); + PrintAndLog(" R.A.W.: %u | Read After Write is %s", raw, raw ? "On" : "Off"); + PrintAndLog(" Disable: %u | Disable Command is %s", disable, disable ? "Accepted" : "Not Accepted"); + PrintAndLog(" R.T.F.: %u | Reader Talk First is %s", rtf, rtf ? "Enabled" : "Disabled"); + PrintAndLog(" Pigeon: %u | Pigeon Mode is %s\n", pigeon, pigeon ? "Enabled" : "Disabled"); } void printEM4x05info(uint8_t chipType, uint8_t cap, uint16_t custCode, uint32_t serial) { @@ -1101,6 +1283,7 @@ int CmdEM4x05info(const char *Cmd) { wordData = 0; if ( EM4x05ReadWord_ext(4, pwd, usePwd, &wordData) != 1 ) { //failed + PrintAndLog("Config block read failed - might be password protected."); return 0; } printEM4x05config(wordData); @@ -1134,6 +1317,7 @@ static command_t CommandTable[] = {"410xread", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"}, {"410xdemod", CmdAskEM410xDemod, 1, "[clock] [invert<0|1>] [maxErr] -- Demodulate an EM410x tag from GraphBuffer (args optional)"}, {"410xsim", CmdEM410xSim, 0, " [clock rate] -- Simulate EM410x tag"}, + {"410xbrute", CmdEM410xBrute, 0, "ids.txt [clock rate] -- Bruteforcing by simulating EM410x tags (1 UID/s)"}, {"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, {"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, {"410xwrite", CmdEM410xWrite, 0, " <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},