]> cvs.zerfleddert.de Git - proxmark3-svn/blame - client/cmdlf.c
Added output to file for 'lf hitag list' command
[proxmark3-svn] / client / cmdlf.c
CommitLineData
a553f267 1//-----------------------------------------------------------------------------
2// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
3//
4// This code is licensed to you under the terms of the GNU GPL, version 2 or,
5// at your option, any later version. See the LICENSE.txt file for the text of
6// the license.
7//-----------------------------------------------------------------------------
8// Low frequency commands
9//-----------------------------------------------------------------------------
10
7fe9b0b7 11#include <stdio.h>
590f8ff9 12#include <stdlib.h>
7fe9b0b7 13#include <string.h>
393c3ef9 14#include <limits.h>
7fe9b0b7 15#include "proxusb.h"
16#include "data.h"
17#include "graph.h"
18#include "ui.h"
19#include "cmdparser.h"
040a7baa 20#include "cmdmain.h"
7fe9b0b7 21#include "cmddata.h"
22#include "cmdlf.h"
23#include "cmdlfhid.h"
24#include "cmdlfti.h"
25#include "cmdlfem4x.h"
db09cb3a 26#include "cmdlfhitag.h"
7fe9b0b7 27
28static int CmdHelp(const char *Cmd);
29
30/* send a command before reading */
31int CmdLFCommandRead(const char *Cmd)
32{
33 static char dummy[3];
34
35 dummy[0]= ' ';
36
37 UsbCommand c = {CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K};
38 sscanf(Cmd, "%i %i %i %s %s", &c.arg[0], &c.arg[1], &c.arg[2], (char *) &c.d.asBytes,(char *) &dummy+1);
39 // in case they specified 'h'
40 strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);
41 SendCommand(&c);
42 return 0;
43}
44
45int CmdFlexdemod(const char *Cmd)
46{
47 int i;
48 for (i = 0; i < GraphTraceLen; ++i) {
49 if (GraphBuffer[i] < 0) {
50 GraphBuffer[i] = -1;
51 } else {
52 GraphBuffer[i] = 1;
53 }
54 }
55
56#define LONG_WAIT 100
57 int start;
58 for (start = 0; start < GraphTraceLen - LONG_WAIT; start++) {
59 int first = GraphBuffer[start];
60 for (i = start; i < start + LONG_WAIT; i++) {
61 if (GraphBuffer[i] != first) {
62 break;
63 }
64 }
65 if (i == (start + LONG_WAIT)) {
66 break;
67 }
68 }
69 if (start == GraphTraceLen - LONG_WAIT) {
70 PrintAndLog("nothing to wait for");
71 return 0;
72 }
73
74 GraphBuffer[start] = 2;
75 GraphBuffer[start+1] = -2;
76
77 uint8_t bits[64];
78
79 int bit;
80 i = start;
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) {
88 bits[bit] = 1;
89 } else {
90 bits[bit] = 0;
91 }
92 PrintAndLog("bit %d sum %d", bit, sum);
93 }
94
95 for (bit = 0; bit < 64; bit++) {
96 int j;
97 int sum = 0;
98 for (j = 0; j < 16; j++) {
99 sum += GraphBuffer[i++];
100 }
101 if (sum > 0 && bits[bit] != 1) {
102 PrintAndLog("oops1 at %d", bit);
103 }
104 if (sum < 0 && bits[bit] != 0) {
105 PrintAndLog("oops2 at %d", bit);
106 }
107 }
108
109 GraphTraceLen = 32*64;
110 i = 0;
111 int phase = 0;
112 for (bit = 0; bit < 64; bit++) {
113 if (bits[bit] == 0) {
114 phase = 0;
115 } else {
116 phase = 1;
117 }
118 int j;
119 for (j = 0; j < 32; j++) {
120 GraphBuffer[i++] = phase;
121 phase = !phase;
122 }
123 }
124
125 RepaintGraphWindow();
126 return 0;
127}
128
129int CmdIndalaDemod(const char *Cmd)
130{
131 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
132
133 int state = -1;
134 int count = 0;
135 int i, j;
136 // worst case with GraphTraceLen=64000 is < 4096
137 // under normal conditions it's < 2048
138 uint8_t rawbits[4096];
139 int rawbit = 0;
140 int worst = 0, worstPos = 0;
141 PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32);
142 for (i = 0; i < GraphTraceLen-1; i += 2) {
143 count += 1;
144 if ((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {
145 if (state == 0) {
146 for (j = 0; j < count - 8; j += 16) {
147 rawbits[rawbit++] = 0;
148 }
149 if ((abs(count - j)) > worst) {
150 worst = abs(count - j);
151 worstPos = i;
152 }
153 }
154 state = 1;
155 count = 0;
156 } else if ((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {
157 if (state == 1) {
158 for (j = 0; j < count - 8; j += 16) {
159 rawbits[rawbit++] = 1;
160 }
161 if ((abs(count - j)) > worst) {
162 worst = abs(count - j);
163 worstPos = i;
164 }
165 }
166 state = 0;
167 count = 0;
168 }
169 }
170 PrintAndLog("Recovered %d raw bits", rawbit);
171 PrintAndLog("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
172
173 // Finding the start of a UID
174 int uidlen, long_wait;
175 if (strcmp(Cmd, "224") == 0) {
176 uidlen = 224;
177 long_wait = 30;
178 } else {
179 uidlen = 64;
180 long_wait = 29;
181 }
182 int start;
183 int first = 0;
184 for (start = 0; start <= rawbit - uidlen; start++) {
185 first = rawbits[start];
186 for (i = start; i < start + long_wait; i++) {
187 if (rawbits[i] != first) {
188 break;
189 }
190 }
191 if (i == (start + long_wait)) {
192 break;
193 }
194 }
195 if (start == rawbit - uidlen + 1) {
196 PrintAndLog("nothing to wait for");
197 return 0;
198 }
199
200 // Inverting signal if needed
201 if (first == 1) {
202 for (i = start; i < rawbit; i++) {
203 rawbits[i] = !rawbits[i];
204 }
205 }
206
207 // Dumping UID
208 uint8_t bits[224];
209 char showbits[225];
210 showbits[uidlen]='\0';
211 int bit;
212 i = start;
213 int times = 0;
214 if (uidlen > rawbit) {
215 PrintAndLog("Warning: not enough raw bits to get a full UID");
216 for (bit = 0; bit < rawbit; bit++) {
217 bits[bit] = rawbits[i++];
218 // As we cannot know the parity, let's use "." and "/"
219 showbits[bit] = '.' + bits[bit];
220 }
221 showbits[bit+1]='\0';
222 PrintAndLog("Partial UID=%s", showbits);
223 return 0;
224 } else {
225 for (bit = 0; bit < uidlen; bit++) {
226 bits[bit] = rawbits[i++];
227 showbits[bit] = '0' + bits[bit];
228 }
229 times = 1;
230 }
2414f978 231
232 //convert UID to HEX
233 uint32_t uid1, uid2, uid3, uid4, uid5, uid6, uid7;
234 int idx;
235 uid1=0;
236 uid2=0;
237 if (uidlen==64){
238 for( idx=0; idx<64; idx++) {
239 if (showbits[idx] == '0') {
240 uid1=(uid1<<1)|(uid2>>31);
241 uid2=(uid2<<1)|0;
242 } else {
243 uid1=(uid1<<1)|(uid2>>31);
244 uid2=(uid2<<1)|1;
245 }
246 }
247 PrintAndLog("UID=%s (%x%08x)", showbits, uid1, uid2);
248 }
249 else {
250 uid3=0;
251 uid4=0;
252 uid5=0;
253 uid6=0;
254 uid7=0;
255 for( idx=0; idx<224; idx++) {
256 uid1=(uid1<<1)|(uid2>>31);
257 uid2=(uid2<<1)|(uid3>>31);
258 uid3=(uid3<<1)|(uid4>>31);
259 uid4=(uid4<<1)|(uid5>>31);
260 uid5=(uid5<<1)|(uid6>>31);
261 uid6=(uid6<<1)|(uid7>>31);
262 if (showbits[idx] == '0') uid7=(uid7<<1)|0;
263 else uid7=(uid7<<1)|1;
264 }
265 PrintAndLog("UID=%s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
266 }
7fe9b0b7 267
268 // Checking UID against next occurences
269 for (; i + uidlen <= rawbit;) {
270 int failed = 0;
271 for (bit = 0; bit < uidlen; bit++) {
272 if (bits[bit] != rawbits[i++]) {
273 failed = 1;
274 break;
275 }
276 }
277 if (failed == 1) {
278 break;
279 }
280 times += 1;
281 }
282 PrintAndLog("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);
283
284 // Remodulating for tag cloning
285 GraphTraceLen = 32*uidlen;
286 i = 0;
287 int phase = 0;
288 for (bit = 0; bit < uidlen; bit++) {
289 if (bits[bit] == 0) {
290 phase = 0;
291 } else {
292 phase = 1;
293 }
294 int j;
295 for (j = 0; j < 32; j++) {
296 GraphBuffer[i++] = phase;
297 phase = !phase;
298 }
299 }
300
301 RepaintGraphWindow();
302 return 0;
303}
304
2414f978 305int CmdIndalaClone(const char *Cmd)
306{
307 unsigned int uid1, uid2, uid3, uid4, uid5, uid6, uid7;
308 UsbCommand c;
309 uid1=0;
310 uid2=0;
311 uid3=0;
312 uid4=0;
313 uid5=0;
314 uid6=0;
315 uid7=0;
316 int n = 0, i = 0;
317
318 if (strchr(Cmd,'l') != 0) {
319 while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
320 uid1 = (uid1 << 4) | (uid2 >> 28);
321 uid2 = (uid2 << 4) | (uid3 >> 28);
322 uid3 = (uid3 << 4) | (uid4 >> 28);
323 uid4 = (uid4 << 4) | (uid5 >> 28);
324 uid5 = (uid5 << 4) | (uid6 >> 28);
325 uid6 = (uid6 << 4) | (uid7 >> 28);
326 uid7 = (uid7 << 4) | (n & 0xf);
327 }
328 PrintAndLog("Cloning 224bit tag with UID %x%08x%08x%08x%08x%08x%08x", uid1, uid2, uid3, uid4, uid5, uid6, uid7);
329 c.cmd = CMD_INDALA_CLONE_TAG_L;
330 c.d.asDwords[0] = uid1;
331 c.d.asDwords[1] = uid2;
332 c.d.asDwords[2] = uid3;
333 c.d.asDwords[3] = uid4;
334 c.d.asDwords[4] = uid5;
335 c.d.asDwords[5] = uid6;
336 c.d.asDwords[6] = uid7;
337 }
338 else
339 {
340 while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
341 uid1 = (uid1 << 4) | (uid2 >> 28);
342 uid2 = (uid2 << 4) | (n & 0xf);
343 }
344 PrintAndLog("Cloning 64bit tag with UID %x%08x", uid1, uid2);
345 c.cmd = CMD_INDALA_CLONE_TAG;
346 c.arg[0] = uid1;
347 c.arg[1] = uid2;
348 }
349
350 SendCommand(&c);
351 return 0;
352}
353
7fe9b0b7 354int CmdLFRead(const char *Cmd)
355{
356 UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K};
357 // 'h' means higher-low-frequency, 134 kHz
358 if(*Cmd == 'h') {
359 c.arg[0] = 1;
360 } else if (*Cmd == '\0') {
361 c.arg[0] = 0;
362 } else {
363 PrintAndLog("use 'read' or 'read h'");
364 return 0;
365 }
366 SendCommand(&c);
bdd1de1b 367 WaitForResponse(CMD_ACK);
7fe9b0b7 368 return 0;
369}
370
371static void ChkBitstream(const char *str)
372{
373 int i;
374
375 /* convert to bitstream if necessary */
376 for (i = 0; i < (int)(GraphTraceLen / 2); i++)
377 {
378 if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)
379 {
380 CmdBitstream(str);
381 break;
382 }
383 }
384}
385
386int CmdLFSim(const char *Cmd)
387{
388 int i;
389 static int gap;
390
391 sscanf(Cmd, "%i", &gap);
392
393 /* convert to bitstream if necessary */
394 ChkBitstream(Cmd);
395
396 PrintAndLog("Sending data, please wait...");
397 for (i = 0; i < GraphTraceLen; i += 48) {
398 UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}};
399 int j;
400 for (j = 0; j < 48; j++) {
401 c.d.asBytes[j] = GraphBuffer[i+j];
402 }
403 SendCommand(&c);
404 WaitForResponse(CMD_ACK);
405 }
406
407 PrintAndLog("Starting simulator...");
408 UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}};
409 SendCommand(&c);
410 return 0;
411}
412
413int CmdLFSimBidir(const char *Cmd)
414{
415 /* Set ADC to twice the carrier for a slight supersampling */
416 UsbCommand c = {CMD_LF_SIMULATE_BIDIR, {47, 384, 0}};
417 SendCommand(&c);
418 return 0;
419}
420
421/* simulate an LF Manchester encoded tag with specified bitstream, clock rate and inter-id gap */
422int CmdLFSimManchester(const char *Cmd)
423{
424 static int clock, gap;
425 static char data[1024], gapstring[8];
426
427 /* get settings/bits */
428 sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap);
429
430 /* clear our graph */
431 ClearGraph(0);
432
433 /* fill it with our bitstream */
434 for (int i = 0; i < strlen(data) ; ++i)
435 AppendGraph(0, clock, data[i]- '0');
436
437 /* modulate */
438 CmdManchesterMod("");
439
440 /* show what we've done */
441 RepaintGraphWindow();
442
443 /* simulate */
444 sprintf(&gapstring[0], "%i", gap);
445 CmdLFSim(gapstring);
446 return 0;
447}
448
449int CmdVchDemod(const char *Cmd)
450{
451 // Is this the entire sync pattern, or does this also include some
452 // data bits that happen to be the same everywhere? That would be
453 // lovely to know.
454 static const int SyncPattern[] = {
455 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
456 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
457 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
458 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
459 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
460 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
461 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
462 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
463 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
464 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
465 };
466
467 // So first, we correlate for the sync pattern, and mark that.
468 int bestCorrel = 0, bestPos = 0;
469 int i;
470 // It does us no good to find the sync pattern, with fewer than
471 // 2048 samples after it...
472 for (i = 0; i < (GraphTraceLen-2048); i++) {
473 int sum = 0;
474 int j;
475 for (j = 0; j < arraylen(SyncPattern); j++) {
476 sum += GraphBuffer[i+j]*SyncPattern[j];
477 }
478 if (sum > bestCorrel) {
479 bestCorrel = sum;
480 bestPos = i;
481 }
482 }
483 PrintAndLog("best sync at %d [metric %d]", bestPos, bestCorrel);
484
485 char bits[257];
486 bits[256] = '\0';
487
488 int worst = INT_MAX;
fddf220a 489 int worstPos = 0;
7fe9b0b7 490
491 for (i = 0; i < 2048; i += 8) {
492 int sum = 0;
493 int j;
494 for (j = 0; j < 8; j++) {
495 sum += GraphBuffer[bestPos+i+j];
496 }
497 if (sum < 0) {
498 bits[i/8] = '.';
499 } else {
500 bits[i/8] = '1';
501 }
502 if(abs(sum) < worst) {
503 worst = abs(sum);
504 worstPos = i;
505 }
506 }
507 PrintAndLog("bits:");
508 PrintAndLog("%s", bits);
509 PrintAndLog("worst metric: %d at pos %d", worst, worstPos);
510
511 if (strcmp(Cmd, "clone")==0) {
512 GraphTraceLen = 0;
513 char *s;
514 for(s = bits; *s; s++) {
515 int j;
516 for(j = 0; j < 16; j++) {
517 GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;
518 }
519 }
520 RepaintGraphWindow();
521 }
522 return 0;
523}
524
525static command_t CommandTable[] =
526{
527 {"help", CmdHelp, 1, "This help"},
528 {"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)"},
37239a7c 529 {"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"},
7fe9b0b7 530 {"flexdemod", CmdFlexdemod, 1, "Demodulate samples for FlexPass"},
37239a7c 531 {"hid", CmdLFHID, 1, "{ HID RFIDs... }"},
7fe9b0b7 532 {"indalademod", CmdIndalaDemod, 1, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
2414f978 533 {"indalaclone", CmdIndalaClone, 1, "<UID> ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"},
7fe9b0b7 534 {"read", CmdLFRead, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
535 {"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"},
536 {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
537 {"simman", CmdLFSimManchester, 0, "<Clock> <Bitstream> [GAP] Simulate arbitrary Manchester LF tag"},
37239a7c 538 {"ti", CmdLFTI, 1, "{ TI RFIDs... }"},
db09cb3a 539 {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"},
7fe9b0b7 540 {"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"},
541 {NULL, NULL, 0, NULL}
542};
543
544int CmdLF(const char *Cmd)
545{
546 CmdsParse(CommandTable, Cmd);
547 return 0;
548}
549
550int CmdHelp(const char *Cmd)
551{
552 CmdsHelp(CommandTable);
553 return 0;
554}
Impressum, Datenschutz