2018-03-19 01:00:41 +08:00
//-----------------------------------------------------------------------------
2022-01-07 08:58:03 +08:00
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
2018-03-19 01:00:41 +08:00
//
2022-01-07 08:58:03 +08:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
2018-03-19 01:00:41 +08:00
//-----------------------------------------------------------------------------
// Trace commands
//-----------------------------------------------------------------------------
# include "cmdtrace.h"
2019-08-08 22:57:33 +08:00
# include <ctype.h>
# include "cmdparser.h" // command_t
# include "protocols.h"
# include "parity.h" // oddparity
# include "cmdhflist.h" // annotations
2021-01-27 06:14:20 +08:00
# include "commonutil.h" // ARRAYLEN
# include "mifare/mifaredefault.h" // mifare default key array
2019-08-08 22:57:33 +08:00
# include "comms.h" // for sending cmds to device. GetFromBigBuf
2019-08-21 20:41:33 +08:00
# include "fileutils.h" // for saveFile
2020-01-20 18:37:10 +08:00
# include "cmdlfhitag.h" // annotate hitag
2020-05-19 08:14:43 +08:00
# include "pm3_cmd.h" // tracelog_hdr_t
2020-10-10 01:45:29 +08:00
# include "cliparser.h" // args..
2019-08-08 22:57:33 +08:00
2018-03-19 01:00:41 +08:00
static int CmdHelp ( const char * Cmd ) ;
2018-03-19 02:58:22 +08:00
// trace pointer
2021-08-22 06:51:37 +08:00
static uint8_t * gs_trace ;
2022-02-17 03:28:38 +08:00
static uint16_t gs_traceLen = 0 ;
2019-03-09 15:59:13 +08:00
2020-05-19 06:25:40 +08:00
static bool is_last_record ( uint16_t tracepos , uint16_t traceLen ) {
return ( ( tracepos + TRACELOG_HDR_LEN ) > = traceLen ) ;
2018-03-19 01:00:41 +08:00
}
2019-04-11 06:10:21 +08:00
static bool next_record_is_response ( uint16_t tracepos , uint8_t * trace ) {
2020-05-19 06:25:40 +08:00
tracelog_hdr_t * hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
2020-05-19 08:14:43 +08:00
return ( hdr - > isResponse ) ;
2018-03-19 01:00:41 +08:00
}
2019-04-11 06:10:21 +08:00
static bool merge_topaz_reader_frames ( uint32_t timestamp , uint32_t * duration , uint16_t * tracepos , uint16_t traceLen ,
2019-04-11 13:40:50 +08:00
uint8_t * trace , uint8_t * frame , uint8_t * topaz_reader_command , uint16_t * data_len ) {
2019-03-10 06:35:06 +08:00
# define MAX_TOPAZ_READER_CMD_LEN 16
uint32_t last_timestamp = timestamp + * duration ;
if ( ( * data_len ! = 1 ) | | ( frame [ 0 ] = = TOPAZ_WUPA ) | | ( frame [ 0 ] = = TOPAZ_REQA ) ) return false ;
memcpy ( topaz_reader_command , frame , * data_len ) ;
2020-05-19 06:25:40 +08:00
while ( ! is_last_record ( * tracepos , traceLen ) & & ! next_record_is_response ( * tracepos , trace ) ) {
tracelog_hdr_t * hdr = ( tracelog_hdr_t * ) ( trace + * tracepos ) ;
2020-06-08 09:15:10 +08:00
2020-05-19 08:14:43 +08:00
* tracepos + = TRACELOG_HDR_LEN + hdr - > data_len ;
2020-05-19 06:25:40 +08:00
2020-05-19 08:14:43 +08:00
if ( ( hdr - > data_len = = 1 ) & & ( * data_len + hdr - > data_len < = MAX_TOPAZ_READER_CMD_LEN ) ) {
memcpy ( topaz_reader_command + * data_len , hdr - > frame , hdr - > data_len ) ;
* data_len + = hdr - > data_len ;
last_timestamp = hdr - > timestamp + hdr - > duration ;
2019-03-10 06:35:06 +08:00
} else {
// rewind and exit
2020-05-19 08:14:43 +08:00
* tracepos = * tracepos - hdr - > data_len - TRACELOG_HDR_LEN ;
2019-03-10 06:35:06 +08:00
break ;
}
2020-05-19 08:14:43 +08:00
* tracepos + = TRACELOG_PARITY_LEN ( hdr ) ;
2019-03-10 06:35:06 +08:00
}
* duration = last_timestamp - timestamp ;
return true ;
2018-03-19 01:00:41 +08:00
}
2022-02-16 07:20:02 +08:00
static uint8_t calc_pos ( const uint8_t * d ) {
2022-01-31 04:18:59 +08:00
// PCB [CID] [NAD] [INF] CRC CRC
uint8_t pos = 1 ;
if ( ( d [ 0 ] & 0x08 ) = = 0x08 ) // cid byte following
pos + + ;
if ( ( d [ 0 ] & 0x04 ) = = 0x04 ) // nad byte following
pos + + ;
2022-02-05 19:32:50 +08:00
return pos ;
2022-01-31 04:18:59 +08:00
}
static uint8_t extract_uid [ 10 ] = { 0 } ;
static uint8_t extract_uidlen = 0 ;
static uint8_t extract_epurse [ 8 ] = { 0 } ;
# define SKIP_TO_NEXT(a) (TRACELOG_HDR_LEN + (a)->data_len + TRACELOG_PARITY_LEN((a)))
2022-02-07 03:56:33 +08:00
static uint16_t extractChall_ev2 ( uint16_t tracepos , uint8_t * trace , uint8_t cmdpos , uint8_t long_jmp ) {
tracelog_hdr_t * next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
if ( next_hdr - > data_len ! = 21 ) {
return 0 ;
}
tracepos + = TRACELOG_HDR_LEN + next_hdr - > data_len + TRACELOG_PARITY_LEN ( next_hdr ) ;
PrintAndLogEx ( INFO , " 1499999999 %s " NOLF , sprint_hex_inrow ( next_hdr - > frame + 1 , 16 ) ) ;
next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = TRACELOG_HDR_LEN + next_hdr - > data_len + TRACELOG_PARITY_LEN ( next_hdr ) ;
if ( next_hdr - > frame [ cmdpos ] = = MFDES_ADDITIONAL_FRAME ) {
PrintAndLogEx ( NORMAL , " %s " , sprint_hex_inrow ( next_hdr - > frame + cmdpos + long_jmp , 32 ) ) ;
} else {
PrintAndLogEx ( NORMAL , " " ) ;
}
return tracepos ;
}
2022-01-31 04:18:59 +08:00
static uint16_t extractChallenges ( uint16_t tracepos , uint16_t traceLen , uint8_t * trace ) {
2022-02-05 19:32:50 +08:00
// sanity check
2022-01-31 04:18:59 +08:00
if ( is_last_record ( tracepos , traceLen ) ) {
return traceLen ;
}
tracelog_hdr_t * hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
uint16_t data_len = hdr - > data_len ;
uint8_t * frame = hdr - > frame ;
// sanity check tracking position is less then available trace size
if ( tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN ( hdr ) > traceLen ) {
PrintAndLogEx ( DEBUG , " trace pos offset % " PRIu64 " larger than reported tracelen %u " ,
2022-02-05 19:32:50 +08:00
tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN ( hdr ) ,
traceLen
) ;
2022-01-31 04:18:59 +08:00
return traceLen ;
}
// set trace position
tracepos + = SKIP_TO_NEXT ( hdr ) ;
// sanity check data frame length
if ( data_len = = 0 ) {
return tracepos ;
}
// extract MFC
switch ( frame [ 0 ] ) {
case MIFARE_AUTH_KEYA : {
if ( data_len > 3 ) {
}
break ;
}
case MIFARE_AUTH_KEYB : {
if ( data_len > 3 ) {
}
break ;
}
}
2022-02-05 19:32:50 +08:00
// extract MFU-C
2022-01-31 04:18:59 +08:00
switch ( frame [ 0 ] ) {
case MIFARE_ULC_AUTH_1 : {
if ( data_len ! = 4 ) {
break ;
}
// time to skip to next
tracelog_hdr_t * next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = SKIP_TO_NEXT ( next_hdr ) ;
if ( next_hdr - > data_len ! = 11 ) {
break ;
}
if ( next_hdr - > frame [ 0 ] ! = MIFARE_ULC_AUTH_2 ) {
2022-02-05 19:32:50 +08:00
break ;
2022-01-31 04:18:59 +08:00
}
PrintAndLogEx ( INFO , " MFU-C AUTH " ) ;
PrintAndLogEx ( INFO , " 3DES %s " NOLF , sprint_hex_inrow ( next_hdr - > frame + 1 , 8 ) ) ;
next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = SKIP_TO_NEXT ( next_hdr ) ;
if ( next_hdr - > frame [ 0 ] = = MIFARE_ULC_AUTH_2 & & next_hdr - > data_len = = 19 ) {
PrintAndLogEx ( NORMAL , " %s " , sprint_hex_inrow ( next_hdr - > frame + 1 , 16 ) ) ;
}
2022-02-05 19:32:50 +08:00
2022-01-31 04:18:59 +08:00
return tracepos ;
}
}
// extract iCLASS
// --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b
2022-02-05 19:32:50 +08:00
2022-01-31 04:18:59 +08:00
if ( hdr - > isResponse = = false ) {
2022-02-05 19:32:50 +08:00
2022-01-31 04:18:59 +08:00
uint8_t c = frame [ 0 ] & 0x0F ;
switch ( c ) {
case ICLASS_CMD_SELECT : {
tracelog_hdr_t * next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = SKIP_TO_NEXT ( next_hdr ) ;
if ( next_hdr - > data_len ! = 10 ) {
break ;
}
memcpy ( extract_uid , next_hdr - > frame , 8 ) ;
extract_uidlen = 8 ;
break ;
}
case ICLASS_CMD_READCHECK : {
// get epurse
if ( frame [ 1 ] = = 2 & & data_len = = 2 ) {
tracelog_hdr_t * next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = SKIP_TO_NEXT ( next_hdr ) ;
if ( next_hdr - > data_len < 8 ) {
break ;
}
memcpy ( extract_epurse , next_hdr - > frame , 8 ) ;
}
break ;
}
case ICLASS_CMD_CHECK : {
// get macs
if ( data_len = = 9 ) {
if ( extract_uidlen = = 8 ) {
PrintAndLogEx ( INFO , " hf iclass lookup --csn %s " NOLF , sprint_hex_inrow ( extract_uid , extract_uidlen ) ) ;
PrintAndLogEx ( NORMAL , " --epurse %s " NOLF , sprint_hex_inrow ( extract_epurse , 8 ) ) ;
2022-02-05 19:32:50 +08:00
PrintAndLogEx ( NORMAL , " --macs %s " NOLF , sprint_hex_inrow ( frame + 1 , 8 ) ) ;
2022-01-31 04:18:59 +08:00
PrintAndLogEx ( NORMAL , " -f iclass_default_keys.dic " ) ;
return tracepos ;
}
}
break ;
}
}
}
// extract UID
switch ( frame [ 0 ] ) {
case ISO14443A_CMD_ANTICOLL_OR_SELECT : {
// 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor)
// 93 50 = Bit oriented anti-collision (usage: 9350+ up to 5bytes, 9350 answer - up to 5bytes UID+BCC)
// 93 70 = Select (usage: 9370+5bytes 9370 answer - answer: 1byte SAK)
if ( frame [ 1 ] = = 0x70 ) {
if ( frame [ 2 ] = = 0x88 ) {
memcpy ( extract_uid , frame + 3 , 3 ) ;
extract_uidlen = 3 ;
} else {
memcpy ( extract_uid , frame + 2 , 4 ) ;
extract_uidlen = 4 ;
PrintAndLogEx ( INFO , " UID... " _YELLOW_ ( " %s " ) , sprint_hex_inrow ( extract_uid , extract_uidlen ) ) ;
}
}
break ;
}
case ISO14443A_CMD_ANTICOLL_OR_SELECT_2 : {
// 95 20 = Anticollision of cascade level2
// 95 50 = Bit oriented anti-collision level2
// 95 70 = Select of cascade level2
if ( frame [ 1 ] = = 0x70 ) {
if ( frame [ 2 ] = = 0x88 ) {
memcpy ( extract_uid + extract_uidlen , frame + 3 , 3 ) ;
extract_uidlen + = 3 ;
} else {
memcpy ( extract_uid + extract_uidlen , frame + 2 , 4 ) ;
extract_uidlen + = 4 ;
PrintAndLogEx ( INFO , " UID... " _YELLOW_ ( " %s " ) , sprint_hex_inrow ( extract_uid , extract_uidlen ) ) ;
2022-02-05 19:32:50 +08:00
}
2022-01-31 04:18:59 +08:00
}
break ;
}
case ISO14443A_CMD_ANTICOLL_OR_SELECT_3 : {
// 97 20 = Anticollision of cascade level3
// 97 50 = Bit oriented anti-collision level3
// 97 70 = Select of cascade level3
if ( frame [ 1 ] = = 0x70 ) {
memcpy ( extract_uid + extract_uidlen , frame + 2 , 4 ) ;
extract_uidlen + = 4 ;
PrintAndLogEx ( INFO , " UID... " _YELLOW_ ( " %s " ) , sprint_hex_inrow ( extract_uid , extract_uidlen ) ) ;
}
break ;
}
}
// extract DESFIRE
if ( ( frame [ 0 ] & 0xC0 ) ! = 0x00 ) {
return tracepos ;
}
2022-02-07 03:56:33 +08:00
if ( hdr - > isResponse ) {
return tracepos ;
}
2022-01-31 04:18:59 +08:00
// PCB [CID] [NAD] [INF] CRC CRC
uint8_t pos = calc_pos ( frame ) ;
uint8_t long_jmp = ( data_len > 6 ) ? 4 : 1 ;
for ( uint8_t i = 0 ; i < 2 ; i + + , pos + + ) {
switch ( frame [ pos ] ) {
case MFDES_AUTHENTICATE : {
2022-02-07 03:56:33 +08:00
2022-02-05 19:32:50 +08:00
// Assume wrapped or unwrapped
2022-01-31 04:18:59 +08:00
PrintAndLogEx ( INFO , " AUTH NATIVE (keyNo %d) " , frame [ pos + long_jmp ] ) ;
2022-02-07 03:56:33 +08:00
if ( next_record_is_response ( tracepos , trace ) = = false ) {
break ;
}
2022-02-05 19:32:50 +08:00
2022-02-07 03:56:33 +08:00
tracelog_hdr_t * next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
if ( next_hdr - > data_len < 7 ) {
break ;
}
tracepos + = TRACELOG_HDR_LEN + next_hdr - > data_len + TRACELOG_PARITY_LEN ( next_hdr ) ;
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
PrintAndLogEx ( INFO , " DES 1499999999 %s " NOLF , sprint_hex_inrow ( next_hdr - > frame + 1 , 8 ) ) ;
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = TRACELOG_HDR_LEN + next_hdr - > data_len + TRACELOG_PARITY_LEN ( next_hdr ) ;
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
if ( next_hdr - > frame [ pos ] = = MFDES_ADDITIONAL_FRAME ) {
PrintAndLogEx ( NORMAL , " %s " , sprint_hex_inrow ( next_hdr - > frame + pos + long_jmp , 16 ) ) ;
} else {
PrintAndLogEx ( NORMAL , " " ) ;
2022-02-05 19:32:50 +08:00
}
2022-02-07 03:56:33 +08:00
return tracepos ; // AUTHENTICATE_NATIVE
2022-01-31 04:18:59 +08:00
}
case MFDES_AUTHENTICATE_ISO : {
2022-02-05 19:32:50 +08:00
// Assume wrapped or unwrapped
2022-01-31 04:18:59 +08:00
PrintAndLogEx ( INFO , " AUTH ISO (keyNo %d) " , frame [ pos + long_jmp ] ) ;
2022-02-07 03:56:33 +08:00
if ( next_record_is_response ( tracepos , trace ) = = false ) {
break ;
}
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
tracelog_hdr_t * next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = TRACELOG_HDR_LEN + next_hdr - > data_len + TRACELOG_PARITY_LEN ( next_hdr ) ;
if ( next_hdr - > data_len < 7 ) {
break ;
}
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
uint8_t tdea = 8 ;
if ( next_hdr - > data_len > 20 ) {
tdea = 16 ;
PrintAndLogEx ( INFO , " 3TDEA 1499999999 %s " NOLF , sprint_hex_inrow ( next_hdr - > frame + 1 , tdea ) ) ;
} else {
PrintAndLogEx ( INFO , " 2TDEA 1499999999 %s " NOLF , sprint_hex_inrow ( next_hdr - > frame + 1 , tdea ) ) ;
}
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = TRACELOG_HDR_LEN + next_hdr - > data_len + TRACELOG_PARITY_LEN ( next_hdr ) ;
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
if ( next_hdr - > frame [ pos ] = = MFDES_ADDITIONAL_FRAME ) {
PrintAndLogEx ( NORMAL , " %s " , sprint_hex_inrow ( next_hdr - > frame + pos + long_jmp , ( tdea < < 1 ) ) ) ;
} else {
PrintAndLogEx ( NORMAL , " " ) ;
2022-01-31 04:18:59 +08:00
}
2022-02-07 03:56:33 +08:00
return tracepos ; // AUTHENTICATE_STANDARD
2022-01-31 04:18:59 +08:00
}
case MFDES_AUTHENTICATE_AES : {
2022-02-05 19:32:50 +08:00
// Assume wrapped or unwrapped
2022-01-31 04:18:59 +08:00
PrintAndLogEx ( INFO , " AUTH AES (keyNo %d) " , frame [ pos + long_jmp ] ) ;
2022-02-07 03:56:33 +08:00
if ( next_record_is_response ( tracepos , trace ) ) {
break ;
}
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
tracelog_hdr_t * next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = TRACELOG_HDR_LEN + next_hdr - > data_len + TRACELOG_PARITY_LEN ( next_hdr ) ;
if ( next_hdr - > data_len < 7 ) {
break ;
}
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
PrintAndLogEx ( INFO , " AES 1499999999 %s " NOLF , sprint_hex_inrow ( next_hdr - > frame + 1 , 8 ) ) ;
2022-01-31 04:18:59 +08:00
2022-02-07 03:56:33 +08:00
next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
tracepos + = TRACELOG_HDR_LEN + next_hdr - > data_len + TRACELOG_PARITY_LEN ( next_hdr ) ;
if ( next_hdr - > frame [ pos ] = = MFDES_ADDITIONAL_FRAME ) {
PrintAndLogEx ( NORMAL , " %s " , sprint_hex_inrow ( next_hdr - > frame + pos + long_jmp , 16 ) ) ;
} else {
PrintAndLogEx ( NORMAL , " " ) ;
2022-01-31 04:18:59 +08:00
}
2022-02-07 03:56:33 +08:00
return tracepos ;
2022-01-31 04:18:59 +08:00
}
case MFDES_AUTHENTICATE_EV2F : {
2022-02-07 03:56:33 +08:00
PrintAndLogEx ( INFO , " AUTH EV2 First " ) ;
uint16_t tmp = extractChall_ev2 ( tracepos , trace , pos , long_jmp ) ;
if ( tmp = = 0 )
break ;
else
return tmp ;
2022-01-31 04:18:59 +08:00
}
case MFDES_AUTHENTICATE_EV2NF : {
2022-02-07 03:56:33 +08:00
PrintAndLogEx ( INFO , " AUTH EV2 Non First " ) ;
uint16_t tmp = extractChall_ev2 ( tracepos , trace , pos , long_jmp ) ;
if ( tmp = = 0 )
break ;
else
return tmp ;
2022-01-31 04:18:59 +08:00
}
}
2022-02-05 19:32:50 +08:00
}
2022-01-31 04:18:59 +08:00
return tracepos ;
}
2018-03-19 01:00:41 +08:00
2019-05-09 22:34:06 +08:00
static uint16_t printHexLine ( uint16_t tracepos , uint16_t traceLen , uint8_t * trace , uint8_t protocol ) {
// sanity check
2020-05-19 06:25:40 +08:00
if ( is_last_record ( tracepos , traceLen ) ) return traceLen ;
2019-05-09 22:34:06 +08:00
2020-05-19 05:49:45 +08:00
tracelog_hdr_t * hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
2019-05-09 22:34:06 +08:00
2020-05-19 08:14:43 +08:00
if ( TRACELOG_HDR_LEN + hdr - > data_len + TRACELOG_PARITY_LEN ( hdr ) > traceLen ) {
2019-05-09 22:34:06 +08:00
return traceLen ;
}
2020-05-19 05:49:45 +08:00
//set trace position
2020-05-19 08:14:43 +08:00
tracepos + = TRACELOG_HDR_LEN + hdr - > data_len + TRACELOG_PARITY_LEN ( hdr ) ;
2020-05-19 05:49:45 +08:00
if ( hdr - > data_len = = 0 ) {
2019-05-09 22:34:06 +08:00
PrintAndLogEx ( NORMAL , " <empty trace - possible error> " ) ;
return tracepos ;
}
2019-10-09 21:23:58 +08:00
uint16_t ret ;
2019-05-09 22:34:06 +08:00
switch ( protocol ) {
2019-05-13 02:38:03 +08:00
case ISO_14443A : {
2019-05-09 22:34:06 +08:00
/* https://www.kaiser.cx/pcap-iso14443.html defines a pseudo header:
* version ( currently 0x00 ) , event ( Rdr : 0xfe , Tag : 0xff ) , length ( 2 bytes )
* to convert to pcap ( ng ) via text2pcap or to import into Wireshark
* we use format timestamp , newline , offset ( 0x000000 ) , pseudo header , data
* ` text2pcap - t " %S. " - l 264 - n < input - text - file > < output - pcapng - file > `
*/
2022-06-12 07:38:58 +08:00
int line_len = ( hdr - > data_len * 3 ) + 1 ;
2022-06-12 06:40:33 +08:00
char line [ line_len ] ;
char * ptr = line ;
2019-05-09 22:34:06 +08:00
2020-05-19 05:49:45 +08:00
for ( int i = 0 ; i < hdr - > data_len ; i + + ) {
2022-06-12 07:38:58 +08:00
ptr + = snprintf ( ptr , line_len , " %02x " , hdr - > frame [ i ] ) ;
line_len - = 3 ;
if ( line_len < = 0 ) {
break ;
}
2019-05-09 22:34:06 +08:00
}
char data_len_str [ 5 ] ;
char temp_str1 [ 3 ] = { 0 } ;
char temp_str2 [ 3 ] = { 0 } ;
2020-06-08 09:15:10 +08:00
2022-06-12 06:40:33 +08:00
snprintf ( data_len_str , sizeof ( data_len_str ) , " %04x " , hdr - > data_len ) ;
2020-10-06 20:39:36 +08:00
memmove ( temp_str1 , data_len_str , 2 ) ;
memmove ( temp_str2 , data_len_str + 2 , 2 ) ;
2019-05-09 22:34:06 +08:00
2020-05-19 05:49:45 +08:00
PrintAndLogEx ( NORMAL , " 0.%010u " , hdr - > timestamp ) ;
2019-05-09 22:34:06 +08:00
PrintAndLogEx ( NORMAL , " 000000 00 %s %s %s %s " ,
2020-05-19 08:14:43 +08:00
( hdr - > isResponse ? " ff " : " fe " ) ,
2019-05-13 02:38:03 +08:00
temp_str1 ,
temp_str2 ,
line ) ;
2019-10-09 21:23:58 +08:00
ret = tracepos ;
2019-10-10 18:34:11 +08:00
break ;
2019-05-13 02:38:03 +08:00
}
default :
2019-05-09 22:34:06 +08:00
PrintAndLogEx ( NORMAL , " Currently only 14a supported " ) ;
2019-10-09 21:23:58 +08:00
ret = traceLen ;
2019-10-10 18:34:11 +08:00
break ;
2019-05-09 22:34:06 +08:00
}
2019-10-09 21:23:58 +08:00
return ret ;
2019-05-09 22:34:06 +08:00
}
2021-02-09 23:56:55 +08:00
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 ,
2021-01-27 06:14:20 +08:00
const uint64_t * mfDicKeys , uint32_t mfDicKeysCount ) {
2019-03-10 06:35:06 +08:00
// sanity check
2020-07-10 01:43:00 +08:00
if ( is_last_record ( tracepos , traceLen ) ) {
PrintAndLogEx ( DEBUG , " last record triggered. t-pos: %u t-len %u " , tracepos , traceLen ) ;
return traceLen ;
}
2019-03-10 06:35:06 +08:00
2020-07-13 19:55:19 +08:00
uint32_t end_of_transmission_timestamp = 0 ;
2019-03-10 06:35:06 +08:00
uint8_t topaz_reader_command [ 9 ] ;
2020-05-06 18:14:05 +08:00
char explanation [ 40 ] = { 0 } ;
2020-05-19 06:36:30 +08:00
tracelog_hdr_t * first_hdr = ( tracelog_hdr_t * ) ( trace ) ;
tracelog_hdr_t * hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
2019-03-10 06:35:06 +08:00
2022-01-31 04:18:59 +08:00
uint32_t duration = hdr - > duration ;
uint16_t data_len = hdr - > data_len ;
2019-03-10 06:35:06 +08:00
2020-05-19 08:14:43 +08:00
if ( tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN ( hdr ) > traceLen ) {
2022-01-31 04:18:59 +08:00
PrintAndLogEx ( DEBUG , " trace pos offset % " PRIu64 " larger than reported tracelen %u " ,
2022-02-05 19:32:50 +08:00
tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN ( hdr ) ,
traceLen
) ;
2019-03-10 06:35:06 +08:00
return traceLen ;
}
2020-07-13 19:55:19 +08:00
2020-08-13 18:25:04 +08:00
// adjust for different time scales
if ( protocol = = ICLASS | | protocol = = ISO_15693 ) {
duration * = 32 ;
}
2020-07-13 19:55:19 +08:00
2020-05-19 06:36:30 +08:00
uint8_t * frame = hdr - > frame ;
uint8_t * parityBytes = hdr - > frame + data_len ;
2020-05-19 08:14:43 +08:00
tracepos + = TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN ( hdr ) ;
2019-03-10 06:35:06 +08:00
2020-05-19 08:14:43 +08:00
if ( protocol = = TOPAZ & & ! hdr - > isResponse ) {
2019-03-10 06:35:06 +08:00
// topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each.
// merge them:
2020-05-19 08:14:43 +08:00
if ( merge_topaz_reader_frames ( hdr - > timestamp , & duration , & tracepos , traceLen , trace , frame , topaz_reader_command , & data_len ) ) {
2019-03-10 06:35:06 +08:00
frame = topaz_reader_command ;
}
}
//Check the CRC status
uint8_t crcStatus = 2 ;
if ( data_len > 2 ) {
switch ( protocol ) {
case ICLASS :
2020-05-19 08:14:43 +08:00
crcStatus = iclass_CRC_check ( hdr - > isResponse , frame , data_len ) ;
2019-03-10 06:35:06 +08:00
break ;
case ISO_14443B :
case TOPAZ :
2020-12-18 09:37:31 +08:00
crcStatus = iso14443B_CRC_check ( frame , data_len ) ;
break ;
2019-03-10 06:35:06 +08:00
case FELICA :
2019-11-01 22:19:09 +08:00
crcStatus = ! felica_CRC_check ( frame + 2 , data_len - 4 ) ;
2019-03-10 06:35:06 +08:00
break ;
case PROTO_MIFARE :
2020-05-19 08:14:43 +08:00
crcStatus = mifare_CRC_check ( hdr - > isResponse , frame , data_len ) ;
2019-03-10 06:35:06 +08:00
break ;
case ISO_14443A :
case MFDES :
2019-12-24 07:57:15 +08:00
case LTO :
2022-01-17 02:03:17 +08:00
case SEOS :
2020-05-19 08:14:43 +08:00
crcStatus = iso14443A_CRC_check ( hdr - > isResponse , frame , data_len ) ;
2019-03-10 06:35:06 +08:00
break ;
2020-12-18 09:37:31 +08:00
case ISO_7816_4 :
crcStatus = iso14443A_CRC_check ( hdr - > isResponse , frame , data_len ) = = 1 ? 3 : 0 ;
crcStatus = iso14443B_CRC_check ( frame , data_len ) = = 1 ? 4 : crcStatus ;
break ;
2019-08-02 02:06:07 +08:00
case THINFILM :
2019-08-02 06:26:48 +08:00
frame [ data_len - 1 ] ^ = frame [ data_len - 2 ] ;
frame [ data_len - 2 ] ^ = frame [ data_len - 1 ] ;
frame [ data_len - 1 ] ^ = frame [ data_len - 2 ] ;
2019-08-02 02:06:07 +08:00
crcStatus = iso14443A_CRC_check ( true , frame , data_len ) ;
2019-08-02 06:26:48 +08:00
frame [ data_len - 1 ] ^ = frame [ data_len - 2 ] ;
frame [ data_len - 2 ] ^ = frame [ data_len - 1 ] ;
frame [ data_len - 1 ] ^ = frame [ data_len - 2 ] ;
2019-08-02 02:06:07 +08:00
break ;
2019-03-10 06:35:06 +08:00
case ISO_15693 :
crcStatus = iso15693_CRC_check ( frame , data_len ) ;
break ;
2020-01-20 18:37:10 +08:00
case PROTO_HITAG1 :
case PROTO_HITAGS :
2021-12-30 08:40:13 +08:00
crcStatus = hitag1_CRC_check ( frame , ( data_len * 8 ) - ( ( 8 - parityBytes [ 0 ] ) % 8 ) ) ;
case PROTO_CRYPTORF :
case PROTO_HITAG2 :
2019-03-10 06:35:06 +08:00
default :
break ;
}
}
//0 CRC-command, CRC not ok
//1 CRC-command, CRC ok
//2 Not crc-command
2020-06-08 09:15:10 +08:00
//--- Draw the data column
2022-12-31 17:04:30 +08:00
char line [ 18 ] [ 160 ] = { { 0 } } ;
2019-03-10 06:35:06 +08:00
2020-06-08 09:15:10 +08:00
if ( data_len = = 0 ) {
2020-07-13 19:55:19 +08:00
if ( protocol = = ICLASS & & duration = = 2048 ) {
2022-06-12 06:40:33 +08:00
snprintf ( line [ 0 ] , sizeof ( line [ 0 ] ) , " <SOF> " ) ;
2020-08-13 18:25:04 +08:00
} else if ( protocol = = ISO_15693 & & duration = = 512 ) {
2022-06-12 06:40:33 +08:00
snprintf ( line [ 0 ] , sizeof ( line [ 0 ] ) , " <EOF> " ) ;
2020-08-13 18:25:04 +08:00
} else {
2022-06-12 06:40:33 +08:00
snprintf ( line [ 0 ] , sizeof ( line [ 0 ] ) , " <empty trace - possible error> " ) ;
2020-07-13 19:55:19 +08:00
}
2020-05-19 06:46:10 +08:00
}
2021-12-30 06:40:18 +08:00
uint8_t partialbytebuff = 0 ;
uint8_t offset = 0 ;
2019-03-10 07:00:59 +08:00
for ( int j = 0 ; j < data_len & & j / 18 < 18 ; j + + ) {
2019-03-10 06:35:06 +08:00
uint8_t parityBits = parityBytes [ j > > 3 ] ;
2019-03-14 19:30:32 +08:00
if ( protocol ! = LEGIC
& & protocol ! = ISO_14443B
2019-09-11 20:03:14 +08:00
& & protocol ! = ISO_15693
& & protocol ! = ICLASS
2019-03-14 19:30:32 +08:00
& & protocol ! = ISO_7816_4
2020-01-20 18:37:10 +08:00
& & protocol ! = PROTO_HITAG1
& & protocol ! = PROTO_HITAG2
& & protocol ! = PROTO_HITAGS
2019-08-02 02:06:07 +08:00
& & protocol ! = THINFILM
2019-10-30 20:42:52 +08:00
& & protocol ! = FELICA
2019-12-24 07:57:15 +08:00
& & protocol ! = LTO
2020-08-16 15:59:41 +08:00
& & protocol ! = PROTO_CRYPTORF
2022-01-17 02:03:17 +08:00
& & ( hdr - > isResponse | | protocol = = ISO_14443A | | protocol = = PROTO_MIFARE | | protocol = = SEOS )
2019-03-14 19:30:32 +08:00
& & ( oddparity8 ( frame [ j ] ) ! = ( ( parityBits > > ( 7 - ( j & 0x0007 ) ) ) & 0x01 ) ) ) {
2019-03-10 06:35:06 +08:00
2020-05-06 18:14:05 +08:00
snprintf ( line [ j / 18 ] + ( ( j % 18 ) * 4 ) , 120 , " %02x! " , frame [ j ] ) ;
2020-05-19 08:14:43 +08:00
} else if ( protocol = = ICLASS & & hdr - > isResponse = = false ) {
2019-09-11 20:03:14 +08:00
uint8_t parity = 0 ;
2019-09-13 22:32:37 +08:00
for ( int i = 0 ; i < 6 ; i + + ) {
2019-09-11 20:03:14 +08:00
parity ^ = ( ( frame [ 0 ] > > i ) & 1 ) ;
}
2019-09-13 22:32:37 +08:00
if ( parity = = ( ( frame [ 0 ] > > 7 ) & 1 ) ) {
2020-05-06 18:14:05 +08:00
snprintf ( line [ j / 18 ] + ( ( j % 18 ) * 4 ) , 120 , " %02x " , frame [ j ] ) ;
2019-09-11 20:03:14 +08:00
} else {
2020-05-06 18:14:05 +08:00
snprintf ( line [ j / 18 ] + ( ( j % 18 ) * 4 ) , 120 , " %02x! " , frame [ j ] ) ;
2019-09-11 20:03:14 +08:00
}
2019-09-11 22:22:37 +08:00
2021-12-30 19:41:23 +08:00
} else if ( ( ( protocol = = PROTO_HITAG1 ) | | ( protocol = = PROTO_HITAG2 ) | | ( protocol = = PROTO_HITAGS ) ) & & ( parityBytes [ 0 ] > 0 ) ) {
2021-12-30 06:40:18 +08:00
// handle partial bytes
uint8_t nbits = parityBytes [ 0 ] ;
2021-12-30 19:41:23 +08:00
if ( j = = 0 ) {
2021-12-30 06:40:18 +08:00
partialbytebuff = frame [ 0 ] < < nbits ;
snprintf ( line [ 0 ] , 120 , " %02x(%i) " , frame [ 0 ] > > ( 8 - nbits ) , nbits ) ;
offset = 2 ;
} else {
uint8_t byte = partialbytebuff | ( frame [ j ] > > ( 8 - nbits ) ) ;
partialbytebuff = frame [ j ] < < nbits ;
snprintf ( line [ j / 18 ] + ( ( j % 18 ) * 4 ) + offset , 120 , " %02x " , byte ) ;
}
2019-09-13 22:32:37 +08:00
} else {
2020-05-06 18:14:05 +08:00
snprintf ( line [ j / 18 ] + ( ( j % 18 ) * 4 ) , 120 , " %02x " , frame [ j ] ) ;
2019-03-10 06:35:06 +08:00
}
}
2022-12-31 17:04:30 +08:00
2022-11-05 04:10:47 +08:00
uint8_t crc_format_string_offset = 0 ;
2022-12-31 17:04:30 +08:00
if ( markCRCBytes & & data_len > 2 ) {
2019-03-10 06:35:06 +08:00
//CRC-command
2021-12-30 06:40:18 +08:00
if ( ( ( protocol = = PROTO_HITAG1 ) | | ( protocol = = PROTO_HITAGS ) ) & & ( data_len > 1 ) ) {
2021-12-30 08:40:13 +08:00
// Note that UID REQUEST response has no CRC, but we don't know
// if the response we see is a UID
2021-12-30 06:40:18 +08:00
char * pos1 = line [ ( data_len - 1 ) / 18 ] + ( ( ( data_len - 1 ) % 18 ) * 4 ) + offset - 1 ;
2019-03-10 06:35:06 +08:00
( * pos1 ) = ' [ ' ;
2021-12-30 06:40:18 +08:00
char * pos2 = line [ ( data_len ) / 18 ] + ( ( ( data_len ) % 18 ) * 4 ) + offset - 2 ;
2022-06-12 06:40:33 +08:00
( * pos2 ) = ' ] ' ;
( * ( pos2 + 1 ) ) = ' \0 ' ;
2021-12-30 06:40:18 +08:00
} else {
2022-11-05 04:10:47 +08:00
2021-12-30 06:40:18 +08:00
if ( crcStatus = = 0 | | crcStatus = = 1 ) {
2022-12-31 17:04:30 +08:00
2022-11-05 04:10:47 +08:00
char * pos1 = line [ ( data_len - 2 ) / 18 ] ;
pos1 + = ( ( ( data_len - 2 ) % 18 ) * 4 ) - 1 ;
( * ( pos1 + 6 + 1 ) ) = ' \0 ' ;
char * cb_str = str_dup ( pos1 + 1 ) ;
if ( hdr - > isResponse ) {
if ( g_session . supports_colors ) {
if ( crcStatus = = 0 ) {
snprintf ( pos1 , 24 , " " _RED_ ( " %s " ) " " , cb_str ) ;
} else {
snprintf ( pos1 , 24 , " " _GREEN_ ( " %s " ) " " , cb_str ) ;
}
crc_format_string_offset = 9 ;
} else {
snprintf ( pos1 , 9 , " [%s] " , cb_str ) ;
}
} else {
if ( g_session . supports_colors ) {
if ( crcStatus = = 0 ) {
snprintf ( pos1 , 24 , AEND " " _RED_ ( " %s " ) " " , cb_str ) ;
} else {
snprintf ( pos1 , 24 , AEND " " _GREEN_ ( " %s " ) " " , cb_str ) ;
}
crc_format_string_offset = 13 ;
} else {
snprintf ( pos1 , 9 , " [%s] " , cb_str ) ;
}
}
2022-11-12 06:51:30 +08:00
free ( cb_str ) ;
2021-12-30 06:40:18 +08:00
}
2019-03-10 06:35:06 +08:00
}
}
// Draw the CRC column
2022-12-03 19:35:22 +08:00
const char * crcstrings [ ] = { _RED_ ( " !! " ) , _GREEN_ ( " ok " ) , " " , _GREEN_ ( " A ok " ) , _GREEN_ ( " B ok " ) } ;
2020-12-18 09:37:31 +08:00
const char * crc = crcstrings [ crcStatus ] ;
2019-03-10 06:35:06 +08:00
2020-09-07 16:35:09 +08:00
// mark short bytes (less than 8 Bit + Parity)
if ( protocol = = ISO_14443A | |
protocol = = PROTO_MIFARE | |
protocol = = THINFILM ) {
2020-08-17 18:35:42 +08:00
// approximated with 128 * (9 * data_len);
uint16_t bitime = 1056 + 32 ;
if ( duration < bitime ) {
uint8_t m = 7 ;
while ( m > 0 ) {
2020-09-07 16:35:09 +08:00
bitime - = 128 ;
if ( duration > bitime ) {
2020-08-17 18:35:42 +08:00
break ;
2020-09-07 16:35:09 +08:00
}
2020-08-17 18:35:42 +08:00
m - - ;
}
2021-04-20 04:18:37 +08:00
if ( data_len ) {
line [ ( data_len - 1 ) / 16 ] [ ( ( data_len - 1 ) % 16 ) * 4 + 2 ] = ' ( ' ;
line [ ( data_len - 1 ) / 16 ] [ ( ( data_len - 1 ) % 16 ) * 4 + 3 ] = m + 0x30 ;
line [ ( data_len - 1 ) / 16 ] [ ( ( data_len - 1 ) % 16 ) * 4 + 4 ] = ' ) ' ;
}
2020-09-07 16:35:09 +08:00
}
}
2020-08-17 18:35:42 +08:00
2020-07-13 19:55:19 +08:00
2020-08-12 03:39:51 +08:00
uint32_t previous_end_of_transmission_timestamp = 0 ;
2020-07-13 19:55:19 +08:00
if ( prev_eot ) {
2020-08-13 18:25:04 +08:00
if ( * prev_eot ) {
previous_end_of_transmission_timestamp = * prev_eot ;
} else {
previous_end_of_transmission_timestamp = hdr - > timestamp ;
}
2020-08-12 03:39:51 +08:00
}
2020-07-13 19:55:19 +08:00
end_of_transmission_timestamp = hdr - > timestamp + duration ;
2020-08-12 03:39:51 +08:00
if ( prev_eot )
2020-07-13 19:55:19 +08:00
* prev_eot = end_of_transmission_timestamp ;
2019-03-10 06:35:06 +08:00
2020-08-16 15:59:41 +08:00
// Always annotate these protocols both reader/tag messages
switch ( protocol ) {
2021-10-15 07:31:16 +08:00
case ISO_14443A :
case ISO_7816_4 :
annotateIso14443a ( explanation , sizeof ( explanation ) , frame , data_len , hdr - > isResponse ) ;
break ;
2020-08-16 15:59:41 +08:00
case PROTO_MIFARE :
annotateMifare ( explanation , sizeof ( explanation ) , frame , data_len , parityBytes , TRACELOG_PARITY_LEN ( hdr ) , hdr - > isResponse ) ;
break ;
case PROTO_HITAG1 :
annotateHitag1 ( explanation , sizeof ( explanation ) , frame , data_len , hdr - > isResponse ) ;
break ;
case PROTO_HITAG2 :
annotateHitag2 ( explanation , sizeof ( explanation ) , frame , data_len , hdr - > isResponse ) ;
break ;
case PROTO_HITAGS :
annotateHitagS ( explanation , sizeof ( explanation ) , frame , data_len , hdr - > isResponse ) ;
break ;
2020-08-20 03:51:10 +08:00
case ICLASS :
2020-09-07 16:35:09 +08:00
annotateIclass ( explanation , sizeof ( explanation ) , frame , data_len , hdr - > isResponse ) ;
break ;
2020-08-16 15:59:41 +08:00
default :
break ;
2020-08-12 03:39:51 +08:00
}
2019-10-30 20:35:03 +08:00
2020-08-12 03:39:51 +08:00
if ( hdr - > isResponse = = false ) {
2020-08-16 15:59:41 +08:00
2019-03-10 07:00:59 +08:00
switch ( protocol ) {
2020-08-16 15:59:41 +08:00
case LEGIC :
annotateLegic ( explanation , sizeof ( explanation ) , frame , data_len ) ;
break ;
2019-03-10 07:00:59 +08:00
case MFDES :
annotateMfDesfire ( explanation , sizeof ( explanation ) , frame , data_len ) ;
break ;
case ISO_14443B :
annotateIso14443b ( explanation , sizeof ( explanation ) , frame , data_len ) ;
break ;
case TOPAZ :
annotateTopaz ( explanation , sizeof ( explanation ) , frame , data_len ) ;
break ;
case ISO_7816_4 :
annotateIso7816 ( explanation , sizeof ( explanation ) , frame , data_len ) ;
break ;
case ISO_15693 :
annotateIso15693 ( explanation , sizeof ( explanation ) , frame , data_len ) ;
break ;
case FELICA :
annotateFelica ( explanation , sizeof ( explanation ) , frame , data_len ) ;
2020-01-04 01:19:42 +08:00
break ;
2019-12-24 07:57:15 +08:00
case LTO :
annotateLTO ( explanation , sizeof ( explanation ) , frame , data_len ) ;
2019-03-10 07:00:59 +08:00
break ;
2020-08-16 15:59:41 +08:00
case PROTO_CRYPTORF :
annotateCryptoRF ( explanation , sizeof ( explanation ) , frame , data_len ) ;
break ;
2022-01-17 02:03:17 +08:00
case SEOS :
2022-01-24 03:02:57 +08:00
annotateSeos ( explanation , sizeof ( explanation ) , frame , data_len ) ;
2022-01-17 02:03:17 +08:00
break ;
2019-03-10 07:00:59 +08:00
default :
break ;
2019-03-10 06:35:06 +08:00
}
}
2019-03-10 07:00:59 +08:00
int num_lines = MIN ( ( data_len - 1 ) / 18 + 1 , 18 ) ;
2019-03-10 06:35:06 +08:00
for ( int j = 0 ; j < num_lines ; j + + ) {
if ( j = = 0 ) {
2020-08-12 03:39:51 +08:00
2020-07-13 19:55:19 +08:00
uint32_t time1 = hdr - > timestamp - first_hdr - > timestamp ;
2020-08-13 18:25:04 +08:00
uint32_t time2 = end_of_transmission_timestamp - first_hdr - > timestamp ;
if ( prev_eot ) {
time1 = hdr - > timestamp - previous_end_of_transmission_timestamp ;
time2 = duration ;
}
2020-08-12 03:39:51 +08:00
2021-04-20 04:18:37 +08:00
if ( hdr - > isResponse ) {
// tag row
if ( use_us ) {
2022-11-05 04:10:47 +08:00
PrintAndLogEx ( NORMAL , " %10.1f | %10.1f | Tag |%-*s | %s| %s " ,
2021-05-06 03:04:48 +08:00
( float ) time1 / 13.56 ,
( float ) time2 / 13.56 ,
2022-11-05 04:10:47 +08:00
72 + crc_format_string_offset ,
2021-05-06 03:04:48 +08:00
line [ j ] ,
( j = = num_lines - 1 ) ? crc : " " ,
( j = = num_lines - 1 ) ? explanation : " "
) ;
2021-04-20 04:18:37 +08:00
} else {
2022-11-05 04:10:47 +08:00
PrintAndLogEx ( NORMAL , " %10u | %10u | Tag |%-*s | %s| %s " ,
2022-12-02 18:13:13 +08:00
time1 ,
time2 ,
2022-11-05 04:10:47 +08:00
72 + crc_format_string_offset ,
2021-05-06 03:04:48 +08:00
line [ j ] ,
( j = = num_lines - 1 ) ? crc : " " ,
( j = = num_lines - 1 ) ? explanation : " "
) ;
2021-04-20 04:18:37 +08:00
}
2020-07-13 19:55:19 +08:00
} else {
2021-04-20 04:18:37 +08:00
// reader row
if ( use_us ) {
2021-05-06 03:04:48 +08:00
PrintAndLogEx ( NORMAL ,
2022-11-05 04:10:47 +08:00
_YELLOW_ ( " %10.1f " ) " | " _YELLOW_ ( " %10.1f " ) " | " _YELLOW_ ( " Rdr " ) " | " _YELLOW_ ( " %-*s " ) " | " _YELLOW_ ( " %s " ) " | " _YELLOW_ ( " %s " ) ,
2021-05-06 03:04:48 +08:00
( float ) time1 / 13.56 ,
( float ) time2 / 13.56 ,
2022-11-05 04:10:47 +08:00
72 + crc_format_string_offset ,
2021-05-06 03:04:48 +08:00
line [ j ] ,
( j = = num_lines - 1 ) ? crc : " " ,
( j = = num_lines - 1 ) ? explanation : " "
) ;
2021-04-20 04:18:37 +08:00
} else {
PrintAndLogEx ( NORMAL ,
2022-11-05 04:10:47 +08:00
_YELLOW_ ( " %10u " ) " | " _YELLOW_ ( " %10u " ) " | " _YELLOW_ ( " Rdr " ) " | " _YELLOW_ ( " %-*s " ) " | " _YELLOW_ ( " %s " ) " | " _YELLOW_ ( " %s " ) ,
2022-12-02 18:13:13 +08:00
time1 ,
time2 ,
2022-11-05 04:10:47 +08:00
72 + crc_format_string_offset ,
2021-05-06 03:04:48 +08:00
line [ j ] ,
( j = = num_lines - 1 ) ? crc : " " ,
( j = = num_lines - 1 ) ? explanation : " "
) ;
2021-04-20 04:18:37 +08:00
}
2020-08-12 03:39:51 +08:00
}
2020-07-13 19:55:19 +08:00
2019-03-10 06:35:06 +08:00
} else {
2021-04-20 04:18:37 +08:00
if ( hdr - > isResponse ) {
2022-11-05 04:10:47 +08:00
PrintAndLogEx ( NORMAL , " | | |%-*s | %s| %s " ,
72 + crc_format_string_offset ,
2021-05-06 03:04:48 +08:00
line [ j ] ,
( j = = num_lines - 1 ) ? crc : " " ,
( j = = num_lines - 1 ) ? explanation : " "
) ;
2021-04-20 04:18:37 +08:00
} else {
2022-11-05 04:10:47 +08:00
PrintAndLogEx ( NORMAL , " | | | " _YELLOW_ ( " %-*s " ) " | " _YELLOW_ ( " %s " ) " | " _YELLOW_ ( " %s " ) ,
72 + crc_format_string_offset ,
2021-05-06 03:04:48 +08:00
line [ j ] ,
( j = = num_lines - 1 ) ? crc : " " ,
( j = = num_lines - 1 ) ? explanation : " "
) ;
2021-04-20 04:18:37 +08:00
}
2019-03-10 06:35:06 +08:00
}
}
2020-07-13 18:25:44 +08:00
if ( protocol = = PROTO_MIFARE ) {
2023-01-15 08:43:38 +08:00
uint8_t mfData [ 32 ] = { 0 } ;
size_t mfDataLen = 0 ;
2021-01-27 06:14:20 +08:00
if ( DecodeMifareData ( frame , data_len , parityBytes , hdr - > isResponse , mfData , & mfDataLen , mfDicKeys , mfDicKeysCount ) ) {
2020-07-13 18:25:44 +08:00
memset ( explanation , 0x00 , sizeof ( explanation ) ) ;
2021-10-15 07:31:16 +08:00
annotateIso14443a ( explanation , sizeof ( explanation ) , mfData , mfDataLen , hdr - > isResponse ) ;
2020-07-13 18:25:44 +08:00
uint8_t crcc = iso14443A_CRC_check ( hdr - > isResponse , mfData , mfDataLen ) ;
2022-11-05 04:10:47 +08:00
PrintAndLogEx ( NORMAL , " | | * |%-*s | %-4s| %s " ,
72 + crc_format_string_offset ,
2020-07-13 18:25:44 +08:00
sprint_hex_inrow_spaces ( mfData , mfDataLen , 2 ) ,
2022-12-03 19:35:22 +08:00
( crcc = = 0 ? _RED_ ( " !! " ) : ( crcc = = 1 ? _GREEN_ ( " ok " ) : " " ) ) ,
2020-07-13 18:25:44 +08:00
explanation ) ;
2019-03-10 06:35:06 +08:00
}
2019-10-30 20:35:03 +08:00
}
2019-03-10 06:35:06 +08:00
2020-07-13 18:25:44 +08:00
if ( is_last_record ( tracepos , traceLen ) ) {
return traceLen ;
}
2019-03-10 06:35:06 +08:00
2020-08-12 03:39:51 +08:00
if ( showWaitCycles & & hdr - > isResponse = = false & & next_record_is_response ( tracepos , trace ) ) {
2020-06-08 09:15:10 +08:00
2020-05-19 06:46:10 +08:00
tracelog_hdr_t * next_hdr = ( tracelog_hdr_t * ) ( trace + tracepos ) ;
2020-06-08 09:15:10 +08:00
2022-12-02 18:13:13 +08:00
uint32_t time1 = end_of_transmission_timestamp - first_hdr - > timestamp ;
uint32_t time2 = next_hdr - > timestamp - first_hdr - > timestamp ;
if ( prev_eot ) {
time1 = 0 ;
time2 = next_hdr - > timestamp - end_of_transmission_timestamp ;
}
if ( use_us ) {
PrintAndLogEx ( NORMAL , " %10.1f | %10.1f | %s |fdt (Frame Delay Time): " _YELLOW_ ( " %.1f " ) ,
2023-01-07 06:53:25 +08:00
( float ) time1 / 13.56 ,
( float ) time2 / 13.56 ,
" " ,
( float ) ( next_hdr - > timestamp - end_of_transmission_timestamp ) / 13.56 ) ;
2022-12-02 18:13:13 +08:00
} else {
PrintAndLogEx ( NORMAL , " %10u | %10u | %s |fdt (Frame Delay Time): " _YELLOW_ ( " %d " ) ,
2023-01-07 06:53:25 +08:00
time1 ,
time2 ,
" " ,
( next_hdr - > timestamp - end_of_transmission_timestamp ) ) ;
2022-12-02 18:13:13 +08:00
}
2019-03-10 07:00:59 +08:00
}
2019-03-10 06:35:06 +08:00
return tracepos ;
2018-03-19 01:00:41 +08:00
}
2020-06-04 17:50:41 +08:00
static int download_trace ( void ) {
2020-06-08 09:15:10 +08:00
2020-07-13 18:25:44 +08:00
if ( IfPm3Present ( ) = = false ) {
2021-06-23 15:52:29 +08:00
PrintAndLogEx ( FAILED , " You requested a trace upload in offline mode, consider using parameter '-1' for working from Tracebuffer " ) ;
2020-06-04 17:50:41 +08:00
return PM3_EINVARG ;
}
// reserve some space.
2021-08-22 06:51:37 +08:00
if ( gs_trace )
free ( gs_trace ) ;
2020-06-04 17:50:41 +08:00
2021-08-22 06:51:37 +08:00
gs_traceLen = 0 ;
2020-06-04 17:50:41 +08:00
2021-08-22 06:51:37 +08:00
gs_trace = calloc ( PM3_CMD_DATA_SIZE , sizeof ( uint8_t ) ) ;
if ( gs_trace = = NULL ) {
2020-06-04 17:50:41 +08:00
PrintAndLogEx ( FAILED , " Cannot allocate memory for trace " ) ;
return PM3_EMALLOC ;
}
2020-07-13 18:25:44 +08:00
PrintAndLogEx ( INFO , " downloading tracelog data from device " ) ;
2020-06-04 17:50:41 +08:00
// Query for the size of the trace, downloading PM3_CMD_DATA_SIZE
PacketResponseNG response ;
2021-08-22 06:51:37 +08:00
if ( ! GetFromDevice ( BIG_BUF , gs_trace , PM3_CMD_DATA_SIZE , 0 , NULL , 0 , & response , 4000 , true ) ) {
2020-06-04 17:50:41 +08:00
PrintAndLogEx ( WARNING , " timeout while waiting for reply. " ) ;
2021-08-22 06:51:37 +08:00
free ( gs_trace ) ;
gs_trace = NULL ;
2020-06-04 17:50:41 +08:00
return PM3_ETIMEOUT ;
}
2021-08-22 06:51:37 +08:00
gs_traceLen = response . oldarg [ 2 ] ;
2020-06-04 17:50:41 +08:00
// if tracelog buffer was larger and we need to download more.
2021-08-22 06:51:37 +08:00
if ( gs_traceLen > PM3_CMD_DATA_SIZE ) {
2020-06-04 17:50:41 +08:00
2021-08-22 06:51:37 +08:00
free ( gs_trace ) ;
gs_trace = calloc ( gs_traceLen , sizeof ( uint8_t ) ) ;
if ( gs_trace = = NULL ) {
2020-06-04 17:50:41 +08:00
PrintAndLogEx ( FAILED , " Cannot allocate memory for trace " ) ;
return PM3_EMALLOC ;
}
2021-08-22 06:51:37 +08:00
if ( ! GetFromDevice ( BIG_BUF , gs_trace , gs_traceLen , 0 , NULL , 0 , NULL , 2500 , false ) ) {
2020-06-04 17:50:41 +08:00
PrintAndLogEx ( WARNING , " command execution time out " ) ;
2021-08-22 06:51:37 +08:00
free ( gs_trace ) ;
gs_trace = NULL ;
2020-06-04 17:50:41 +08:00
return PM3_ETIMEOUT ;
}
}
return PM3_SUCCESS ;
}
2018-03-19 02:58:22 +08:00
// sanity check. Don't use proxmark if it is offline and you didn't specify useTraceBuffer
2018-08-13 03:54:31 +08:00
/*
2018-03-19 02:58:22 +08:00
static int SanityOfflineCheck ( bool useTraceBuffer ) {
2019-03-10 06:35:06 +08:00
if ( ! useTraceBuffer & & offline ) {
PrintAndLogEx ( NORMAL , " Your proxmark3 device is offline. Specify [1] to use TraceBuffer data instead " ) ;
return 0 ;
}
return 1 ;
2018-03-19 02:58:22 +08:00
}
2018-08-13 03:54:31 +08:00
*/
2018-03-19 02:58:22 +08:00
2022-01-31 04:18:59 +08:00
static int CmdTraceExtract ( const char * Cmd ) {
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " trace extract " ,
" Extracts protocol authentication challenges from trace buffer \n " ,
" trace extract \n "
" trace extract -1 \n "
) ;
void * argtable [ ] = {
arg_param_begin ,
2022-02-05 19:32:50 +08:00
arg_lit0 ( " 1 " , " buffer " , " use data from trace buffer " ) ,
2022-01-31 04:18:59 +08:00
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
bool use_buffer = arg_get_lit ( ctx , 1 ) ;
CLIParserFree ( ctx ) ;
clearCommandBuffer ( ) ;
if ( use_buffer = = false ) {
download_trace ( ) ;
} else if ( gs_traceLen = = 0 ) {
PrintAndLogEx ( FAILED , " You requested a trace list in offline mode but there is no trace. " ) ;
PrintAndLogEx ( FAILED , " Consider using " _YELLOW_ ( " `trace load` " ) " or removing parameter " _YELLOW_ ( " `-1` " ) ) ;
return PM3_EINVARG ;
}
2022-02-27 20:53:43 +08:00
PrintAndLogEx ( SUCCESS , " Recorded activity (trace len = " _YELLOW_ ( " %u " ) " bytes) " , gs_traceLen ) ;
2022-01-31 04:18:59 +08:00
if ( gs_traceLen = = 0 ) {
return PM3_SUCCESS ;
}
uint16_t tracepos = 0 ;
while ( tracepos < gs_traceLen ) {
tracepos = extractChallenges ( tracepos , gs_traceLen , gs_trace ) ;
if ( kbd_enter_pressed ( ) )
break ;
}
return PM3_SUCCESS ;
}
2019-04-12 06:38:54 +08:00
static int CmdTraceLoad ( const char * Cmd ) {
2020-10-10 01:45:29 +08:00
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " trace load " ,
" Load protocol data from binary file to trace buffer \n "
2020-12-05 20:27:39 +08:00
" File extension is <.trace> " ,
" trace load -f mytracefile -> w/o file extension "
2020-10-10 01:45:29 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2022-01-01 16:39:05 +08:00
arg_str1 ( " f " , " file " , " <fn> " , " Specify trace file to load " ) ,
2020-10-10 01:45:29 +08:00
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , false ) ;
int fnlen = 0 ;
char filename [ FILE_PATH_SIZE ] = { 0 } ;
CLIParamStrToBuf ( arg_get_str ( ctx , 1 ) , ( uint8_t * ) filename , FILE_PATH_SIZE , & fnlen ) ;
CLIParserFree ( ctx ) ;
2019-04-12 06:38:54 +08:00
2021-08-22 06:51:37 +08:00
if ( gs_trace ) {
free ( gs_trace ) ;
gs_trace = NULL ;
2021-08-21 20:34:20 +08:00
}
2019-04-12 06:38:54 +08:00
2020-06-03 18:29:52 +08:00
size_t len = 0 ;
2021-08-22 06:51:37 +08:00
if ( loadFile_safe ( filename , " .trace " , ( void * * ) & gs_trace , & len ) ! = PM3_SUCCESS ) {
2020-06-03 18:29:52 +08:00
PrintAndLogEx ( FAILED , " Could not open file " _YELLOW_ ( " %s " ) , filename ) ;
return PM3_EIO ;
2019-04-12 06:38:54 +08:00
}
2020-06-08 09:15:10 +08:00
2021-08-22 06:51:37 +08:00
gs_traceLen = ( long ) len ;
2020-06-08 09:15:10 +08:00
2022-02-27 20:53:43 +08:00
PrintAndLogEx ( SUCCESS , " Recorded Activity (TraceLen = " _YELLOW_ ( " %u " ) " bytes) " , gs_traceLen ) ;
2021-09-23 04:30:25 +08:00
PrintAndLogEx ( HINT , " try " _YELLOW_ ( " `trace list -1 -t ...` " ) " to view trace. Remember the " _YELLOW_ ( " `-1` " ) " param " ) ;
2019-11-25 04:14:27 +08:00
return PM3_SUCCESS ;
2019-04-12 06:38:54 +08:00
}
static int CmdTraceSave ( const char * Cmd ) {
2020-06-08 09:15:10 +08:00
2020-10-10 01:45:29 +08:00
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " trace save " ,
" Save protocol data from trace buffer to binary file \n "
2020-12-05 20:27:39 +08:00
" File extension is <.trace> " ,
" trace save -f mytracefile -> w/o file extension "
2020-10-10 01:45:29 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2022-01-01 16:39:05 +08:00
arg_str1 ( " f " , " file " , " <fn> " , " Specify trace file to save " ) ,
2020-10-10 01:45:29 +08:00
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , false ) ;
int fnlen = 0 ;
char filename [ FILE_PATH_SIZE ] = { 0 } ;
CLIParamStrToBuf ( arg_get_str ( ctx , 1 ) , ( uint8_t * ) filename , FILE_PATH_SIZE , & fnlen ) ;
CLIParserFree ( ctx ) ;
2020-08-12 03:39:51 +08:00
2021-08-22 06:51:37 +08:00
if ( gs_traceLen = = 0 ) {
2020-06-04 17:50:41 +08:00
download_trace ( ) ;
2021-08-22 06:51:37 +08:00
if ( gs_traceLen = = 0 ) {
2021-01-29 03:31:39 +08:00
PrintAndLogEx ( WARNING , " trace is empty, nothing to save " ) ;
return PM3_SUCCESS ;
}
2019-04-12 06:38:54 +08:00
}
2021-08-22 06:51:37 +08:00
saveFile ( filename , " .trace " , gs_trace , gs_traceLen ) ;
2019-11-25 04:14:27 +08:00
return PM3_SUCCESS ;
2019-04-12 06:38:54 +08:00
}
2021-04-20 03:21:47 +08:00
int CmdTraceListAlias ( const char * Cmd , const char * alias , const char * protocol ) {
2021-04-19 20:35:09 +08:00
CLIParserContext * ctx ;
2021-04-20 03:21:47 +08:00
char desc [ 500 ] = { 0 } ;
snprintf ( desc , sizeof ( desc ) - 1 ,
2021-05-06 03:04:48 +08:00
" Alias of `trace list -t %s` with selected protocol data to annotate trace buffer \n "
" You can load a trace from file (see `trace load -h`) or it be downloaded from device by default \n "
" It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol " ,
protocol ) ;
2021-04-19 20:35:09 +08:00
char example [ 200 ] = { 0 } ;
2021-04-20 03:21:47 +08:00
snprintf ( example , sizeof ( example ) - 1 ,
2022-11-20 23:48:20 +08:00
" %s list --frame -> show frame delay times \n "
" %s list -1 -> use trace buffer " ,
2021-05-06 03:04:48 +08:00
alias , alias ) ;
2021-04-20 03:21:47 +08:00
char fullalias [ 100 ] = { 0 } ;
snprintf ( fullalias , sizeof ( fullalias ) - 1 , " %s list " , alias ) ;
CLIParserInit ( & ctx , fullalias , desc , example ) ;
2021-04-19 20:35:09 +08:00
void * argtable [ ] = {
arg_param_begin ,
arg_lit0 ( " 1 " , " buffer " , " use data from trace buffer " ) ,
2022-11-20 23:48:20 +08:00
arg_lit0 ( NULL , " frame " , " show frame delay times " ) ,
2021-04-19 20:35:09 +08:00
arg_lit0 ( " c " , NULL , " mark CRC bytes " ) ,
arg_lit0 ( " r " , NULL , " show relative times (gap and duration) " ) ,
arg_lit0 ( " u " , NULL , " display times in microseconds instead of clock cycles " ) ,
arg_lit0 ( " x " , NULL , " show hexdump to convert to pcap(ng) \n "
" or to import into Wireshark using encapsulation type \" ISO 14443 \" " ) ,
2022-11-20 23:48:20 +08:00
arg_str0 ( " f " , " file " , " <fn> " , " filename of dictionary " ) ,
2021-04-19 20:35:09 +08:00
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2021-04-20 05:31:11 +08:00
CLIParserFree ( ctx ) ;
2021-04-20 03:21:47 +08:00
char args [ 128 ] = { 0 } ;
2022-11-20 23:48:20 +08:00
snprintf ( args , sizeof ( args ) , " -c -t %s " , protocol ) ;
2021-04-20 05:25:13 +08:00
strncat ( args , Cmd , sizeof ( args ) - strlen ( args ) - 1 ) ;
2021-04-20 03:21:47 +08:00
return CmdTraceList ( args ) ;
2021-04-19 20:35:09 +08:00
}
2019-03-10 18:20:22 +08:00
int CmdTraceList ( const char * Cmd ) {
2020-10-10 01:45:29 +08:00
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " trace list " ,
2020-10-12 04:40:05 +08:00
" Annotate trace buffer with selected protocol data \n "
" You can load a trace from file (see `trace load -h`) or it be downloaded from device by default \n " ,
" trace list -t raw -> just show raw data without annotations \n "
2022-01-17 02:03:17 +08:00
" \n "
2022-01-04 05:12:30 +08:00
" trace list -t 14a -> interpret as " _YELLOW_ ( " ISO14443-A " ) " \n "
" trace list -t 14b -> interpret as " _YELLOW_ ( " ISO14443-B " ) " \n "
" trace list -t 15 -> interpret as " _YELLOW_ ( " ISO15693 " ) " \n "
2022-01-17 02:03:17 +08:00
" trace list -t 7816 -> interpret as " _YELLOW_ ( " ISO7816-4 " ) " \n "
" trace list -t cryptorf -> interpret as " _YELLOW_ ( " CryptoRF " ) " \n \n "
" trace list -t des -> interpret as " _YELLOW_ ( " MIFARE DESFire " ) " \n "
2022-01-04 05:12:30 +08:00
" trace list -t felica -> interpret as " _YELLOW_ ( " ISO18092 / FeliCa " ) " \n "
" trace list -t hitag1 -> interpret as " _YELLOW_ ( " Hitag1 " ) " \n "
" trace list -t hitag2 -> interpret as " _YELLOW_ ( " Hitag2 " ) " \n "
" trace list -t hitags -> interpret as " _YELLOW_ ( " HitagS " ) " \n "
2022-01-17 02:03:17 +08:00
" trace list -t iclass -> interpret as " _YELLOW_ ( " iCLASS " ) " \n "
" trace list -t legic -> interpret as " _YELLOW_ ( " LEGIC " ) " \n "
2022-01-04 05:12:30 +08:00
" trace list -t lto -> interpret as " _YELLOW_ ( " LTO-CM " ) " \n "
2022-01-17 02:03:17 +08:00
" trace list -t mf -> interpret as " _YELLOW_ ( " MIFARE Classic " ) " and decrypt crypto1 stream \n "
" trace list -t seos -> interpret as " _YELLOW_ ( " SEOS " ) " \n "
" trace list -t thinfilm -> interpret as " _YELLOW_ ( " Thinfilm " ) " \n "
2022-01-24 03:02:57 +08:00
" trace list -t topaz -> interpret as " _YELLOW_ ( " Topaz " ) " \n "
2022-01-17 02:03:17 +08:00
" \n "
2022-11-20 23:48:20 +08:00
" trace list -t mf -f mfc_default_keys.dic -> use default dictionary file \n "
" trace list -t 14a --frame -> show frame delay times \n "
" trace list -t 14a -1 -> use trace buffer "
2020-10-12 04:40:05 +08:00
) ;
2020-10-10 01:45:29 +08:00
void * argtable [ ] = {
arg_param_begin ,
arg_lit0 ( " 1 " , " buffer " , " use data from trace buffer " ) ,
2022-11-20 23:48:20 +08:00
arg_lit0 ( NULL , " frame " , " show frame delay times " ) ,
2020-10-10 01:45:29 +08:00
arg_lit0 ( " c " , NULL , " mark CRC bytes " ) ,
arg_lit0 ( " r " , NULL , " show relative times (gap and duration) " ) ,
arg_lit0 ( " u " , NULL , " display times in microseconds instead of clock cycles " ) ,
arg_lit0 ( " x " , NULL , " show hexdump to convert to pcap(ng) \n "
2020-10-12 04:40:05 +08:00
" or to import into Wireshark using encapsulation type \" ISO 14443 \" " ) ,
2022-01-01 09:37:00 +08:00
arg_str0 ( " t " , " type " , NULL , " protocol to annotate the trace " ) ,
2022-11-20 23:48:20 +08:00
arg_str0 ( " f " , " file " , " <fn> " , " filename of dictionary " ) ,
2020-10-10 01:45:29 +08:00
arg_param_end
} ;
2022-01-02 07:13:20 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-10-12 04:40:05 +08:00
2020-10-10 01:45:29 +08:00
bool use_buffer = arg_get_lit ( ctx , 1 ) ;
bool show_wait_cycles = arg_get_lit ( ctx , 2 ) ;
bool mark_crc = arg_get_lit ( ctx , 3 ) ;
bool use_relative = arg_get_lit ( ctx , 4 ) ;
2020-10-12 04:40:05 +08:00
bool use_us = arg_get_lit ( ctx , 5 ) ;
2020-10-10 01:45:29 +08:00
bool show_hex = arg_get_lit ( ctx , 6 ) ;
int tlen = 0 ;
2019-03-10 06:35:06 +08:00
char type [ 10 ] = { 0 } ;
2020-10-10 01:45:29 +08:00
CLIParamStrToBuf ( arg_get_str ( ctx , 7 ) , ( uint8_t * ) type , sizeof ( type ) , & tlen ) ;
str_lower ( type ) ;
2020-10-12 04:40:05 +08:00
2021-01-27 06:14:20 +08:00
int diclen = 0 ;
2021-01-27 19:43:50 +08:00
char dictionary [ FILE_PATH_SIZE + 2 ] = { 0 } ;
if ( CLIParamStrToBuf ( arg_get_str ( ctx , 8 ) , ( uint8_t * ) dictionary , FILE_PATH_SIZE , & diclen ) ) {
PrintAndLogEx ( FAILED , " Dictionary file name too long or invalid. " ) ;
diclen = 0 ;
}
2021-01-27 06:14:20 +08:00
2020-10-10 01:45:29 +08:00
CLIParserFree ( ctx ) ;
2019-03-10 06:35:06 +08:00
2020-10-10 01:45:29 +08:00
clearCommandBuffer ( ) ;
2019-03-10 06:35:06 +08:00
2020-10-10 01:45:29 +08:00
// no crc, no annotations
uint8_t protocol = - 1 ;
// validate type of output
2022-01-24 03:02:57 +08:00
if ( strcmp ( type , " 14a " ) = = 0 ) protocol = ISO_14443A ;
2020-10-10 01:45:29 +08:00
else if ( strcmp ( type , " 14b " ) = = 0 ) protocol = ISO_14443B ;
2022-01-17 02:03:17 +08:00
else if ( strcmp ( type , " 15 " ) = = 0 ) protocol = ISO_15693 ;
2020-10-10 01:45:29 +08:00
else if ( strcmp ( type , " 7816 " ) = = 0 ) protocol = ISO_7816_4 ;
2022-01-17 02:03:17 +08:00
else if ( strcmp ( type , " cryptorf " ) = = 0 ) protocol = PROTO_CRYPTORF ;
2020-10-10 01:45:29 +08:00
else if ( strcmp ( type , " des " ) = = 0 ) protocol = MFDES ;
else if ( strcmp ( type , " felica " ) = = 0 ) protocol = FELICA ;
else if ( strcmp ( type , " hitag1 " ) = = 0 ) protocol = PROTO_HITAG1 ;
else if ( strcmp ( type , " hitag2 " ) = = 0 ) protocol = PROTO_HITAG2 ;
else if ( strcmp ( type , " hitags " ) = = 0 ) protocol = PROTO_HITAGS ;
2022-01-17 02:03:17 +08:00
else if ( strcmp ( type , " iclass " ) = = 0 ) protocol = ICLASS ;
else if ( strcmp ( type , " legic " ) = = 0 ) protocol = LEGIC ;
2020-10-10 01:45:29 +08:00
else if ( strcmp ( type , " lto " ) = = 0 ) protocol = LTO ;
2022-01-17 02:03:17 +08:00
else if ( strcmp ( type , " mf " ) = = 0 ) protocol = PROTO_MIFARE ;
2020-10-12 04:40:05 +08:00
else if ( strcmp ( type , " raw " ) = = 0 ) protocol = - 1 ;
2022-01-17 02:03:17 +08:00
else if ( strcmp ( type , " seos " ) = = 0 ) protocol = SEOS ;
else if ( strcmp ( type , " thinfilm " ) = = 0 ) protocol = THINFILM ;
else if ( strcmp ( type , " topaz " ) = = 0 ) protocol = TOPAZ ;
2022-01-02 07:13:20 +08:00
else if ( strcmp ( type , " " ) = = 0 ) protocol = - 1 ;
else {
PrintAndLogEx ( FAILED , " Unknown protocol \" %s \" " , type ) ;
return PM3_EINVARG ;
}
2020-10-10 01:45:29 +08:00
2021-04-19 20:22:15 +08:00
if ( use_buffer = = false ) {
2020-06-04 17:50:41 +08:00
download_trace ( ) ;
2021-08-22 06:51:37 +08:00
} else if ( gs_traceLen = = 0 ) {
2022-01-31 04:18:59 +08:00
PrintAndLogEx ( FAILED , " You requested a trace list in offline mode but there is no trace. " ) ;
PrintAndLogEx ( FAILED , " Consider using " _YELLOW_ ( " `trace load` " ) " or removing parameter " _YELLOW_ ( " `-1` " ) ) ;
2021-04-19 20:22:15 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
2022-02-27 20:53:43 +08:00
PrintAndLogEx ( SUCCESS , " Recorded activity (trace len = " _YELLOW_ ( " %u " ) " bytes) " , gs_traceLen ) ;
2021-08-22 06:51:37 +08:00
if ( gs_traceLen = = 0 ) {
2020-05-08 18:30:18 +08:00
return PM3_SUCCESS ;
}
uint16_t tracepos = 0 ;
2019-10-30 20:35:03 +08:00
/*
2019-03-10 06:35:06 +08:00
if ( protocol = = FELICA ) {
2021-08-22 06:51:37 +08:00
printFelica ( gs_traceLen , gs_trace ) ;
2019-10-30 20:35:03 +08:00
} */
2020-10-10 01:45:29 +08:00
if ( show_hex ) {
2021-08-22 06:51:37 +08:00
while ( tracepos < gs_traceLen ) {
tracepos = printHexLine ( tracepos , gs_traceLen , gs_trace , protocol ) ;
2019-05-09 22:34:06 +08:00
}
2019-03-10 06:35:06 +08:00
} else {
2020-07-13 19:55:19 +08:00
2020-08-13 18:25:04 +08:00
if ( use_relative ) {
2020-07-13 19:55:19 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " gap " ) " = time between transfers. " _YELLOW_ ( " duration " ) " = duration of data transfer. " _YELLOW_ ( " src " ) " = source of transfer " ) ;
2020-08-13 18:25:04 +08:00
} else {
2020-07-13 19:55:19 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " start " ) " = start of start frame " _YELLOW_ ( " end " ) " = end of frame. " _YELLOW_ ( " src " ) " = source of transfer " ) ;
2020-08-13 18:25:04 +08:00
}
2020-07-13 19:55:19 +08:00
if ( protocol = = ISO_14443A | | protocol = = PROTO_MIFARE | | protocol = = MFDES | | protocol = = TOPAZ | | protocol = = LTO ) {
if ( use_us )
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO14443A " ) " - all times are in microseconds " ) ;
else
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO14443A " ) " - all times are in carrier periods (1/13.56MHz) " ) ;
}
if ( protocol = = THINFILM ) {
if ( use_us )
2020-08-12 03:39:51 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " Thinfilm " ) " - all times are in microseconds " ) ;
2020-07-13 19:55:19 +08:00
else
PrintAndLogEx ( INFO , _YELLOW_ ( " Thinfilm " ) " - all times are in carrier periods (1/13.56MHz) " ) ;
}
if ( protocol = = ICLASS | | protocol = = ISO_15693 ) {
if ( use_us )
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO15693 / iCLASS " ) " - all times are in microseconds " ) ;
else
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO15693 / iCLASS " ) " - all times are in carrier periods (1/13.56MHz) " ) ;
}
2019-03-10 07:00:59 +08:00
if ( protocol = = LEGIC )
2020-07-13 19:55:19 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " LEGIC " ) " - Reader Mode: Timings are in ticks (1us == 1.5ticks) \n "
2019-03-10 07:00:59 +08:00
" Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us) " ) ;
2020-07-13 19:55:19 +08:00
2020-08-16 15:59:41 +08:00
if ( protocol = = ISO_14443B | | protocol = = PROTO_CRYPTORF ) {
2020-07-13 19:55:19 +08:00
if ( use_us )
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO14443B " ) " - all times are in microseconds " ) ;
else
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO14443B " ) " - all times are in carrier periods (1/13.56MHz) " ) ;
}
2019-03-10 07:00:59 +08:00
if ( protocol = = ISO_7816_4 )
2020-07-13 19:55:19 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO7816-4 / Smartcard " ) " - Timings N/A " ) ;
2020-01-20 18:37:10 +08:00
if ( protocol = = PROTO_HITAG1 | | protocol = = PROTO_HITAG2 | | protocol = = PROTO_HITAGS )
2020-07-13 19:55:19 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " Hitag1 / Hitag2 / HitagS " ) " - Timings in ETU (8us) " ) ;
if ( protocol = = FELICA ) {
if ( use_us )
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO18092 / FeliCa " ) " - all times are in microseconds " ) ;
else
PrintAndLogEx ( INFO , _YELLOW_ ( " ISO18092 / FeliCa " ) " - all times are in carrier periods (1/13.56MHz) " ) ;
}
2020-04-16 15:01:14 +08:00
2021-01-27 06:14:20 +08:00
const uint64_t * dicKeys = NULL ;
uint32_t dicKeysCount = 0 ;
bool dictionaryLoad = false ;
if ( protocol = = PROTO_MIFARE ) {
if ( diclen > 0 ) {
uint8_t * keyBlock = NULL ;
int res = loadFileDICTIONARY_safe ( dictionary , ( void * * ) & keyBlock , 6 , & dicKeysCount ) ;
if ( res ! = PM3_SUCCESS | | dicKeysCount = = 0 | | keyBlock = = NULL ) {
PrintAndLogEx ( FAILED , " An error occurred while loading the dictionary! (we will use the default keys now) " ) ;
} else {
dicKeys = calloc ( dicKeysCount , sizeof ( uint64_t ) ) ;
for ( int i = 0 ; i < dicKeysCount ; i + + ) {
uint64_t key = bytes_to_num ( keyBlock + i * 6 , 6 ) ;
memcpy ( ( uint8_t * ) & dicKeys [ i ] , & key , sizeof ( uint64_t ) ) ;
}
dictionaryLoad = true ;
}
if ( keyBlock ! = NULL ) {
free ( keyBlock ) ;
}
}
if ( dicKeys = = NULL ) {
dicKeys = g_mifare_default_keys ;
dicKeysCount = ARRAYLEN ( g_mifare_default_keys ) ;
}
}
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2020-08-13 18:25:04 +08:00
if ( use_relative ) {
PrintAndLogEx ( NORMAL , " Gap | Duration | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation " ) ;
} else {
2020-07-13 19:55:19 +08:00
PrintAndLogEx ( NORMAL , " Start | End | Src | Data (! denotes parity error) | CRC | Annotation " ) ;
}
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " ------------+------------+-----+-------------------------------------------------------------------------+-----+-------------------- " ) ;
2020-07-13 18:25:44 +08:00
// clean authentication data used with the mifare classic decrypt fct
if ( protocol = = ISO_14443A | | protocol = = PROTO_MIFARE )
ClearAuthData ( ) ;
2020-07-13 19:55:19 +08:00
uint32_t previous_EOT = 0 ;
uint32_t * prev_EOT = NULL ;
if ( use_relative ) {
prev_EOT = & previous_EOT ;
}
2020-08-12 03:39:51 +08:00
2021-08-22 06:51:37 +08:00
while ( tracepos < gs_traceLen ) {
tracepos = printTraceLine ( tracepos , gs_traceLen , gs_trace , protocol , show_wait_cycles , mark_crc , prev_EOT , use_us , dicKeys , dicKeysCount ) ;
2019-08-07 18:12:44 +08:00
2019-08-05 01:13:54 +08:00
if ( kbd_enter_pressed ( ) )
break ;
2019-03-10 06:35:06 +08:00
}
2021-01-27 06:14:20 +08:00
if ( dictionaryLoad )
free ( ( void * ) dicKeys ) ;
2019-03-10 06:35:06 +08:00
}
2020-10-12 04:40:05 +08:00
2020-10-10 01:45:29 +08:00
if ( show_hex )
PrintAndLogEx ( HINT , " syntax to use: " _YELLOW_ ( " `text2pcap -t \" %%S. \" -l 264 -n <input-text-file> <output-pcapng-file>` " ) ) ;
2019-11-25 04:14:27 +08:00
return PM3_SUCCESS ;
2018-03-19 01:00:41 +08:00
}
2020-06-04 17:50:41 +08:00
static command_t CommandTable [ ] = {
{ " help " , CmdHelp , AlwaysAvailable , " This help " } ,
2022-01-31 04:18:59 +08:00
{ " extract " , CmdTraceExtract , AlwaysAvailable , " Extract authentication challenges found in trace " } ,
2020-06-04 17:50:41 +08:00
{ " list " , CmdTraceList , AlwaysAvailable , " List protocol data in trace buffer " } ,
{ " load " , CmdTraceLoad , AlwaysAvailable , " Load trace from file " } ,
{ " save " , CmdTraceSave , AlwaysAvailable , " Save trace buffer to file " } ,
{ NULL , NULL , NULL , NULL }
} ;
static int CmdHelp ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
CmdsHelp ( CommandTable ) ;
return PM3_SUCCESS ;
}
int CmdTrace ( const char * Cmd ) {
clearCommandBuffer ( ) ;
return CmdsParse ( CommandTable , Cmd ) ;
}