1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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 //-----------------------------------------------------------------------------
17 //-----------------------------------------------------------------------------
22 #include "cmdparser.h" // command_t
23 #include "protocols.h"
24 #include "parity.h" // oddparity
25 #include "cmdhflist.h" // annotations
26 #include "commonutil.h" // ARRAYLEN
27 #include "mifare/mifaredefault.h" // mifare default key array
28 #include "comms.h" // for sending cmds to device. GetFromBigBuf
29 #include "fileutils.h" // for saveFile
30 #include "cmdlfhitag.h" // annotate hitag
31 #include "pm3_cmd.h" // tracelog_hdr_t
32 #include "cliparser.h" // args..
34 static int CmdHelp(const char *Cmd
);
37 static uint8_t *gs_trace
;
38 static uint16_t gs_traceLen
= 0;
40 static bool is_last_record(uint16_t tracepos
, uint16_t traceLen
) {
41 return ((tracepos
+ TRACELOG_HDR_LEN
) >= traceLen
);
44 static bool next_record_is_response(uint16_t tracepos
, uint8_t *trace
) {
45 const tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
46 return (hdr
->isResponse
);
49 static bool merge_topaz_reader_frames(uint32_t timestamp
, uint32_t *duration
, uint16_t *tracepos
, uint16_t traceLen
,
50 uint8_t *trace
, const uint8_t *frame
, uint8_t *topaz_reader_command
, uint16_t *data_len
) {
52 #define MAX_TOPAZ_READER_CMD_LEN 16
54 uint32_t last_timestamp
= timestamp
+ *duration
;
56 if ((*data_len
!= 1) || (frame
[0] == TOPAZ_WUPA
) || (frame
[0] == TOPAZ_REQA
)) return false;
58 memcpy(topaz_reader_command
, frame
, *data_len
);
60 while (!is_last_record(*tracepos
, traceLen
) && !next_record_is_response(*tracepos
, trace
)) {
62 const tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ *tracepos
);
64 *tracepos
+= TRACELOG_HDR_LEN
+ hdr
->data_len
;
66 if ((hdr
->data_len
== 1) && (*data_len
+ hdr
->data_len
<= MAX_TOPAZ_READER_CMD_LEN
)) {
67 memcpy(topaz_reader_command
+ *data_len
, hdr
->frame
, hdr
->data_len
);
68 *data_len
+= hdr
->data_len
;
69 last_timestamp
= hdr
->timestamp
+ hdr
->duration
;
72 *tracepos
= *tracepos
- hdr
->data_len
- TRACELOG_HDR_LEN
;
75 *tracepos
+= TRACELOG_PARITY_LEN(hdr
);
78 *duration
= last_timestamp
- timestamp
;
82 static uint8_t calc_pos(const uint8_t *d
) {
83 // PCB [CID] [NAD] [INF] CRC CRC
85 if ((d
[0] & 0x08) == 0x08) // cid byte following
88 if ((d
[0] & 0x04) == 0x04) // nad byte following
94 // Copy an existing buffer into client trace buffer
95 // I think this is cleaner than further globalizing gs_trace, and may lend itself to more modularity later?
96 bool ImportTraceBuffer(const uint8_t *trace_src
, uint16_t trace_len
) {
97 if (trace_len
== 0 || trace_src
== NULL
) return (false);
102 gs_trace
= calloc(trace_len
, sizeof(uint8_t));
103 if (gs_trace
== NULL
) {
106 memcpy(gs_trace
, trace_src
, trace_len
);
107 gs_traceLen
= trace_len
;
111 static uint8_t extract_uid
[10] = {0};
112 static uint8_t extract_uidlen
= 0;
113 static uint8_t extract_epurse
[8] = {0};
115 #define SKIP_TO_NEXT(a) (TRACELOG_HDR_LEN + (a)->data_len + TRACELOG_PARITY_LEN((a)))
117 static uint16_t extractChall_ev2(uint16_t tracepos
, uint8_t *trace
, uint8_t cmdpos
, uint8_t long_jmp
) {
118 tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
119 if (next_hdr
->data_len
!= 21) {
123 tracepos
+= TRACELOG_HDR_LEN
+ next_hdr
->data_len
+ TRACELOG_PARITY_LEN(next_hdr
);
125 PrintAndLogEx(INFO
, "1499999999 %s " NOLF
, sprint_hex_inrow(next_hdr
->frame
+ 1, 16));
127 next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
128 tracepos
+= TRACELOG_HDR_LEN
+ next_hdr
->data_len
+ TRACELOG_PARITY_LEN(next_hdr
);
130 if (next_hdr
->frame
[cmdpos
] == MFDES_ADDITIONAL_FRAME
) {
131 PrintAndLogEx(NORMAL
, "%s", sprint_hex_inrow(next_hdr
->frame
+ cmdpos
+ long_jmp
, 32));
133 PrintAndLogEx(NORMAL
, "");
138 static uint16_t extractChallenges(uint16_t tracepos
, uint16_t traceLen
, uint8_t *trace
) {
141 if (is_last_record(tracepos
, traceLen
)) {
145 tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
146 uint16_t data_len
= hdr
->data_len
;
147 uint8_t *frame
= hdr
->frame
;
149 // sanity check tracking position is less then available trace size
150 if (tracepos
+ TRACELOG_HDR_LEN
+ data_len
+ TRACELOG_PARITY_LEN(hdr
) > traceLen
) {
151 PrintAndLogEx(DEBUG
, "trace pos offset %"PRIu64
" larger than reported tracelen %u",
152 tracepos
+ TRACELOG_HDR_LEN
+ data_len
+ TRACELOG_PARITY_LEN(hdr
),
158 // set trace position
159 tracepos
+= SKIP_TO_NEXT(hdr
);
161 // sanity check data frame length
168 case MIFARE_AUTH_KEYA
: {
173 case MIFARE_AUTH_KEYB
: {
182 case MIFARE_ULC_AUTH_1
: {
187 // time to skip to next
188 tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
189 tracepos
+= SKIP_TO_NEXT(next_hdr
);
190 if (next_hdr
->data_len
!= 11) {
194 if (next_hdr
->frame
[0] != MIFARE_ULC_AUTH_2
) {
198 PrintAndLogEx(INFO
, "MFU-C AUTH");
199 PrintAndLogEx(INFO
, "3DES %s " NOLF
, sprint_hex_inrow(next_hdr
->frame
+ 1, 8));
201 next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
202 tracepos
+= SKIP_TO_NEXT(next_hdr
);
204 if (next_hdr
->frame
[0] == MIFARE_ULC_AUTH_2
&& next_hdr
->data_len
== 19) {
205 PrintAndLogEx(NORMAL
, "%s", sprint_hex_inrow(next_hdr
->frame
+ 1, 16));
213 // --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b
215 if (hdr
->isResponse
== false) {
217 uint8_t c
= frame
[0] & 0x0F;
219 case ICLASS_CMD_SELECT
: {
221 const tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
222 tracepos
+= SKIP_TO_NEXT(next_hdr
);
223 if (next_hdr
->data_len
!= 10) {
226 memcpy(extract_uid
, next_hdr
->frame
, 8);
230 case ICLASS_CMD_READCHECK
: {
233 if (frame
[1] == 2 && data_len
== 2) {
234 const tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
235 tracepos
+= SKIP_TO_NEXT(next_hdr
);
236 if (next_hdr
->data_len
< 8) {
239 memcpy(extract_epurse
, next_hdr
->frame
, 8);
243 case ICLASS_CMD_CHECK
: {
246 if (extract_uidlen
== 8) {
247 PrintAndLogEx(INFO
, "hf iclass lookup --csn %s " NOLF
, sprint_hex_inrow(extract_uid
, extract_uidlen
));
248 PrintAndLogEx(NORMAL
, "--epurse %s " NOLF
, sprint_hex_inrow(extract_epurse
, 8));
249 PrintAndLogEx(NORMAL
, "--macs %s " NOLF
, sprint_hex_inrow(frame
+ 1, 8));
250 PrintAndLogEx(NORMAL
, "-f iclass_default_keys.dic");
261 case ISO14443A_CMD_ANTICOLL_OR_SELECT
: {
262 // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor)
263 // 93 50 = Bit oriented anti-collision (usage: 9350+ up to 5bytes, 9350 answer - up to 5bytes UID+BCC)
264 // 93 70 = Select (usage: 9370+5bytes 9370 answer - answer: 1byte SAK)
265 if (frame
[1] == 0x70) {
266 if (frame
[2] == 0x88) {
267 memcpy(extract_uid
, frame
+ 3, 3);
270 memcpy(extract_uid
, frame
+ 2, 4);
272 PrintAndLogEx(INFO
, "UID... " _YELLOW_("%s"), sprint_hex_inrow(extract_uid
, extract_uidlen
));
277 case ISO14443A_CMD_ANTICOLL_OR_SELECT_2
: {
278 // 95 20 = Anticollision of cascade level2
279 // 95 50 = Bit oriented anti-collision level2
280 // 95 70 = Select of cascade level2
281 if (frame
[1] == 0x70) {
282 if (frame
[2] == 0x88) {
283 memcpy(extract_uid
+ extract_uidlen
, frame
+ 3, 3);
286 memcpy(extract_uid
+ extract_uidlen
, frame
+ 2, 4);
288 PrintAndLogEx(INFO
, "UID... " _YELLOW_("%s"), sprint_hex_inrow(extract_uid
, extract_uidlen
));
293 case ISO14443A_CMD_ANTICOLL_OR_SELECT_3
: {
294 // 97 20 = Anticollision of cascade level3
295 // 97 50 = Bit oriented anti-collision level3
296 // 97 70 = Select of cascade level3
297 if (frame
[1] == 0x70) {
298 memcpy(extract_uid
+ extract_uidlen
, frame
+ 2, 4);
300 PrintAndLogEx(INFO
, "UID... " _YELLOW_("%s"), sprint_hex_inrow(extract_uid
, extract_uidlen
));
307 if ((frame
[0] & 0xC0) != 0x00) {
311 if (hdr
->isResponse
) {
315 // PCB [CID] [NAD] [INF] CRC CRC
316 uint8_t pos
= calc_pos(frame
);
317 uint8_t long_jmp
= (data_len
> 6) ? 4 : 1;
319 for (uint8_t i
= 0; i
< 2; i
++, pos
++) {
321 switch (frame
[pos
]) {
323 case MFDES_AUTHENTICATE
: {
325 // Assume wrapped or unwrapped
326 PrintAndLogEx(INFO
, "AUTH NATIVE (keyNo %d)", frame
[pos
+ long_jmp
]);
327 if (next_record_is_response(tracepos
, trace
) == false) {
331 tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
332 if (next_hdr
->data_len
< 7) {
335 tracepos
+= TRACELOG_HDR_LEN
+ next_hdr
->data_len
+ TRACELOG_PARITY_LEN(next_hdr
);
337 PrintAndLogEx(INFO
, "DES 1499999999 %s " NOLF
, sprint_hex_inrow(next_hdr
->frame
+ 1, 8));
339 next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
340 tracepos
+= TRACELOG_HDR_LEN
+ next_hdr
->data_len
+ TRACELOG_PARITY_LEN(next_hdr
);
342 if (next_hdr
->frame
[pos
] == MFDES_ADDITIONAL_FRAME
) {
343 PrintAndLogEx(NORMAL
, "%s", sprint_hex_inrow(next_hdr
->frame
+ pos
+ long_jmp
, 16));
345 PrintAndLogEx(NORMAL
, "");
347 return tracepos
; // AUTHENTICATE_NATIVE
349 case MFDES_AUTHENTICATE_ISO
: {
350 // Assume wrapped or unwrapped
351 PrintAndLogEx(INFO
, "AUTH ISO (keyNo %d)", frame
[pos
+ long_jmp
]);
352 if (next_record_is_response(tracepos
, trace
) == false) {
356 tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
357 tracepos
+= TRACELOG_HDR_LEN
+ next_hdr
->data_len
+ TRACELOG_PARITY_LEN(next_hdr
);
358 if (next_hdr
->data_len
< 7) {
363 if (next_hdr
->data_len
> 20) {
365 PrintAndLogEx(INFO
, "3TDEA 1499999999 %s " NOLF
, sprint_hex_inrow(next_hdr
->frame
+ 1, tdea
));
367 PrintAndLogEx(INFO
, "2TDEA 1499999999 %s " NOLF
, sprint_hex_inrow(next_hdr
->frame
+ 1, tdea
));
370 next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
371 tracepos
+= TRACELOG_HDR_LEN
+ next_hdr
->data_len
+ TRACELOG_PARITY_LEN(next_hdr
);
373 if (next_hdr
->frame
[pos
] == MFDES_ADDITIONAL_FRAME
) {
374 PrintAndLogEx(NORMAL
, "%s", sprint_hex_inrow(next_hdr
->frame
+ pos
+ long_jmp
, (tdea
<< 1)));
376 PrintAndLogEx(NORMAL
, "");
378 return tracepos
; // AUTHENTICATE_STANDARD
380 case MFDES_AUTHENTICATE_AES
: {
381 // Assume wrapped or unwrapped
382 PrintAndLogEx(INFO
, "AUTH AES (keyNo %d)", frame
[pos
+ long_jmp
]);
383 if (next_record_is_response(tracepos
, trace
)) {
387 tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
388 tracepos
+= TRACELOG_HDR_LEN
+ next_hdr
->data_len
+ TRACELOG_PARITY_LEN(next_hdr
);
389 if (next_hdr
->data_len
< 7) {
393 PrintAndLogEx(INFO
, "AES 1499999999 %s " NOLF
, sprint_hex_inrow(next_hdr
->frame
+ 1, 8));
395 next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
396 tracepos
+= TRACELOG_HDR_LEN
+ next_hdr
->data_len
+ TRACELOG_PARITY_LEN(next_hdr
);
398 if (next_hdr
->frame
[pos
] == MFDES_ADDITIONAL_FRAME
) {
399 PrintAndLogEx(NORMAL
, "%s", sprint_hex_inrow(next_hdr
->frame
+ pos
+ long_jmp
, 16));
401 PrintAndLogEx(NORMAL
, "");
405 case MFDES_AUTHENTICATE_EV2F
: {
406 PrintAndLogEx(INFO
, "AUTH EV2 First");
407 uint16_t tmp
= extractChall_ev2(tracepos
, trace
, pos
, long_jmp
);
414 case MFDES_AUTHENTICATE_EV2NF
: {
415 PrintAndLogEx(INFO
, "AUTH EV2 Non First");
416 uint16_t tmp
= extractChall_ev2(tracepos
, trace
, pos
, long_jmp
);
428 static uint16_t printHexLine(uint16_t tracepos
, uint16_t traceLen
, uint8_t *trace
, uint8_t protocol
) {
430 if (is_last_record(tracepos
, traceLen
)) return traceLen
;
432 tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
434 if (TRACELOG_HDR_LEN
+ hdr
->data_len
+ TRACELOG_PARITY_LEN(hdr
) > traceLen
) {
439 tracepos
+= TRACELOG_HDR_LEN
+ hdr
->data_len
+ TRACELOG_PARITY_LEN(hdr
);
441 if (hdr
->data_len
== 0) {
442 PrintAndLogEx(NORMAL
, "<empty trace - possible error>");
450 /* https://www.kaiser.cx/pcap-iso14443.html defines a pseudo header:
451 * version (currently 0x00), event (Rdr: 0xfe, Tag: 0xff), length (2 bytes)
452 * to convert to pcap(ng) via text2pcap or to import into Wireshark
453 * we use format timestamp, newline, offset (0x000000), pseudo header, data
454 * `text2pcap -t "%S." -l 264 -n <input-text-file> <output-pcapng-file>`
456 int line_len
= (hdr
->data_len
* 3) + 1;
460 for (int i
= 0; i
< hdr
->data_len
; i
++) {
461 ptr
+= snprintf(ptr
, line_len
, "%02x ", hdr
->frame
[i
]);
468 char data_len_str
[5];
469 char temp_str1
[3] = {0};
470 char temp_str2
[3] = {0};
472 snprintf(data_len_str
, sizeof(data_len_str
), "%04x", hdr
->data_len
);
473 memmove(temp_str1
, data_len_str
, 2);
474 memmove(temp_str2
, data_len_str
+ 2, 2);
476 PrintAndLogEx(NORMAL
, "0.%010u", hdr
->timestamp
);
477 PrintAndLogEx(NORMAL
, "000000 00 %s %s %s %s",
478 (hdr
->isResponse
? "ff" : "fe"),
486 PrintAndLogEx(NORMAL
, "Currently only 14a supported");
494 static uint16_t printTraceLine(uint16_t tracepos
, uint16_t traceLen
, uint8_t *trace
, uint8_t protocol
, bool showWaitCycles
, bool markCRCBytes
, uint32_t *prev_eot
, bool use_us
,
495 const uint64_t *mfDicKeys
, uint32_t mfDicKeysCount
) {
497 if (is_last_record(tracepos
, traceLen
)) {
498 PrintAndLogEx(DEBUG
, "last record triggered. t-pos: %u t-len %u", tracepos
, traceLen
);
502 uint32_t end_of_transmission_timestamp
= 0;
503 uint8_t topaz_reader_command
[9];
504 char explanation
[60] = {0};
505 tracelog_hdr_t
*first_hdr
= (tracelog_hdr_t
*)(trace
);
506 tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
508 uint32_t duration
= hdr
->duration
;
509 uint16_t data_len
= hdr
->data_len
;
511 if (tracepos
+ TRACELOG_HDR_LEN
+ data_len
+ TRACELOG_PARITY_LEN(hdr
) > traceLen
) {
512 PrintAndLogEx(DEBUG
, "trace pos offset %"PRIu64
" larger than reported tracelen %u",
513 tracepos
+ TRACELOG_HDR_LEN
+ data_len
+ TRACELOG_PARITY_LEN(hdr
),
519 // adjust for different time scales
520 if (protocol
== ICLASS
|| protocol
== ISO_15693
) {
524 uint8_t *frame
= hdr
->frame
;
525 uint8_t *parityBytes
= hdr
->frame
+ data_len
;
527 tracepos
+= TRACELOG_HDR_LEN
+ data_len
+ TRACELOG_PARITY_LEN(hdr
);
529 if (protocol
== TOPAZ
&& !hdr
->isResponse
) {
530 // topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each.
532 if (merge_topaz_reader_frames(hdr
->timestamp
, &duration
, &tracepos
, traceLen
, trace
, frame
, topaz_reader_command
, &data_len
)) {
533 frame
= topaz_reader_command
;
537 //Check the CRC status
538 uint8_t crcStatus
= 2;
543 crcStatus
= iclass_CRC_check(hdr
->isResponse
, frame
, data_len
);
547 crcStatus
= iso14443B_CRC_check(frame
, data_len
);
550 crcStatus
= !felica_CRC_check(frame
+ 2, data_len
- 4);
554 crcStatus
= mifare_CRC_check(hdr
->isResponse
, frame
, data_len
);
560 crcStatus
= iso14443A_CRC_check(hdr
->isResponse
, frame
, data_len
);
563 crcStatus
= iso14443A_CRC_check(hdr
->isResponse
, frame
, data_len
) == 1 ? 3 : 0;
564 crcStatus
= iso14443B_CRC_check(frame
, data_len
) == 1 ? 4 : crcStatus
;
567 frame
[data_len
- 1] ^= frame
[data_len
- 2];
568 frame
[data_len
- 2] ^= frame
[data_len
- 1];
569 frame
[data_len
- 1] ^= frame
[data_len
- 2];
570 crcStatus
= iso14443A_CRC_check(true, frame
, data_len
);
571 frame
[data_len
- 1] ^= frame
[data_len
- 2];
572 frame
[data_len
- 2] ^= frame
[data_len
- 1];
573 frame
[data_len
- 1] ^= frame
[data_len
- 2];
576 crcStatus
= iso15693_CRC_check(frame
, data_len
);
580 crcStatus
= hitag1_CRC_check(frame
, (data_len
* 8) - ((8 - parityBytes
[0]) % 8));
587 //0 CRC-command, CRC not ok
588 //1 CRC-command, CRC ok
591 // Draw the data column
592 #define TRACE_MAX_LINES 36
593 // number of hex bytes to be printed per row (16 data + 2 crc)
594 #define TRACE_MAX_HEX_BYTES 18
596 char line
[TRACE_MAX_LINES
][160] = {{0}};
599 if (protocol
== ICLASS
&& duration
== 2048) {
600 snprintf(line
[0], sizeof(line
[0]), "<SOF>");
601 } else if (protocol
== ISO_15693
&& duration
== 512) {
602 snprintf(line
[0], sizeof(line
[0]), "<EOF>");
604 snprintf(line
[0], sizeof(line
[0]), "<empty trace - possible error>");
608 // uint8_t partialbytebuff = 0;
610 for (int j
= 0; j
< data_len
&& (j
/ TRACE_MAX_HEX_BYTES
) < TRACE_MAX_HEX_BYTES
; j
++) {
611 uint8_t parityBits
= parityBytes
[j
>> 3];
612 if (protocol
!= LEGIC
613 && protocol
!= ISO_14443B
614 && protocol
!= ISO_15693
615 && protocol
!= ICLASS
616 && protocol
!= ISO_7816_4
617 && protocol
!= PROTO_HITAG1
618 && protocol
!= PROTO_HITAG2
619 && protocol
!= PROTO_HITAGS
620 && protocol
!= THINFILM
621 && protocol
!= FELICA
623 && protocol
!= PROTO_CRYPTORF
624 && (hdr
->isResponse
|| protocol
== ISO_14443A
|| protocol
== PROTO_MIFARE
|| protocol
== PROTO_MFPLUS
|| protocol
== SEOS
)
625 && (oddparity8(frame
[j
]) != ((parityBits
>> (7 - (j
& 0x0007))) & 0x01))) {
627 snprintf(line
[j
/ 18] + ((j
% 18) * 4), 120, "%02x! ", frame
[j
]);
629 } else if (protocol
== ICLASS
&& hdr
->isResponse
== false) {
632 for (int i
= 0; i
< 6; i
++) {
633 parity
^= ((frame
[0] >> i
) & 1);
636 if (parity
== ((frame
[0] >> 7) & 1)) {
637 snprintf(line
[j
/ 18] + ((j
% 18) * 4), 120, "%02x ", frame
[j
]);
639 snprintf(line
[j
/ 18] + ((j
% 18) * 4), 120, "%02x! ", frame
[j
]);
642 } else if (((protocol
== PROTO_HITAG1
) || (protocol
== PROTO_HITAG2
) || (protocol
== PROTO_HITAGS
))) {
646 // handle partial bytes. The parity array[0] is used to store number of left over bits from NBYTES
647 // This part prints the number of bits in the trace entry for hitag.
648 uint8_t nbits
= parityBytes
[0];
650 // only apply this to lesser than one byte
651 if (data_len
== 1 && nbits
!= 0) {
653 snprintf(line
[0], 120, "%2u: %02X ", nbits
, frame
[0] >> (8 - nbits
));
657 snprintf(line
[0], 120, "%2u: %02X ", (uint16_t)(data_len
* 8), frame
[0]);
659 snprintf(line
[0], 120, "%2u: %02X ", (uint16_t)(((data_len
- 1) * 8) + nbits
), frame
[0]);
665 snprintf(line
[j
/ 18] + ((j
% 18) * 4) + offset
, 120, "%02X ", frame
[j
]);
669 snprintf(line
[j
/ 18] + ((j
% 18) * 4), 120, "%02X ", frame
[j
]);
674 if (markCRCBytes
&& data_len
> 2) {
676 if (((protocol
== PROTO_HITAG1
) || (protocol
== PROTO_HITAGS
))) {
677 // Note that UID REQUEST response has no CRC, but we don't know
678 // if the response we see is a UID
679 char *pos1
= line
[(data_len
- 1) / 18] + (((data_len
- 1) % 18) * 4) + offset
- 1;
681 char *pos2
= line
[(data_len
) / 18] + (((data_len
) % 18) * 4) + offset
- 2;
683 (*(pos2
+ 1)) = '\0';
686 if (crcStatus
== 0 || crcStatus
== 1) {
688 char *pos1
= line
[(data_len
- 2) / TRACE_MAX_HEX_BYTES
];
689 int delta
= (data_len
- 2) % TRACE_MAX_HEX_BYTES
? 1 : 0;
690 pos1
+= (((data_len
- 2) % TRACE_MAX_HEX_BYTES
) * 4) - delta
;
692 (*(pos1
+ 6 + delta
)) = '\0';
694 char *cb_str
= str_dup(pos1
+ delta
);
696 if (g_session
.supports_colors
) {
697 if (crcStatus
== 0) {
698 snprintf(pos1
, 24, AEND
" " _RED_("%s"), cb_str
);
700 snprintf(pos1
, 24, AEND
" " _GREEN_("%s"), cb_str
);
703 snprintf(pos1
, 9, "[%s]", cb_str
);
706 // odd case of second crc byte is alone in a new line
707 if (strlen(cb_str
) < 5) {
711 pos1
= line
[((data_len
- 2) / TRACE_MAX_HEX_BYTES
) + 1];
712 cb_str
= str_dup(pos1
);
714 if (g_session
.supports_colors
) {
715 if (crcStatus
== 0) {
716 snprintf(pos1
, 24, _RED_("%s"), cb_str
);
718 snprintf(pos1
, 24, _GREEN_("%s"), cb_str
);
721 snprintf(pos1
, 9, "[%s]", cb_str
);
730 // Draw the CRC column
731 const char *crcstrings
[] = { _RED_(" !! "), _GREEN_(" ok "), " ", _GREEN_("A ok"), _GREEN_("B ok") };
732 const char *crc
= crcstrings
[crcStatus
];
734 // mark short bytes (less than 8 Bit + Parity)
735 if (protocol
== ISO_14443A
||
736 protocol
== PROTO_MIFARE
||
737 protocol
== PROTO_MFPLUS
||
738 protocol
== THINFILM
) {
740 // approximated with 128 * (9 * data_len);
741 uint16_t bitime
= 1056 + 32;
743 if (duration
< bitime
) {
748 if (duration
> bitime
) {
755 line
[(data_len
- 1) / 16][((data_len
- 1) % 16) * 4 + 2] = '(';
756 line
[(data_len
- 1) / 16][((data_len
- 1) % 16) * 4 + 3] = m
+ 0x30;
757 line
[(data_len
- 1) / 16][((data_len
- 1) % 16) * 4 + 4] = ')';
763 uint32_t previous_end_of_transmission_timestamp
= 0;
766 previous_end_of_transmission_timestamp
= *prev_eot
;
768 previous_end_of_transmission_timestamp
= hdr
->timestamp
;
772 end_of_transmission_timestamp
= hdr
->timestamp
+ duration
;
775 *prev_eot
= end_of_transmission_timestamp
;
778 // Always annotate these protocols both reader/tag messages
782 annotateIso14443a(explanation
, sizeof(explanation
), frame
, data_len
, hdr
->isResponse
);
786 annotateMifare(explanation
, sizeof(explanation
), frame
, data_len
, parityBytes
, TRACELOG_PARITY_LEN(hdr
), hdr
->isResponse
);
789 annotateHitag1(explanation
, sizeof(explanation
), frame
, data_len
, hdr
->isResponse
);
792 annotateHitag2(explanation
, sizeof(explanation
), frame
, data_len
, parityBytes
[0], hdr
->isResponse
, mfDicKeys
, mfDicKeysCount
, false);
795 annotateHitagS(explanation
, sizeof(explanation
), frame
, data_len
, hdr
->isResponse
);
798 annotateIclass(explanation
, sizeof(explanation
), frame
, data_len
, hdr
->isResponse
);
804 if (hdr
->isResponse
== false) {
807 annotateLegic(explanation
, sizeof(explanation
), frame
, data_len
);
810 annotateMfDesfire(explanation
, sizeof(explanation
), frame
, data_len
);
813 annotateMfPlus(explanation
, sizeof(explanation
), frame
, data_len
);
816 annotateIso14443b(explanation
, sizeof(explanation
), frame
, data_len
);
819 annotateTopaz(explanation
, sizeof(explanation
), frame
, data_len
);
822 annotateIso7816(explanation
, sizeof(explanation
), frame
, data_len
);
825 annotateIso15693(explanation
, sizeof(explanation
), frame
, data_len
);
828 annotateFelica(explanation
, sizeof(explanation
), frame
, data_len
);
831 annotateLTO(explanation
, sizeof(explanation
), frame
, data_len
);
834 annotateCryptoRF(explanation
, sizeof(explanation
), frame
, data_len
);
837 annotateSeos(explanation
, sizeof(explanation
), frame
, data_len
);
845 int num_lines
= MIN((data_len
- 1) / TRACE_MAX_HEX_BYTES
+ 1, TRACE_MAX_HEX_BYTES
);
847 for (int j
= 0; j
< num_lines
; j
++) {
849 bool last_line
= (j
== num_lines
- 1);
855 uint32_t time1
= hdr
->timestamp
- first_hdr
->timestamp
;
856 uint32_t time2
= end_of_transmission_timestamp
- first_hdr
->timestamp
;
858 time1
= hdr
->timestamp
- previous_end_of_transmission_timestamp
;
862 // ansi codes addes extra chars that needs to be taken in consideration.
863 if (last_line
&& (memcmp(crc
, "\x20\x20\x20\x20", 4) != 0) && g_session
.supports_colors
&& markCRCBytes
) {
867 if (hdr
->isResponse
) {
870 PrintAndLogEx(NORMAL
, " %10.1f | %10.1f | Tag |%-*s | %s| %s",
871 (float)time1
/ 13.56,
872 (float)time2
/ 13.56,
875 (last_line
) ? crc
: " ",
876 (last_line
) ? explanation
: ""
879 PrintAndLogEx(NORMAL
, " %10u | %10u | Tag |%-*s | %s| %s",
884 (last_line
) ? crc
: " ",
885 (last_line
) ? explanation
: ""
891 PrintAndLogEx(NORMAL
,
892 _YELLOW_(" %10.1f") " | " _YELLOW_("%10.1f") " | " _YELLOW_("Rdr") " |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
893 (float)time1
/ 13.56,
894 (float)time2
/ 13.56,
897 (last_line
) ? crc
: " ",
898 (last_line
) ? explanation
: ""
901 PrintAndLogEx(NORMAL
,
902 _YELLOW_(" %10u") " | " _YELLOW_("%10u") " | " _YELLOW_("Rdr") " |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
907 (last_line
) ? crc
: " ",
908 (last_line
) ? explanation
: ""
916 if (last_line
&& (memcmp(crc
, "\x20\x20\x20\x20", 4) != 0) && g_session
.supports_colors
&& markCRCBytes
) {
918 // odd case of multiline, and last single byte on empty row has been colorised...
919 if (strlen(line
[j
]) < 14) {
924 if (hdr
->isResponse
) {
925 PrintAndLogEx(NORMAL
, " | | |%-*s | %s| %s",
928 last_line
? crc
: " ",
929 last_line
? explanation
: ""
932 PrintAndLogEx(NORMAL
, " | | |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
935 last_line
? crc
: " ",
936 last_line
? explanation
: ""
943 if (protocol
== PROTO_MIFARE
|| protocol
== PROTO_MFPLUS
) {
944 uint8_t mfData
[32] = {0};
945 size_t mfDataLen
= 0;
946 if (DecodeMifareData(frame
, data_len
, parityBytes
, hdr
->isResponse
, mfData
, &mfDataLen
, mfDicKeys
, mfDicKeysCount
)) {
947 memset(explanation
, 0x00, sizeof(explanation
));
949 if (protocol
== PROTO_MFPLUS
) {
950 annotateMfPlus(explanation
, sizeof(explanation
), mfData
, mfDataLen
);
952 annotateIso14443a(explanation
, sizeof(explanation
), mfData
, mfDataLen
, hdr
->isResponse
);
954 uint8_t crcc
= iso14443A_CRC_check(hdr
->isResponse
, mfData
, mfDataLen
);
956 // iceman: colorise crc bytes here will need a refactor of code from above.
957 for (int j
= 0; j
< mfDataLen
; j
+= TRACE_MAX_HEX_BYTES
) {
959 int plen
= MIN((mfDataLen
- j
), TRACE_MAX_HEX_BYTES
);
961 if (hdr
->isResponse
) {
962 PrintAndLogEx(NORMAL
, " | | * |%-*s | %-4s| %s",
964 sprint_hex_inrow_spaces(mfData
+ j
, plen
, 2),
965 (crcc
== 0 ? _RED_(" !! ") : (crcc
== 1 ? _GREEN_(" ok ") : " ")),
968 PrintAndLogEx(NORMAL
, " | | * |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
970 sprint_hex_inrow_spaces(mfData
+ j
, plen
, 2),
971 (crcc
== 0 ? _RED_(" !! ") : (crcc
== 1 ? _GREEN_(" ok ") : " ")),
978 if (protocol
== PROTO_HITAG2
) {
980 uint8_t ht2plain
[9] = {0};
982 if (hitag2_get_plain(ht2plain
, &n
)) {
984 memset(explanation
, 0x00, sizeof(explanation
));
986 // handle partial bytes. The parity array[0] is used to store number of left over bits from NBYTES
987 // This part prints the number of bits in the trace entry for hitag.
988 uint8_t nbits
= parityBytes
[0];
989 annotateHitag2(explanation
, sizeof(explanation
), ht2plain
, n
, nbits
, hdr
->isResponse
, NULL
, 0, true);
991 // iceman: colorise crc bytes here will need a refactor of code from above.
992 for (int j
= 0; j
< n
&& (j
/ TRACE_MAX_HEX_BYTES
) < TRACE_MAX_HEX_BYTES
; j
++) {
997 // only apply this to lesser than one byte
999 snprintf(line
[0], 120, "%2u: %02X ", nbits
, ht2plain
[0] >> (8 - nbits
));
1003 snprintf(line
[0], 120, "%2u: %02X ", (uint16_t)(n
* 8), ht2plain
[0]);
1005 snprintf(line
[0], 120, "%2u: %02X ", (uint16_t)(((n
- 1) * 8) + nbits
), ht2plain
[0]);
1011 snprintf(line
[j
/ 18] + ((j
% 18) * 4) + offset
, 120, "%02X ", ht2plain
[j
]);
1015 num_lines
= MIN((n
- 1) / TRACE_MAX_HEX_BYTES
+ 1, TRACE_MAX_HEX_BYTES
);
1017 for (int j
= 0; j
< num_lines
; j
++) {
1018 if (hdr
->isResponse
) {
1019 PrintAndLogEx(NORMAL
, " | | * |%-*s | %-4s| %s",
1025 PrintAndLogEx(NORMAL
, " | | * |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
1036 if (is_last_record(tracepos
, traceLen
)) {
1040 if (showWaitCycles
&& hdr
->isResponse
== false && next_record_is_response(tracepos
, trace
)) {
1042 const tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
1044 uint32_t time1
= end_of_transmission_timestamp
- first_hdr
->timestamp
;
1045 uint32_t time2
= next_hdr
->timestamp
- first_hdr
->timestamp
;
1048 time2
= next_hdr
->timestamp
- end_of_transmission_timestamp
;
1052 PrintAndLogEx(NORMAL
, " %10.1f | %10.1f | %s |fdt (Frame Delay Time): " _YELLOW_("%.1f"),
1053 (float)time1
/ 13.56,
1054 (float)time2
/ 13.56,
1056 (float)(next_hdr
->timestamp
- end_of_transmission_timestamp
) / 13.56);
1058 PrintAndLogEx(NORMAL
, " %10u | %10u | %s |fdt (Frame Delay Time): " _YELLOW_("%d"),
1062 (next_hdr
->timestamp
- end_of_transmission_timestamp
));
1069 static int download_trace(void) {
1071 if (IfPm3Present() == false) {
1072 PrintAndLogEx(FAILED
, "You requested a trace upload in offline mode, consider using parameter `" _YELLOW_("-1") "` for working from Tracebuffer");
1076 // reserve some space.
1083 gs_trace
= calloc(PM3_CMD_DATA_SIZE
, sizeof(uint8_t));
1084 if (gs_trace
== NULL
) {
1085 PrintAndLogEx(FAILED
, "Cannot allocate memory for trace");
1089 PrintAndLogEx(DEBUG
, "downloading tracelog data from device");
1091 // Query for the size of the trace, downloading PM3_CMD_DATA_SIZE
1092 PacketResponseNG resp
;
1093 if (!GetFromDevice(BIG_BUF
, gs_trace
, PM3_CMD_DATA_SIZE
, 0, NULL
, 0, &resp
, 4000, true)) {
1094 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
1097 return PM3_ETIMEOUT
;
1100 gs_traceLen
= resp
.oldarg
[2];
1102 // if tracelog buffer was larger and we need to download more.
1103 if (gs_traceLen
> PM3_CMD_DATA_SIZE
) {
1106 gs_trace
= calloc(gs_traceLen
, sizeof(uint8_t));
1107 if (gs_trace
== NULL
) {
1108 PrintAndLogEx(FAILED
, "Cannot allocate memory for trace");
1112 if (!GetFromDevice(BIG_BUF
, gs_trace
, gs_traceLen
, 0, NULL
, 0, NULL
, 2500, false)) {
1113 PrintAndLogEx(WARNING
, "command execution time out");
1116 return PM3_ETIMEOUT
;
1122 // sanity check. Don't use proxmark if it is offline and you didn't specify useTraceBuffer
1124 static int SanityOfflineCheck( bool useTraceBuffer ){
1125 if ( !useTraceBuffer && offline) {
1126 PrintAndLogEx(NORMAL, "Your proxmark3 device is offline. Specify [1] to use TraceBuffer data instead");
1133 static int CmdTraceExtract(const char *Cmd
) {
1134 CLIParserContext
*ctx
;
1135 CLIParserInit(&ctx
, "trace extract",
1136 "Extracts protocol authentication challenges from trace buffer\n",
1138 "trace extract -1\n"
1141 void *argtable
[] = {
1143 arg_lit0("1", "buffer", "use data from trace buffer"),
1146 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1147 bool use_buffer
= arg_get_lit(ctx
, 1);
1150 clearCommandBuffer();
1152 if (use_buffer
== false) {
1154 } else if (gs_traceLen
== 0) {
1155 PrintAndLogEx(FAILED
, "You requested a trace list in offline mode but there is no trace.");
1156 PrintAndLogEx(FAILED
, "Consider using `" _YELLOW_("trace load") "` or removing parameter `" _YELLOW_("-1") "`");
1160 PrintAndLogEx(SUCCESS
, "Recorded activity ( " _YELLOW_("%u") " bytes )", gs_traceLen
);
1161 if (gs_traceLen
== 0) {
1165 uint16_t tracepos
= 0;
1167 while (tracepos
< gs_traceLen
) {
1168 tracepos
= extractChallenges(tracepos
, gs_traceLen
, gs_trace
);
1170 if (kbd_enter_pressed()) {
1177 static int CmdTraceLoad(const char *Cmd
) {
1179 CLIParserContext
*ctx
;
1180 CLIParserInit(&ctx
, "trace load",
1181 "Load protocol data from binary file to trace buffer\n"
1182 "File extension is <.trace>",
1183 "trace load -f mytracefile -> w/o file extension"
1186 void *argtable
[] = {
1188 arg_str1("f", "file", "<fn>", "Specify trace file to load"),
1191 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1194 char filename
[FILE_PATH_SIZE
] = {0};
1195 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
1199 free(gs_trace
); // maybe better to not clobber this until we have successful load?
1205 if (loadFile_safe(filename
, ".trace", (void **)&gs_trace
, &len
) != PM3_SUCCESS
) {
1206 PrintAndLogEx(FAILED
, "Could not open file " _YELLOW_("%s"), filename
);
1210 gs_traceLen
= (long)len
;
1212 PrintAndLogEx(SUCCESS
, "Recorded Activity (TraceLen = " _YELLOW_("%u") " bytes)", gs_traceLen
);
1213 PrintAndLogEx(HINT
, "try " _YELLOW_("`trace list -1 -t ...`") " to view trace. Remember the " _YELLOW_("`-1`") " param");
1217 static int CmdTraceSave(const char *Cmd
) {
1219 CLIParserContext
*ctx
;
1220 CLIParserInit(&ctx
, "trace save",
1221 "Save protocol data from trace buffer to binary file\n"
1222 "File extension is <.trace>",
1223 "trace save -f mytracefile -> w/o file extension"
1226 void *argtable
[] = {
1228 arg_str1("f", "file", "<fn>", "Specify trace file to save"),
1231 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1234 char filename
[FILE_PATH_SIZE
] = {0};
1235 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
1238 if (gs_traceLen
== 0) {
1240 if (gs_traceLen
== 0) {
1241 PrintAndLogEx(WARNING
, "trace is empty, nothing to save");
1246 saveFile(filename
, ".trace", gs_trace
, gs_traceLen
);
1250 int CmdTraceListAlias(const char *Cmd
, const char *alias
, const char *protocol
) {
1251 CLIParserContext
*ctx
;
1252 char desc
[500] = {0};
1253 snprintf(desc
, sizeof(desc
) - 1,
1254 "Alias of `trace list -t %s` with selected protocol data to annotate trace buffer\n"
1255 "You can load a trace from file (see `trace load -h`) or it be downloaded from device by default\n"
1256 "It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
1258 char example
[200] = {0};
1259 snprintf(example
, sizeof(example
) - 1,
1260 "%s list --frame -> show frame delay times\n"
1261 "%s list -1 -> use trace buffer ",
1263 char fullalias
[100] = {0};
1264 snprintf(fullalias
, sizeof(fullalias
) - 1, "%s list", alias
);
1265 CLIParserInit(&ctx
, fullalias
, desc
, example
);
1267 void *argtable
[] = {
1269 arg_lit0("1", "buffer", "use data from trace buffer"),
1270 arg_lit0(NULL
, "frame", "show frame delay times"),
1271 arg_lit0("c", NULL
, "mark CRC bytes"),
1272 arg_lit0("r", NULL
, "show relative times (gap and duration)"),
1273 arg_lit0("u", NULL
, "display times in microseconds instead of clock cycles"),
1274 arg_lit0("x", NULL
, "show hexdump to convert to pcap(ng)\n"
1275 " or to import into Wireshark using encapsulation type \"ISO 14443\""),
1276 arg_str0("f", "file", "<fn>", "filename of dictionary"),
1279 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1282 char args
[128] = {0};
1283 snprintf(args
, sizeof(args
), "-t %s ", protocol
);
1284 strncat(args
, Cmd
, sizeof(args
) - strlen(args
) - 1);
1285 return CmdTraceList(args
);
1288 int CmdTraceList(const char *Cmd
) {
1289 CLIParserContext
*ctx
;
1290 CLIParserInit(&ctx
, "trace list",
1291 "Annotate trace buffer with selected protocol data\n"
1292 "You can load a trace from file (see `trace load -h`) or it be downloaded from device by default\n",
1293 "trace list -t raw -> just show raw data without annotations\n"
1295 "trace list -t 14a -> interpret as " _YELLOW_("ISO14443-A") "\n"
1296 "trace list -t 14b -> interpret as " _YELLOW_("ISO14443-B") "\n"
1297 "trace list -t 15 -> interpret as " _YELLOW_("ISO15693") "\n"
1298 "trace list -t 7816 -> interpret as " _YELLOW_("ISO7816-4") "\n"
1299 "trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") "\n\n"
1300 "trace list -t des -> interpret as " _YELLOW_("MIFARE DESFire") "\n"
1301 "trace list -t felica -> interpret as " _YELLOW_("ISO18092 / FeliCa") "\n"
1302 "trace list -t hitag1 -> interpret as " _YELLOW_("Hitag 1") "\n"
1303 "trace list -t hitag2 -> interpret as " _YELLOW_("Hitag 2") "\n"
1304 "trace list -t hitags -> interpret as " _YELLOW_("Hitag S") "\n"
1305 "trace list -t iclass -> interpret as " _YELLOW_("iCLASS") "\n"
1306 "trace list -t legic -> interpret as " _YELLOW_("LEGIC") "\n"
1307 "trace list -t lto -> interpret as " _YELLOW_("LTO-CM") "\n"
1308 "trace list -t mf -> interpret as " _YELLOW_("MIFARE Classic") " and decrypt crypto1 stream\n"
1309 "trace list -t seos -> interpret as " _YELLOW_("SEOS") "\n"
1310 "trace list -t thinfilm -> interpret as " _YELLOW_("Thinfilm") "\n"
1311 "trace list -t topaz -> interpret as " _YELLOW_("Topaz") "\n"
1312 "trace list -t mfp -> interpret as " _YELLOW_("MIFARE Plus") "\n"
1314 "trace list -t mf -f mfc_default_keys.dic -> use default dictionary file\n"
1315 "trace list -t 14a --frame -> show frame delay times\n"
1316 "trace list -t 14a -1 -> use trace buffer "
1319 void *argtable
[] = {
1321 arg_lit0("1", "buffer", "use data from trace buffer"),
1322 arg_lit0(NULL
, "frame", "show frame delay times"),
1323 arg_lit0("c", NULL
, "mark CRC bytes"),
1324 arg_lit0("r", NULL
, "show relative times (gap and duration)"),
1325 arg_lit0("u", NULL
, "display times in microseconds instead of clock cycles"),
1326 arg_lit0("x", NULL
, "show hexdump to convert to pcap(ng)\n"
1327 " or to import into Wireshark using encapsulation type \"ISO 14443\""),
1328 arg_str0("t", "type", NULL
, "protocol to annotate the trace"),
1329 arg_str0("f", "file", "<fn>", "filename of dictionary"),
1332 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1334 bool use_buffer
= arg_get_lit(ctx
, 1);
1335 bool show_wait_cycles
= arg_get_lit(ctx
, 2);
1336 bool mark_crc
= arg_get_lit(ctx
, 3);
1337 bool use_relative
= arg_get_lit(ctx
, 4);
1338 bool use_us
= arg_get_lit(ctx
, 5);
1339 bool show_hex
= arg_get_lit(ctx
, 6);
1342 char type
[10] = {0};
1343 CLIParamStrToBuf(arg_get_str(ctx
, 7), (uint8_t *)type
, sizeof(type
), &tlen
);
1347 char dictionary
[FILE_PATH_SIZE
+ 2] = {0};
1348 if (CLIParamStrToBuf(arg_get_str(ctx
, 8), (uint8_t *)dictionary
, FILE_PATH_SIZE
, &diclen
)) {
1349 PrintAndLogEx(FAILED
, "Dictionary file name too long or invalid.");
1355 clearCommandBuffer();
1357 // no crc, no annotations
1358 uint8_t protocol
= -1;
1360 // validate type of output
1361 if (strcmp(type
, "14a") == 0) protocol
= ISO_14443A
;
1362 else if (strcmp(type
, "14b") == 0) protocol
= ISO_14443B
;
1363 else if (strcmp(type
, "15") == 0) protocol
= ISO_15693
;
1364 else if (strcmp(type
, "7816") == 0) protocol
= ISO_7816_4
;
1365 else if (strcmp(type
, "cryptorf") == 0) protocol
= PROTO_CRYPTORF
;
1366 else if (strcmp(type
, "des") == 0) protocol
= MFDES
;
1367 else if (strcmp(type
, "felica") == 0) protocol
= FELICA
;
1368 else if (strcmp(type
, "hitag1") == 0) protocol
= PROTO_HITAG1
;
1369 else if (strcmp(type
, "hitag2") == 0) protocol
= PROTO_HITAG2
;
1370 else if (strcmp(type
, "hitags") == 0) protocol
= PROTO_HITAGS
;
1371 else if (strcmp(type
, "iclass") == 0) protocol
= ICLASS
;
1372 else if (strcmp(type
, "legic") == 0) protocol
= LEGIC
;
1373 else if (strcmp(type
, "lto") == 0) protocol
= LTO
;
1374 else if (strcmp(type
, "mf") == 0) protocol
= PROTO_MIFARE
;
1375 else if (strcmp(type
, "raw") == 0) protocol
= -1;
1376 else if (strcmp(type
, "seos") == 0) protocol
= SEOS
;
1377 else if (strcmp(type
, "thinfilm") == 0) protocol
= THINFILM
;
1378 else if (strcmp(type
, "topaz") == 0) protocol
= TOPAZ
;
1379 else if (strcmp(type
, "mfp") == 0) protocol
= PROTO_MFPLUS
;
1380 else if (strcmp(type
, "") == 0) protocol
= -1;
1382 PrintAndLogEx(FAILED
, "Unknown protocol \"%s\"", type
);
1386 if (use_buffer
== false) {
1388 } else if (gs_traceLen
== 0 || gs_trace
== NULL
) {
1390 if (IfPm3Present() == false) {
1391 PrintAndLogEx(FAILED
, "You requested a trace list in offline mode but there is no trace.");
1393 PrintAndLogEx(FAILED
, "You requested a trace list but there is no trace.");
1396 PrintAndLogEx(FAILED
, "Consider using `" _YELLOW_("trace load") "` or removing parameter `" _YELLOW_("-1") "`");
1400 PrintAndLogEx(SUCCESS
, "Recorded activity ( " _YELLOW_("%u") " bytes )", gs_traceLen
);
1401 if (gs_traceLen
== 0) {
1405 uint16_t tracepos
= 0;
1408 if (protocol == FELICA) {
1409 printFelica(gs_traceLen, gs_trace);
1413 while (tracepos
< gs_traceLen
) {
1414 tracepos
= printHexLine(tracepos
, gs_traceLen
, gs_trace
, protocol
);
1419 PrintAndLogEx(INFO
, _YELLOW_("gap") " = time between transfers. " _YELLOW_("duration") " = duration of data transfer. " _YELLOW_("src") " = source of transfer.");
1421 PrintAndLogEx(INFO
, _YELLOW_("start") " = start of start frame. " _YELLOW_("end") " = end of frame. " _YELLOW_("src") " = source of transfer.");
1424 if (protocol
== ISO_14443A
|| protocol
== PROTO_MIFARE
|| protocol
== MFDES
|| protocol
== PROTO_MFPLUS
|| protocol
== TOPAZ
|| protocol
== LTO
) {
1426 PrintAndLogEx(INFO
, _YELLOW_("ISO14443A") " - all times are in microseconds");
1428 PrintAndLogEx(INFO
, _YELLOW_("ISO14443A") " - all times are in carrier periods (1/13.56MHz)");
1431 if (protocol
== THINFILM
) {
1433 PrintAndLogEx(INFO
, _YELLOW_("Thinfilm") " - all times are in microseconds");
1435 PrintAndLogEx(INFO
, _YELLOW_("Thinfilm") " - all times are in carrier periods (1/13.56MHz)");
1438 if (protocol
== ICLASS
|| protocol
== ISO_15693
) {
1440 PrintAndLogEx(INFO
, _YELLOW_("ISO15693 / iCLASS") " - all times are in microseconds");
1442 PrintAndLogEx(INFO
, _YELLOW_("ISO15693 / iCLASS") " - all times are in carrier periods (1/13.56MHz)");
1445 if (protocol
== LEGIC
)
1446 PrintAndLogEx(INFO
, _YELLOW_("LEGIC") " - Reader Mode: Timings are in ticks (1us == 1.5ticks)\n"
1447 " Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)");
1449 if (protocol
== ISO_14443B
|| protocol
== PROTO_CRYPTORF
) {
1451 PrintAndLogEx(INFO
, _YELLOW_("ISO14443B") " - all times are in microseconds");
1453 PrintAndLogEx(INFO
, _YELLOW_("ISO14443B") " - all times are in carrier periods (1/13.56MHz)");
1456 if (protocol
== ISO_7816_4
)
1457 PrintAndLogEx(INFO
, _YELLOW_("ISO7816-4 / Smartcard") " - Timings n/a");
1459 if (protocol
== PROTO_HITAG1
|| protocol
== PROTO_HITAG2
|| protocol
== PROTO_HITAGS
) {
1460 PrintAndLogEx(INFO
, _YELLOW_("Hitag 1 / Hitag 2 / Hitag S") " - Timings in ETU (8us)");
1463 if (protocol
== FELICA
) {
1465 PrintAndLogEx(INFO
, _YELLOW_("ISO18092 / FeliCa") " - all times are in microseconds");
1467 PrintAndLogEx(INFO
, _YELLOW_("ISO18092 / FeliCa") " - all times are in carrier periods (1/13.56MHz)");
1471 const uint64_t *dicKeys
= NULL
;
1472 uint32_t dicKeysCount
= 0;
1473 bool dictionaryLoad
= false;
1475 if (protocol
== PROTO_MIFARE
|| protocol
== PROTO_MFPLUS
) {
1477 uint8_t *keyBlock
= NULL
;
1478 int res
= loadFileDICTIONARY_safe(dictionary
, (void **) &keyBlock
, 6, &dicKeysCount
);
1479 if (res
!= PM3_SUCCESS
|| dicKeysCount
== 0 || keyBlock
== NULL
) {
1480 PrintAndLogEx(FAILED
, "An error occurred while loading the dictionary! (we will use the default keys now)");
1482 dicKeys
= calloc(dicKeysCount
, sizeof(uint64_t));
1483 for (int i
= 0; i
< dicKeysCount
; i
++) {
1484 uint64_t key
= bytes_to_num(keyBlock
+ i
* 6, 6);
1485 memcpy((uint8_t *) &dicKeys
[i
], &key
, sizeof(uint64_t));
1487 dictionaryLoad
= true;
1489 if (keyBlock
!= NULL
) {
1493 if (dicKeys
== NULL
) {
1494 dicKeys
= g_mifare_default_keys
;
1495 dicKeysCount
= ARRAYLEN(g_mifare_default_keys
);
1499 if (protocol
== PROTO_HITAG2
) {
1501 if (strlen(dictionary
) == 0) {
1502 snprintf(dictionary
, sizeof(dictionary
), HITAG_DICTIONARY
);
1506 uint8_t *keyBlock
= NULL
;
1507 int res
= loadFileDICTIONARY_safe(dictionary
, (void **) &keyBlock
, HITAG_CRYPTOKEY_SIZE
, &dicKeysCount
);
1508 if (res
!= PM3_SUCCESS
|| dicKeysCount
== 0 || keyBlock
== NULL
) {
1509 PrintAndLogEx(FAILED
, "An error occurred while loading the dictionary!");
1511 dicKeys
= calloc(dicKeysCount
, sizeof(uint64_t));
1512 for (int i
= 0; i
< dicKeysCount
; i
++) {
1513 uint64_t key
= bytes_to_num(keyBlock
+ i
* HITAG_CRYPTOKEY_SIZE
, HITAG_CRYPTOKEY_SIZE
);
1514 memcpy((uint8_t *) &dicKeys
[i
], &key
, sizeof(uint64_t));
1516 dictionaryLoad
= true;
1518 if (keyBlock
!= NULL
) {
1523 PrintAndLogEx(NORMAL
, "");
1525 PrintAndLogEx(NORMAL
, " Gap | Duration | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation");
1527 PrintAndLogEx(NORMAL
, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation");
1529 PrintAndLogEx(NORMAL
, "------------+------------+-----+-------------------------------------------------------------------------+-----+--------------------");
1531 // clean authentication data used with the mifare classic decrypt fct
1532 if (protocol
== ISO_14443A
|| protocol
== PROTO_MIFARE
|| protocol
== PROTO_MFPLUS
) {
1536 // reset hitag state machine
1537 if (protocol
== PROTO_HITAG1
|| protocol
== PROTO_HITAG2
|| protocol
== PROTO_HITAGS
) {
1538 annotateHitag2_init();
1541 uint32_t previous_EOT
= 0;
1542 uint32_t *prev_EOT
= NULL
;
1544 prev_EOT
= &previous_EOT
;
1547 while (tracepos
< gs_traceLen
) {
1548 tracepos
= printTraceLine(tracepos
, gs_traceLen
, gs_trace
, protocol
, show_wait_cycles
, mark_crc
, prev_EOT
, use_us
, dicKeys
, dicKeysCount
);
1550 if (kbd_enter_pressed()) {
1555 if (dictionaryLoad
) {
1556 free((void *) dicKeys
);
1561 PrintAndLogEx(HINT
, "syntax to use: " _YELLOW_("`text2pcap -t \"%%S.\" -l 264 -n <input-text-file> <output-pcapng-file>`"));
1567 static command_t CommandTable
[] = {
1568 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
1569 {"extract", CmdTraceExtract
, AlwaysAvailable
, "Extract authentication challenges found in trace"},
1570 {"list", CmdTraceList
, AlwaysAvailable
, "List protocol data in trace buffer"},
1571 {"load", CmdTraceLoad
, AlwaysAvailable
, "Load trace from file"},
1572 {"save", CmdTraceSave
, AlwaysAvailable
, "Save trace buffer to file"},
1573 {NULL
, NULL
, NULL
, NULL
}
1576 static int CmdHelp(const char *Cmd
) {
1577 (void)Cmd
; // Cmd is not used so far
1578 CmdsHelp(CommandTable
);
1582 int CmdTrace(const char *Cmd
) {
1583 clearCommandBuffer();
1584 return CmdsParse(CommandTable
, Cmd
);