This repository was archived by the owner on Feb 24, 2021. It is now read-only.
forked from Proxmark/proxmark3
-
-
Notifications
You must be signed in to change notification settings - Fork 116
Expand file tree
/
Copy pathcmdlfem4x.c
More file actions
1455 lines (1287 loc) · 47.4 KB
/
cmdlfem4x.c
File metadata and controls
1455 lines (1287 loc) · 47.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Low frequency EM4x commands
//-----------------------------------------------------------------------------
#include "cmdlfem4x.h"
uint64_t g_em410xid = 0;
static int CmdHelp(const char *Cmd);
//////////////// 410x commands
int usage_lf_em410x_demod(void){
PrintAndLogEx(NORMAL, "Usage: lf em 410x_demod [h] [clock] <0|1> [maxError]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " clock - set clock as integer, optional, if not set, autodetect.");
PrintAndLogEx(NORMAL, " <0|1> - 0 normal output, 1 for invert output");
PrintAndLogEx(NORMAL, " maxerror - set maximum allowed errors, default = 100.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 410x_demod = demod an EM410x Tag ID from GraphBuffer");
PrintAndLogEx(NORMAL, " lf em 410x_demod 32 = demod an EM410x Tag ID from GraphBuffer using a clock of RF/32");
PrintAndLogEx(NORMAL, " lf em 410x_demod 32 1 = demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data");
PrintAndLogEx(NORMAL, " lf em 410x_demod 1 = demod an EM410x Tag ID from GraphBuffer while inverting data");
PrintAndLogEx(NORMAL, " lf em 410x_demod 64 1 0 = demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors");
return 0;
}
int usage_lf_em410x_write(void) {
PrintAndLogEx(NORMAL, "Writes EM410x ID to a T55x7 / T5555 (Q5) tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_write [h] <id> <card> [clock]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " <id> - ID number");
PrintAndLogEx(NORMAL, " <card> - 0|1 T5555 (Q5) / T55x7");
PrintAndLogEx(NORMAL, " <clock> - 16|32|40|64, optional, set R/F clock rate, defaults to 64");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 410x_write 0F0368568B");
return 0;
}
int usage_lf_em410x_ws(void) {
PrintAndLogEx(NORMAL, "Watch 'nd Spoof, activates reader, waits until a EM410x tag gets presented then it starts simulating the found UID");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_spoof [h]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 410x_spoof");
return 0;
}
int usage_lf_em410x_clone(void) {
PrintAndLogEx(NORMAL, "Simulating EM410x tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_clone [h] <uid> <clock>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " uid - uid (10 HEX symbols)");
PrintAndLogEx(NORMAL, " clock - clock (32|64) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 410x_clone 0F0368568B");
PrintAndLogEx(NORMAL, " lf em 410x_clone 0F0368568B 32");
return 0;
}
int usage_lf_em410x_sim(void) {
PrintAndLogEx(NORMAL, "Simulating EM410x tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_sim [h] <uid> <clock>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " uid - uid (10 HEX symbols)");
PrintAndLogEx(NORMAL, " clock - clock (32|64) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 410x_sim 0F0368568B");
PrintAndLogEx(NORMAL, " lf em 410x_sim 0F0368568B 32");
return 0;
}
int usage_lf_em410x_brute(void) {
PrintAndLogEx(NORMAL, "Bruteforcing by emulating EM410x tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_brute [h] ids.txt [d 2000] [c clock]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " ids.txt - file with UIDs in HEX format, one per line");
PrintAndLogEx(NORMAL, " d (2000) - pause delay in milliseconds between UIDs simulation, default 1000 ms (optional)");
PrintAndLogEx(NORMAL, " c (32) - clock (32|64), default 64 (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 410x_brute ids.txt");
PrintAndLogEx(NORMAL, " lf em 410x_brute ids.txt c 32");
PrintAndLogEx(NORMAL, " lf em 410x_brute ids.txt d 3000");
PrintAndLogEx(NORMAL, " lf em 410x_brute ids.txt d 3000 c 32");
return 0;
}
//////////////// 4050 / 4450 commands
int usage_lf_em4x50_dump(void) {
PrintAndLogEx(NORMAL, "Dump EM4x50/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_dump [h] <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x50_dump");
PrintAndLogEx(NORMAL, " lf em 4x50_dump 11223344");
return 0;
}
int usage_lf_em4x50_read(void) {
PrintAndLogEx(NORMAL, "Read EM 4x50/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_read [h] <address> <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " address - memory address to read. (0-15)");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x50_read 1");
PrintAndLogEx(NORMAL, " lf em 4x50_read 1 11223344");
return 0;
}
int usage_lf_em4x50_write(void) {
PrintAndLogEx(NORMAL, "Write EM 4x50/4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_write [h] <address> <data> <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " address - memory address to write to. (0-15)");
PrintAndLogEx(NORMAL, " data - data to write (hex)");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x50_write 1 deadc0de");
PrintAndLogEx(NORMAL, " lf em 4x50_write 1 deadc0de 11223344");
return 0;
}
//////////////// 4205 / 4305 commands
int usage_lf_em4x05_dump(void) {
PrintAndLogEx(NORMAL, "Dump EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_dump [h] <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_dump");
PrintAndLogEx(NORMAL, " lf em 4x05_dump 11223344");
return 0;
}
int usage_lf_em4x05_read(void) {
PrintAndLogEx(NORMAL, "Read EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_read [h] <address> <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " address - memory address to read. (0-15)");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_read 1");
PrintAndLogEx(NORMAL, " lf em 4x05_read 1 11223344");
return 0;
}
int usage_lf_em4x05_write(void) {
PrintAndLogEx(NORMAL, "Write EM4x05/4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_write [h] <address> <data> <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " address - memory address to write to. (0-15)");
PrintAndLogEx(NORMAL, " data - data to write (hex)");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_write 1 deadc0de");
PrintAndLogEx(NORMAL, " lf em 4x05_write 1 deadc0de 11223344");
return 0;
}
int usage_lf_em4x05_info(void) {
PrintAndLogEx(NORMAL, "Tag information EM4205/4305/4469//4569 tags. Tag must be on antenna.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_info [h] <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_info");
PrintAndLogEx(NORMAL, " lf em 4x05_info deadc0de");
return 0;
}
/* 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
*/
// Construct the graph for emulating an EM410X tag
void ConstructEM410xEmulGraph(const char *uid,const uint8_t clock) {
int i, j, binary[4], parity[4];
uint32_t n;
/* clear our graph */
ClearGraph(0);
/* write 9 start bits */
for (i = 0; i < 9; i++)
AppendGraph(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(&uid[i], "%1x", &n);
for (j = 3; j >= 0; j--, n/= 2)
binary[j] = n % 2;
/* append each bit */
AppendGraph(0, clock, binary[0]);
AppendGraph(0, clock, binary[1]);
AppendGraph(0, clock, binary[2]);
AppendGraph(0, clock, binary[3]);
/* append parity bit */
AppendGraph(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 */
AppendGraph(0, clock, parity[0]);
AppendGraph(0, clock, parity[1]);
AppendGraph(0, clock, parity[2]);
AppendGraph(0, clock, parity[3]);
/* stop bit */
AppendGraph(1, clock, 0);
}
//by marshmellow
//print 64 bit EM410x ID in multiple formats
void printEM410x(uint32_t hi, uint64_t id) {
if (!id && !hi) return;
PrintAndLogEx(NORMAL, "EM410x %s pattern found", (hi) ? "XL" : "" );
uint64_t iii=1;
uint64_t id2lo=0;
uint32_t ii=0;
uint32_t i=0;
for (ii=5; ii>0;ii--){
for (i=0;i<8;i++){
id2lo=(id2lo<<1LL) | ((id & (iii << (i+((ii-1)*8)))) >> (i+((ii-1)*8)));
}
}
if (hi){
//output 88 bit em id
PrintAndLogEx(NORMAL, "\nEM TAG ID : %06X%016" PRIX64, hi, id);
} else {
//output 40 bit em id
PrintAndLogEx(NORMAL, "\nEM TAG ID : %010" PRIX64, id);
PrintAndLogEx(NORMAL, "\nPossible de-scramble patterns");
PrintAndLogEx(NORMAL, "Unique TAG ID : %010" PRIX64, id2lo);
PrintAndLogEx(NORMAL, "HoneyWell IdentKey {");
PrintAndLogEx(NORMAL, "DEZ 8 : %08" PRIu64, id & 0xFFFFFF);
PrintAndLogEx(NORMAL, "DEZ 10 : %010" PRIu64, id & 0xFFFFFFFF);
PrintAndLogEx(NORMAL, "DEZ 5.5 : %05" PRIu64 ".%05" PRIu64, (id>>16LL) & 0xFFFF, (id & 0xFFFF));
PrintAndLogEx(NORMAL, "DEZ 3.5A : %03" PRIu64 ".%05" PRIu64, (id>>32ll), (id & 0xFFFF));
PrintAndLogEx(NORMAL, "DEZ 3.5B : %03" PRIu64 ".%05" PRIu64, (id & 0xFF000000) >> 24, (id & 0xFFFF));
PrintAndLogEx(NORMAL, "DEZ 3.5C : %03" PRIu64 ".%05" PRIu64, (id & 0xFF0000) >> 16, (id & 0xFFFF));
PrintAndLogEx(NORMAL, "DEZ 14/IK2 : %014" PRIu64, id);
PrintAndLogEx(NORMAL, "DEZ 15/IK3 : %015" PRIu64, id2lo);
PrintAndLogEx(NORMAL, "DEZ 20/ZK : %02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64,
(id2lo & 0xf000000000) >> 36,
(id2lo & 0x0f00000000) >> 32,
(id2lo & 0x00f0000000) >> 28,
(id2lo & 0x000f000000) >> 24,
(id2lo & 0x0000f00000) >> 20,
(id2lo & 0x00000f0000) >> 16,
(id2lo & 0x000000f000) >> 12,
(id2lo & 0x0000000f00) >> 8,
(id2lo & 0x00000000f0) >> 4,
(id2lo & 0x000000000f)
);
uint64_t paxton = (((id>>32) << 24) | (id & 0xffffff)) + 0x143e00;
PrintAndLogEx(NORMAL, "}\nOther : %05" PRIu64 "_%03" PRIu64 "_%08" PRIu64, (id&0xFFFF), ((id>>16LL) & 0xFF), (id & 0xFFFFFF));
PrintAndLogEx(NORMAL, "Pattern Paxton : %" PRIu64 " [0x%" PRIX64 "]", paxton, paxton);
uint32_t p1id = (id & 0xFFFFFF);
uint8_t arr[32] = {0x00};
int i =0;
int j = 23;
for (; i < 24; ++i, --j ){
arr[i] = (p1id >> i) & 1;
}
uint32_t p1 = 0;
p1 |= arr[23] << 21;
p1 |= arr[22] << 23;
p1 |= arr[21] << 20;
p1 |= arr[20] << 22;
p1 |= arr[19] << 18;
p1 |= arr[18] << 16;
p1 |= arr[17] << 19;
p1 |= arr[16] << 17;
p1 |= arr[15] << 13;
p1 |= arr[14] << 15;
p1 |= arr[13] << 12;
p1 |= arr[12] << 14;
p1 |= arr[11] << 6;
p1 |= arr[10] << 2;
p1 |= arr[9] << 7;
p1 |= arr[8] << 1;
p1 |= arr[7] << 0;
p1 |= arr[6] << 8;
p1 |= arr[5] << 11;
p1 |= arr[4] << 3;
p1 |= arr[3] << 10;
p1 |= arr[2] << 4;
p1 |= arr[1] << 5;
p1 |= arr[0] << 9;
PrintAndLogEx(NORMAL, "Pattern 1 : %d [0x%X]", p1, p1);
uint16_t sebury1 = id & 0xFFFF;
uint8_t sebury2 = (id >> 16) & 0x7F;
uint32_t sebury3 = id & 0x7FFFFF;
PrintAndLogEx(NORMAL, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3);
}
}
/* 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
*/
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo ) {
size_t idx = 0;
uint8_t bits[512] = {0};
size_t size = sizeof(bits);
if ( !getDemodBuf(bits, &size) ) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x problem during copy from ASK demod");
return 0;
}
int ans = Em410xDecode(bits, &size, &idx, hi, lo);
if ( ans < 0){
if (ans == -1)
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x not only 0|1 in decoded bitstream");
else if (ans == -2)
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x not enough samples after demod");
else if (ans == -4)
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x preamble not found");
else if (ans == -5)
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x Size not correct: %d", size);
else if (ans == -6)
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x parity failed");
return 0;
}
if (!lo && !hi) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Em410x decoded to all zeros");
return 0;
}
//set GraphBuffer for clone or sim command
setDemodBuf(DemodBuffer, (size==40) ? 64 : 128, idx+1);
setClockGrid(g_DemodClock, g_DemodStartIdx + ((idx+1)*g_DemodClock));
PrintAndLogEx(DEBUG, "DEBUG: Em410x idx: %d, Len: %d, Printing Demod Buffer:", idx, size);
if (g_debugMode)
printDemodBuff();
if (verbose)
printEM410x(*hi, *lo);
return 1;
}
int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose) {
bool st = true;
if (!ASKDemod_ext(Cmd, false, false, 1, &st)) return 0;
return AskEm410xDecode(verbose, hi, lo);
}
// this read is the "normal" read, which download lf signal and tries to demod here.
int CmdEM410xRead(const char *Cmd) {
lf_read(true, 8192);
CmdEM410xDemod(Cmd);
return 0;
}
// this read loops on device side.
// uses the demod in lfops.c
int CmdEM410xRead_device(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0);
uint8_t findone = (cmdp == '1') ? 1 : 0;
UsbCommand c = {CMD_EM410X_DEMOD, {findone, 0, 0}};
SendCommand(&c);
return 0;
}
//by marshmellow
//takes 3 arguments - clock, invert and maxErr as integers
//attempts to demodulate ask while decoding manchester
//prints binary found and saves in graphbuffer for further commands
int CmdEM410xDemod(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 10 || cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_demod();
uint32_t hi = 0;
uint64_t lo = 0;
if(AskEm410xDemod(Cmd, &hi, &lo, true) != 1) return 0;
g_em410xid = lo;
return 1;
}
// emulate an EM410X tag
int CmdEM410xSim(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0);
if (cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_sim();
uint8_t uid[5] = {0x00};
/* clock is 64 in EM410x tags */
uint8_t clock = 64;
if (param_gethex(Cmd, 0, uid, 10)) {
PrintAndLogEx(NORMAL, "UID must include 10 HEX symbols");
return 0;
}
param_getdec(Cmd, 1, &clock);
PrintAndLogEx(NORMAL, "Starting simulating UID %02X%02X%02X%02X%02X clock: %d", uid[0],uid[1],uid[2],uid[3],uid[4],clock);
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation");
ConstructEM410xEmulGraph(Cmd, clock);
CmdLFSim("0"); //240 start_gap.
return 0;
}
int CmdEM410xBrute(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0};
FILE *f = NULL;
char buf[11];
uint32_t uidcnt = 0;
uint8_t stUidBlock = 20;
uint8_t *uidBlock = NULL, *p = NULL;
uint8_t uid[5] = {0x00};
/* clock is 64 in EM410x tags */
uint8_t clock = 64;
/* default pause time: 1 second */
uint32_t delay = 1000;
char cmdp = param_getchar(Cmd, 0);
if (cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_brute();
cmdp = param_getchar(Cmd, 1);
if (cmdp == 'd' || cmdp == 'D') {
delay = param_get32ex(Cmd, 2, 1000, 10);
param_getdec(Cmd, 4, &clock);
} else if (cmdp == 'c' || cmdp == 'C') {
param_getdec(Cmd, 2, &clock);
delay = param_get32ex(Cmd, 4, 1000, 10);
}
int filelen = param_getstr(Cmd, 0, filename, FILE_PATH_SIZE);
if (filelen == 0) {
PrintAndLogEx(WARNING, "Error: Please specify a filename");
return 1;
}
if ((f = fopen(filename, "r")) == NULL) {
PrintAndLogEx(WARNING, "Error: Could not open UIDs file [%s]", filename);
return 1;
}
uidBlock = calloc(stUidBlock, 5);
if (uidBlock == NULL) return 1;
while( fgets(buf, sizeof(buf), f) ) {
if (strlen(buf) < 10 || buf[9] == '\n') continue;
while (fgetc(f) != '\n' && !feof(f)); //goto next line
//The line start with # is comment, skip
if( buf[0]=='#' ) continue;
if (param_gethex(buf, 0, uid, 10)) {
PrintAndLogEx(NORMAL, "UIDs must include 10 HEX symbols");
free(uidBlock);
fclose(f);
return 1;
}
buf[10] = 0;
if ( stUidBlock - uidcnt < 2) {
p = realloc(uidBlock, 5 * (stUidBlock += 10) );
if (!p) {
PrintAndLogEx(WARNING, "Cannot allocate memory for UIDs");
free(uidBlock);
fclose(f);
return 1;
}
uidBlock = p;
}
memset(uidBlock + 5 * uidcnt, 0, 5);
num_to_bytes(strtoll(buf, NULL, 16), 5, uidBlock + 5 * uidcnt);
uidcnt++;
memset(buf, 0, sizeof(buf));
}
fclose(f);
if (uidcnt == 0) {
PrintAndLogEx(NORMAL, "No UIDs found in file");
free(uidBlock);
return 1;
}
PrintAndLogEx(NORMAL, "Loaded %d UIDs from %s, pause delay: %d ms", uidcnt, filename, delay);
// loop
for(uint32_t c = 0; c < uidcnt; ++c ) {
char testuid[11];
testuid[10] = 0;
if (ukbhit()) {
int gc = getchar(); (void)gc;
PrintAndLogEx(NORMAL, "\nAborted via keyboard!\n");
free(uidBlock);
return 0;
}
sprintf(testuid, "%010" PRIX64, bytes_to_num(uidBlock + 5*c, 5));
PrintAndLogEx(NORMAL, "Bruteforce %d / %d: simulating UID %s, clock %d", c + 1, uidcnt, testuid, clock);
ConstructEM410xEmulGraph(testuid, clock);
CmdLFSim("0"); //240 start_gap.
msleep(delay);
}
free(uidBlock);
return 0;
}
/* Function is equivalent of lf read + data samples + em410xread
* looped until an EM410x tag is detected
*
* Why is CmdSamples("16000")?
* TBD: Auto-grow sample size based on detected sample rate. IE: If the
* rate gets lower, then grow the number of samples
* Changed by martin, 4000 x 4 = 16000,
* see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235
*
* EDIT -- capture enough to get 2 complete preambles at the slowest data rate known to be used (rf/64) (64*64*2+9 = 8201) marshmellow
*/
int CmdEM410xWatch(const char *Cmd) {
do {
if (ukbhit()) {
int gc = getchar(); (void)gc;
PrintAndLogEx(NORMAL, "\naborted via keyboard!\n");
break;
}
lf_read(true, 8201);
} while (!CmdEM410xRead(""));
return 0;
}
//currently only supports manchester modulations
int CmdEM410xWatchnSpoof(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0);
if (cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_ws();
// loops if the captured ID was in XL-format.
CmdEM410xWatch(Cmd);
PrintAndLogEx(NORMAL, "# Replaying captured ID: %010" PRIx64 , g_em410xid);
CmdLFaskSim("");
return 0;
}
int CmdEM410xWrite(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0);
if (cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_write();
uint64_t id = 0xFFFFFFFFFFFFFFFF; // invalid id value
int card = 0xFF; // invalid card value
uint32_t clock = 0; // invalid clock value
sscanf(Cmd, "%" SCNx64 " %d %d", &id, &card, &clock);
// Check ID
if (id == 0xFFFFFFFFFFFFFFFF) {
PrintAndLogEx(WARNING, "Error! ID is required.\n");
return 0;
}
if (id >= 0x10000000000) {
PrintAndLogEx(WARNING, "Error! Given EM410x ID is longer than 40 bits.\n");
return 0;
}
// Check Card
if (card == 0xFF) {
PrintAndLogEx(WARNING, "Error! Card type required.\n");
return 0;
}
if (card < 0) {
PrintAndLogEx(WARNING, "Error! Bad card type selected.\n");
return 0;
}
// Check Clock
if (clock == 0)
clock = 64;
// Allowed clock rates: 16, 32, 40 and 64
if ((clock != 16) && (clock != 32) && (clock != 64) && (clock != 40)) {
PrintAndLogEx(WARNING, "Error! Clock rate %d not valid. Supported clock rates are 16, 32, 40 and 64.\n", clock);
return 0;
}
if (card == 1) {
PrintAndLogEx(NORMAL, "Writing %s tag with UID 0x%010" PRIx64 " (clock rate: %d)", "T55x7", id, clock);
// NOTE: We really should pass the clock in as a separate argument, but to
// provide for backwards-compatibility for older firmware, and to avoid
// having to add another argument to CMD_EM410X_WRITE_TAG, we just store
// the clock rate in bits 8-15 of the card value
card = (card & 0xFF) | ((clock << 8) & 0xFF00);
} else if (card == 0) {
PrintAndLogEx(NORMAL, "Writing %s tag with UID 0x%010" PRIx64, "T5555", id, clock);
card = (card & 0xFF) | ((clock << 8) & 0xFF00);
} else {
PrintAndLogEx(WARNING, "Error! Bad card type selected.\n");
return 0;
}
UsbCommand c = {CMD_EM410X_WRITE_TAG, {card, (uint32_t)(id >> 32), (uint32_t)id}};
SendCommand(&c);
return 0;
}
//**************** Start of EM4x50 Code ************************
bool EM_EndParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
if (rows*cols>size) return false;
uint8_t colP=0;
//assume last col is a parity and do not test
for (uint8_t colNum = 0; colNum < cols-1; colNum++) {
for (uint8_t rowNum = 0; rowNum < rows; rowNum++) {
colP ^= BitStream[(rowNum*cols)+colNum];
}
if (colP != pType) return false;
}
return true;
}
bool EM_ByteParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
if (rows*cols>size) return false;
uint8_t rowP=0;
//assume last row is a parity row and do not test
for (uint8_t rowNum = 0; rowNum < rows-1; rowNum++) {
for (uint8_t colNum = 0; colNum < cols; colNum++) {
rowP ^= BitStream[(rowNum*cols)+colNum];
}
if (rowP != pType) return false;
}
return true;
}
// EM word parity test.
// 9*5 = 45 bits in total
// 012345678|r1
// 012345678|r2
// 012345678|r3
// 012345678|r4
// ------------
//c012345678| 0
// |- must be zero
bool EMwordparitytest(uint8_t *bits){
// last row/col parity must be 0
if (bits[44] != 0 ) return false;
// col parity check
uint8_t c1 = bytebits_to_byte(bits, 8) ^ bytebits_to_byte(bits+9, 8) ^ bytebits_to_byte(bits+18, 8) ^ bytebits_to_byte(bits+27, 8);
uint8_t c2 = bytebits_to_byte(bits+36, 8);
if ( c1 != c2 ) return false;
// row parity check
uint8_t rowP = 0;
for ( uint8_t i = 0; i < 36; ++i ) {
rowP ^= bits[i];
if ( i>0 && (i % 9) == 0) {
if ( rowP != EVEN )
return false;
rowP = 0;
}
}
// all checks ok.
return true;
}
//////////////// 4050 / 4450 commands
uint32_t OutputEM4x50_Block(uint8_t *BitStream, size_t size, bool verbose, bool pTest) {
if (size<45) return 0;
uint32_t code = bytebits_to_byte(BitStream,8);
code = code<<8 | bytebits_to_byte(BitStream+9,8);
code = code<<8 | bytebits_to_byte(BitStream+18,8);
code = code<<8 | bytebits_to_byte(BitStream+27,8);
if (verbose || g_debugMode){
for (uint8_t i = 0; i<5; i++){
if (i == 4) PrintAndLogEx(NORMAL, ""); //parity byte spacer
PrintAndLogEx(NORMAL, "%d%d%d%d%d%d%d%d %d -> 0x%02x",
BitStream[i*9],
BitStream[i*9+1],
BitStream[i*9+2],
BitStream[i*9+3],
BitStream[i*9+4],
BitStream[i*9+5],
BitStream[i*9+6],
BitStream[i*9+7],
BitStream[i*9+8],
bytebits_to_byte(BitStream+i*9,8)
);
}
if (pTest)
PrintAndLogEx(NORMAL, "Parity Passed");
else
PrintAndLogEx(NORMAL, "Parity Failed");
}
return code;
}
/* Read the transmitted data of an EM4x50 tag from the graphbuffer
* 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.
*/
//completed by Marshmellow
int EM4x50Read(const char *Cmd, bool verbose) {
uint8_t fndClk[] = {8,16,32,40,50,64,128};
int clk = 0;
int invert = 0;
int tol = 0;
int i, j, startblock, skip, block, start, end, low, high, minClk;
bool complete = false;
int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
uint32_t Code[6];
char tmp[6];
char tmp2[20];
int phaseoff;
high = low = 0;
memset(tmpbuff, 0, sizeof(tmpbuff) );
// get user entry if any
sscanf(Cmd, "%i %i", &clk, &invert);
// 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];
}
i = 0;
j = 0;
minClk = 255;
// get to first full low to prime loop and skip incomplete first pulse
while ((GraphBuffer[i] < high) && (i < GraphTraceLen))
++i;
while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
++i;
skip = i;
// populate tmpbuff buffer with pulse lengths
while (i < GraphTraceLen) {
// measure from low to low
while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
++i;
start= i;
while ((GraphBuffer[i] < high) && (i < GraphTraceLen))
++i;
while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
++i;
if (j>=(MAX_GRAPH_TRACE_LEN/64)) {
break;
}
tmpbuff[j++]= i - start;
if (i-start < minClk && i < GraphTraceLen) {
minClk = i - start;
}
}
// set clock
if (!clk) {
for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) {
tol = fndClk[clkCnt]/8;
if (minClk >= fndClk[clkCnt]-tol && minClk <= fndClk[clkCnt]+1) {
clk=fndClk[clkCnt];
break;
}
}
if (!clk) {
if (verbose || g_debugMode) PrintAndLogEx(WARNING, "Error: EM4x50 - didn't find a clock");
return 0;
}
} else tol = clk/8;
// look for data start - should be 2 pairs of LW (pulses of clk*3,clk*2)
start = -1;
for (i= 0; i < j - 4 ; ++i) {
skip += tmpbuff[i];
if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol) //3 clocks
if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol) //2 clocks
if (tmpbuff[i+2] >= clk*3-tol && tmpbuff[i+2] <= clk*3+tol) //3 clocks
if (tmpbuff[i+3] >= clk-tol) //1.5 to 2 clocks - depends on bit following
{
start= i + 4;
break;
}
}
startblock = i + 4;
// skip over the remainder of LW
skip += tmpbuff[i+1] + tmpbuff[i+2] + clk;
if (tmpbuff[i+3]>clk)
phaseoff = tmpbuff[i+3]-clk;
else
phaseoff = 0;
// now do it again to find the end
end = skip;
for (i += 3; i < j - 4 ; ++i) {
end += tmpbuff[i];
if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol) //3 clocks
if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol) //2 clocks
if (tmpbuff[i+2] >= clk*3-tol && tmpbuff[i+2] <= clk*3+tol) //3 clocks
if (tmpbuff[i+3] >= clk-tol) //1.5 to 2 clocks - depends on bit following
{
complete= true;
break;
}
}
end = i;
// report back
if (verbose || g_debugMode) {
if (start >= 0) {
PrintAndLogEx(NORMAL, "\nNote: one block = 50 bits (32 data, 12 parity, 6 marker)");
} else {
PrintAndLogEx(NORMAL, "No data found!, clock tried:%d",clk);
PrintAndLogEx(NORMAL, "Try again with more samples.");
PrintAndLogEx(NORMAL, " or after a 'data askedge' command to clean up the read");
return 0;
}
} else if (start < 0) return 0;
start = skip;
snprintf(tmp2, sizeof(tmp2),"%d %d 1000 %d", clk, invert, clk*47);
// save GraphBuffer - to restore it later
save_restoreGB(GRAPH_SAVE);
// get rid of leading crap
snprintf(tmp, sizeof(tmp), "%i", skip);
CmdLtrim(tmp);
bool pTest;
bool AllPTest = true;
// now work through remaining buffer printing out data blocks
block = 0;
i = startblock;
while (block < 6) {
if (verbose || g_debugMode) PrintAndLogEx(NORMAL, "\nBlock %i:", block);
skip = phaseoff;
// look for LW before start of next block
for ( ; i < j - 4 ; ++i) {
skip += tmpbuff[i];
if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol)
if (tmpbuff[i+1] >= clk-tol)
break;
}
if (i >= j-4) break; //next LW not found
skip += clk;
if (tmpbuff[i+1]>clk)
phaseoff = tmpbuff[i+1]-clk;
else
phaseoff = 0;
i += 2;
if (ASKDemod(tmp2, false, false, 1) < 1) {
save_restoreGB(GRAPH_RESTORE);
return 0;
}
//set DemodBufferLen to just one block
DemodBufferLen = skip/clk;
//test parities
pTest = EM_ByteParityTest(DemodBuffer,DemodBufferLen,5,9,0);
pTest &= EM_EndParityTest(DemodBuffer,DemodBufferLen,5,9,0);
AllPTest &= pTest;
//get output
Code[block] = OutputEM4x50_Block(DemodBuffer,DemodBufferLen,verbose, pTest);
PrintAndLogEx(DEBUG, "\nskipping %d samples, bits:%d", skip, skip/clk);
//skip to start of next block
snprintf(tmp,sizeof(tmp),"%i",skip);
CmdLtrim(tmp);
block++;
if (i >= end) break; //in case chip doesn't output 6 blocks
}
//print full code:
if (verbose || g_debugMode || AllPTest){
if (!complete) {
PrintAndLogEx(NORMAL, "*** Warning!");
PrintAndLogEx(NORMAL, "Partial data - no end found!");
PrintAndLogEx(NORMAL, "Try again with more samples.");
}
PrintAndLogEx(NORMAL, "Found data at sample: %i - using clock: %i", start, clk);
end = block;
for (block=0; block < end; block++){
PrintAndLogEx(NORMAL, "Block %d: %08x",block,Code[block]);
}
if (AllPTest) {
PrintAndLogEx(NORMAL, "Parities Passed");
} else {
PrintAndLogEx(NORMAL, "Parities Failed");
PrintAndLogEx(NORMAL, "Try cleaning the read samples with 'data askedge'");
}
}
//restore GraphBuffer
save_restoreGB(GRAPH_RESTORE);
return (int)AllPTest;
}
int CmdEM4x50Read(const char *Cmd) {
uint8_t ctmp = param_getchar(Cmd, 0);
if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em4x50_read();
return EM4x50Read(Cmd, true);
}
int CmdEM4x50Write(const char *Cmd){
uint8_t ctmp = param_getchar(Cmd, 0);
if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em4x50_write();
PrintAndLogEx(NORMAL, "no implemented yet");
return 0;
}
int CmdEM4x50Dump(const char *Cmd){
uint8_t ctmp = param_getchar(Cmd, 0);
if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em4x50_dump();
PrintAndLogEx(NORMAL, "no implemented yet");
return 0;
}
#define EM_PREAMBLE_LEN 6
// download samples from device and copy to Graphbuffer
bool downloadSamplesEM(){
// 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
uint8_t got[6000];
if ( !GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 2500, false)) {
PrintAndLogEx(WARNING, "command execution time out");
return false;