1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 iceman <iceman at iuse.se>
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
7 //-----------------------------------------------------------------------------
9 //-----------------------------------------------------------------------------
14 #include "cmdparser.h" // command_t
15 #include "protocols.h"
16 #include "parity.h" // oddparity
17 #include "cmdhflist.h" // annotations
18 #include "commonutil.h" // ARRAYLEN
19 #include "mifare/mifaredefault.h" // mifare default key array
20 #include "comms.h" // for sending cmds to device. GetFromBigBuf
21 #include "fileutils.h" // for saveFile
22 #include "cmdlfhitag.h" // annotate hitag
23 #include "pm3_cmd.h" // tracelog_hdr_t
24 #include "cliparser.h" // args..
26 static int CmdHelp(const char *Cmd
);
29 static uint8_t *g_trace
;
30 static long g_traceLen
= 0;
32 static bool is_last_record(uint16_t tracepos
, uint16_t traceLen
) {
33 return ((tracepos
+ TRACELOG_HDR_LEN
) >= traceLen
);
36 static bool next_record_is_response(uint16_t tracepos
, uint8_t *trace
) {
37 tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
38 return (hdr
->isResponse
);
41 static bool merge_topaz_reader_frames(uint32_t timestamp
, uint32_t *duration
, uint16_t *tracepos
, uint16_t traceLen
,
42 uint8_t *trace
, uint8_t *frame
, uint8_t *topaz_reader_command
, uint16_t *data_len
) {
44 #define MAX_TOPAZ_READER_CMD_LEN 16
46 uint32_t last_timestamp
= timestamp
+ *duration
;
48 if ((*data_len
!= 1) || (frame
[0] == TOPAZ_WUPA
) || (frame
[0] == TOPAZ_REQA
)) return false;
50 memcpy(topaz_reader_command
, frame
, *data_len
);
52 while (!is_last_record(*tracepos
, traceLen
) && !next_record_is_response(*tracepos
, trace
)) {
54 tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ *tracepos
);
56 *tracepos
+= TRACELOG_HDR_LEN
+ hdr
->data_len
;
58 if ((hdr
->data_len
== 1) && (*data_len
+ hdr
->data_len
<= MAX_TOPAZ_READER_CMD_LEN
)) {
59 memcpy(topaz_reader_command
+ *data_len
, hdr
->frame
, hdr
->data_len
);
60 *data_len
+= hdr
->data_len
;
61 last_timestamp
= hdr
->timestamp
+ hdr
->duration
;
64 *tracepos
= *tracepos
- hdr
->data_len
- TRACELOG_HDR_LEN
;
67 *tracepos
+= TRACELOG_PARITY_LEN(hdr
);
70 *duration
= last_timestamp
- timestamp
;
75 static uint16_t printHexLine(uint16_t tracepos
, uint16_t traceLen
, uint8_t *trace
, uint8_t protocol
) {
77 if (is_last_record(tracepos
, traceLen
)) return traceLen
;
79 tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
81 if (TRACELOG_HDR_LEN
+ hdr
->data_len
+ TRACELOG_PARITY_LEN(hdr
) > traceLen
) {
86 tracepos
+= TRACELOG_HDR_LEN
+ hdr
->data_len
+ TRACELOG_PARITY_LEN(hdr
);
88 if (hdr
->data_len
== 0) {
89 PrintAndLogEx(NORMAL
, "<empty trace - possible error>");
97 /* https://www.kaiser.cx/pcap-iso14443.html defines a pseudo header:
98 * version (currently 0x00), event (Rdr: 0xfe, Tag: 0xff), length (2 bytes)
99 * to convert to pcap(ng) via text2pcap or to import into Wireshark
100 * we use format timestamp, newline, offset (0x000000), pseudo header, data
101 * `text2pcap -t "%S." -l 264 -n <input-text-file> <output-pcapng-file>`
103 char line
[(hdr
->data_len
* 3) + 1];
104 char *ptr
= &line
[0];
106 for (int i
= 0; i
< hdr
->data_len
; i
++) {
107 ptr
+= sprintf(ptr
, "%02x ", hdr
->frame
[i
]);
110 char data_len_str
[5];
111 char temp_str1
[3] = {0};
112 char temp_str2
[3] = {0};
114 sprintf(data_len_str
, "%04x", hdr
->data_len
);
115 memmove(temp_str1
, data_len_str
, 2);
116 memmove(temp_str2
, data_len_str
+ 2, 2);
118 PrintAndLogEx(NORMAL
, "0.%010u", hdr
->timestamp
);
119 PrintAndLogEx(NORMAL
, "000000 00 %s %s %s %s",
120 (hdr
->isResponse
? "ff" : "fe"),
128 PrintAndLogEx(NORMAL
, "Currently only 14a supported");
136 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
,
137 const uint64_t *mfDicKeys
, uint32_t mfDicKeysCount
) {
139 if (is_last_record(tracepos
, traceLen
)) {
140 PrintAndLogEx(DEBUG
, "last record triggered. t-pos: %u t-len %u", tracepos
, traceLen
);
144 uint32_t end_of_transmission_timestamp
= 0;
147 uint8_t topaz_reader_command
[9];
148 char explanation
[40] = {0};
149 uint8_t mfData
[32] = {0};
150 size_t mfDataLen
= 0;
151 tracelog_hdr_t
*first_hdr
= (tracelog_hdr_t
*)(trace
);
152 tracelog_hdr_t
*hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
154 duration
= hdr
->duration
;
155 data_len
= hdr
->data_len
;
157 if (tracepos
+ TRACELOG_HDR_LEN
+ data_len
+ TRACELOG_PARITY_LEN(hdr
) > traceLen
) {
158 PrintAndLogEx(DEBUG
, "trace pos offset %"PRIu64
" larger than reported tracelen %u", tracepos
+ TRACELOG_HDR_LEN
+ data_len
+ TRACELOG_PARITY_LEN(hdr
), traceLen
);
162 // adjust for different time scales
163 if (protocol
== ICLASS
|| protocol
== ISO_15693
) {
167 uint8_t *frame
= hdr
->frame
;
168 uint8_t *parityBytes
= hdr
->frame
+ data_len
;
170 tracepos
+= TRACELOG_HDR_LEN
+ data_len
+ TRACELOG_PARITY_LEN(hdr
);
172 if (protocol
== TOPAZ
&& !hdr
->isResponse
) {
173 // topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each.
175 if (merge_topaz_reader_frames(hdr
->timestamp
, &duration
, &tracepos
, traceLen
, trace
, frame
, topaz_reader_command
, &data_len
)) {
176 frame
= topaz_reader_command
;
180 //Check the CRC status
181 uint8_t crcStatus
= 2;
186 crcStatus
= iclass_CRC_check(hdr
->isResponse
, frame
, data_len
);
190 crcStatus
= iso14443B_CRC_check(frame
, data_len
);
193 crcStatus
= !felica_CRC_check(frame
+ 2, data_len
- 4);
196 crcStatus
= mifare_CRC_check(hdr
->isResponse
, frame
, data_len
);
201 crcStatus
= iso14443A_CRC_check(hdr
->isResponse
, frame
, data_len
);
204 crcStatus
= iso14443A_CRC_check(hdr
->isResponse
, frame
, data_len
) == 1 ? 3 : 0;
205 crcStatus
= iso14443B_CRC_check(frame
, data_len
) == 1 ? 4 : crcStatus
;
208 frame
[data_len
- 1] ^= frame
[data_len
- 2];
209 frame
[data_len
- 2] ^= frame
[data_len
- 1];
210 frame
[data_len
- 1] ^= frame
[data_len
- 2];
211 crcStatus
= iso14443A_CRC_check(true, frame
, data_len
);
212 frame
[data_len
- 1] ^= frame
[data_len
- 2];
213 frame
[data_len
- 2] ^= frame
[data_len
- 1];
214 frame
[data_len
- 1] ^= frame
[data_len
- 2];
217 crcStatus
= iso15693_CRC_check(frame
, data_len
);
227 //0 CRC-command, CRC not ok
228 //1 CRC-command, CRC ok
231 //--- Draw the data column
232 char line
[18][120] = {{0}};
235 if (protocol
== ICLASS
&& duration
== 2048) {
236 sprintf(line
[0], "<SOF>");
237 } else if (protocol
== ISO_15693
&& duration
== 512) {
238 sprintf(line
[0], "<EOF>");
240 sprintf(line
[0], "<empty trace - possible error>");
244 for (int j
= 0; j
< data_len
&& j
/ 18 < 18; j
++) {
245 uint8_t parityBits
= parityBytes
[j
>> 3];
246 if (protocol
!= LEGIC
247 && protocol
!= ISO_14443B
248 && protocol
!= ISO_15693
249 && protocol
!= ICLASS
250 && protocol
!= ISO_7816_4
251 && protocol
!= PROTO_HITAG1
252 && protocol
!= PROTO_HITAG2
253 && protocol
!= PROTO_HITAGS
254 && protocol
!= THINFILM
255 && protocol
!= FELICA
257 && protocol
!= PROTO_CRYPTORF
258 && (hdr
->isResponse
|| protocol
== ISO_14443A
|| protocol
== PROTO_MIFARE
)
259 && (oddparity8(frame
[j
]) != ((parityBits
>> (7 - (j
& 0x0007))) & 0x01))) {
261 snprintf(line
[j
/ 18] + ((j
% 18) * 4), 120, "%02x! ", frame
[j
]);
262 } else if (protocol
== ICLASS
&& hdr
->isResponse
== false) {
264 for (int i
= 0; i
< 6; i
++) {
265 parity
^= ((frame
[0] >> i
) & 1);
267 if (parity
== ((frame
[0] >> 7) & 1)) {
268 snprintf(line
[j
/ 18] + ((j
% 18) * 4), 120, "%02x ", frame
[j
]);
270 snprintf(line
[j
/ 18] + ((j
% 18) * 4), 120, "%02x! ", frame
[j
]);
274 snprintf(line
[j
/ 18] + ((j
% 18) * 4), 120, "%02x ", frame
[j
]);
281 if (crcStatus
== 0 || crcStatus
== 1) {
282 char *pos1
= line
[(data_len
- 2) / 18] + (((data_len
- 2) % 18) * 4) - 1;
284 char *pos2
= line
[(data_len
) / 18] + (((data_len
) % 18) * 4) - 1;
285 sprintf(pos2
, "%c", ']');
289 // Draw the CRC column
290 const char *crcstrings
[] = { "!crc", " ok ", " ", "A ok", "B ok" };
291 const char *crc
= crcstrings
[crcStatus
];
293 // mark short bytes (less than 8 Bit + Parity)
294 if (protocol
== ISO_14443A
||
295 protocol
== PROTO_MIFARE
||
296 protocol
== THINFILM
) {
298 // approximated with 128 * (9 * data_len);
299 uint16_t bitime
= 1056 + 32;
301 if (duration
< bitime
) {
306 if (duration
> bitime
) {
313 line
[(data_len
- 1) / 16][((data_len
- 1) % 16) * 4 + 2] = '(';
314 line
[(data_len
- 1) / 16][((data_len
- 1) % 16) * 4 + 3] = m
+ 0x30;
315 line
[(data_len
- 1) / 16][((data_len
- 1) % 16) * 4 + 4] = ')';
321 uint32_t previous_end_of_transmission_timestamp
= 0;
324 previous_end_of_transmission_timestamp
= *prev_eot
;
326 previous_end_of_transmission_timestamp
= hdr
->timestamp
;
330 end_of_transmission_timestamp
= hdr
->timestamp
+ duration
;
333 *prev_eot
= end_of_transmission_timestamp
;
335 // Always annotate these protocols both reader/tag messages
338 annotateMifare(explanation
, sizeof(explanation
), frame
, data_len
, parityBytes
, TRACELOG_PARITY_LEN(hdr
), hdr
->isResponse
);
341 annotateHitag1(explanation
, sizeof(explanation
), frame
, data_len
, hdr
->isResponse
);
344 annotateHitag2(explanation
, sizeof(explanation
), frame
, data_len
, hdr
->isResponse
);
347 annotateHitagS(explanation
, sizeof(explanation
), frame
, data_len
, hdr
->isResponse
);
350 annotateIclass(explanation
, sizeof(explanation
), frame
, data_len
, hdr
->isResponse
);
356 if (hdr
->isResponse
== false) {
360 annotateLegic(explanation
, sizeof(explanation
), frame
, data_len
);
363 annotateIso14443a(explanation
, sizeof(explanation
), frame
, data_len
);
366 annotateMfDesfire(explanation
, sizeof(explanation
), frame
, data_len
);
369 annotateIso14443b(explanation
, sizeof(explanation
), frame
, data_len
);
372 annotateTopaz(explanation
, sizeof(explanation
), frame
, data_len
);
375 annotateIso14443a(explanation
, sizeof(explanation
), frame
, data_len
);
376 annotateIso7816(explanation
, sizeof(explanation
), frame
, data_len
);
379 annotateIso15693(explanation
, sizeof(explanation
), frame
, data_len
);
382 annotateFelica(explanation
, sizeof(explanation
), frame
, data_len
);
385 annotateLTO(explanation
, sizeof(explanation
), frame
, data_len
);
388 annotateCryptoRF(explanation
, sizeof(explanation
), frame
, data_len
);
395 int num_lines
= MIN((data_len
- 1) / 18 + 1, 18);
396 for (int j
= 0; j
< num_lines
; j
++) {
399 uint32_t time1
= hdr
->timestamp
- first_hdr
->timestamp
;
400 uint32_t time2
= end_of_transmission_timestamp
- first_hdr
->timestamp
;
402 time1
= hdr
->timestamp
- previous_end_of_transmission_timestamp
;
406 if (hdr
->isResponse
) {
409 PrintAndLogEx(NORMAL
, " %10.1f | %10.1f | Tag |%-72s | %s| %s",
410 (float)time1
/ 13.56,
411 (float)time2
/ 13.56,
413 (j
== num_lines
- 1) ? crc
: " ",
414 (j
== num_lines
- 1) ? explanation
: ""
417 PrintAndLogEx(NORMAL
, " %10u | %10u | Tag |%-72s | %s| %s",
418 (hdr
->timestamp
- first_hdr
->timestamp
),
419 (end_of_transmission_timestamp
- first_hdr
->timestamp
),
421 (j
== num_lines
- 1) ? crc
: " ",
422 (j
== num_lines
- 1) ? explanation
: ""
428 PrintAndLogEx(NORMAL
,
429 _YELLOW_(" %10.1f") " | " _YELLOW_("%10.1f") " | " _YELLOW_("Rdr") " |" _YELLOW_("%-72s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
430 (float)time1
/ 13.56,
431 (float)time2
/ 13.56,
433 (j
== num_lines
- 1) ? crc
: " ",
434 (j
== num_lines
- 1) ? explanation
: ""
437 PrintAndLogEx(NORMAL
,
438 _YELLOW_(" %10u") " | " _YELLOW_("%10u") " | " _YELLOW_("Rdr") " |" _YELLOW_("%-72s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
439 (hdr
->timestamp
- first_hdr
->timestamp
),
440 (end_of_transmission_timestamp
- first_hdr
->timestamp
),
442 (j
== num_lines
- 1) ? crc
: " ",
443 (j
== num_lines
- 1) ? explanation
: ""
450 if (hdr
->isResponse
) {
451 PrintAndLogEx(NORMAL
, " | | |%-72s | %s| %s",
453 (j
== num_lines
- 1) ? crc
: " ",
454 (j
== num_lines
- 1) ? explanation
: ""
457 PrintAndLogEx(NORMAL
, " | | |" _YELLOW_("%-72s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
459 (j
== num_lines
- 1) ? crc
: " ",
460 (j
== num_lines
- 1) ? explanation
: ""
466 if (protocol
== PROTO_MIFARE
) {
467 if (DecodeMifareData(frame
, data_len
, parityBytes
, hdr
->isResponse
, mfData
, &mfDataLen
, mfDicKeys
, mfDicKeysCount
)) {
468 memset(explanation
, 0x00, sizeof(explanation
));
469 if (hdr
->isResponse
== false) {
470 annotateIso14443a(explanation
, sizeof(explanation
), mfData
, mfDataLen
);
472 uint8_t crcc
= iso14443A_CRC_check(hdr
->isResponse
, mfData
, mfDataLen
);
473 PrintAndLogEx(NORMAL
, " | | * |%-72s | %-4s| %s",
474 sprint_hex_inrow_spaces(mfData
, mfDataLen
, 2),
475 (crcc
== 0 ? "!crc" : (crcc
== 1 ? " ok " : " ")),
480 if (is_last_record(tracepos
, traceLen
)) {
484 if (showWaitCycles
&& hdr
->isResponse
== false && next_record_is_response(tracepos
, trace
)) {
486 tracelog_hdr_t
*next_hdr
= (tracelog_hdr_t
*)(trace
+ tracepos
);
488 PrintAndLogEx(NORMAL
, " %10u | %10u | %s |fdt (Frame Delay Time): " _YELLOW_("%d"),
489 (end_of_transmission_timestamp
- first_hdr
->timestamp
),
490 (next_hdr
->timestamp
- first_hdr
->timestamp
),
492 (next_hdr
->timestamp
- end_of_transmission_timestamp
));
498 static int download_trace(void) {
500 if (IfPm3Present() == false) {
501 PrintAndLogEx(FAILED
, "You requested a trace upload in offline mode, consider using parameter '1' for working from Tracebuffer");
505 // reserve some space.
511 g_trace
= calloc(PM3_CMD_DATA_SIZE
, sizeof(uint8_t));
512 if (g_trace
== NULL
) {
513 PrintAndLogEx(FAILED
, "Cannot allocate memory for trace");
517 PrintAndLogEx(INFO
, "downloading tracelog data from device");
519 // Query for the size of the trace, downloading PM3_CMD_DATA_SIZE
520 PacketResponseNG response
;
521 if (!GetFromDevice(BIG_BUF
, g_trace
, PM3_CMD_DATA_SIZE
, 0, NULL
, 0, &response
, 4000, true)) {
522 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
527 g_traceLen
= response
.oldarg
[2];
529 // if tracelog buffer was larger and we need to download more.
530 if (g_traceLen
> PM3_CMD_DATA_SIZE
) {
533 g_trace
= calloc(g_traceLen
, sizeof(uint8_t));
534 if (g_trace
== NULL
) {
535 PrintAndLogEx(FAILED
, "Cannot allocate memory for trace");
539 if (!GetFromDevice(BIG_BUF
, g_trace
, g_traceLen
, 0, NULL
, 0, NULL
, 2500, false)) {
540 PrintAndLogEx(WARNING
, "command execution time out");
548 // sanity check. Don't use proxmark if it is offline and you didn't specify useTraceBuffer
550 static int SanityOfflineCheck( bool useTraceBuffer ){
551 if ( !useTraceBuffer && offline) {
552 PrintAndLogEx(NORMAL, "Your proxmark3 device is offline. Specify [1] to use TraceBuffer data instead");
559 static int CmdTraceLoad(const char *Cmd
) {
561 CLIParserContext
*ctx
;
562 CLIParserInit(&ctx
, "trace load",
563 "Load protocol data from binary file to trace buffer\n"
564 "File extension is <.trace>",
565 "trace load -f mytracefile -> w/o file extension"
570 arg_strx0("f", "file", "<filename>", "trace file to load"),
573 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
576 char filename
[FILE_PATH_SIZE
] = {0};
577 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
584 if (loadFile_safe(filename
, ".trace", (void **)&g_trace
, &len
) != PM3_SUCCESS
) {
585 PrintAndLogEx(FAILED
, "Could not open file " _YELLOW_("%s"), filename
);
589 g_traceLen
= (long)len
;
591 PrintAndLogEx(SUCCESS
, "Recorded Activity (TraceLen = " _YELLOW_("%lu") " bytes)", g_traceLen
);
595 static int CmdTraceSave(const char *Cmd
) {
597 CLIParserContext
*ctx
;
598 CLIParserInit(&ctx
, "trace save",
599 "Save protocol data from trace buffer to binary file\n"
600 "File extension is <.trace>",
601 "trace save -f mytracefile -> w/o file extension"
606 arg_strx0("f", "file", "<filename>", "trace file to save"),
609 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
612 char filename
[FILE_PATH_SIZE
] = {0};
613 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
616 if (g_traceLen
== 0) {
618 if (g_traceLen
== 0) {
619 PrintAndLogEx(WARNING
, "trace is empty, nothing to save");
624 saveFile(filename
, ".trace", g_trace
, g_traceLen
);
628 int CmdTraceListAlias(const char *Cmd
, const char *alias
, const char *protocol
) {
629 CLIParserContext
*ctx
;
630 char desc
[500] = {0};
631 snprintf(desc
, sizeof(desc
) - 1,
632 "Alias of `trace list -t %s` with selected protocol data to annotate trace buffer\n"
633 "You can load a trace from file (see `trace load -h`) or it be downloaded from device by default\n"
634 "It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
636 char example
[200] = {0};
637 snprintf(example
, sizeof(example
) - 1,
638 "%s list -f -> show frame delay times\n"
639 "%s list -1 -> use trace buffer ",
641 char fullalias
[100] = {0};
642 snprintf(fullalias
, sizeof(fullalias
) - 1, "%s list", alias
);
643 CLIParserInit(&ctx
, fullalias
, desc
, example
);
647 arg_lit0("1", "buffer", "use data from trace buffer"),
648 arg_lit0("f", NULL
, "show frame delay times"),
649 arg_lit0("c", NULL
, "mark CRC bytes"),
650 arg_lit0("r", NULL
, "show relative times (gap and duration)"),
651 arg_lit0("u", NULL
, "display times in microseconds instead of clock cycles"),
652 arg_lit0("x", NULL
, "show hexdump to convert to pcap(ng)\n"
653 " or to import into Wireshark using encapsulation type \"ISO 14443\""),
654 arg_strx0(NULL
, "dict", "<file>", "use dictionary keys file"),
657 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
660 char args
[128] = {0};
661 snprintf(args
, sizeof(args
), "-t %s ", protocol
);
662 strncat(args
, Cmd
, sizeof(args
) - strlen(args
) - 1);
663 return CmdTraceList(args
);
666 int CmdTraceList(const char *Cmd
) {
667 CLIParserContext
*ctx
;
668 CLIParserInit(&ctx
, "trace list",
669 "Annotate trace buffer with selected protocol data\n"
670 "You can load a trace from file (see `trace load -h`) or it be downloaded from device by default\n",
671 "trace list -t raw -> just show raw data without annotations\n"
672 "trace list -t 14a -> interpret as " _YELLOW_("ISO14443-A") " communications\n"
673 "trace list -t thinfilm -> interpret as " _YELLOW_("Thinfilm") " communications\n"
674 "trace list -t topaz -> interpret as " _YELLOW_("Topaz") " communications\n"
675 "trace list -t mf -> interpret as " _YELLOW_("MIFARE Classic") " communications and decrypt crypto1 stream\n"
676 "trace list -t des -> interpret as " _YELLOW_("MIFARE DESFire") " communications\n"
677 "trace list -t 14b -> interpret as " _YELLOW_("ISO14443-B") " communications\n"
678 "trace list -t 7816 -> interpret as " _YELLOW_("ISO7816-4") " communications\n"
679 "trace list -t 15 -> interpret as " _YELLOW_("ISO15693") " communications\n"
680 "trace list -t iclass -> interpret as " _YELLOW_("iCLASS") " communications\n"
681 "trace list -t legic -> interpret as " _YELLOW_("LEGIC") " communications\n"
682 "trace list -t felica -> interpret as " _YELLOW_("ISO18092 / FeliCa") " communications\n"
683 "trace list -t hitag1 -> interpret as " _YELLOW_("Hitag1") " communications\n"
684 "trace list -t hitag2 -> interpret as " _YELLOW_("Hitag2") " communications\n"
685 "trace list -t hitags -> interpret as " _YELLOW_("HitagS") " communications\n"
686 "trace list -t lto -> interpret as " _YELLOW_("LTO-CM") " communications\n"
687 "trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") " communitcations\n"
688 "trace list -t mf --dict <mfc_default_keys> -> use dictionary keys file\n"
689 "trace list -t 14a -f -> show frame delay times\n"
690 "trace list -t 14a -1 -> use trace buffer "
695 arg_lit0("1", "buffer", "use data from trace buffer"),
696 arg_lit0("f", NULL
, "show frame delay times"),
697 arg_lit0("c", NULL
, "mark CRC bytes"),
698 arg_lit0("r", NULL
, "show relative times (gap and duration)"),
699 arg_lit0("u", NULL
, "display times in microseconds instead of clock cycles"),
700 arg_lit0("x", NULL
, "show hexdump to convert to pcap(ng)\n"
701 " or to import into Wireshark using encapsulation type \"ISO 14443\""),
702 arg_strx0("t", "type", NULL
, "protocol to annotate the trace"),
703 arg_strx0(NULL
, "dict", "<file>", "use dictionary keys file"),
706 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
708 bool use_buffer
= arg_get_lit(ctx
, 1);
709 bool show_wait_cycles
= arg_get_lit(ctx
, 2);
710 bool mark_crc
= arg_get_lit(ctx
, 3);
711 bool use_relative
= arg_get_lit(ctx
, 4);
712 bool use_us
= arg_get_lit(ctx
, 5);
713 bool show_hex
= arg_get_lit(ctx
, 6);
717 CLIParamStrToBuf(arg_get_str(ctx
, 7), (uint8_t *)type
, sizeof(type
), &tlen
);
721 char dictionary
[FILE_PATH_SIZE
+ 2] = {0};
722 if (CLIParamStrToBuf(arg_get_str(ctx
, 8), (uint8_t *)dictionary
, FILE_PATH_SIZE
, &diclen
)) {
723 PrintAndLogEx(FAILED
, "Dictionary file name too long or invalid.");
729 clearCommandBuffer();
731 // no crc, no annotations
732 uint8_t protocol
= -1;
734 // validate type of output
735 if (strcmp(type
, "iclass") == 0) protocol
= ICLASS
;
736 else if (strcmp(type
, "14a") == 0) protocol
= ISO_14443A
;
737 else if (strcmp(type
, "14b") == 0) protocol
= ISO_14443B
;
738 else if (strcmp(type
, "topaz") == 0) protocol
= TOPAZ
;
739 else if (strcmp(type
, "7816") == 0) protocol
= ISO_7816_4
;
740 else if (strcmp(type
, "des") == 0) protocol
= MFDES
;
741 else if (strcmp(type
, "legic") == 0) protocol
= LEGIC
;
742 else if (strcmp(type
, "15") == 0) protocol
= ISO_15693
;
743 else if (strcmp(type
, "felica") == 0) protocol
= FELICA
;
744 else if (strcmp(type
, "mf") == 0) protocol
= PROTO_MIFARE
;
745 else if (strcmp(type
, "hitag1") == 0) protocol
= PROTO_HITAG1
;
746 else if (strcmp(type
, "hitag2") == 0) protocol
= PROTO_HITAG2
;
747 else if (strcmp(type
, "hitags") == 0) protocol
= PROTO_HITAGS
;
748 else if (strcmp(type
, "thinfilm") == 0) protocol
= THINFILM
;
749 else if (strcmp(type
, "lto") == 0) protocol
= LTO
;
750 else if (strcmp(type
, "cryptorf") == 0) protocol
= PROTO_CRYPTORF
;
751 else if (strcmp(type
, "raw") == 0) protocol
= -1;
753 if (use_buffer
== false) {
755 } else if (g_traceLen
== 0) {
756 PrintAndLogEx(FAILED
, "You requested a trace list in offline mode but there is no trace, consider using 'trace load' or removing parameter '1'");
760 PrintAndLogEx(SUCCESS
, "Recorded activity (trace len = " _YELLOW_("%lu") " bytes)", g_traceLen
);
761 if (g_traceLen
== 0) {
765 uint16_t tracepos
= 0;
768 if (protocol == FELICA) {
769 printFelica(g_traceLen, g_trace);
773 while (tracepos
< g_traceLen
) {
774 tracepos
= printHexLine(tracepos
, g_traceLen
, g_trace
, protocol
);
779 PrintAndLogEx(INFO
, _YELLOW_("gap") " = time between transfers. " _YELLOW_("duration") " = duration of data transfer. " _YELLOW_("src") " = source of transfer");
781 PrintAndLogEx(INFO
, _YELLOW_("start") " = start of start frame " _YELLOW_("end") " = end of frame. " _YELLOW_("src") " = source of transfer");
784 if (protocol
== ISO_14443A
|| protocol
== PROTO_MIFARE
|| protocol
== MFDES
|| protocol
== TOPAZ
|| protocol
== LTO
) {
786 PrintAndLogEx(INFO
, _YELLOW_("ISO14443A") " - all times are in microseconds");
788 PrintAndLogEx(INFO
, _YELLOW_("ISO14443A") " - all times are in carrier periods (1/13.56MHz)");
791 if (protocol
== THINFILM
) {
793 PrintAndLogEx(INFO
, _YELLOW_("Thinfilm") " - all times are in microseconds");
795 PrintAndLogEx(INFO
, _YELLOW_("Thinfilm") " - all times are in carrier periods (1/13.56MHz)");
798 if (protocol
== ICLASS
|| protocol
== ISO_15693
) {
800 PrintAndLogEx(INFO
, _YELLOW_("ISO15693 / iCLASS") " - all times are in microseconds");
802 PrintAndLogEx(INFO
, _YELLOW_("ISO15693 / iCLASS") " - all times are in carrier periods (1/13.56MHz)");
805 if (protocol
== LEGIC
)
806 PrintAndLogEx(INFO
, _YELLOW_("LEGIC") " - Reader Mode: Timings are in ticks (1us == 1.5ticks)\n"
807 " Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)");
809 if (protocol
== ISO_14443B
|| protocol
== PROTO_CRYPTORF
) {
811 PrintAndLogEx(INFO
, _YELLOW_("ISO14443B") " - all times are in microseconds");
813 PrintAndLogEx(INFO
, _YELLOW_("ISO14443B") " - all times are in carrier periods (1/13.56MHz)");
816 if (protocol
== ISO_7816_4
)
817 PrintAndLogEx(INFO
, _YELLOW_("ISO7816-4 / Smartcard") " - Timings N/A");
819 if (protocol
== PROTO_HITAG1
|| protocol
== PROTO_HITAG2
|| protocol
== PROTO_HITAGS
)
820 PrintAndLogEx(INFO
, _YELLOW_("Hitag1 / Hitag2 / HitagS") " - Timings in ETU (8us)");
822 if (protocol
== FELICA
) {
824 PrintAndLogEx(INFO
, _YELLOW_("ISO18092 / FeliCa") " - all times are in microseconds");
826 PrintAndLogEx(INFO
, _YELLOW_("ISO18092 / FeliCa") " - all times are in carrier periods (1/13.56MHz)");
830 const uint64_t *dicKeys
= NULL
;
831 uint32_t dicKeysCount
= 0;
832 bool dictionaryLoad
= false;
834 if (protocol
== PROTO_MIFARE
) {
836 uint8_t *keyBlock
= NULL
;
837 int res
= loadFileDICTIONARY_safe(dictionary
, (void **) &keyBlock
, 6, &dicKeysCount
);
838 if (res
!= PM3_SUCCESS
|| dicKeysCount
== 0 || keyBlock
== NULL
) {
839 PrintAndLogEx(FAILED
, "An error occurred while loading the dictionary! (we will use the default keys now)");
841 dicKeys
= calloc(dicKeysCount
, sizeof(uint64_t));
842 for (int i
= 0; i
< dicKeysCount
; i
++) {
843 uint64_t key
= bytes_to_num(keyBlock
+ i
* 6, 6);
844 memcpy((uint8_t *) &dicKeys
[i
], &key
, sizeof(uint64_t));
846 dictionaryLoad
= true;
848 if (keyBlock
!= NULL
) {
852 if (dicKeys
== NULL
) {
853 dicKeys
= g_mifare_default_keys
;
854 dicKeysCount
= ARRAYLEN(g_mifare_default_keys
);
858 PrintAndLogEx(NORMAL
, "");
860 PrintAndLogEx(NORMAL
, " Gap | Duration | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation");
862 PrintAndLogEx(NORMAL
, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation");
864 PrintAndLogEx(NORMAL
, "------------+------------+-----+-------------------------------------------------------------------------+-----+--------------------");
866 // clean authentication data used with the mifare classic decrypt fct
867 if (protocol
== ISO_14443A
|| protocol
== PROTO_MIFARE
)
870 uint32_t previous_EOT
= 0;
871 uint32_t *prev_EOT
= NULL
;
873 prev_EOT
= &previous_EOT
;
876 while (tracepos
< g_traceLen
) {
877 tracepos
= printTraceLine(tracepos
, g_traceLen
, g_trace
, protocol
, show_wait_cycles
, mark_crc
, prev_EOT
, use_us
, dicKeys
, dicKeysCount
);
879 if (kbd_enter_pressed())
884 free((void *) dicKeys
);
888 PrintAndLogEx(HINT
, "syntax to use: " _YELLOW_("`text2pcap -t \"%%S.\" -l 264 -n <input-text-file> <output-pcapng-file>`"));
893 static command_t CommandTable
[] = {
894 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
895 {"list", CmdTraceList
, AlwaysAvailable
, "List protocol data in trace buffer"},
896 {"load", CmdTraceLoad
, AlwaysAvailable
, "Load trace from file"},
897 {"save", CmdTraceSave
, AlwaysAvailable
, "Save trace buffer to file"},
898 {NULL
, NULL
, NULL
, NULL
}
901 static int CmdHelp(const char *Cmd
) {
902 (void)Cmd
; // Cmd is not used so far
903 CmdsHelp(CommandTable
);
907 int CmdTrace(const char *Cmd
) {
908 clearCommandBuffer();
909 return CmdsParse(CommandTable
, Cmd
);