X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/15db5fb71a07c6f7431ebdaff78f53df3c4fe022..8172fb35dd18116560c903b14c432394b1cdd06b:/winsrc/command.cpp diff --git a/winsrc/command.cpp b/winsrc/command.cpp index 0397ea37..b5d3e3d7 100644 --- a/winsrc/command.cpp +++ b/winsrc/command.cpp @@ -52,6 +52,13 @@ static void CmdReset(char *str) SendCommand(&c, FALSE); } +static void CmdBuffClear(char *str) +{ + UsbCommand c; + c.cmd = CMD_BUFF_CLEAR; + SendCommand(&c, FALSE); + CmdClearGraph(TRUE); +} static void CmdQuit(char *str) { @@ -249,6 +256,148 @@ static void CmdEM410xwatch(char *str) } while (go); } +/* Read the transmitted data of an EM4x50 tag + * 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 + * CCCCCCCC <- 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. + */ +static void CmdEM4x50read(char *str) +{ + int i, j, startblock, clock, skip, block, start, end, low, high; + BOOL complete= FALSE; + int tmpbuff[MAX_GRAPH_TRACE_LEN / 64]; + char tmp[6]; + + high= low= 0; + clock= 64; + + /* first get high and low values */ + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + + /* populate a buffer with pulse lengths */ + i= 0; + j= 0; + while(i < GraphTraceLen) + { + // measure from low to low + while(GraphBuffer[i] > low) + ++i; + start= i; + while(GraphBuffer[i] < high) + ++i; + while(GraphBuffer[i] > low) + ++i; + tmpbuff[j++]= i - start; + } + + + /* look for data start - should be 2 pairs of LW (pulses of 192,128) */ + start= -1; + skip= 0; + for (i= 0; i < j - 4 ; ++i) + { + skip += tmpbuff[i]; + if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194) + if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130) + if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194) + if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130) + { + start= i + 3; + break; + } + } + startblock= i + 3; + + /* skip over the remainder of the LW */ + skip += tmpbuff[i+1]+tmpbuff[i+2]; + while(GraphBuffer[skip] > low) + ++skip; + skip += 8; + + /* now do it again to find the end */ + end= start; + for (i += 3; i < j - 4 ; ++i) + { + end += tmpbuff[i]; + if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194) + if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130) + if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194) + if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130) + { + complete= TRUE; + break; + } + } + + if (start >= 0) + PrintToScrollback("Found data at sample: %i",skip); + else + { + PrintToScrollback("No data found!"); + PrintToScrollback("Try again with more samples."); + return; + } + + if (!complete) + { + PrintToScrollback("*** Warning!"); + PrintToScrollback("Partial data - no end found!"); + PrintToScrollback("Try again with more samples."); + } + + /* get rid of leading crap */ + sprintf(tmp,"%i",skip); + CmdLtrim(tmp); + + /* now work through remaining buffer printing out data blocks */ + block= 0; + i= startblock; + while(block < 6) + { + PrintToScrollback("Block %i:", block); + // mandemod routine needs to be split so we can call it for data + // just print for now for debugging + Cmdmanchesterdemod("i 64"); + skip= 0; + /* look for LW before start of next block */ + for ( ; i < j - 4 ; ++i) + { + skip += tmpbuff[i]; + if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194) + if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130) + break; + } + while(GraphBuffer[skip] > low) + ++skip; + skip += 8; + sprintf(tmp,"%i",skip); + CmdLtrim(tmp); + start += skip; + block++; + } +} + + /* Read the ID of an EM410x tag. * Format: * 1111 1111 1 <-- standard non-repeatable header @@ -262,6 +411,7 @@ static void CmdEM410xread(char *str) int i, j, clock, header, rows, bit, hithigh, hitlow, first, bit2idx, high, low; int parity[4]; char id[11]; + int retested = 0; int BitStream[MAX_GRAPH_TRACE_LEN]; high = low = 0; @@ -307,14 +457,15 @@ static void CmdEM410xread(char *str) if (hithigh && hitlow) break; } - + /* If we didn't hit both high and low peaks, we had a bit transition */ if (!hithigh || !hitlow) bit ^= 1; - + BitStream[bit2idx++] = bit; } - + +retest: /* We go till 5 before the graph ends because we'll get that far below */ for (i = 1; i < bit2idx - 5; i++) { @@ -363,7 +514,7 @@ static void CmdEM410xread(char *str) /* Stop any loops */ go = 0; - break; + return; } /* Crap! Incorrect parity or no stop bit, start all over */ @@ -388,6 +539,16 @@ static void CmdEM410xread(char *str) header = 0; } } + + /* if we've already retested after flipping bits, return */ + if (retested++) + return; + + /* if this didn't work, try flipping bits */ + for (i = 0; i < bit2idx; i++) + BitStream[i] ^= 1; + + goto retest; } /* emulate an EM410X tag @@ -478,7 +639,6 @@ static void ChkBitstream(char *str) static void CmdLosim(char *str) { int i; - char *zero = "0"; /* convert to bitstream if necessary */ ChkBitstream(str); @@ -516,6 +676,37 @@ static void CmdLoread(char *str) SendCommand(&c, FALSE); } +static void CmdDetectReader(char *str) +{ + UsbCommand c; + // 'l' means LF - 125/134 kHz + if(*str == 'l') { + c.ext1 = 1; + } else if (*str == 'h') { + c.ext1 = 2; + } else if (*str != '\0') { + PrintToScrollback("use 'detectreader' or 'detectreader l' or 'detectreader h'"); + return; + } + c.cmd = CMD_LISTEN_READER_FIELD; + SendCommand(&c, FALSE); +} + +/* send a command before reading */ +static void CmdLoCommandRead(char *str) +{ + static char dummy[3]; + + dummy[0]= ' '; + + UsbCommand c; + c.cmd = CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K; + sscanf(str, "%i %i %i %s %s", &c.ext1, &c.ext2, &c.ext3, &c.d.asBytes,&dummy+1); + // in case they specified 'h' + strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy); + SendCommand(&c, FALSE); +} + static void CmdLosamples(char *str) { int cnt = 0; @@ -1835,8 +2026,7 @@ static void CmdFlexdemod(char *str) static void Cmdaskdemod(char *str) { int i; - int n = 0; - int c,high,low = 0; + int c, high = 0, low = 0; // TODO: complain if we do not give 2 arguments here ! sscanf(str, "%i", &c); @@ -1862,7 +2052,7 @@ static void Cmdaskdemod(char *str) { * - we're high: transition if we hit a low * (we need to do it this way because some tags keep high or * low for long periods, others just reach the peak and go - * down) + * down) */ if ((GraphBuffer[i]==high) && (GraphBuffer[i-1] == c)) { GraphBuffer[i]=1-c; @@ -2046,7 +2236,7 @@ static void Cmdmanchestermod(char *str) * Typical values can be 64, 32, 128... */ static void Cmdmanchesterdemod(char *str) { - int i, j; + int i, j, invert= 0; int bit; int clock; int lastval; @@ -2058,6 +2248,16 @@ static void Cmdmanchesterdemod(char *str) { int bit2idx = 0; int warnings = 0; + /* check if we're inverting output */ + if(*str == 'i') + { + PrintToScrollback("Inverting output"); + invert= 1; + do + ++str; + while(*str == ' '); // in case a 2nd argument was given + } + /* Holds the decoded bitstream: each clock period contains 2 bits */ /* later simplified to 1 bit after manchester decoding. */ /* Add 10 bits to allow for noisy / uncertain traces without aborting */ @@ -2128,7 +2328,7 @@ static void Cmdmanchesterdemod(char *str) { if (!hithigh || !hitlow) bit ^= 1; - BitStream[bit2idx++] = bit; + BitStream[bit2idx++] = bit ^ invert; } } @@ -2136,7 +2336,7 @@ static void Cmdmanchesterdemod(char *str) { else { - /* Then detect duration between 2 successive transitions */ + /* Then detect duration between 2 successive transitions */ for (bitidx = 1; i < GraphTraceLen; i++) { if (GraphBuffer[i-1] != GraphBuffer[i]) @@ -2171,18 +2371,18 @@ static void Cmdmanchesterdemod(char *str) { PrintToScrollback("Error: too many detection errors, aborting."); return; } + } } } - } - // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream - // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful - // to stop output at the final bitidx2 value, not bitidx - for (i = 0; i < bitidx; i += 2) { - if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) { - BitStream[bit2idx++] = 1; + // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream + // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful + // to stop output at the final bitidx2 value, not bitidx + for (i = 0; i < bitidx; i += 2) { + if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) { + BitStream[bit2idx++] = 1 ^ invert; } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) { - BitStream[bit2idx++] = 0; + BitStream[bit2idx++] = 0 ^ invert; } else { // We cannot end up in this state, this means we are unsynchronized, // move up 1 bit: @@ -2196,8 +2396,8 @@ static void Cmdmanchesterdemod(char *str) { PrintToScrollback("Error: too many decode errors, aborting."); return; } - } - } + } + } } PrintToScrollback("Manchester decoded bitstream"); @@ -2384,11 +2584,14 @@ static struct { "autocorr", CmdAutoCorr,1, " -- Autocorrelation over window", "bitsamples", CmdBitsamples,0, " Get raw samples as bitstring", "bitstream", Cmdbitstream,1, "[clock rate] -- Convert waveform into a bitstream", + "buffclear", CmdBuffClear,0, " Clear sample buffer and graph window", "dec", CmdDec,1, " Decimate samples", "detectclock", Cmddetectclockrate,1, " Detect clock rate", + "detectreader", CmdDetectReader,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)", "em410xsim", CmdEM410xsim,1, " -- Simulate EM410x tag", "em410xread", CmdEM410xread,1, "[clock rate] -- Extract ID from EM410x tag", "em410xwatch", CmdEM410xwatch,0, " Watches for EM410x tags", + "em4x50read", CmdEM4x50read,1, " Extract data from EM4x50 tag", "exit", CmdQuit,1, " Exit program", "flexdemod", CmdFlexdemod,1, " Demodulate samples for FlexPass", "fpgaoff", CmdFPGAOff,0, " Set FPGA off", // ## FPGA Control @@ -2416,15 +2619,16 @@ static struct { "hisamplest", CmdHi14readt,0, " Get samples HF, for testing", "hisimlisten", CmdHisimlisten,0, " Get HF samples as fake tag", "hpf", CmdHpf,1, " Remove DC offset from trace", - "indalademod", CmdIndalademod,0, "['224'] -- Demodulate samples for Indala", + "indalademod", CmdIndalademod,0, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)", "lcd", CmdLcd,0, " -- Send command/data to LCD", "lcdreset", CmdLcdReset,0, " Hardware reset LCD", "load", CmdLoad,1, " -- Load trace (to graph window", + "locomread", CmdLoCommandRead,0, " <'0' period> <'1' period> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)", "loread", CmdLoread,0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)", "losamples", CmdLosamples,0, "[128 - 16000] -- Get raw samples for LF tag", "losim", CmdLosim,0, " Simulate LF tag", "ltrim", CmdLtrim,1, " -- Trim samples from left of trace", - "mandemod", Cmdmanchesterdemod,1, "[clock rate] -- Try a Manchester demodulation on a binary stream", + "mandemod", Cmdmanchesterdemod,1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)", "manmod", Cmdmanchestermod,1, "[clock rate] -- Manchester modulate a binary stream", "norm", CmdNorm,1, " Normalize max/min to +/-500", "plot", CmdPlot,1, " Show graph window",