]> git.zerfleddert.de Git - proxmark3-svn/blob - client/cmdhflegic.c
add LEGIC decoder (submitted by Sourcerer, untested by me)
[proxmark3-svn] / client / cmdhflegic.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "proxusb.h"
4 #include "cmdparser.h"
5 #include "cmdhflegic.h"
6 #include "cmdmain.h"
7 #include "data.h"
8 #include "ui.h"
9 #include <string.h>
10 #include <stdio.h>
11
12 static int CmdHelp(const char *Cmd);
13
14 int CmdLegicRFRead(const char *Cmd)
15 {
16 int byte_count=0,offset=0;
17 sscanf(Cmd, "%i %i", &offset, &byte_count);
18 if(byte_count == 0) byte_count = 256;
19 if(byte_count + offset > 256) byte_count = 256 - offset;
20 UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}};
21 SendCommand(&c);
22 return 0;
23 }
24
25 static command_t CommandTable[] =
26 {
27 {"help", CmdHelp, 1, "This help"},
28 {"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"},
29 {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"},
30 {NULL, NULL, 0, NULL}
31 };
32
33 int CmdHFLegic(const char *Cmd)
34 {
35 CmdsParse(CommandTable, Cmd);
36 return 0;
37 }
38
39 int CmdHelp(const char *Cmd)
40 {
41 CmdsHelp(CommandTable);
42 return 0;
43 }
44
45 /*
46 * Output BigBuf and deobfuscate LEGIC RF tag data.
47 * This is based on information given in the talk held
48 * by Henryk Ploetz and Karsten Nohl at 26c3
49 * FIXME: will crash if sample buffer does not contain valid legic data
50 */
51 int CmdLegicDecode(const char *Cmd)
52 {
53 int h, i, j, k, n;
54 int segment_len = 0;
55 int segment_flag = 0;
56 int stamp_len = 0;
57 int crc = 0;
58 int wrp = 0;
59 int wrc = 0;
60 int data_buf[1032]; // receiver buffer
61 char out_string[3076]; // just use big buffer - bad practice
62 char token_type[4];
63 int delivered = 0;
64
65 h = 0;
66
67 // copy data from proxmark into buffer
68 for (i = 0; i < 256; i += 12, h += 48) {
69 UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {i, 0, 0}};
70 SendCommand(&c);
71 WaitForResponse(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K);
72
73 for (j = 0; j < 48; j += 8) {
74 for (k = 0; k < 8; k++) {
75 data_buf[h+j+k] = sample_buf[j+k];
76 }
77 delivered += 8;
78 if (delivered >= 1024)
79 break;
80 }
81 }
82
83 // Output CDF System area (9 bytes) plus remaining header area (12 bytes)
84
85 PrintAndLog("\nCDF: System Area");
86
87 PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x",
88 data_buf[0],
89 data_buf[1],
90 data_buf[2],
91 data_buf[3],
92 data_buf[4]
93 );
94
95 crc = data_buf[4];
96
97 switch (data_buf[5]&0x7f) {
98 case 0x00 ... 0x2f:
99 strncpy(token_type, "IAM",sizeof(token_type));
100 break;
101 case 0x30 ... 0x6f:
102 strcpy(token_type, "SAM");
103 break;
104 case 0x70 ... 0x7f:
105 strcpy(token_type, "GAM");
106 break;
107 default:
108 strcpy(token_type, "???");
109 break;
110 }
111
112 stamp_len = 0xfc - data_buf[6];
113
114 PrintAndLog("DCF: %02x %02x, Token_Type=%s (OLE=%01u), Stamp_len=%02u",
115 data_buf[5],
116 data_buf[6],
117 token_type,
118 (data_buf[5]&0x80)>>7,
119 stamp_len
120 );
121
122 PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x",
123 data_buf[7]&0x0f,
124 (data_buf[7]&0x70)>>4,
125 (data_buf[7]&0x80)>>7,
126 data_buf[7],
127 data_buf[8]
128 );
129
130 PrintAndLog("Remaining Header Area");
131
132 PrintAndLog("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
133 data_buf[9],
134 data_buf[10],
135 data_buf[11],
136 data_buf[12],
137 data_buf[13],
138 data_buf[14],
139 data_buf[15],
140 data_buf[16],
141 data_buf[17],
142 data_buf[18],
143 data_buf[19],
144 data_buf[20],
145 data_buf[21]
146 );
147
148 PrintAndLog("\nADF: User Area");
149
150 i = 22;
151 for (n=0; n<64; n++) {
152 segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc);
153 segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4;
154
155 wrp = (data_buf[i+2]^crc);
156 wrc = ((data_buf[i+3]^crc)&0x70)>>4;
157
158 PrintAndLog("Segment %02u: raw header=%02x %02x %02x %02x, flag=%01x (valid=%01u, last=%01u), len=%04u, WRP=%02u, WRC=%02u, RD=%01u, CRC=%02x",
159 n,
160 data_buf[i]^crc,
161 data_buf[i+1]^crc,
162 data_buf[i+2]^crc,
163 data_buf[i+3]^crc,
164 segment_flag,
165 (segment_flag&0x4)>>2,
166 (segment_flag&0x8)>>3,
167 segment_len,
168 wrp,
169 wrc,
170 ((data_buf[i+3]^crc)&0x80)>>7,
171 (data_buf[i+4]^crc)
172 );
173
174 i+=5;
175
176 if (wrc>0) {
177 PrintAndLog("WRC protected area:");
178 for (k=0, j=0; k < wrc; k++, i++, j += 3) {
179 sprintf(&out_string[j], "%02x", (data_buf[i]^crc));
180 out_string[j+2] = ' ';
181 };
182
183 out_string[j] = '\0';
184
185 PrintAndLog("%s", out_string);
186 }
187
188 if (wrp>wrc) {
189 PrintAndLog("Remaining write protected area:");
190
191 for (k=0, j=0; k < (wrp-wrc); k++, i++, j += 3) {
192 sprintf(&out_string[j], "%02x", (data_buf[i]^crc));
193 out_string[j+2] = ' ';
194 };
195
196 out_string[j] = '\0';
197
198 PrintAndLog("%s", out_string);
199 if((wrp-wrc) == 8) {
200 sprintf(out_string,"Card ID: %2X%02X%02X",data_buf[i-4]^crc,data_buf[i-3]^crc,data_buf[i-2]^crc);
201 PrintAndLog("%s", out_string);
202 }
203 }
204
205 PrintAndLog("Remaining segment payload:");
206 for (k=0, j=0; k < (segment_len - wrp - 5); k++, i++, j += 3) {
207 sprintf(&out_string[j], "%02x", (data_buf[i]^crc));
208 out_string[j+2] = ' ';
209 };
210
211 out_string[j] = '\0';
212
213 PrintAndLog("%s", out_string);
214
215 // end with last segment
216 if (segment_flag & 0x8)
217 return 0;
218 };
219 return 0;
220 }
Impressum, Datenschutz