]> git.zerfleddert.de Git - proxmark3-svn/blobdiff - client/cmdlfem4x.c
Add EM410x bruteforcing function by simulating EM410x tags (1 UID/s)
[proxmark3-svn] / client / cmdlfem4x.c
index 1dfab39430704b191e18aeca498097665a06357a..da6c30945da360c557cb194dc5f66e31348b503a 100644 (file)
@@ -22,6 +22,8 @@
 #include "cmdlf.h"
 #include "cmdmain.h"
 #include "lfdemod.h"
+#include "protocols.h"
+#include "util_posix.h"
 
 uint64_t g_em410xId=0;
 
@@ -145,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;
@@ -231,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 */
@@ -279,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 
  * 
@@ -297,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;
@@ -472,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)
@@ -571,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);
@@ -598,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
@@ -637,7 +753,7 @@ int EM4x50Read(const char *Cmd, bool verbose)
        }
 
        //restore GraphBuffer
-       save_restoreGB(0);
+       save_restoreGB(GRAPH_RESTORE);
        return (int)AllPTest;
 }
 
@@ -703,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;
@@ -899,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] <address> <data> <pwd>");
+       PrintAndLog("Usage:  lf em 4x05writeword [h] a <address> d <data> p <pwd> [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 <address> - memory address to write to. (0-15)");
+       PrintAndLog("       d <data>    - data to write (hex)");        
+       PrintAndLog("       p <pwd>     - 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);
        }
 
@@ -968,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));
@@ -980,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;
@@ -1009,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) {
@@ -1102,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);
@@ -1135,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, "<UID> [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, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
Impressum, Datenschutz