X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/30f2a7d38fd35b2427a7eb42e1cd75fb1105f927..8172fb35dd18116560c903b14c432394b1cdd06b:/winsrc/command.cpp diff --git a/winsrc/command.cpp b/winsrc/command.cpp index f947f45c..b5d3e3d7 100644 --- a/winsrc/command.cpp +++ b/winsrc/command.cpp @@ -14,7 +14,10 @@ #include "../common/iso14443_crc.c" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) +#define BIT(x) GraphBuffer[x * clock] +#define BITS (GraphTraceLen / clock) +int go = 0; static int CmdHisamplest(char *str, int nrlow); static void GetFromBigBuf(BYTE *dest, int bytes) @@ -34,7 +37,7 @@ static void GetFromBigBuf(BYTE *dest, int bytes) SendCommand(&c, FALSE); ReceiveCommand(&c); if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { - PrintToScrollback("bad resp\n"); + PrintToScrollback("bad resp"); return; } @@ -42,6 +45,21 @@ static void GetFromBigBuf(BYTE *dest, int bytes) } } +static void CmdReset(char *str) +{ + UsbCommand c; + c.cmd = CMD_HARDWARE_RESET; + 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) { exit(0); @@ -76,6 +94,19 @@ static void CmdHi14read(char *str) SendCommand(&c, FALSE); } + +/* New command to read the contents of a SRI512 tag + * SRI512 tags are ISO14443-B modulated memory tags, + * this command just dumps the contents of the memory/ + */ +static void CmdSri512read(char *str) +{ + UsbCommand c; + c.cmd = CMD_READ_SRI512_TAG; + c.ext1 = atoi(str); + SendCommand(&c, FALSE); +} + // ## New command static void CmdHi14areader(char *str) { @@ -140,8 +171,6 @@ static void CmdHi14sim(char *str) c.cmd = CMD_SIMULATE_TAG_ISO_14443; SendCommand(&c, FALSE); } - - static void CmdHi14asim(char *str) // ## simulate iso14443a tag { // ## greg - added ability to specify tag UID @@ -184,11 +213,437 @@ static void CmdFPGAOff(char *str) // ## FPGA Control SendCommand(&c, FALSE); } +/* clear out our graph window */ +int CmdClearGraph(int redraw) +{ + int gtl = GraphTraceLen; + GraphTraceLen = 0; + + if (redraw) + RepaintGraphWindow(); + + return gtl; +} + +/* write a bit to the graph */ +static void CmdAppendGraph(int redraw, int clock, int bit) +{ + int i; + + for (i = 0; i < (int)(clock/2); i++) + GraphBuffer[GraphTraceLen++] = bit ^ 1; + + for (i = (int)(clock/2); i < clock; i++) + GraphBuffer[GraphTraceLen++] = bit; + + if (redraw) + RepaintGraphWindow(); +} + +/* Function is equivalent of loread + losamples + em410xread + * looped until an EM410x tag is detected */ +static void CmdEM410xwatch(char *str) +{ + char *zero = ""; + char *twok = "2000"; + go = 1; + + do + { + CmdLoread(zero); + CmdLosamples(twok); + CmdEM410xread(zero); + } 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 + * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID + * .... + * CCCC <-- each bit here is parity for the 10 bits above in corresponding column + * 0 <-- stop bit, end of tag + */ +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; + + /* Detect high and lows and clock */ + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + + /* get clock */ + clock = GetClock(str, high); + + /* parity for our 4 columns */ + parity[0] = parity[1] = parity[2] = parity[3] = 0; + header = rows = 0; + + /* manchester demodulate */ + bit = bit2idx = 0; + for (i = 0; i < (int)(GraphTraceLen / clock); i++) + { + hithigh = 0; + hitlow = 0; + first = 1; + + /* Find out if we hit both high and low peaks */ + for (j = 0; j < clock; j++) + { + if (GraphBuffer[(i * clock) + j] == high) + hithigh = 1; + else if (GraphBuffer[(i * clock) + j] == low) + hitlow = 1; + + /* it doesn't count if it's the first part of our read + because it's really just trailing from the last sequence */ + if (first && (hithigh || hitlow)) + hithigh = hitlow = 0; + else + first = 0; + + 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++) + { + /* Step 2: We have our header but need our tag ID */ + if (header == 9 && rows < 10) + { + /* Confirm parity is correct */ + if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4]) + { + /* Read another byte! */ + sprintf(id+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3])); + rows++; + + /* Keep parity info */ + parity[0] ^= BitStream[i]; + parity[1] ^= BitStream[i+1]; + parity[2] ^= BitStream[i+2]; + parity[3] ^= BitStream[i+3]; + + /* Move 4 bits ahead */ + i += 4; + } + + /* Damn, something wrong! reset */ + else + { + PrintToScrollback("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i); + + /* Start back rows * 5 + 9 header bits, -1 to not start at same place */ + i -= 9 + (5 * rows) - 5; + + rows = header = 0; + } + } + + /* Step 3: Got our 40 bits! confirm column parity */ + else if (rows == 10) + { + /* We need to make sure our 4 bits of parity are correct and we have a stop bit */ + if (BitStream[i] == parity[0] && BitStream[i+1] == parity[1] && + BitStream[i+2] == parity[2] && BitStream[i+3] == parity[3] && + BitStream[i+4] == 0) + { + /* Sweet! */ + PrintToScrollback("EM410x Tag ID: %s", id); + + /* Stop any loops */ + go = 0; + return; + } + + /* Crap! Incorrect parity or no stop bit, start all over */ + else + { + rows = header = 0; + + /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */ + i -= 59; + } + } + + /* Step 1: get our header */ + else if (header < 9) + { + /* Need 9 consecutive 1's */ + if (BitStream[i] == 1) + header++; + + /* We don't have a header, not enough consecutive 1 bits */ + else + 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 + * Format: + * 1111 1111 1 <-- standard non-repeatable header + * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID + * .... + * CCCC <-- each bit here is parity for the 10 bits above in corresponding column + * 0 <-- stop bit, end of tag + */ +static void CmdEM410xsim(char *str) +{ + int i, n, j, h, binary[4], parity[4]; + char *s = "0"; + + /* clock is 64 in EM410x tags */ + int clock = 64; + + /* clear our graph */ + CmdClearGraph(0); + + /* write it out a few times */ + for (h = 0; h < 4; h++) + { + /* write 9 start bits */ + for (i = 0; i < 9; i++) + CmdAppendGraph(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(&str[i], "%1x", &n); + for (j = 3; j >= 0; j--, n/= 2) + binary[j] = n % 2; + + /* append each bit */ + CmdAppendGraph(0, clock, binary[0]); + CmdAppendGraph(0, clock, binary[1]); + CmdAppendGraph(0, clock, binary[2]); + CmdAppendGraph(0, clock, binary[3]); + + /* append parity bit */ + CmdAppendGraph(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 */ + CmdAppendGraph(0, clock, parity[0]); + CmdAppendGraph(0, clock, parity[1]); + CmdAppendGraph(0, clock, parity[2]); + CmdAppendGraph(0, clock, parity[3]); + + /* stop bit */ + CmdAppendGraph(0, clock, 0); + } + + /* modulate that biatch */ + Cmdmanchestermod(s); + + /* booyah! */ + RepaintGraphWindow(); + + CmdLosim(s); +} + +static void ChkBitstream(char *str) +{ + int i; + + /* convert to bitstream if necessary */ + for (i = 0; i < (int)(GraphTraceLen / 2); i++) + { + if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) + { + Cmdbitstream(str); + break; + } + } +} + static void CmdLosim(char *str) { int i; - for(i = 0; i < GraphTraceLen; i += 48) { + /* convert to bitstream if necessary */ + ChkBitstream(str); + + for (i = 0; i < GraphTraceLen; i += 48) { UsbCommand c; int j; for(j = 0; j < 48; j++) { @@ -221,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; @@ -238,7 +724,8 @@ static void CmdLosamples(char *str) SendCommand(&c, FALSE); ReceiveCommand(&c); if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { - PrintToScrollback("bad resp\n"); + if (!go) + PrintToScrollback("bad resp"); return; } int j; @@ -264,7 +751,7 @@ static void CmdBitsamples(char *str) SendCommand(&c, FALSE); ReceiveCommand(&c); if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { - PrintToScrollback("bad resp\n"); + PrintToScrollback("bad resp"); return; } int j, k; @@ -295,7 +782,7 @@ static void CmdHisamples(char *str) SendCommand(&c, FALSE); ReceiveCommand(&c); if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { - PrintToScrollback("bad resp\n"); + PrintToScrollback("bad resp"); return; } int j; @@ -328,7 +815,7 @@ static int CmdHisamplest(char *str, int nrlow) SendCommand(&c, FALSE); ReceiveCommand(&c); if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { - PrintToScrollback("bad resp\n"); + PrintToScrollback("bad resp"); return 0; } int j; @@ -397,7 +884,7 @@ static void CmdHexsamples(char *str) SendCommand(&c, FALSE); ReceiveCommand(&c); if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { - PrintToScrollback("bad resp\n"); + PrintToScrollback("bad resp"); return; } int j; @@ -436,7 +923,7 @@ static void CmdHisampless(char *str) SendCommand(&c, FALSE); ReceiveCommand(&c); if(c.cmd != CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { - PrintToScrollback("bad resp\n"); + PrintToScrollback("bad resp"); return; } int j; @@ -792,7 +1279,7 @@ static void CmdHi15demod(char *str) { // The sampling rate is 106.353 ksps/s, for T = 18.8 us - // SOF defined as + // SOF defined as // 1) Unmodulated time of 56.64us // 2) 24 pulses of 423.75khz // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz) @@ -820,7 +1307,7 @@ static void CmdHi15demod(char *str) 1, 1, 1, 1 }; - // EOF defined as + // EOF defined as // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us) // 2) 24 pulses of 423.75khz // 3) Unmodulated time of 56.64us @@ -926,7 +1413,7 @@ static void CmdTibits(char *str) SendCommand(&c, FALSE); ReceiveCommand(&c); if(c.cmd != CMD_DOWNLOADED_RAW_BITS_TI_TYPE) { - PrintToScrollback("bad resp\n"); + PrintToScrollback("bad resp"); return; } int j; @@ -1524,185 +2011,422 @@ static void CmdFlexdemod(char *str) RepaintGraphWindow(); } - -/* - * Generic command to demodulate ASK. bit length in argument. - * Giving the bit length helps discriminate ripple effects - * upon zero crossing for noisy traces. - * - * Second is convention: positive or negative (High mod means zero - * or high mod means one) - * - * Updates the Graph trace with 0/1 values - * - * Arguments: - * sl : bit length in terms of number of samples per bit - * (use yellow/purple markers to compute). - * c : 0 or 1 - */ - -static void Cmdaskdemod(char *str) { - int i; - int sign = 1; - int n = 0; - int c = 0; - int t1 = 0; - - // TODO: complain if we do not give 2 arguments here ! - sscanf(str, "%i %i", &n, &c); - if (c == 0) { - c = 1 ; - } else { - c = -1; - } - - if (GraphBuffer[0]*c > 0) { - GraphBuffer[0] = 1; - } else { - GraphBuffer[0] = 0; - } - for(i=1;i n/4 ) { - sign = -sign; - t1=i; - if (GraphBuffer[i]*c > 0){ - GraphBuffer[i]=1; - } else { - GraphBuffer[i]=0; - } - } else { - /* This is a ripple, set the current sample value - to the same as previous */ - GraphBuffer[i] = GraphBuffer[i-1]; - } - } else { - GraphBuffer[i] = GraphBuffer[i-1]; - } - } - RepaintGraphWindow(); -} - - -/* - * Manchester demodulate a bitstream. The bitstream needs to be already in - * the GraphBuffer as 0 and 1 values - * - * Give the clock rate as argument in order to help the sync - the algorithm - * resyncs at each pulse anyway. - * - * Not optimized by any means, this is the 1st time I'm writing this type of - * routine, feel free to improve... - * - * 1st argument: clock rate (as number of samples per clock rate) - * Typical values can be 64, 32, 128... - */ -static void Cmdmanchesterdemod(char *str) { - int i; - int clock; - int lastval; - int lc = 0; - int bitidx = 0; - int bit2idx = 0; - - - sscanf(str, "%i", &clock); - - int tolerance = clock/4; - /* 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 */ - /* int BitStream[GraphTraceLen*2/clock+10]; */ - - /* But it does not work if compiling on WIndows: therefore we just allocate a */ - /* large array */ - int BitStream[MAX_GRAPH_TRACE_LEN]; - - /* Detect first transition */ - /* Lo-Hi (arbitrary) */ - for(i=1;i (GraphTraceLen*2/clock+8) ) { - PrintToScrollback("Error: the clock you gave is probably wrong, aborting."); - return; - } - // Then switch depending on lc length: - // Tolerance is 1/4 of clock rate (arbitrary) - if (abs(lc-clock/2) < tolerance) { - // Short pulse : either "1" or "0" - BitStream[bitidx++]=GraphBuffer[i-1]; - } else if (abs(lc-clock) < tolerance) { - // Long pulse: either "11" or "00" - BitStream[bitidx++]=GraphBuffer[i-1]; - BitStream[bitidx++]=GraphBuffer[i-1]; - } else { - // Error - PrintToScrollback("Warning: Manchester decode error for pulse width detection."); - PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)"); - } - } - } - - // 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; - } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) { - BitStream[bit2idx++] = 0; - } else { - // We cannot end up in this state, this means we are unsynchronized, - // move up 1 bit: - i++; - PrintToScrollback("Unsynchronized, resync..."); - PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)"); - } - } - PrintToScrollback("Manchester decoded bitstream \n---------"); - // Now output the bitstream to the scrollback by line of 16 bits - for (i = 0; i < (bit2idx-16); i+=16) { - PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", - BitStream[i], - BitStream[i+1], - BitStream[i+2], - BitStream[i+3], - BitStream[i+4], - BitStream[i+5], - BitStream[i+6], - BitStream[i+7], - BitStream[i+8], - BitStream[i+9], - BitStream[i+10], - BitStream[i+11], - BitStream[i+12], - BitStream[i+13], - BitStream[i+14], - BitStream[i+15]); - } -} - - - -/* - * Usage ??? + +/* + * Generic command to demodulate ASK. + * + * Argument is convention: positive or negative (High mod means zero + * or high mod means one) + * + * Updates the Graph trace with 0/1 values + * + * Arguments: + * c : 0 or 1 + */ + +static void Cmdaskdemod(char *str) { + int i; + int c, high = 0, low = 0; + + // TODO: complain if we do not give 2 arguments here ! + sscanf(str, "%i", &c); + + /* Detect high and lows and clock */ + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + + if (GraphBuffer[0] > 0) { + GraphBuffer[0] = 1-c; + } else { + GraphBuffer[0] = c; + } + for(i=1;i peak) + peak = GraphBuffer[i]; + + for (i = 1; i < GraphTraceLen; i++) + { + /* If this is the beginning of a peak */ + if (GraphBuffer[i-1] != GraphBuffer[i] && GraphBuffer[i] == peak) + { + /* Find lowest difference between peaks */ + if (lastpeak && i - lastpeak < clock) + { + clock = i - lastpeak; + } + lastpeak = i; + } + } + + return clock; +} + +/* Get or auto-detect clock rate */ +int GetClock(char *str, int peak) +{ + int clock; + + sscanf(str, "%i", &clock); + if (!strcmp(str, "")) + clock = 0; + + /* Auto-detect clock */ + if (!clock) + { + clock = detectclock(peak); + + /* Only print this message if we're not looping something */ + if (!go) + PrintToScrollback("Auto-detected clock rate: %d", clock); + } + + return clock; +} + +/* + * Convert to a bitstream + */ +static void Cmdbitstream(char *str) { + int i, j; + int bit; + int gtl; + int clock; + int low = 0; + int high = 0; + int hithigh, hitlow, first; + + /* Detect high and lows and clock */ + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + + /* Get our clock */ + clock = GetClock(str, high); + + gtl = CmdClearGraph(0); + + bit = 0; + for (i = 0; i < (int)(gtl / clock); i++) + { + hithigh = 0; + hitlow = 0; + first = 1; + + /* Find out if we hit both high and low peaks */ + for (j = 0; j < clock; j++) + { + if (GraphBuffer[(i * clock) + j] == high) + hithigh = 1; + else if (GraphBuffer[(i * clock) + j] == low) + hitlow = 1; + + /* it doesn't count if it's the first part of our read + because it's really just trailing from the last sequence */ + if (first && (hithigh || hitlow)) + hithigh = hitlow = 0; + else + first = 0; + + if (hithigh && hitlow) + break; + } + + /* If we didn't hit both high and low peaks, we had a bit transition */ + if (!hithigh || !hitlow) + bit ^= 1; + + CmdAppendGraph(0, clock, bit); +// for (j = 0; j < (int)(clock/2); j++) +// GraphBuffer[(i * clock) + j] = bit ^ 1; +// for (j = (int)(clock/2); j < clock; j++) +// GraphBuffer[(i * clock) + j] = bit; + } + + RepaintGraphWindow(); +} + +/* Modulate our data into manchester */ +static void Cmdmanchestermod(char *str) +{ + int i, j; + int clock; + int bit, lastbit, wave; + + /* Get our clock */ + clock = GetClock(str, 0); + + wave = 0; + lastbit = 1; + for (i = 0; i < (int)(GraphTraceLen / clock); i++) + { + bit = GraphBuffer[i * clock] ^ 1; + + for (j = 0; j < (int)(clock/2); j++) + GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave; + for (j = (int)(clock/2); j < clock; j++) + GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1; + + /* Keep track of how we start our wave and if we changed or not this time */ + wave ^= bit ^ lastbit; + lastbit = bit; + } + + RepaintGraphWindow(); +} + +/* + * Manchester demodulate a bitstream. The bitstream needs to be already in + * the GraphBuffer as 0 and 1 values + * + * Give the clock rate as argument in order to help the sync - the algorithm + * resyncs at each pulse anyway. + * + * Not optimized by any means, this is the 1st time I'm writing this type of + * routine, feel free to improve... + * + * 1st argument: clock rate (as number of samples per clock rate) + * Typical values can be 64, 32, 128... + */ +static void Cmdmanchesterdemod(char *str) { + int i, j, invert= 0; + int bit; + int clock; + int lastval; + int low = 0; + int high = 0; + int hithigh, hitlow, first; + int lc = 0; + int bitidx = 0; + 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 */ + /* int BitStream[GraphTraceLen*2/clock+10]; */ + + /* But it does not work if compiling on WIndows: therefore we just allocate a */ + /* large array */ + int BitStream[MAX_GRAPH_TRACE_LEN]; + + /* Detect high and lows */ + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + + /* Get our clock */ + clock = GetClock(str, high); + + int tolerance = clock/4; + + /* Detect first transition */ + /* Lo-Hi (arbitrary) */ + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] == low) + { + lastval = i; + break; + } + } + + /* If we're not working with 1/0s, demod based off clock */ + if (high != 1) + { + bit = 0; /* We assume the 1st bit is zero, it may not be + * the case: this routine (I think) has an init problem. + * Ed. + */ + for (; i < (int)(GraphTraceLen / clock); i++) + { + hithigh = 0; + hitlow = 0; + first = 1; + + /* Find out if we hit both high and low peaks */ + for (j = 0; j < clock; j++) + { + if (GraphBuffer[(i * clock) + j] == high) + hithigh = 1; + else if (GraphBuffer[(i * clock) + j] == low) + hitlow = 1; + + /* it doesn't count if it's the first part of our read + because it's really just trailing from the last sequence */ + if (first && (hithigh || hitlow)) + hithigh = hitlow = 0; + else + first = 0; + + 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 ^ invert; + } + } + + /* standard 1/0 bitstream */ + else + { + + /* Then detect duration between 2 successive transitions */ + for (bitidx = 1; i < GraphTraceLen; i++) + { + if (GraphBuffer[i-1] != GraphBuffer[i]) + { + lc = i-lastval; + lastval = i; + + // Error check: if bitidx becomes too large, we do not + // have a Manchester encoded bitstream or the clock is really + // wrong! + if (bitidx > (GraphTraceLen*2/clock+8) ) { + PrintToScrollback("Error: the clock you gave is probably wrong, aborting."); + return; + } + // Then switch depending on lc length: + // Tolerance is 1/4 of clock rate (arbitrary) + if (abs(lc-clock/2) < tolerance) { + // Short pulse : either "1" or "0" + BitStream[bitidx++]=GraphBuffer[i-1]; + } else if (abs(lc-clock) < tolerance) { + // Long pulse: either "11" or "00" + BitStream[bitidx++]=GraphBuffer[i-1]; + BitStream[bitidx++]=GraphBuffer[i-1]; + } else { + // Error + warnings++; + PrintToScrollback("Warning: Manchester decode error for pulse width detection."); + PrintToScrollback("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)"); + + if (warnings > 100) + { + 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 ^ invert; + } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) { + BitStream[bit2idx++] = 0 ^ invert; + } else { + // We cannot end up in this state, this means we are unsynchronized, + // move up 1 bit: + i++; + warnings++; + PrintToScrollback("Unsynchronized, resync..."); + PrintToScrollback("(too many of those messages mean the stream is not Manchester encoded)"); + + if (warnings > 100) + { + PrintToScrollback("Error: too many decode errors, aborting."); + return; + } + } + } + } + + PrintToScrollback("Manchester decoded bitstream"); + // Now output the bitstream to the scrollback by line of 16 bits + for (i = 0; i < (bit2idx-16); i+=16) { + PrintToScrollback("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", + BitStream[i], + BitStream[i+1], + BitStream[i+2], + BitStream[i+3], + BitStream[i+4], + BitStream[i+5], + BitStream[i+6], + BitStream[i+7], + BitStream[i+8], + BitStream[i+9], + BitStream[i+10], + BitStream[i+11], + BitStream[i+12], + BitStream[i+13], + BitStream[i+14], + BitStream[i+15]); + } +} + + + +/* + * Usage ??? */ static void CmdHiddemod(char *str) { @@ -1816,14 +2540,16 @@ static void CmdLcd(char *str) } } + + static void CmdTest(char *str) { } - -/* - * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below - * 600kHz. - */ + +/* + * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below + * 600kHz. + */ static void CmdSetDivisor(char *str) { UsbCommand c; @@ -1843,71 +2569,85 @@ static void CmdSweepLF(char *str) c.cmd = CMD_SWEEP_LF; SendCommand(&c, FALSE); } - - + typedef void HandlerFunction(char *cmdline); +/* in alphabetic order */ static struct { - char *name; - HandlerFunction *handler; - char *docString; + char *name; + HandlerFunction *handler; + int offline; // 1 if the command can be used when in offline mode + char *docString; } CommandTable[] = { - "tune", CmdTune, "measure antenna tuning", - "tiread", CmdTiread, "read a TI-type 134 kHz tag", - "tibits", CmdTibits, "get raw bits for TI-type LF tag", - "tidemod", CmdTidemod, "demod raw bits for TI-type LF tag", - "vchdemod", CmdVchdemod, "demod samples for VeriChip", - "plot", CmdPlot, "show graph window", - "hide", CmdHide, "hide graph window", - "losim", CmdLosim, "simulate LF tag", - "loread", CmdLoread, "read (125/134 kHz) LF ID-only tag", - "losamples", CmdLosamples, "get raw samples for LF tag", - "hisamples", CmdHisamples, "get raw samples for HF tag", - "hisampless", CmdHisampless, "get signed raw samples, HF tag", - "hisamplest", CmdHi14readt, "get samples HF, for testing", - "higet", CmdHi14read_sim, "get samples HF, 'analog'", - "bitsamples", CmdBitsamples, "get raw samples as bitstring", - "hexsamples", CmdHexsamples, "dump big buffer as hex bytes", - "hi15read", CmdHi15read, "read HF tag (ISO 15693)", - "hi15reader", CmdHi15reader, "act like an ISO15693 reader", // new command greg - "hi15sim", CmdHi15tag, "fake an ISO15693 tag", // new command greg - "hi14read", CmdHi14read, "read HF tag (ISO 14443)", - "hi14areader", CmdHi14areader, "act like an ISO14443 Type A reader", // ## New reader command - "hi15demod", CmdHi15demod, "demod ISO15693 from tag", - "hi14bdemod", CmdHi14bdemod, "demod ISO14443 Type B from tag", - "autocorr", CmdAutoCorr, "autocorrelation over window", - "norm", CmdNorm, "normalize max/min to +/-500", - "dec", CmdDec, "decimate", - "hpf", CmdHpf, "remove DC offset from trace", - "zerocrossings", CmdZerocrossings, "count time between zero-crossings", - "ltrim", CmdLtrim, "trim from left of trace", - "scale", CmdScale, "set cursor display scale", - "flexdemod", CmdFlexdemod, "demod samples for FlexPass", - "indalademod", CmdIndalademod, "demod samples for Indala", - "save", CmdSave, "save trace (from graph window)", - "load", CmdLoad, "load trace (to graph window", - "hisimlisten", CmdHisimlisten, "get HF samples as fake tag", - "hi14sim", CmdHi14sim, "fake ISO 14443 tag", - "hi14asim", CmdHi14asim, "fake ISO 14443a tag", // ## Simulate 14443a tag - "hi14snoop", CmdHi14snoop, "eavesdrop ISO 14443", - "hi14asnoop", CmdHi14asnoop, "eavesdrop ISO 14443 Type A", // ## New snoop command - "hi14list", CmdHi14list, "list ISO 14443 history", - "hi14alist", CmdHi14alist, "list ISO 14443a history", // ## New list command - "hiddemod", CmdHiddemod, "HID Prox Card II (not optimal)", - "hidfskdemod", CmdHIDdemodFSK, "HID FSK demodulator", - "askdemod", Cmdaskdemod, "Attempt to demodulate simple ASK tags", - "hidsimtag", CmdHIDsimTAG, "HID tag simulator", - "mandemod", Cmdmanchesterdemod, "Try a Manchester demodulation on a binary stream", - "fpgaoff", CmdFPGAOff, "set FPGA off", // ## FPGA Control - "lcdreset", CmdLcdReset, "Hardware reset LCD", - "lcd", CmdLcd, "Send command/data to LCD", - "test", CmdTest, "Placeholder command for testing new code", - "setlfdivisor", CmdSetDivisor, "Drive LF antenna at 12Mhz/(divisor+1)", - "sweeplf", CmdSweepLF, "Sweep through LF freq range and store results in buffer", - "quit", CmdQuit, "quit program" + "askdemod", Cmdaskdemod,1, " <0|1> -- Attempt to demodulate simple ASK tags", + "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 + "hexsamples", CmdHexsamples,0, " -- Dump big buffer as hex bytes", + "hi14alist", CmdHi14alist,0, " List ISO 14443a history", // ## New list command + "hi14areader", CmdHi14areader,0, " Act like an ISO14443 Type A reader", // ## New reader command + "hi14asim", CmdHi14asim,0, " -- Fake ISO 14443a tag", // ## Simulate 14443a tag + "hi14asnoop", CmdHi14asnoop,0, " Eavesdrop ISO 14443 Type A", // ## New snoop command + "hi14bdemod", CmdHi14bdemod,1, " Demodulate ISO14443 Type B from tag", + "hi14list", CmdHi14list,0, " List ISO 14443 history", + "hi14read", CmdHi14read,0, " Read HF tag (ISO 14443)", + "hi14sim", CmdHi14sim,0, " Fake ISO 14443 tag", + "hi14snoop", CmdHi14snoop,0, " Eavesdrop ISO 14443", + "hi15demod", CmdHi15demod,1, " Demodulate ISO15693 from tag", + "hi15read", CmdHi15read,0, " Read HF tag (ISO 15693)", + "hi15reader", CmdHi15reader,0, " Act like an ISO15693 reader", // new command greg + "hi15sim", CmdHi15tag,0, " Fake an ISO15693 tag", // new command greg + "hiddemod", CmdHiddemod,1, " Demodulate HID Prox Card II (not optimal)", + "hide", CmdHide,1, " Hide graph window", + "hidfskdemod", CmdHIDdemodFSK,0, " Realtime HID FSK demodulator", + "hidsimtag", CmdHIDsimTAG,0, " -- HID tag simulator", + "higet", CmdHi14read_sim,0, " -- Get samples HF, 'analog'", + "hisamples", CmdHisamples,0, " Get raw samples for HF tag", + "hisampless", CmdHisampless,0, " -- Get signed raw samples, HF tag", + "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 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, "[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", + "quit", CmdQuit,1, " Quit program", + "reset", CmdReset,0, " Reset the Proxmark3", + "save", CmdSave,1, " -- Save trace (from graph window)", + "scale", CmdScale,1, " -- Set cursor display scale", + "setlfdivisor", CmdSetDivisor,0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)", + "sri512read", CmdSri512read,0, " -- Read contents of a SRI512 tag", + "sweeplf", CmdSweepLF,0, " Sweep through LF freq range and store results in buffer", + "tibits", CmdTibits,0, " Get raw bits for TI-type LF tag", + "tidemod", CmdTidemod,0, " Demodulate raw bits for TI-type LF tag", + "tiread", CmdTiread,0, " Read a TI-type 134 kHz tag", + "tune", CmdTune,0, " Measure antenna tuning", + "vchdemod", CmdVchdemod,0, "['clone'] -- Demodulate samples for VeriChip", + "zerocrossings", CmdZerocrossings,1, " Count time between zero-crossings", }; + //----------------------------------------------------------------------------- // Entry point into our code: called whenever the user types a command and // then presses Enter, which the full command line that they typed. @@ -1919,8 +2659,10 @@ void CommandReceived(char *cmd) PrintToScrollback("> %s", cmd); if(strcmp(cmd, "help")==0) { + if (offline) PrintToScrollback("Operating in OFFLINE mode (no device connected)"); PrintToScrollback("\r\nAvailable commands:"); for(i = 0; i < sizeof(CommandTable) / sizeof(CommandTable[0]); i++) { + if (offline && (CommandTable[i].offline==0)) continue; char line[256]; memset(line, ' ', sizeof(line)); strcpy(line+2, CommandTable[i].name); @@ -1942,6 +2684,10 @@ void CommandReceived(char *cmd) while(*cmd == ' ') { cmd++; } + if (offline && (CommandTable[i].offline==0)) { + PrintToScrollback("Offline mode, cannot use this command."); + return; + } (CommandTable[i].handler)(cmd); return; } @@ -1964,7 +2710,7 @@ void UsbCommandReceived(UsbCommand *c) memcpy(s, c->d.asBytes, c->ext1); s[c->ext1] = '\0'; PrintToScrollback("#db# %s", s); - break; + break; } case CMD_DEBUG_PRINT_INTEGERS: