fix one too small
[RRG-proxmark3.git] / client / src / cmdhflegic.c
blobb12ac869a76f86de25b94fb76710e4fc006141fb
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency Legic commands
17 //-----------------------------------------------------------------------------
18 #include "cmdhflegic.h"
20 #include <ctype.h> // tolower
22 #include "pm3line.h" // pm3line_read, pm3line_free
23 #include "cliparser.h"
24 #include "cmdparser.h" // command_t
25 #include "comms.h" // clearCommandBuffer
26 #include "cmdtrace.h"
27 #include "crc.h"
28 #include "crc16.h"
29 #include "fileutils.h" //saveFile
31 static int CmdHelp(const char *Cmd);
33 #define LEGIC_PRIME_MIM22 22
34 #define LEGIC_PRIME_MIM256 256
35 #define LEGIC_PRIME_MIM1024 1024
36 #define LEGIC_BLOCK_SIZE 8
37 #define LEGIC_PACKET_SIZE (PM3_CMD_DATA_SIZE - sizeof(legic_packet_t))
39 static bool legic_xor(uint8_t *data, uint16_t cardsize) {
41 if (cardsize <= 22) {
42 PrintAndLogEx(INFO, "No obsfuscation such small dump");
43 return false;
46 uint8_t crc = data[4];
47 uint32_t calc_crc = CRC8Legic(data, 4);
48 if (crc != calc_crc) {
49 PrintAndLogEx(INFO, "CRC mismatch, obsfuscation not possible");
50 return false;
53 for (uint16_t i = 22; i < cardsize; i++) {
54 data[i] ^= crc;
56 PrintAndLogEx(SUCCESS, "Applying xoring of data done!");
57 return true;
60 static int decode_and_print_memory(uint16_t card_size, const uint8_t *input_buffer) {
62 if (!(card_size == LEGIC_PRIME_MIM22 || card_size == LEGIC_PRIME_MIM256 || card_size == LEGIC_PRIME_MIM1024)) {
63 PrintAndLogEx(FAILED, "Bytebuffer is not any known legic card size! (MIM22, MIM256, MIM1024)");
64 return PM3_EFAILED;
67 // copy input buffer into newly allocated buffer, because the existing code mutates the data inside.
68 uint8_t *data = calloc(card_size, sizeof(uint8_t));
69 if (data == NULL) {
70 PrintAndLogEx(WARNING, "Cannot allocate memory");
71 return PM3_EMALLOC;
73 memcpy(data, input_buffer, card_size);
75 int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0;
76 int wrp = 0, wrc = 0, dcf = 0;
77 uint8_t stamp_len = 0;
78 char token_type[6] = {0, 0, 0, 0, 0, 0};
79 int bIsSegmented = 0;
80 int return_value = PM3_SUCCESS;
82 // Output CDF System area (9 bytes) plus remaining header area (12 bytes)
83 int crc = data[4];
84 uint32_t calc_crc = CRC8Legic(data, 4);
86 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ----------------------------------------");
87 PrintAndLogEx(NORMAL, "");
88 PrintAndLogEx(SUCCESS, " " _CYAN_("CDF: System Area"));
89 PrintAndLogEx(INFO, "------------------------------------------------------");
90 PrintAndLogEx(SUCCESS, "MCD: " _GREEN_("%02X") " MSN: " _GREEN_("%s") " MCC: " _GREEN_("%02X") " ( %s )",
91 data[0],
92 sprint_hex(data + 1, 3),
93 data[4],
94 (calc_crc == crc) ? _GREEN_("ok") : _RED_("fail")
97 // MCD = Manufacturer ID (should be list meaning something?)
99 token_type[0] = 0;
100 dcf = ((int)data[6] << 8) | (int)data[5];
102 // New unwritten media?
103 if (dcf == 0xFFFF) {
105 PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type=NM (New Media)",
106 dcf,
107 data[5],
108 data[6]
111 } else if (dcf > 60000) { // Master token?
113 int fl = 0;
115 if (data[6] == 0xEC) {
116 strncpy(token_type, "XAM", sizeof(token_type) - 1);
117 fl = 1;
118 stamp_len = 0x0c - (data[5] >> 4);
119 } else {
121 uint8_t tmp = data[5] & 0x7F;
122 if (tmp <= 0x2F) {
123 strncpy(token_type, "IAM", sizeof(token_type) - 1);
124 fl = (0x2F - tmp) + 1;
125 } else if (tmp >= 0x30 && tmp <= 0x6F) {
126 strncpy(token_type, "SAM", sizeof(token_type) - 1);
127 fl = (0x6F - tmp) + 1;
128 } else if (tmp >= 0x70 && tmp <= 0x7F) {
129 strncpy(token_type, "GAM", sizeof(token_type) - 1);
130 fl = (0x7F - tmp) + 1;
133 stamp_len = 0xFC - data[6];
136 PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x) Token Type=" _YELLOW_("%s") " (OLE=%01u) OL=%02u FL=%02u",
137 dcf,
138 data[5],
139 data[6],
140 token_type,
141 (data[5] & 0x80) >> 7,
142 stamp_len,
146 } else { // Is IM(-S) type of card...
148 if (data[7] == 0x9F && data[8] == 0xFF) {
149 bIsSegmented = 1;
150 strncpy(token_type, "IM-S", sizeof(token_type) - 1);
151 } else {
152 strncpy(token_type, "IM", sizeof(token_type) - 1);
155 PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x) Token Type = %s (OLE = %01u)",
156 dcf,
157 data[5],
158 data[6],
159 token_type,
160 (data[5] & 0x80) >> 7
164 // Makes no sense to show this on blank media...
165 if (dcf != 0xFFFF) {
167 if (bIsSegmented) {
168 PrintAndLogEx(SUCCESS, "WRP = %02u WRC = %01u RD = %01u SSC = %02X",
169 data[7] & 0x0f,
170 (data[7] & 0x70) >> 4,
171 (data[7] & 0x80) >> 7,
172 data[8]
176 // Header area is only available on IM-S cards, on master tokens this data is the master token data itself
177 if (bIsSegmented || dcf > 60000) {
178 if (dcf > 60000) {
179 PrintAndLogEx(SUCCESS, "Master token data");
180 PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 8, 14));
181 } else {
182 PrintAndLogEx(SUCCESS, "Remaining Header Area");
183 PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 9, 13));
187 PrintAndLogEx(INFO, "------------------------------------------------------");
189 uint8_t segCrcBytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
190 uint32_t segCalcCRC = 0;
191 uint32_t segCRC = 0;
193 // Not a data card by dcf or too small to contain data (MIM22)?
194 if (dcf > 60000 || card_size == LEGIC_PRIME_MIM22) {
195 goto out;
198 PrintAndLogEx(INFO, "");
199 PrintAndLogEx(SUCCESS, _CYAN_("ADF: User Area"));
200 PrintAndLogEx(INFO, "------------------------------------------------------");
202 if (bIsSegmented) {
204 // Data start point on segmented cards
205 i = 22;
207 // decode segments
208 for (segmentNum = 1; segmentNum < 128; segmentNum++) {
209 // for decoding the segment header we need at least 4 bytes left in buffer
210 if ((i + 4) > card_size) {
211 PrintAndLogEx(FAILED, "Cannot read segment header, because the input buffer is too small.");
212 PrintAndLogEx(FAILED, "Please check that the data is correct and properly aligned");
213 return_value = PM3_EOUTOFBOUND;
214 goto out;
216 segment_len = ((data[i + 1] ^ crc) & 0x0f) * 256 + (data[i] ^ crc);
217 segment_flag = ((data[i + 1] ^ crc) & 0xf0) >> 4;
218 wrp = (data[i + 2] ^ crc);
219 wrc = ((data[i + 3] ^ crc) & 0x70) >> 4;
221 bool hasWRC = (wrc > 0);
222 bool hasWRP = (wrp > wrc);
223 int wrp_len = (wrp - wrc);
224 int remain_seg_payload_len = (segment_len - wrp - 5);
226 // validate segment-crc
227 segCrcBytes[0] = data[0]; //uid0
228 segCrcBytes[1] = data[1]; //uid1
229 segCrcBytes[2] = data[2]; //uid2
230 segCrcBytes[3] = data[3]; //uid3
231 segCrcBytes[4] = (data[i] ^ crc); //hdr0
232 segCrcBytes[5] = (data[i + 1] ^ crc); //hdr1
233 segCrcBytes[6] = (data[i + 2] ^ crc); //hdr2
234 segCrcBytes[7] = (data[i + 3] ^ crc); //hdr3
236 segCalcCRC = CRC8Legic(segCrcBytes, 8);
237 segCRC = data[i + 4] ^ crc;
239 PrintAndLogEx(SUCCESS, "Segment....... " _YELLOW_("%02u"), segmentNum);
240 PrintAndLogEx(SUCCESS, "Raw header.... 0x%02X 0x%02X 0x%02X 0x%02X",
241 data[i] ^ crc,
242 data[i + 1] ^ crc,
243 data[i + 2] ^ crc,
244 data[i + 3] ^ crc
246 PrintAndLogEx(SUCCESS, "Segment len... %u Flag: 0x%X (valid:%01u last:%01u)",
247 segment_len,
248 segment_flag,
249 (segment_flag & 0x4) >> 2,
250 (segment_flag & 0x8) >> 3
252 PrintAndLogEx(SUCCESS, " WRP: %02u WRC: %02u RD: %01u CRC: 0x%02X ( %s )",
253 wrp,
254 wrc,
255 ((data[i + 3] ^ crc) & 0x80) >> 7,
256 segCRC,
257 (segCRC == segCalcCRC) ? _GREEN_("ok") : _RED_("fail")
260 i += 5;
262 // for printing the complete segment we need at least wrc + wrp_len + remain_seg_payload_len bytes
263 if ((i + wrc + wrp_len + remain_seg_payload_len) > card_size) {
264 PrintAndLogEx(FAILED, "Cannot read segment body, because the input buffer is too small. "
265 "Please check that the data is correct and properly aligned. ");
266 return_value = PM3_EOUTOFBOUND;
267 goto out;
270 if (hasWRC) {
271 PrintAndLogEx(INFO, "");
272 PrintAndLogEx(SUCCESS, _CYAN_("WRC protected area:") " (I %d | K %d| WRC %d)", i, k, wrc);
273 PrintAndLogEx(INFO, "");
274 PrintAndLogEx(INFO, "## | data | ascii");
275 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
277 for (k = i; k < (i + wrc); ++k)
278 data[k] ^= crc;
280 print_hex_break(data + i, wrc, 16);
281 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
282 PrintAndLogEx(INFO, "");
283 i += wrc;
286 if (hasWRP) {
287 PrintAndLogEx(SUCCESS, _CYAN_("Remaining write protected area:") " (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)", i, k, wrc, wrp, wrp_len);
288 PrintAndLogEx(INFO, "");
289 PrintAndLogEx(INFO, "## | data | ascii");
290 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
292 for (k = i; k < (i + wrp_len); ++k)
293 data[k] ^= crc;
295 print_hex_break(data + i, wrp_len, 16);
296 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
297 PrintAndLogEx(INFO, "");
298 i += wrp_len;
300 // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
301 if (wrp_len == 8) {
302 PrintAndLogEx(SUCCESS, "Card ID: " _YELLOW_("%2X%02X%02X"),
303 data[i - 4] ^ crc,
304 data[i - 3] ^ crc,
305 data[i - 2] ^ crc
309 if (remain_seg_payload_len > 0) {
310 PrintAndLogEx(SUCCESS, _CYAN_("Remaining segment payload:") " (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
311 PrintAndLogEx(INFO, "");
312 PrintAndLogEx(INFO, "## | data | ascii");
313 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
315 for (k = i; k < (i + remain_seg_payload_len); ++k)
316 data[k] ^= crc;
318 print_hex_break(data + i, remain_seg_payload_len, 16);
319 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------\n");
320 i += remain_seg_payload_len;
322 // end with last segment
323 if (segment_flag & 0x8)
324 goto out;
326 } // end for loop
328 } else {
329 // Data start point on unsegmented cards
330 i = 8;
332 wrp = data[7] & 0x0F;
333 wrc = (data[7] & 0x70) >> 4;
335 bool hasWRC = (wrc > 0);
336 bool hasWRP = (wrp > wrc);
337 int wrp_len = (wrp - wrc);
338 int remain_seg_payload_len = (card_size - 22 - wrp);
340 PrintAndLogEx(SUCCESS, "Unsegmented card - WRP: %02u WRC: %02u RD: %01u",
341 wrp,
342 wrc,
343 (data[7] & 0x80) >> 7
346 // for printing the complete segment we need at least wrc + wrp_len + remain_seg_payload_len bytes
347 if ((i + wrc + wrp_len + remain_seg_payload_len) > card_size) {
348 PrintAndLogEx(FAILED, "Cannot read segment body, because the input buffer is too small. "
349 "Please check that the data is correct and properly aligned. ");
350 return_value = PM3_EOUTOFBOUND;
351 goto out;
354 if (hasWRC) {
355 PrintAndLogEx(SUCCESS, _CYAN_("WRC protected area:") " (I %d | WRC %d)", i, wrc);
356 PrintAndLogEx(INFO, "");
357 PrintAndLogEx(INFO, "## | data | ascii");
358 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
359 print_hex_break(data + i, wrc, 16);
360 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
361 PrintAndLogEx(INFO, "");
362 i += wrc;
365 if (hasWRP) {
366 PrintAndLogEx(SUCCESS, _CYAN_("Remaining write protected area:") " (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len);
367 PrintAndLogEx(INFO, "");
368 PrintAndLogEx(INFO, "## | data | ascii");
369 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
370 print_hex_break(data + i, wrp_len, 16);
371 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
372 PrintAndLogEx(INFO, "");
373 i += wrp_len;
375 // Q: does this one work?
376 // A: Only if KGH/BGH is used with BCD encoded card number. Maybe this will show just garbage
377 if (wrp_len == 8) {
378 PrintAndLogEx(SUCCESS, "Card ID: " _YELLOW_("%2X%02X%02X"),
379 data[i - 4],
380 data[i - 3],
381 data[i - 2]
386 if (remain_seg_payload_len > 0) {
387 PrintAndLogEx(SUCCESS, _CYAN_("Remaining segment payload:") " (I %d | Remain LEN %d)", i, remain_seg_payload_len);
388 PrintAndLogEx(INFO, "");
389 PrintAndLogEx(INFO, "## | data | ascii");
390 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
391 print_hex_break(data + i, remain_seg_payload_len, 16);
392 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------\n");
396 out:
397 free(data);
398 return (return_value);
402 * Output BigBuf and deobfuscate LEGIC RF tag data.
403 * This is based on information given in the talk held
404 * by Henryk Ploetz and Karsten Nohl at 26c3
406 static int CmdLegicInfo(const char *Cmd) {
407 CLIParserContext *ctx;
408 CLIParserInit(&ctx, "hf legic info",
409 "Gets information from a LEGIC Prime tag like systemarea, user areas, etc",
410 "hf legic info");
412 void *argtable[] = {
413 arg_param_begin,
414 arg_lit0("v", "verbose", "verbose output"),
415 arg_param_end
417 CLIExecWithReturn(ctx, Cmd, argtable, true);
418 bool verbose = arg_get_lit(ctx, 1);
419 CLIParserFree(ctx);
421 uint16_t datalen = 0;
423 // tagtype
424 legic_card_select_t card;
425 if (legic_get_type(&card) != PM3_SUCCESS) {
426 PrintAndLogEx(WARNING, "Failed to identify tagtype");
427 return PM3_ESOFT;
430 PrintAndLogEx(SUCCESS, "Reading full tag memory of " _YELLOW_("%d") " bytes...", card.cardsize);
432 // allocate receiver buffer
433 uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
434 if (data == NULL) {
435 PrintAndLogEx(WARNING, "Cannot allocate memory");
436 return PM3_EMALLOC;
439 int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen);
440 if (status != PM3_SUCCESS) {
441 PrintAndLogEx(WARNING, "Failed reading memory");
442 free(data);
443 return status;
446 if (verbose) {
447 PrintAndLogEx(NORMAL, "");
448 PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
449 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
450 print_hex_break(data, datalen, 16);
453 PrintAndLogEx(NORMAL, "");
454 decode_and_print_memory(card.cardsize, data);
455 free(data);
456 return PM3_SUCCESS;
459 // params:
460 // offset in data memory
461 // number of bytes to read
462 static int CmdLegicRdbl(const char *Cmd) {
463 CLIParserContext *ctx;
464 CLIParserInit(&ctx, "hf legic rdbl",
465 "Read data from a LEGIC Prime tag",
466 "hf legic rdbl -o 0 -l 16 -> read 16 bytes from offset 0 (system header)\n"
467 "hf legic rdbl -o 0 -l 4 --iv 55 -> read 4 bytes from offset 0\n"
468 "hf legic rdbl -o 0 -l 256 --iv 55 -> read 256 bytes from offset 0");
470 void *argtable[] = {
471 arg_param_begin,
472 arg_int0("o", "offset", "<dec>", "offset in data array to start download from"),
473 arg_int0("l", "length", "<dec>", "number of bytes to read"),
474 arg_str0(NULL, "iv", "<hex>", "Initialization vector to use. Must be odd and 7bits max"),
475 arg_param_end
477 CLIExecWithReturn(ctx, Cmd, argtable, false);
479 int offset = arg_get_int_def(ctx, 1, 0);
480 int len = arg_get_int_def(ctx, 2, 16);
482 int iv_len = 0;
483 uint8_t iv[1] = {0x01};
484 CLIGetHexWithReturn(ctx, 3, iv, &iv_len);
485 CLIParserFree(ctx);
487 // sanity checks
488 if (len + offset >= LEGIC_PRIME_MIM1024) {
489 PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", LEGIC_PRIME_MIM1024, len + offset);
490 return PM3_EOUTOFBOUND;
493 PrintAndLogEx(SUCCESS, "Reading %d bytes, from offset %d", len, offset);
495 // allocate receiver buffer
496 uint8_t *data = calloc(len, sizeof(uint8_t));
497 if (!data) {
498 PrintAndLogEx(WARNING, "Cannot allocate memory");
499 return PM3_EMALLOC;
502 uint16_t datalen = 0;
503 int status = legic_read_mem(offset, len, iv[0], data, &datalen);
504 if (status == PM3_SUCCESS) {
505 PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
506 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
507 print_hex_break(data, datalen, 16);
509 free(data);
510 return status;
513 static int CmdLegicSim(const char *Cmd) {
514 CLIParserContext *ctx;
515 CLIParserInit(&ctx, "hf legic sim",
516 "Simulates a LEGIC Prime tag.\n"
517 "Following types supported (MIM22, MIM256, MIM1024)",
518 "hf legic sim --22\n"
521 void *argtable[] = {
522 arg_param_begin,
523 arg_lit0(NULL, "22", "LEGIC Prime MIM22"),
524 arg_lit0(NULL, "256", "LEGIC Prime MIM256 (def)"),
525 arg_lit0(NULL, "1024", "LEGIC Prime MIM1024"),
526 arg_param_end
528 CLIExecWithReturn(ctx, Cmd, argtable, true);
529 bool m1 = arg_get_lit(ctx, 1);
530 bool m2 = arg_get_lit(ctx, 2);
531 bool m3 = arg_get_lit(ctx, 3);
532 CLIParserFree(ctx);
534 // validations
535 if (m1 + m2 + m3 > 1) {
536 PrintAndLogEx(WARNING, "Only specify one LEGIC Prime Type");
537 return PM3_EINVARG;
538 } else if (m1 + m2 + m3 == 0) {
539 m2 = true;
542 struct {
543 uint8_t tagtype;
544 bool send_reply;
545 } PACKED payload;
547 payload.send_reply = true;
548 if (m1)
549 payload.tagtype = 0;
550 else if (m2)
551 payload.tagtype = 1;
552 else if (m3)
553 payload.tagtype = 2;
555 clearCommandBuffer();
556 SendCommandNG(CMD_HF_LEGIC_SIMULATE, (uint8_t *)&payload, sizeof(payload));
557 PacketResponseNG resp;
559 PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or " _GREEN_("<Enter>") " to abort simulation");
560 for (;;) {
561 if (kbd_enter_pressed()) {
562 SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
563 PrintAndLogEx(DEBUG, "User aborted");
564 break;
567 if (WaitForResponseTimeout(CMD_HF_LEGIC_SIMULATE, &resp, 1500)) {
568 break;
572 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf legic list") "` to view trace log");
573 PrintAndLogEx(INFO, "Done!");
574 return PM3_SUCCESS;
577 static int CmdLegicWrbl(const char *Cmd) {
578 CLIParserContext *ctx;
579 CLIParserInit(&ctx, "hf legic wrbl",
580 "Write data to a LEGIC Prime tag. It autodetects tagsize to ensure proper write",
581 "hf legic wrbl -o 0 -d 11223344 -> Write 0x11223344 starting from offset 0)\n"
582 "hf legic wrbl -o 10 -d DEADBEEF -> Write 0xdeadbeef starting from offset 10");
584 void *argtable[] = {
585 arg_param_begin,
586 arg_int1("o", "offset", "<dec>", "offset in data array to start writing"),
587 arg_str1("d", "data", "<hex>", "data to write"),
588 arg_lit0(NULL, "danger", "Auto-confirm dangerous operations"),
589 arg_param_end
591 CLIExecWithReturn(ctx, Cmd, argtable, false);
593 int offset = arg_get_int_def(ctx, 1, 0);
595 int dlen = 0;
596 uint8_t data[LEGIC_PRIME_MIM1024] = {0};
597 CLIGetHexWithReturn(ctx, 2, data, &dlen);
599 bool autoconfirm = arg_get_lit(ctx, 3);
601 CLIParserFree(ctx);
603 // OUT-OF-BOUNDS checks
604 // UID 4+1 bytes can't be written to.
605 if (offset < 5) {
606 PrintAndLogEx(WARNING, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset);
607 return PM3_EOUTOFBOUND;
610 // tagtype
611 legic_card_select_t card;
612 if (legic_get_type(&card) != PM3_SUCCESS) {
613 PrintAndLogEx(WARNING, "Failed to identify tagtype");
614 return PM3_ESOFT;
617 legic_print_type(card.cardsize, 0);
619 if (dlen + offset > card.cardsize) {
620 PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, dlen + offset);
621 return PM3_EOUTOFBOUND;
624 if ((offset == 5 || offset == 6) && (! autoconfirm)) {
625 PrintAndLogEx(INFO, "############# DANGER ################");
626 PrintAndLogEx(WARNING, "# changing the DCF is irreversible #");
627 PrintAndLogEx(INFO, "#####################################");
628 const char *confirm = "Do you really want to continue? y(es)/n(o) : ";
629 bool overwrite = false;
630 char *answer = pm3line_read(confirm);
631 overwrite = (answer[0] == 'y' || answer[0] == 'Y');
632 pm3line_free(answer);
633 if (overwrite == false) {
634 PrintAndLogEx(WARNING, "command cancelled");
635 return PM3_EOPABORTED;
639 uint32_t IV = 0x55;
640 legic_chk_iv(&IV);
642 PrintAndLogEx(SUCCESS, "Writing to tag to offset %i", offset);
644 legic_packet_t *payload = calloc(1, sizeof(legic_packet_t) + dlen);
645 payload->offset = (offset & 0xFFFF);
646 payload->iv = (IV & 0x7F);
647 payload->len = dlen;
648 memcpy(payload->data, data, dlen);
650 PacketResponseNG resp;
651 clearCommandBuffer();
652 SendCommandNG(CMD_HF_LEGIC_WRITER, (uint8_t *)payload, sizeof(legic_packet_t) + dlen);
653 free(payload);
655 uint8_t timeout = 0;
656 while (WaitForResponseTimeout(CMD_HF_LEGIC_WRITER, &resp, 2000) == false) {
657 ++timeout;
658 PrintAndLogEx(NORMAL, "." NOLF);
659 if (timeout > 10) {
660 PrintAndLogEx(WARNING, "\ncommand execution time out");
661 return PM3_ETIMEOUT;
664 PrintAndLogEx(NORMAL, "");
666 if (resp.status != PM3_SUCCESS) {
667 PrintAndLogEx(WARNING, "Failed writing tag");
668 return PM3_ERFTRANS;
671 return PM3_SUCCESS;
674 static int CmdLegicCalcCrc(const char *Cmd) {
675 CLIParserContext *ctx;
676 CLIParserInit(&ctx, "hf legic crc",
677 "Calculates the legic crc8/crc16 on the given data",
678 "hf legic crc -d deadbeef1122\n"
679 "hf legic crc -d deadbeef1122 --mcc 9A -t 16 -> CRC Type 16");
681 void *argtable[] = {
682 arg_param_begin,
683 arg_str1("d", "data", "<hex>", "bytes to calculate crc over"),
684 arg_str0(NULL, "mcc", "<hex>", "MCC hex byte (UID CRC)"),
685 arg_int0("t", "type", "<dec>", "CRC Type (default: 8)"),
686 arg_param_end
688 CLIExecWithReturn(ctx, Cmd, argtable, false);
690 int data_len = 0;
691 uint8_t data[4096] = {0};
693 CLIGetHexWithReturn(ctx, 1, data, &data_len);
695 int mcc_len = 0;
696 uint8_t mcc[1] = {0}; // formerly uidcrc
698 CLIGetHexWithReturn(ctx, 2, mcc, &mcc_len);
700 int type = arg_get_int_def(ctx, 3, 0);
702 CLIParserFree(ctx);
704 switch (type) {
705 case 16:
706 init_table(CRC_LEGIC_16);
707 PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, data_len, mcc[0]));
708 break;
709 default:
710 PrintAndLogEx(SUCCESS, "Legic crc8: %X", CRC8Legic(data, data_len));
711 break;
714 return PM3_SUCCESS;
717 int legic_read_mem(uint32_t offset, uint32_t len, uint32_t iv, uint8_t *out, uint16_t *outlen) {
719 legic_chk_iv(&iv);
721 legic_packet_t *payload = calloc(1, sizeof(legic_packet_t));
722 payload->offset = (offset & 0xFFFF);
723 payload->iv = iv;
724 payload->len = len;
726 clearCommandBuffer();
727 SendCommandNG(CMD_HF_LEGIC_READER, (uint8_t *)payload, sizeof(legic_packet_t));
728 free(payload);
729 PacketResponseNG resp;
731 uint8_t timeout = 0;
732 while (WaitForResponseTimeout(CMD_HF_LEGIC_READER, &resp, 1000) == false) {
733 ++timeout;
734 PrintAndLogEx(NORMAL, "." NOLF);
735 if (timeout > 14) {
736 PrintAndLogEx(WARNING, "\ncommand execution time out");
737 return PM3_ETIMEOUT;
740 PrintAndLogEx(NORMAL, "");
742 *outlen = resp.data.asDwords[0];
743 if (resp.status != PM3_SUCCESS) {
744 PrintAndLogEx(WARNING, "Failed reading tag");
745 return PM3_ESOFT;
748 if (*outlen != len)
749 PrintAndLogEx(WARNING, "Fail, only managed to read %u bytes", *outlen);
751 // copy data from device
752 if (GetFromDevice(BIG_BUF_EML, out, *outlen, 0, NULL, 0, NULL, 2500, false) == false) {
753 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
754 return PM3_ETIMEOUT;
756 return PM3_SUCCESS;
759 int legic_print_type(uint32_t tagtype, uint8_t spaces) {
760 char spc[11] = " ";
761 spc[10] = 0x00;
762 char *spacer = spc + (10 - spaces);
764 if (tagtype == LEGIC_PRIME_MIM22)
765 PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("MIM%d card (outdated)"), spacer, tagtype);
766 else if (tagtype == LEGIC_PRIME_MIM256)
767 PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("MIM%d card (234 bytes)"), spacer, tagtype);
768 else if (tagtype == LEGIC_PRIME_MIM1024)
769 PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("MIM%d card (1002 bytes)"), spacer, tagtype);
770 else
771 PrintAndLogEx(INFO, "%sTYPE: " _YELLOW_("Unknown %06x"), spacer, tagtype);
772 return PM3_SUCCESS;
774 int legic_get_type(legic_card_select_t *card) {
776 if (card == NULL)
777 return PM3_EINVARG;
779 clearCommandBuffer();
780 SendCommandNG(CMD_HF_LEGIC_INFO, NULL, 0);
781 PacketResponseNG resp;
782 if (WaitForResponseTimeout(CMD_HF_LEGIC_INFO, &resp, 1500) == false)
783 return PM3_ETIMEOUT;
785 if (resp.status != PM3_SUCCESS)
786 return PM3_ESOFT;
788 memcpy(card, resp.data.asBytes, sizeof(legic_card_select_t));
789 return PM3_SUCCESS;
792 void legic_chk_iv(uint32_t *iv) {
793 if ((*iv & 0x7F) != *iv) {
794 *iv &= 0x7F;
795 PrintAndLogEx(INFO, "Truncating IV to 7bits, %u", *iv);
797 // IV must be odd
798 if ((*iv & 1) == 0) {
799 *iv |= 0x01;
800 PrintAndLogEx(INFO, "LSB of IV must be SET %u", *iv);
804 void legic_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) {
806 PrintAndLogEx(INFO, "Uploading to emulator memory");
807 PrintAndLogEx(INFO, "." NOLF);
809 // fast push mode
810 g_conn.block_after_ACK = true;
811 for (size_t i = offset; i < numofbytes; i += LEGIC_PACKET_SIZE) {
813 size_t len = MIN((numofbytes - i), LEGIC_PACKET_SIZE);
814 if (len == numofbytes - i) {
815 // Disable fast mode on last packet
816 g_conn.block_after_ACK = false;
819 legic_packet_t *payload = calloc(1, sizeof(legic_packet_t) + len);
820 payload->offset = i;
821 payload->len = len;
822 memcpy(payload->data, src + i, len);
824 clearCommandBuffer();
825 SendCommandNG(CMD_HF_LEGIC_ESET, (uint8_t *)payload, sizeof(legic_packet_t) + len);
826 free(payload);
827 PrintAndLogEx(NORMAL, "." NOLF);
828 fflush(stdout);
830 PrintAndLogEx(NORMAL, "");
831 PrintAndLogEx(SUCCESS, "uploaded " _YELLOW_("%d") " bytes to emulator memory", numofbytes);
834 static int CmdLegicReader(const char *Cmd) {
835 CLIParserContext *ctx;
836 CLIParserInit(&ctx, "hf legic reader",
837 "Read UID and type information from a LEGIC Prime tag",
838 "hf legic reader");
840 void *argtable[] = {
841 arg_param_begin,
842 arg_lit0("@", NULL, "optional - continuous reader mode"),
843 arg_param_end
845 CLIExecWithReturn(ctx, Cmd, argtable, true);
846 bool cm = arg_get_lit(ctx, 1);
847 CLIParserFree(ctx);
849 if (cm) {
850 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
853 return readLegicUid(cm, true);
856 static int CmdLegicDump(const char *Cmd) {
857 CLIParserContext *ctx;
858 CLIParserInit(&ctx, "hf legic dump",
859 "Read all memory from LEGIC Prime tags and saves to (bin/json) dump file\n"
860 "It autodetects card type (MIM22, MIM256, MIM1024)",
861 "hf legic dump --> use UID as filename\n"
862 "hf legic dump -f myfile \n"
863 "hf legic dump --de --> use UID as filename and deobfuscate data");
865 void *argtable[] = {
866 arg_param_begin,
867 arg_str0("f", "file", "<fn>", "Dump filename"),
868 arg_lit0(NULL, "de", "deobfuscate dump data (xor with MCC)"),
869 arg_param_end
871 CLIExecWithReturn(ctx, Cmd, argtable, true);
873 int fnlen = 0;
874 char filename[FILE_PATH_SIZE] = {0};
875 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
877 bool shall_deobsfuscate = arg_get_lit(ctx, 2);
878 CLIParserFree(ctx);
880 // tagtype
881 legic_card_select_t card;
882 if (legic_get_type(&card) != PM3_SUCCESS) {
883 PrintAndLogEx(WARNING, "Failed to identify tagtype");
884 return PM3_ESOFT;
886 uint16_t dumplen = card.cardsize;
888 legic_print_type(dumplen, 0);
889 PrintAndLogEx(SUCCESS, "Reading tag memory." NOLF);
891 legic_packet_t *payload = calloc(1, sizeof(legic_packet_t));
892 payload->offset = 0;
893 payload->iv = 0x55;
894 payload->len = dumplen;
896 clearCommandBuffer();
897 SendCommandNG(CMD_HF_LEGIC_READER, (uint8_t *)payload, sizeof(legic_packet_t));
898 free(payload);
899 PacketResponseNG resp;
901 uint8_t timeout = 0;
902 while (WaitForResponseTimeout(CMD_HF_LEGIC_READER, &resp, 2000) == false) {
903 ++timeout;
904 PrintAndLogEx(NORMAL, "." NOLF);
905 if (timeout > 10) {
906 PrintAndLogEx(WARNING, "\ncommand execution time out");
907 return PM3_ETIMEOUT;
910 PrintAndLogEx(NORMAL, "");
912 if (resp.status != PM3_SUCCESS) {
913 PrintAndLogEx(WARNING, "Failed dumping tag data");
914 return PM3_ERFTRANS;
917 uint16_t readlen = resp.data.asDwords[0];
918 uint8_t *data = calloc(readlen, sizeof(uint8_t));
919 if (!data) {
920 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
921 return PM3_EMALLOC;
924 if (readlen != dumplen)
925 PrintAndLogEx(WARNING, "Fail, only managed to read 0x%02X bytes of 0x%02X", readlen, dumplen);
927 // copy data from device
928 if (GetFromDevice(BIG_BUF_EML, data, readlen, 0, NULL, 0, NULL, 2500, false) == false) {
929 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
930 free(data);
931 return PM3_ETIMEOUT;
934 if (shall_deobsfuscate) {
935 // Deobfuscate the whole dump. Unused data (after the last sector) will be MCC since
936 // 0x00 ^ MCC = MCC. Finding the end of used data is not part of this function.
937 if (legic_xor(data, dumplen) == false) {
938 PrintAndLogEx(FAILED, "Deobsfuscate failed, exiting...");
939 PrintAndLogEx(HINT, "Try running command without `--de` parameter");
940 free(data);
941 return PM3_EFAILED;
945 // user supplied filename?
946 if (fnlen < 1) {
947 PrintAndLogEx(INFO, "Using UID as filename");
948 strcat(filename, "hf-legic-");
949 FillFileNameByUID(filename, data, "-dump", 4);
952 pm3_save_dump(filename, data, readlen, jsfLegic_v2);
953 free(data);
954 return PM3_SUCCESS;
957 static int CmdLegicRestore(const char *Cmd) {
958 CLIParserContext *ctx;
959 CLIParserInit(&ctx, "hf legic restore",
960 "Reads (bin/eml/json) file and it autodetects card type and verifies that the file has the same size\n"
961 "Then write the data back to card. All bytes except the first 7bytes [UID(4) MCC(1) DCF(2)]",
962 "hf legic restore -f myfile --> use user specified filename\n"
963 "hf legic restore -f myfile --ob --> use UID as filename and obfuscate data");
965 void *argtable[] = {
966 arg_param_begin,
967 arg_str1("f", "file", "<fn>", "Specify a filename to restore"),
968 arg_lit0(NULL, "ob", "obfuscate dump data (xor with MCC)"),
969 arg_param_end
971 CLIExecWithReturn(ctx, Cmd, argtable, false);
973 int fnlen = 0;
974 char filename[FILE_PATH_SIZE] = {0};
975 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
977 bool shall_obsfuscate = arg_get_lit(ctx, 2);
978 CLIParserFree(ctx);
980 // tagtype
981 legic_card_select_t card;
982 if (legic_get_type(&card) != PM3_SUCCESS) {
983 PrintAndLogEx(WARNING, "Failed to identify tagtype");
984 return PM3_ESOFT;
987 legic_print_type(card.cardsize, 0);
989 // read dump file
990 uint8_t *dump = NULL;
991 size_t bytes_read = 0;
992 int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, LEGIC_PRIME_MIM1024);
993 if (res != PM3_SUCCESS) {
994 return res;
997 // validation
998 if (card.cardsize != bytes_read) {
999 PrintAndLogEx(WARNING, "Fail, filesize and cardsize is not equal. [%u != %zu]", card.cardsize, bytes_read);
1000 free(dump);
1001 return PM3_EFILE;
1004 if (shall_obsfuscate) {
1005 if (legic_xor(dump, card.cardsize) == false) {
1006 PrintAndLogEx(FAILED, "Obsfuscate failed, exiting...");
1007 PrintAndLogEx(HINT, "Try running command without `--ob` parameter");
1008 free(dump);
1009 return PM3_EFAILED;
1013 PrintAndLogEx(SUCCESS, "Restoring to card");
1015 // fast push mode
1016 g_conn.block_after_ACK = true;
1018 // transfer to device
1019 PacketResponseNG resp;
1020 // 7 = skip UID bytes and MCC
1021 for (size_t i = 7; i < bytes_read; i += LEGIC_PACKET_SIZE) {
1023 size_t len = MIN((bytes_read - i), LEGIC_PACKET_SIZE);
1024 if (len == bytes_read - i) {
1025 // Disable fast mode on last packet
1026 g_conn.block_after_ACK = false;
1029 legic_packet_t *payload = calloc(1, sizeof(legic_packet_t) + len);
1030 payload->offset = i;
1031 payload->iv = 0x55;
1032 payload->len = len;
1033 memcpy(payload->data, dump + i, len);
1035 clearCommandBuffer();
1036 SendCommandNG(CMD_HF_LEGIC_WRITER, (uint8_t *)payload, sizeof(legic_packet_t) + len);
1037 free(payload);
1039 uint8_t timeout = 0;
1040 while (WaitForResponseTimeout(CMD_HF_LEGIC_WRITER, &resp, 2000) == false) {
1041 ++timeout;
1042 PrintAndLogEx(NORMAL, "." NOLF);
1043 if (timeout > 10) {
1044 PrintAndLogEx(WARNING, "\ncommand execution time out");
1045 free(dump);
1046 return PM3_ETIMEOUT;
1049 PrintAndLogEx(NORMAL, "");
1051 if (resp.status != PM3_SUCCESS) {
1052 PrintAndLogEx(WARNING, "Failed writing tag");
1053 free(dump);
1054 return PM3_ERFTRANS;
1056 PrintAndLogEx(SUCCESS, "Wrote chunk [offset %zu | len %zu | total %zu", i, len, i + len);
1059 free(dump);
1060 PrintAndLogEx(SUCCESS, "Done!");
1061 return PM3_SUCCESS;
1064 static int CmdLegicELoad(const char *Cmd) {
1065 CLIParserContext *ctx;
1066 CLIParserInit(&ctx, "hf legic eload",
1067 "Loads a LEGIC Prime dump file into emulator memory",
1068 "hf legic eload -f myfile\n"
1069 "hf legic eload -f myfile --obfuscate\n"
1072 void *argtable[] = {
1073 arg_param_begin,
1074 arg_str1("f", "file", "<fn>", "Filename to load"),
1075 arg_lit0(NULL, "obfuscate", "Obfuscate dump data (xor with MCC)"),
1076 arg_param_end
1078 CLIExecWithReturn(ctx, Cmd, argtable, false);
1080 int fnlen = 0;
1081 char filename[FILE_PATH_SIZE] = {0};
1082 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1084 bool shall_obsfuscate = arg_get_lit(ctx, 2);
1085 CLIParserFree(ctx);
1087 // read dump file
1088 uint8_t *dump = NULL;
1089 size_t bytes_read = 0;
1090 int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, LEGIC_PRIME_MIM1024);
1091 if (res != PM3_SUCCESS) {
1092 return res;
1095 // validation
1096 if (bytes_read != LEGIC_PRIME_MIM22 &&
1097 bytes_read != LEGIC_PRIME_MIM256 &&
1098 bytes_read != LEGIC_PRIME_MIM1024) {
1099 PrintAndLogEx(ERR, "File content error. Read %zu bytes", bytes_read);
1100 free(dump);
1101 return PM3_EFILE;
1104 if (shall_obsfuscate) {
1105 legic_xor(dump, bytes_read);
1108 legic_seteml(dump, 0, bytes_read);
1110 free(dump);
1112 PrintAndLogEx(HINT, "You are ready to simulate. See " _YELLOW_("`hf legic sim -h`"));
1113 PrintAndLogEx(SUCCESS, "Done!");
1114 return PM3_SUCCESS;
1117 static int CmdLegicESave(const char *Cmd) {
1118 CLIParserContext *ctx;
1119 CLIParserInit(&ctx, "hf legic esave",
1120 "Saves a (bin/json) dump file of emulator memory",
1121 "hf legic esave --> uses UID as filename\n"
1122 "hf legic esave -f myfile --22\n"
1123 "hf legic esave -f myfile --22 --de\n"
1126 void *argtable[] = {
1127 arg_param_begin,
1128 arg_str0("f", "file", "<fn>", "Filename to save"),
1129 arg_lit0(NULL, "22", "LEGIC Prime MIM22"),
1130 arg_lit0(NULL, "256", "LEGIC Prime MIM256 (def)"),
1131 arg_lit0(NULL, "1024", "LEGIC Prime MIM1024"),
1132 arg_lit0(NULL, "de", "De-obfuscate dump data (xor with MCC)"),
1133 arg_param_end
1135 CLIExecWithReturn(ctx, Cmd, argtable, true);
1137 int fnlen = 0;
1138 char filename[FILE_PATH_SIZE] = {0};
1139 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1141 bool m1 = arg_get_lit(ctx, 2);
1142 bool m2 = arg_get_lit(ctx, 3);
1143 bool m3 = arg_get_lit(ctx, 4);
1144 bool shall_deobsfuscate = arg_get_lit(ctx, 5);
1145 CLIParserFree(ctx);
1147 // validations
1148 if (m1 + m2 + m3 > 1) {
1149 PrintAndLogEx(WARNING, "Only specify one LEGIC Prime Type");
1150 return PM3_EINVARG;
1151 } else if (m1 + m2 + m3 == 0) {
1152 m2 = true;
1155 size_t numofbytes = LEGIC_PRIME_MIM256;
1156 if (m1)
1157 numofbytes = LEGIC_PRIME_MIM22;
1158 else if (m2)
1159 numofbytes = LEGIC_PRIME_MIM256;
1160 else if (m3)
1161 numofbytes = LEGIC_PRIME_MIM1024;
1163 // set up buffer
1164 uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
1165 if (data == NULL) {
1166 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1167 return PM3_EMALLOC;
1170 // download emulator memory
1171 PrintAndLogEx(SUCCESS, "Reading emulator memory...");
1172 if (GetFromDevice(BIG_BUF_EML, data, numofbytes, 0, NULL, 0, NULL, 2500, false) == false) {
1173 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
1174 free(data);
1175 return PM3_ETIMEOUT;
1178 // user supplied filename?
1179 if (fnlen < 1) {
1180 PrintAndLogEx(INFO, "Using UID as filename");
1181 strcat(filename, "hf-legic-");
1182 FillFileNameByUID(filename, data, "-dump", 4);
1185 if (shall_deobsfuscate) {
1186 legic_xor(data, numofbytes);
1189 pm3_save_dump(filename, data, numofbytes, jsfLegic_v2);
1190 return PM3_SUCCESS;
1193 static int CmdLegicEView(const char *Cmd) {
1195 CLIParserContext *ctx;
1196 CLIParserInit(&ctx, "hf legic eview",
1197 "It displays emulator memory",
1198 "hf legic eview\n"
1199 "hf legic eview --22\n"
1201 void *argtable[] = {
1202 arg_param_begin,
1203 arg_lit0(NULL, "22", "LEGIC Prime MIM22"),
1204 arg_lit0(NULL, "256", "LEGIC Prime MIM256 (def)"),
1205 arg_lit0(NULL, "1024", "LEGIC Prime MIM1024"),
1206 arg_lit0("v", "verbose", "verbose output"),
1207 arg_param_end
1209 CLIExecWithReturn(ctx, Cmd, argtable, true);
1211 bool m1 = arg_get_lit(ctx, 1);
1212 bool m2 = arg_get_lit(ctx, 2);
1213 bool m3 = arg_get_lit(ctx, 3);
1214 bool verbose = arg_get_lit(ctx, 4);
1215 CLIParserFree(ctx);
1217 // validations
1218 if (m1 + m2 + m3 > 1) {
1219 PrintAndLogEx(WARNING, "Only specify one LEGIC Prime Type");
1220 return PM3_EINVARG;
1221 } else if (m1 + m2 + m3 == 0) {
1222 m2 = true;
1225 size_t bytes = LEGIC_PRIME_MIM256;
1226 if (m1)
1227 bytes = LEGIC_PRIME_MIM22;
1228 else if (m2)
1229 bytes = LEGIC_PRIME_MIM256;
1230 else if (m3)
1231 bytes = LEGIC_PRIME_MIM1024;
1233 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
1234 if (dump == NULL) {
1235 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1236 return PM3_EMALLOC;
1239 PrintAndLogEx(INFO, "downloading emulator memory");
1240 if (GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false) == false) {
1241 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
1242 free(dump);
1243 return PM3_ETIMEOUT;
1246 if (verbose) {
1247 PrintAndLogEx(NORMAL, "");
1248 PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
1249 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
1250 print_hex_break(dump, bytes, 16);
1253 PrintAndLogEx(NORMAL, "");
1254 decode_and_print_memory(bytes, dump);
1256 free(dump);
1257 return PM3_SUCCESS;
1260 static int CmdLegicEInfo(const char *Cmd) {
1262 CLIParserContext *ctx;
1263 CLIParserInit(&ctx, "hf legic einfo",
1264 "It decodes and displays emulator memory",
1265 "hf legic einfo\n"
1266 "hf legic eview --22\n"
1268 void *argtable[] = {
1269 arg_param_begin,
1270 arg_lit0(NULL, "22", "LEGIC Prime MIM22"),
1271 arg_lit0(NULL, "256", "LEGIC Prime MIM256 (def)"),
1272 arg_lit0(NULL, "1024", "LEGIC Prime MIM1024"),
1273 arg_param_end
1275 CLIExecWithReturn(ctx, Cmd, argtable, true);
1276 bool m1 = arg_get_lit(ctx, 1);
1277 bool m2 = arg_get_lit(ctx, 2);
1278 bool m3 = arg_get_lit(ctx, 3);
1279 CLIParserFree(ctx);
1281 // validations
1282 if (m1 + m2 + m3 > 1) {
1283 PrintAndLogEx(WARNING, "Only specify one LEGIC Prime Type");
1284 return PM3_EINVARG;
1285 } else if (m1 + m2 + m3 == 0) {
1286 m2 = true;
1289 size_t card_size = LEGIC_PRIME_MIM256;
1290 if (m1)
1291 card_size = LEGIC_PRIME_MIM22;
1292 else if (m2)
1293 card_size = LEGIC_PRIME_MIM256;
1294 else if (m3)
1295 card_size = LEGIC_PRIME_MIM1024;
1297 uint8_t *dump = calloc(card_size, sizeof(uint8_t));
1298 if (dump == NULL) {
1299 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1300 return PM3_EMALLOC;
1303 PrintAndLogEx(INFO, "downloading emulator memory");
1304 if (GetFromDevice(BIG_BUF_EML, dump, card_size, 0, NULL, 0, NULL, 2500, false) == false) {
1305 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
1306 free(dump);
1307 return PM3_ETIMEOUT;
1310 decode_and_print_memory(card_size, dump);
1312 free(dump);
1313 return PM3_SUCCESS;
1316 static int CmdLegicWipe(const char *Cmd) {
1317 CLIParserContext *ctx;
1318 CLIParserInit(&ctx, "hf legic wipe",
1319 "Fills a LEGIC Prime tags memory with zeros. From byte7 and to the end\n"
1320 "It autodetects card type",
1321 "hf legic wipe");
1323 void *argtable[] = {
1324 arg_param_begin,
1325 arg_param_end
1327 CLIExecWithReturn(ctx, Cmd, argtable, true);
1328 CLIParserFree(ctx);
1330 // tagtype
1331 legic_card_select_t card;
1332 if (legic_get_type(&card) != PM3_SUCCESS) {
1333 PrintAndLogEx(WARNING, "Failed to identify tagtype");
1334 return PM3_ESOFT;
1337 // set up buffer
1338 uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
1339 if (!data) {
1340 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1341 return PM3_EMALLOC;
1344 legic_print_type(card.cardsize, 0);
1346 PrintAndLogEx(SUCCESS, "Erasing");
1347 // fast push mode
1348 g_conn.block_after_ACK = true;
1350 // transfer to device
1351 PacketResponseNG resp;
1352 for (size_t i = 7; i < card.cardsize; i += LEGIC_PACKET_SIZE) {
1354 PrintAndLogEx(NORMAL, "." NOLF);
1356 size_t len = MIN((card.cardsize - i), LEGIC_PACKET_SIZE);
1357 if (len == card.cardsize - i) {
1358 // Disable fast mode on last packet
1359 g_conn.block_after_ACK = false;
1362 legic_packet_t *payload = calloc(1, sizeof(legic_packet_t) + len);
1363 payload->offset = i;
1364 payload->iv = 0x55;
1365 payload->len = len;
1366 memcpy(payload->data, data + i, len);
1368 clearCommandBuffer();
1369 SendCommandNG(CMD_HF_LEGIC_WRITER, (uint8_t *)payload, sizeof(legic_packet_t) + len);
1370 free(payload);
1372 uint8_t timeout = 0;
1373 while (WaitForResponseTimeout(CMD_HF_LEGIC_WRITER, &resp, 2000) == false) {
1374 ++timeout;
1375 PrintAndLogEx(NORMAL, "." NOLF);
1376 if (timeout > 10) {
1377 PrintAndLogEx(WARNING, "\ncommand execution time out");
1378 free(data);
1379 return PM3_ETIMEOUT;
1382 PrintAndLogEx(NORMAL, "");
1384 if (resp.status != PM3_SUCCESS) {
1385 PrintAndLogEx(WARNING, "failed writing tag");
1386 free(data);
1387 return PM3_ERFTRANS;
1390 PrintAndLogEx(SUCCESS, "Done!\n");
1391 free(data);
1392 return PM3_SUCCESS;
1395 static int CmdLegicList(const char *Cmd) {
1396 return CmdTraceListAlias(Cmd, "hf legic", "legic");
1399 static int CmdLegicView(const char *Cmd) {
1400 CLIParserContext *ctx;
1401 CLIParserInit(&ctx, "hf legic view",
1402 "Print a LEGIC Prime dump file (bin/eml/json)",
1403 "hf legic view -f hf-legic-01020304-dump.bin"
1405 void *argtable[] = {
1406 arg_param_begin,
1407 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
1408 arg_lit0("v", "verbose", "verbose output"),
1409 arg_param_end
1411 CLIExecWithReturn(ctx, Cmd, argtable, false);
1412 int fnlen = 0;
1413 char filename[FILE_PATH_SIZE];
1414 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1415 bool verbose = arg_get_lit(ctx, 2);
1416 CLIParserFree(ctx);
1418 // read dump file
1419 uint8_t *dump = NULL;
1420 size_t bytes_read = 0;
1421 int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, LEGIC_PRIME_MIM1024);
1422 if (res != PM3_SUCCESS) {
1423 return res;
1426 if (verbose) {
1427 PrintAndLogEx(NORMAL, "");
1428 PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
1429 PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
1430 print_hex_break(dump, bytes_read, 16);
1433 PrintAndLogEx(NORMAL, "");
1434 decode_and_print_memory(bytes_read, dump);
1435 free(dump);
1436 return PM3_SUCCESS;
1439 static command_t CommandTable[] = {
1440 {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
1441 {"help", CmdHelp, AlwaysAvailable, "This help"},
1442 {"dump", CmdLegicDump, IfPm3Legicrf, "Dump LEGIC Prime tag to binary file"},
1443 {"info", CmdLegicInfo, IfPm3Legicrf, "Display deobfuscated and decoded LEGIC Prime tag data"},
1444 {"list", CmdLegicList, AlwaysAvailable, "List LEGIC history"},
1445 {"rdbl", CmdLegicRdbl, IfPm3Legicrf, "Read bytes from a LEGIC Prime tag"},
1446 {"reader", CmdLegicReader, IfPm3Legicrf, "LEGIC Prime Reader UID and tag info"},
1447 {"restore", CmdLegicRestore, IfPm3Legicrf, "Restore a dump file onto a LEGIC Prime tag"},
1448 {"wipe", CmdLegicWipe, IfPm3Legicrf, "Wipe a LEGIC Prime tag"},
1449 {"wrbl", CmdLegicWrbl, IfPm3Legicrf, "Write data to a LEGIC Prime tag"},
1450 {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"},
1451 {"sim", CmdLegicSim, IfPm3Legicrf, "Start tag simulator"},
1452 {"eload", CmdLegicELoad, IfPm3Legicrf, "Upload file into emulator memory"},
1453 {"esave", CmdLegicESave, IfPm3Legicrf, "Save emulator memory to file"},
1454 {"eview", CmdLegicEView, IfPm3Legicrf, "View emulator memory"},
1455 {"einfo", CmdLegicEInfo, IfPm3Legicrf, "Display deobfuscated and decoded emulator memory"},
1456 {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"},
1457 {"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"},
1458 {"view", CmdLegicView, AlwaysAvailable, "Display deobfuscated and decoded content from tag dump file"},
1459 {NULL, NULL, NULL, NULL}
1462 static int CmdHelp(const char *Cmd) {
1463 (void)Cmd; // Cmd is not used so far
1464 CmdsHelp(CommandTable);
1465 return PM3_SUCCESS;
1468 int CmdHFLegic(const char *Cmd) {
1469 clearCommandBuffer();
1470 return CmdsParse(CommandTable, Cmd);
1473 int readLegicUid(bool loop, bool verbose) {
1475 do {
1476 legic_card_select_t card;
1478 int resp = legic_get_type(&card);
1480 if (loop) {
1481 if (resp != PM3_SUCCESS) {
1482 continue;
1484 } else {
1485 switch (resp) {
1486 case PM3_EINVARG:
1487 return PM3_EINVARG;
1488 case PM3_ETIMEOUT:
1489 if (verbose) PrintAndLogEx(WARNING, "command execution time out");
1490 return PM3_ETIMEOUT;
1491 case PM3_ESOFT:
1492 if (verbose) PrintAndLogEx(WARNING, "legic card select failed");
1493 return PM3_ESOFT;
1494 default:
1495 break;
1499 PrintAndLogEx(NORMAL, "");
1500 PrintAndLogEx(SUCCESS, " MCD: " _GREEN_("%02X"), card.uid[0]);
1501 PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1));
1502 legic_print_type(card.cardsize, 0);
1504 } while (loop && kbd_enter_pressed() == false);
1506 return PM3_SUCCESS;