]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdhflegic.c
extracted download and signature verification functionality to a function in tools...
[proxmark3-svn] / client / cmdhflegic.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// High frequency Legic commands
9//-----------------------------------------------------------------------------
10
8e220a91 11#include <stdio.h>
12#include <string.h>
7fe9b0b7 13#include "proxusb.h"
41dab153 14#include "data.h"
15#include "ui.h"
7fe9b0b7 16#include "cmdparser.h"
17#include "cmdhflegic.h"
669c1b80 18#include "cmdmain.h"
7fe9b0b7 19
20static int CmdHelp(const char *Cmd);
21
7fe9b0b7 22static command_t CommandTable[] =
23{
24 {"help", CmdHelp, 1, "This help"},
669c1b80 25 {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"},
41dab153 26 {"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"},
3612a8a8 27 {"save", CmdLegicSave, 0, "<filename> [<length>] -- Store samples"},
28 {"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
29 {"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
30 {"write", CmdLegicRfWrite,0, "<offset> <length> -- Write sample buffer (user after load or read)"},
31 {"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
7fe9b0b7 32 {NULL, NULL, 0, NULL}
33};
34
35int CmdHFLegic(const char *Cmd)
36{
37 CmdsParse(CommandTable, Cmd);
38 return 0;
39}
40
41int CmdHelp(const char *Cmd)
42{
43 CmdsHelp(CommandTable);
44 return 0;
45}
669c1b80 46
47/*
48 * Output BigBuf and deobfuscate LEGIC RF tag data.
49 * This is based on information given in the talk held
50 * by Henryk Ploetz and Karsten Nohl at 26c3
669c1b80 51 */
52int CmdLegicDecode(const char *Cmd)
53{
54 int h, i, j, k, n;
55 int segment_len = 0;
56 int segment_flag = 0;
57 int stamp_len = 0;
58 int crc = 0;
59 int wrp = 0;
60 int wrc = 0;
61 int data_buf[1032]; // receiver buffer
62 char out_string[3076]; // just use big buffer - bad practice
63 char token_type[4];
64 int delivered = 0;
65
66 h = 0;
67
68 // copy data from proxmark into buffer
69 for (i = 0; i < 256; i += 12, h += 48) {
70 UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {i, 0, 0}};
71 SendCommand(&c);
72 WaitForResponse(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K);
73
74 for (j = 0; j < 48; j += 8) {
75 for (k = 0; k < 8; k++) {
76 data_buf[h+j+k] = sample_buf[j+k];
77 }
78 delivered += 8;
79 if (delivered >= 1024)
80 break;
81 }
82 }
83
84 // Output CDF System area (9 bytes) plus remaining header area (12 bytes)
85
86 PrintAndLog("\nCDF: System Area");
87
88 PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x",
89 data_buf[0],
90 data_buf[1],
91 data_buf[2],
92 data_buf[3],
93 data_buf[4]
94 );
95
96 crc = data_buf[4];
97
98 switch (data_buf[5]&0x7f) {
99 case 0x00 ... 0x2f:
100 strncpy(token_type, "IAM",sizeof(token_type));
101 break;
102 case 0x30 ... 0x6f:
103 strcpy(token_type, "SAM");
104 break;
105 case 0x70 ... 0x7f:
106 strcpy(token_type, "GAM");
107 break;
108 default:
109 strcpy(token_type, "???");
110 break;
111 }
112
113 stamp_len = 0xfc - data_buf[6];
114
115 PrintAndLog("DCF: %02x %02x, Token_Type=%s (OLE=%01u), Stamp_len=%02u",
116 data_buf[5],
117 data_buf[6],
118 token_type,
119 (data_buf[5]&0x80)>>7,
120 stamp_len
121 );
122
123 PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x",
124 data_buf[7]&0x0f,
125 (data_buf[7]&0x70)>>4,
126 (data_buf[7]&0x80)>>7,
127 data_buf[7],
128 data_buf[8]
129 );
130
131 PrintAndLog("Remaining Header Area");
132
133 PrintAndLog("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
134 data_buf[9],
135 data_buf[10],
136 data_buf[11],
137 data_buf[12],
138 data_buf[13],
139 data_buf[14],
140 data_buf[15],
141 data_buf[16],
142 data_buf[17],
143 data_buf[18],
144 data_buf[19],
145 data_buf[20],
146 data_buf[21]
147 );
148
149 PrintAndLog("\nADF: User Area");
150
41dab153 151 i = 22;
669c1b80 152 for (n=0; n<64; n++) {
153 segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc);
154 segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4;
155
156 wrp = (data_buf[i+2]^crc);
157 wrc = ((data_buf[i+3]^crc)&0x70)>>4;
158
159 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",
160 n,
161 data_buf[i]^crc,
162 data_buf[i+1]^crc,
163 data_buf[i+2]^crc,
164 data_buf[i+3]^crc,
165 segment_flag,
166 (segment_flag&0x4)>>2,
167 (segment_flag&0x8)>>3,
168 segment_len,
169 wrp,
170 wrc,
171 ((data_buf[i+3]^crc)&0x80)>>7,
172 (data_buf[i+4]^crc)
173 );
174
175 i+=5;
176
177 if (wrc>0) {
178 PrintAndLog("WRC protected area:");
31332265 179 for (k=0, j=0; k < wrc && j<(sizeof(out_string)-3); k++, i++, j += 3) {
669c1b80 180 sprintf(&out_string[j], "%02x", (data_buf[i]^crc));
181 out_string[j+2] = ' ';
182 };
183
184 out_string[j] = '\0';
185
186 PrintAndLog("%s", out_string);
187 }
188
189 if (wrp>wrc) {
190 PrintAndLog("Remaining write protected area:");
191
31332265 192 for (k=0, j=0; k < (wrp-wrc) && j<(sizeof(out_string)-3); k++, i++, j += 3) {
669c1b80 193 sprintf(&out_string[j], "%02x", (data_buf[i]^crc));
194 out_string[j+2] = ' ';
195 };
196
197 out_string[j] = '\0';
198
199 PrintAndLog("%s", out_string);
200 if((wrp-wrc) == 8) {
201 sprintf(out_string,"Card ID: %2X%02X%02X",data_buf[i-4]^crc,data_buf[i-3]^crc,data_buf[i-2]^crc);
202 PrintAndLog("%s", out_string);
203 }
204 }
205
206 PrintAndLog("Remaining segment payload:");
31332265 207 for (k=0, j=0; k < (segment_len - wrp - 5) && j<(sizeof(out_string)-3); k++, i++, j += 3) {
669c1b80 208 sprintf(&out_string[j], "%02x", (data_buf[i]^crc));
209 out_string[j+2] = ' ';
210 };
211
212 out_string[j] = '\0';
213
214 PrintAndLog("%s", out_string);
215
216 // end with last segment
217 if (segment_flag & 0x8)
218 return 0;
219 };
220 return 0;
221}
41dab153 222
223int CmdLegicRFRead(const char *Cmd)
224{
225 int byte_count=0,offset=0;
226 sscanf(Cmd, "%i %i", &offset, &byte_count);
a2b1414f 227 if(byte_count == 0) byte_count = -1;
228 if(byte_count + offset > 1024) byte_count = 1024 - offset;
41dab153 229 UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}};
230 SendCommand(&c);
231 return 0;
232}
3612a8a8 233
234int CmdLegicLoad(const char *Cmd)
235{
236 FILE *f = fopen(Cmd, "r");
237 if(!f) {
238 PrintAndLog("couldn't open '%s'", Cmd);
239 return -1;
240 }
241 char line[80]; int offset = 0; unsigned int data[8];
242 while(fgets(line, sizeof(line), f)) {
243 int res = sscanf(line, "%x %x %x %x %x %x %x %x",
244 &data[0], &data[1], &data[2], &data[3],
245 &data[4], &data[5], &data[6], &data[7]);
246 if(res != 8) {
247 PrintAndLog("Error: could not read samples");
248 fclose(f);
249 return -1;
250 }
251 UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 0, 0}};
252 int j; for(j = 0; j < 8; j++) {
253 c.d.asBytes[j] = data[j];
254 }
255 SendCommand(&c);
256 WaitForResponse(CMD_ACK);
257 offset += 8;
258 }
259 fclose(f);
260 PrintAndLog("loaded %u samples", offset);
261 return 0;
262}
263
264int CmdLegicSave(const char *Cmd)
265{
266 int n;
267 int requested = 1024;
268 int offset = 0;
269 char filename[1024];
270 sscanf(Cmd, " %s %i %i", filename, &requested, &offset);
271 if (offset % 4 != 0) {
272 PrintAndLog("Offset must be a multiple of 4");
273 return 0;
274 }
275 offset = offset/4;
276
277 int delivered = 0;
278
279 if (requested == 0) {
280 n = 12;
281 requested = 12;
282 } else {
283 n = requested/4;
284 }
285
286 FILE *f = fopen(filename, "w");
287 if(!f) {
288 PrintAndLog("couldn't open '%s'", Cmd+1);
289 return -1;
290 }
291
292 for (int i = offset; i < n+offset; i += 12) {
293 UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {i, 0, 0}};
294 SendCommand(&c);
295 WaitForResponse(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K);
296 for (int j = 0; j < 48; j += 8) {
297 fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
298 sample_buf[j+0],
299 sample_buf[j+1],
300 sample_buf[j+2],
301 sample_buf[j+3],
302 sample_buf[j+4],
303 sample_buf[j+5],
304 sample_buf[j+6],
305 sample_buf[j+7]
306 );
307 delivered += 8;
308 if (delivered >= requested)
309 break;
310 }
311 if (delivered >= requested)
312 break;
313 }
314
315 fclose(f);
316 PrintAndLog("saved %u samples", delivered);
317 return 0;
318}
319
320int CmdLegicRfSim(const char *Cmd)
321{
322 UsbCommand c={CMD_SIMULATE_TAG_LEGIC_RF};
323 c.arg[0] = 6;
324 c.arg[1] = 3;
325 c.arg[2] = 0;
326 sscanf(Cmd, " %i %i %i", &c.arg[0], &c.arg[1], &c.arg[2]);
327 SendCommand(&c);
328 return 0;
329}
330
331int CmdLegicRfWrite(const char *Cmd)
332{
333 UsbCommand c={CMD_WRITER_LEGIC_RF};
334 int res = sscanf(Cmd, " 0x%x 0x%x", &c.arg[0], &c.arg[1]);
335 if(res != 2) {
336 PrintAndLog("Please specify the offset and length as two hex strings");
337 return -1;
338 }
339 SendCommand(&c);
340 return 0;
341}
342
343int CmdLegicRfFill(const char *Cmd)
344{
345 UsbCommand cmd ={CMD_WRITER_LEGIC_RF};
346 int res = sscanf(Cmd, " 0x%x 0x%x 0x%x", &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
347 if(res != 3) {
348 PrintAndLog("Please specify the offset, length and value as two hex strings");
349 return -1;
350 }
351
352 int i;
353 UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
354 for(i = 0; i < 48; i++) {
355 c.d.asBytes[i] = cmd.arg[2];
356 }
357 for(i = 0; i < 22; i++) {
358 c.arg[0] = i*48;
359 SendCommand(&c);
360 WaitForResponse(CMD_ACK);
361 }
362 SendCommand(&cmd);
363 return 0;
364 }
365
Impressum, Datenschutz