]> git.zerfleddert.de Git - proxmark3-svn/blobdiff - client/cmdlf.c
Client cleanup and restructuring. Stage 1...
[proxmark3-svn] / client / cmdlf.c
diff --git a/client/cmdlf.c b/client/cmdlf.c
new file mode 100644 (file)
index 0000000..e82e48a
--- /dev/null
@@ -0,0 +1,453 @@
+#include <stdio.h>
+#include <string.h>
+#include "proxusb.h"
+#include "data.h"
+#include "graph.h"
+#include "ui.h"
+#include "cmdparser.h"
+#include "cmddata.h"
+#include "cmdlf.h"
+#include "cmdlfhid.h"
+#include "cmdlfti.h"
+#include "cmdlfem4x.h"
+
+static int CmdHelp(const char *Cmd);
+
+/* send a command before reading */
+int CmdLFCommandRead(const char *Cmd)
+{
+  static char dummy[3];
+
+  dummy[0]= ' ';
+
+  UsbCommand c = {CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K};
+  sscanf(Cmd, "%i %i %i %s %s", &c.arg[0], &c.arg[1], &c.arg[2], (char *) &c.d.asBytes,(char *) &dummy+1);
+  // in case they specified 'h'
+  strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);
+  SendCommand(&c);
+  return 0;
+}
+
+int CmdFlexdemod(const char *Cmd)
+{
+  int i;
+  for (i = 0; i < GraphTraceLen; ++i) {
+    if (GraphBuffer[i] < 0) {
+      GraphBuffer[i] = -1;
+    } else {
+      GraphBuffer[i] = 1;
+    }
+  }
+
+#define LONG_WAIT 100
+  int start;
+  for (start = 0; start < GraphTraceLen - LONG_WAIT; start++) {
+    int first = GraphBuffer[start];
+    for (i = start; i < start + LONG_WAIT; i++) {
+      if (GraphBuffer[i] != first) {
+        break;
+      }
+    }
+    if (i == (start + LONG_WAIT)) {
+      break;
+    }
+  }
+  if (start == GraphTraceLen - LONG_WAIT) {
+    PrintAndLog("nothing to wait for");
+    return 0;
+  }
+
+  GraphBuffer[start] = 2;
+  GraphBuffer[start+1] = -2;
+
+  uint8_t bits[64];
+
+  int bit;
+  i = start;
+  for (bit = 0; bit < 64; bit++) {
+    int j;
+    int sum = 0;
+    for (j = 0; j < 16; j++) {
+      sum += GraphBuffer[i++];
+    }
+    if (sum > 0) {
+      bits[bit] = 1;
+    } else {
+      bits[bit] = 0;
+    }
+    PrintAndLog("bit %d sum %d", bit, sum);
+  }
+
+  for (bit = 0; bit < 64; bit++) {
+    int j;
+    int sum = 0;
+    for (j = 0; j < 16; j++) {
+      sum += GraphBuffer[i++];
+    }
+    if (sum > 0 && bits[bit] != 1) {
+      PrintAndLog("oops1 at %d", bit);
+    }
+    if (sum < 0 && bits[bit] != 0) {
+      PrintAndLog("oops2 at %d", bit);
+    }
+  }
+
+  GraphTraceLen = 32*64;
+  i = 0;
+  int phase = 0;
+  for (bit = 0; bit < 64; bit++) {
+    if (bits[bit] == 0) {
+      phase = 0;
+    } else {
+      phase = 1;
+    }
+    int j;
+    for (j = 0; j < 32; j++) {
+      GraphBuffer[i++] = phase;
+      phase = !phase;
+    }
+  }
+
+  RepaintGraphWindow();
+  return 0;
+}
+
+int CmdIndalaDemod(const char *Cmd)
+{
+  // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
+
+  int state = -1;
+  int count = 0;
+  int i, j;
+  // worst case with GraphTraceLen=64000 is < 4096
+  // under normal conditions it's < 2048
+  uint8_t rawbits[4096];
+  int rawbit = 0;
+  int worst = 0, worstPos = 0;
+  PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32);
+  for (i = 0; i < GraphTraceLen-1; i += 2) {
+    count += 1;
+    if ((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {
+      if (state == 0) {
+        for (j = 0; j <  count - 8; j += 16) {
+          rawbits[rawbit++] = 0;
+        }
+        if ((abs(count - j)) > worst) {
+          worst = abs(count - j);
+          worstPos = i;
+        }
+      }
+      state = 1;
+      count = 0;
+    } else if ((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {
+      if (state == 1) {
+        for (j = 0; j <  count - 8; j += 16) {
+          rawbits[rawbit++] = 1;
+        }
+        if ((abs(count - j)) > worst) {
+          worst = abs(count - j);
+          worstPos = i;
+        }
+      }
+      state = 0;
+      count = 0;
+    }
+  }
+  PrintAndLog("Recovered %d raw bits", rawbit);
+  PrintAndLog("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
+
+  // Finding the start of a UID
+  int uidlen, long_wait;
+  if (strcmp(Cmd, "224") == 0) {
+    uidlen = 224;
+    long_wait = 30;
+  } else {
+    uidlen = 64;
+    long_wait = 29;
+  }
+  int start;
+  int first = 0;
+  for (start = 0; start <= rawbit - uidlen; start++) {
+    first = rawbits[start];
+    for (i = start; i < start + long_wait; i++) {
+      if (rawbits[i] != first) {
+        break;
+      }
+    }
+    if (i == (start + long_wait)) {
+      break;
+    }
+  }
+  if (start == rawbit - uidlen + 1) {
+    PrintAndLog("nothing to wait for");
+    return 0;
+  }
+
+  // Inverting signal if needed
+  if (first == 1) {
+    for (i = start; i < rawbit; i++) {
+      rawbits[i] = !rawbits[i];
+    }
+  }
+
+  // Dumping UID
+  uint8_t bits[224];
+  char showbits[225];
+  showbits[uidlen]='\0';
+  int bit;
+  i = start;
+  int times = 0;
+  if (uidlen > rawbit) {
+    PrintAndLog("Warning: not enough raw bits to get a full UID");
+    for (bit = 0; bit < rawbit; bit++) {
+      bits[bit] = rawbits[i++];
+      // As we cannot know the parity, let's use "." and "/"
+      showbits[bit] = '.' + bits[bit];
+    }
+    showbits[bit+1]='\0';
+    PrintAndLog("Partial UID=%s", showbits);
+    return 0;
+  } else {
+    for (bit = 0; bit < uidlen; bit++) {
+      bits[bit] = rawbits[i++];
+      showbits[bit] = '0' + bits[bit];
+    }
+    times = 1;
+  }
+  PrintAndLog("UID=%s", showbits);
+
+  // Checking UID against next occurences
+  for (; i + uidlen <= rawbit;) {
+    int failed = 0;
+    for (bit = 0; bit < uidlen; bit++) {
+      if (bits[bit] != rawbits[i++]) {
+        failed = 1;
+        break;
+      }
+    }
+    if (failed == 1) {
+      break;
+    }
+    times += 1;
+  }
+  PrintAndLog("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);
+
+  // Remodulating for tag cloning
+  GraphTraceLen = 32*uidlen;
+  i = 0;
+  int phase = 0;
+  for (bit = 0; bit < uidlen; bit++) {
+    if (bits[bit] == 0) {
+      phase = 0;
+    } else {
+      phase = 1;
+    }
+    int j;
+    for (j = 0; j < 32; j++) {
+      GraphBuffer[i++] = phase;
+      phase = !phase;
+    }
+  }
+
+  RepaintGraphWindow();
+  return 0;
+}
+
+int CmdLFRead(const char *Cmd)
+{
+  UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K};
+  // 'h' means higher-low-frequency, 134 kHz
+  if(*Cmd == 'h') {
+    c.arg[0] = 1;
+  } else if (*Cmd == '\0') {
+    c.arg[0] = 0;
+  } else {
+    PrintAndLog("use 'read' or 'read h'");
+    return 0;
+  }
+  SendCommand(&c);
+  return 0;
+}
+
+static void ChkBitstream(const 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;
+    }
+  }
+}
+
+int CmdLFSim(const char *Cmd)
+{
+  int i;
+  static int gap;
+
+  sscanf(Cmd, "%i", &gap);
+
+  /* convert to bitstream if necessary */
+  ChkBitstream(Cmd);
+
+  PrintAndLog("Sending data, please wait...");
+  for (i = 0; i < GraphTraceLen; i += 48) {
+    UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}};
+    int j;
+    for (j = 0; j < 48; j++) {
+      c.d.asBytes[j] = GraphBuffer[i+j];
+    }
+    SendCommand(&c);
+    WaitForResponse(CMD_ACK);
+  }
+
+  PrintAndLog("Starting simulator...");
+  UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}};
+  SendCommand(&c);
+  return 0;
+}
+
+int CmdLFSimBidir(const char *Cmd)
+{
+  /* Set ADC to twice the carrier for a slight supersampling */
+  UsbCommand c = {CMD_LF_SIMULATE_BIDIR, {47, 384, 0}};
+  SendCommand(&c);
+  return 0;
+}
+
+/* simulate an LF Manchester encoded tag with specified bitstream, clock rate and inter-id gap */
+int CmdLFSimManchester(const char *Cmd)
+{
+  static int clock, gap;
+  static char data[1024], gapstring[8];
+
+  /* get settings/bits */
+  sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap);
+
+  /* clear our graph */
+  ClearGraph(0);
+
+  /* fill it with our bitstream */
+  for (int i = 0; i < strlen(data) ; ++i)
+    AppendGraph(0, clock, data[i]- '0');
+
+  /* modulate */
+  CmdManchesterMod("");
+
+  /* show what we've done */
+  RepaintGraphWindow();
+
+  /* simulate */
+  sprintf(&gapstring[0], "%i", gap);
+  CmdLFSim(gapstring);
+  return 0;
+}
+
+int CmdVchDemod(const char *Cmd)
+{
+  // Is this the entire sync pattern, or does this also include some
+  // data bits that happen to be the same everywhere? That would be
+  // lovely to know.
+  static const int SyncPattern[] = {
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+    1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  };
+
+  // So first, we correlate for the sync pattern, and mark that.
+  int bestCorrel = 0, bestPos = 0;
+  int i;
+  // It does us no good to find the sync pattern, with fewer than
+  // 2048 samples after it...
+  for (i = 0; i < (GraphTraceLen-2048); i++) {
+    int sum = 0;
+    int j;
+    for (j = 0; j < arraylen(SyncPattern); j++) {
+      sum += GraphBuffer[i+j]*SyncPattern[j];
+    }
+    if (sum > bestCorrel) {
+      bestCorrel = sum;
+      bestPos = i;
+    }
+  }
+  PrintAndLog("best sync at %d [metric %d]", bestPos, bestCorrel);
+
+  char bits[257];
+  bits[256] = '\0';
+
+  int worst = INT_MAX;
+  int worstPos;
+
+  for (i = 0; i < 2048; i += 8) {
+    int sum = 0;
+    int j;
+    for (j = 0; j < 8; j++) {
+      sum += GraphBuffer[bestPos+i+j];
+    }
+    if (sum < 0) {
+      bits[i/8] = '.';
+    } else {
+      bits[i/8] = '1';
+    }
+    if(abs(sum) < worst) {
+      worst = abs(sum);
+      worstPos = i;
+    }
+  }
+  PrintAndLog("bits:");
+  PrintAndLog("%s", bits);
+  PrintAndLog("worst metric: %d at pos %d", worst, worstPos);
+
+  if (strcmp(Cmd, "clone")==0) {
+    GraphTraceLen = 0;
+    char *s;
+    for(s = bits; *s; s++) {
+      int j;
+      for(j = 0; j < 16; j++) {
+        GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;
+      }
+    }
+    RepaintGraphWindow();
+  }
+  return 0;
+}
+
+static command_t CommandTable[] = 
+{
+  {"help",        CmdHelp,            1, "This help"},
+  {"cmdread",     CmdLFCommandRead,   0, "<off period> <'0' period> <'1' period> <command> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)"},
+  {"em4x",        CmdLFEM4X,          1, "EM4X RFIDs"},
+  {"flexdemod",   CmdFlexdemod,       1, "Demodulate samples for FlexPass"},
+  {"hid",         CmdLFHID,           1, "HID RFIDs"},
+  {"indalademod", CmdIndalaDemod,     1, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
+  {"read",        CmdLFRead,          0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
+  {"sim",         CmdLFSim,           0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"},
+  {"simbidir",    CmdLFSimBidir,      0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
+  {"simman",      CmdLFSimManchester, 0, "<Clock> <Bitstream> [GAP] Simulate arbitrary Manchester LF tag"},
+  {"ti",          CmdLFTI,            1, "TI RFIDs"},
+  {"vchdemod",    CmdVchDemod,        1, "['clone'] -- Demodulate samples for VeriChip"},
+  {NULL, NULL, 0, NULL}
+};
+
+int CmdLF(const char *Cmd)
+{
+  CmdsParse(CommandTable, Cmd);
+  return 0; 
+}
+
+int CmdHelp(const char *Cmd)
+{
+  CmdsHelp(CommandTable);
+  return 0;
+}
Impressum, Datenschutz