]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdlf.c
Client cleanup and restructuring. Stage 1...
[proxmark3-svn] / client / cmdlf.c
CommitLineData
7fe9b0b7 1#include <stdio.h>
2#include <string.h>
3#include "proxusb.h"
4#include "data.h"
5#include "graph.h"
6#include "ui.h"
7#include "cmdparser.h"
8#include "cmddata.h"
9#include "cmdlf.h"
10#include "cmdlfhid.h"
11#include "cmdlfti.h"
12#include "cmdlfem4x.h"
13
14static int CmdHelp(const char *Cmd);
15
16/* send a command before reading */
17int CmdLFCommandRead(const char *Cmd)
18{
19 static char dummy[3];
20
21 dummy[0]= ' ';
22
23 UsbCommand c = {CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K};
24 sscanf(Cmd, "%i %i %i %s %s", &c.arg[0], &c.arg[1], &c.arg[2], (char *) &c.d.asBytes,(char *) &dummy+1);
25 // in case they specified 'h'
26 strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);
27 SendCommand(&c);
28 return 0;
29}
30
31int CmdFlexdemod(const char *Cmd)
32{
33 int i;
34 for (i = 0; i < GraphTraceLen; ++i) {
35 if (GraphBuffer[i] < 0) {
36 GraphBuffer[i] = -1;
37 } else {
38 GraphBuffer[i] = 1;
39 }
40 }
41
42#define LONG_WAIT 100
43 int start;
44 for (start = 0; start < GraphTraceLen - LONG_WAIT; start++) {
45 int first = GraphBuffer[start];
46 for (i = start; i < start + LONG_WAIT; i++) {
47 if (GraphBuffer[i] != first) {
48 break;
49 }
50 }
51 if (i == (start + LONG_WAIT)) {
52 break;
53 }
54 }
55 if (start == GraphTraceLen - LONG_WAIT) {
56 PrintAndLog("nothing to wait for");
57 return 0;
58 }
59
60 GraphBuffer[start] = 2;
61 GraphBuffer[start+1] = -2;
62
63 uint8_t bits[64];
64
65 int bit;
66 i = start;
67 for (bit = 0; bit < 64; bit++) {
68 int j;
69 int sum = 0;
70 for (j = 0; j < 16; j++) {
71 sum += GraphBuffer[i++];
72 }
73 if (sum > 0) {
74 bits[bit] = 1;
75 } else {
76 bits[bit] = 0;
77 }
78 PrintAndLog("bit %d sum %d", bit, sum);
79 }
80
81 for (bit = 0; bit < 64; bit++) {
82 int j;
83 int sum = 0;
84 for (j = 0; j < 16; j++) {
85 sum += GraphBuffer[i++];
86 }
87 if (sum > 0 && bits[bit] != 1) {
88 PrintAndLog("oops1 at %d", bit);
89 }
90 if (sum < 0 && bits[bit] != 0) {
91 PrintAndLog("oops2 at %d", bit);
92 }
93 }
94
95 GraphTraceLen = 32*64;
96 i = 0;
97 int phase = 0;
98 for (bit = 0; bit < 64; bit++) {
99 if (bits[bit] == 0) {
100 phase = 0;
101 } else {
102 phase = 1;
103 }
104 int j;
105 for (j = 0; j < 32; j++) {
106 GraphBuffer[i++] = phase;
107 phase = !phase;
108 }
109 }
110
111 RepaintGraphWindow();
112 return 0;
113}
114
115int CmdIndalaDemod(const char *Cmd)
116{
117 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
118
119 int state = -1;
120 int count = 0;
121 int i, j;
122 // worst case with GraphTraceLen=64000 is < 4096
123 // under normal conditions it's < 2048
124 uint8_t rawbits[4096];
125 int rawbit = 0;
126 int worst = 0, worstPos = 0;
127 PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32);
128 for (i = 0; i < GraphTraceLen-1; i += 2) {
129 count += 1;
130 if ((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {
131 if (state == 0) {
132 for (j = 0; j < count - 8; j += 16) {
133 rawbits[rawbit++] = 0;
134 }
135 if ((abs(count - j)) > worst) {
136 worst = abs(count - j);
137 worstPos = i;
138 }
139 }
140 state = 1;
141 count = 0;
142 } else if ((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {
143 if (state == 1) {
144 for (j = 0; j < count - 8; j += 16) {
145 rawbits[rawbit++] = 1;
146 }
147 if ((abs(count - j)) > worst) {
148 worst = abs(count - j);
149 worstPos = i;
150 }
151 }
152 state = 0;
153 count = 0;
154 }
155 }
156 PrintAndLog("Recovered %d raw bits", rawbit);
157 PrintAndLog("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
158
159 // Finding the start of a UID
160 int uidlen, long_wait;
161 if (strcmp(Cmd, "224") == 0) {
162 uidlen = 224;
163 long_wait = 30;
164 } else {
165 uidlen = 64;
166 long_wait = 29;
167 }
168 int start;
169 int first = 0;
170 for (start = 0; start <= rawbit - uidlen; start++) {
171 first = rawbits[start];
172 for (i = start; i < start + long_wait; i++) {
173 if (rawbits[i] != first) {
174 break;
175 }
176 }
177 if (i == (start + long_wait)) {
178 break;
179 }
180 }
181 if (start == rawbit - uidlen + 1) {
182 PrintAndLog("nothing to wait for");
183 return 0;
184 }
185
186 // Inverting signal if needed
187 if (first == 1) {
188 for (i = start; i < rawbit; i++) {
189 rawbits[i] = !rawbits[i];
190 }
191 }
192
193 // Dumping UID
194 uint8_t bits[224];
195 char showbits[225];
196 showbits[uidlen]='\0';
197 int bit;
198 i = start;
199 int times = 0;
200 if (uidlen > rawbit) {
201 PrintAndLog("Warning: not enough raw bits to get a full UID");
202 for (bit = 0; bit < rawbit; bit++) {
203 bits[bit] = rawbits[i++];
204 // As we cannot know the parity, let's use "." and "/"
205 showbits[bit] = '.' + bits[bit];
206 }
207 showbits[bit+1]='\0';
208 PrintAndLog("Partial UID=%s", showbits);
209 return 0;
210 } else {
211 for (bit = 0; bit < uidlen; bit++) {
212 bits[bit] = rawbits[i++];
213 showbits[bit] = '0' + bits[bit];
214 }
215 times = 1;
216 }
217 PrintAndLog("UID=%s", showbits);
218
219 // Checking UID against next occurences
220 for (; i + uidlen <= rawbit;) {
221 int failed = 0;
222 for (bit = 0; bit < uidlen; bit++) {
223 if (bits[bit] != rawbits[i++]) {
224 failed = 1;
225 break;
226 }
227 }
228 if (failed == 1) {
229 break;
230 }
231 times += 1;
232 }
233 PrintAndLog("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);
234
235 // Remodulating for tag cloning
236 GraphTraceLen = 32*uidlen;
237 i = 0;
238 int phase = 0;
239 for (bit = 0; bit < uidlen; bit++) {
240 if (bits[bit] == 0) {
241 phase = 0;
242 } else {
243 phase = 1;
244 }
245 int j;
246 for (j = 0; j < 32; j++) {
247 GraphBuffer[i++] = phase;
248 phase = !phase;
249 }
250 }
251
252 RepaintGraphWindow();
253 return 0;
254}
255
256int CmdLFRead(const char *Cmd)
257{
258 UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K};
259 // 'h' means higher-low-frequency, 134 kHz
260 if(*Cmd == 'h') {
261 c.arg[0] = 1;
262 } else if (*Cmd == '\0') {
263 c.arg[0] = 0;
264 } else {
265 PrintAndLog("use 'read' or 'read h'");
266 return 0;
267 }
268 SendCommand(&c);
269 return 0;
270}
271
272static void ChkBitstream(const char *str)
273{
274 int i;
275
276 /* convert to bitstream if necessary */
277 for (i = 0; i < (int)(GraphTraceLen / 2); i++)
278 {
279 if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)
280 {
281 CmdBitstream(str);
282 break;
283 }
284 }
285}
286
287int CmdLFSim(const char *Cmd)
288{
289 int i;
290 static int gap;
291
292 sscanf(Cmd, "%i", &gap);
293
294 /* convert to bitstream if necessary */
295 ChkBitstream(Cmd);
296
297 PrintAndLog("Sending data, please wait...");
298 for (i = 0; i < GraphTraceLen; i += 48) {
299 UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}};
300 int j;
301 for (j = 0; j < 48; j++) {
302 c.d.asBytes[j] = GraphBuffer[i+j];
303 }
304 SendCommand(&c);
305 WaitForResponse(CMD_ACK);
306 }
307
308 PrintAndLog("Starting simulator...");
309 UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}};
310 SendCommand(&c);
311 return 0;
312}
313
314int CmdLFSimBidir(const char *Cmd)
315{
316 /* Set ADC to twice the carrier for a slight supersampling */
317 UsbCommand c = {CMD_LF_SIMULATE_BIDIR, {47, 384, 0}};
318 SendCommand(&c);
319 return 0;
320}
321
322/* simulate an LF Manchester encoded tag with specified bitstream, clock rate and inter-id gap */
323int CmdLFSimManchester(const char *Cmd)
324{
325 static int clock, gap;
326 static char data[1024], gapstring[8];
327
328 /* get settings/bits */
329 sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap);
330
331 /* clear our graph */
332 ClearGraph(0);
333
334 /* fill it with our bitstream */
335 for (int i = 0; i < strlen(data) ; ++i)
336 AppendGraph(0, clock, data[i]- '0');
337
338 /* modulate */
339 CmdManchesterMod("");
340
341 /* show what we've done */
342 RepaintGraphWindow();
343
344 /* simulate */
345 sprintf(&gapstring[0], "%i", gap);
346 CmdLFSim(gapstring);
347 return 0;
348}
349
350int CmdVchDemod(const char *Cmd)
351{
352 // Is this the entire sync pattern, or does this also include some
353 // data bits that happen to be the same everywhere? That would be
354 // lovely to know.
355 static const int SyncPattern[] = {
356 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
357 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
358 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
359 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
360 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
361 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
362 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
363 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
365 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
366 };
367
368 // So first, we correlate for the sync pattern, and mark that.
369 int bestCorrel = 0, bestPos = 0;
370 int i;
371 // It does us no good to find the sync pattern, with fewer than
372 // 2048 samples after it...
373 for (i = 0; i < (GraphTraceLen-2048); i++) {
374 int sum = 0;
375 int j;
376 for (j = 0; j < arraylen(SyncPattern); j++) {
377 sum += GraphBuffer[i+j]*SyncPattern[j];
378 }
379 if (sum > bestCorrel) {
380 bestCorrel = sum;
381 bestPos = i;
382 }
383 }
384 PrintAndLog("best sync at %d [metric %d]", bestPos, bestCorrel);
385
386 char bits[257];
387 bits[256] = '\0';
388
389 int worst = INT_MAX;
390 int worstPos;
391
392 for (i = 0; i < 2048; i += 8) {
393 int sum = 0;
394 int j;
395 for (j = 0; j < 8; j++) {
396 sum += GraphBuffer[bestPos+i+j];
397 }
398 if (sum < 0) {
399 bits[i/8] = '.';
400 } else {
401 bits[i/8] = '1';
402 }
403 if(abs(sum) < worst) {
404 worst = abs(sum);
405 worstPos = i;
406 }
407 }
408 PrintAndLog("bits:");
409 PrintAndLog("%s", bits);
410 PrintAndLog("worst metric: %d at pos %d", worst, worstPos);
411
412 if (strcmp(Cmd, "clone")==0) {
413 GraphTraceLen = 0;
414 char *s;
415 for(s = bits; *s; s++) {
416 int j;
417 for(j = 0; j < 16; j++) {
418 GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;
419 }
420 }
421 RepaintGraphWindow();
422 }
423 return 0;
424}
425
426static command_t CommandTable[] =
427{
428 {"help", CmdHelp, 1, "This help"},
429 {"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)"},
430 {"em4x", CmdLFEM4X, 1, "EM4X RFIDs"},
431 {"flexdemod", CmdFlexdemod, 1, "Demodulate samples for FlexPass"},
432 {"hid", CmdLFHID, 1, "HID RFIDs"},
433 {"indalademod", CmdIndalaDemod, 1, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
434 {"read", CmdLFRead, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
435 {"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"},
436 {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
437 {"simman", CmdLFSimManchester, 0, "<Clock> <Bitstream> [GAP] Simulate arbitrary Manchester LF tag"},
438 {"ti", CmdLFTI, 1, "TI RFIDs"},
439 {"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"},
440 {NULL, NULL, 0, NULL}
441};
442
443int CmdLF(const char *Cmd)
444{
445 CmdsParse(CommandTable, Cmd);
446 return 0;
447}
448
449int CmdHelp(const char *Cmd)
450{
451 CmdsHelp(CommandTable);
452 return 0;
453}
Impressum, Datenschutz