#include <stdbool.h>
#include "util.h"
#include "ui.h"
+#include "cliparser/cliparser.h"
#include "comms.h"
#include "iso14443crc.h"
#include "iso15693tools.h"
}
-void annotateIso14443_4(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){
+void annotateIso14443_4(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
// S-block
if ((cmd[0] & 0xc3) == 0xc2) {
switch (cmd[0] & 0x30) {
0A 11 22 33 44 55 66 = Authenticate (11 22 33 44 55 66 = data to authenticate)
**/
-void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
-{
+void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
switch(cmd[0]){
case ISO14443B_REQB : snprintf(exp,size,"REQB");break;
case ISO14443B_ATTRIB : snprintf(exp,size,"ATTRIB");break;
}
-void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
-{
+void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
switch(cmd[0])
{
case ISO14443A_CMD_WUPA:
}
-bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen)
-{
+bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) {
return(tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen);
}
-bool next_record_is_response(uint16_t tracepos, uint8_t *trace)
-{
+bool next_record_is_response(uint16_t tracepos, uint8_t *trace) {
uint16_t next_records_datalen = *((uint16_t *)(trace + tracepos + sizeof(uint32_t) + sizeof(uint16_t)));
-
return(next_records_datalen & 0x8000);
}
-bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len)
-{
+bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) {
#define MAX_TOPAZ_READER_CMD_LEN 16
}
-uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes)
-{
+uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes, uint32_t *prev_EOT, bool times_in_us) {
bool isResponse;
uint16_t data_len, parity_len;
uint32_t duration;
uint8_t topaz_reader_command[9];
- uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp;
+ uint32_t timestamp, first_timestamp;
+ uint32_t EndOfTransmissionTimestamp = 0;
char explanation[30] = {0};
uint8_t mfData[32] = {0};
size_t mfDataLen = 0;
//--- Draw the CRC column
char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " "));
- EndOfTransmissionTimestamp = timestamp + duration;
-
if (protocol == PROTO_MIFARE)
annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse);
}
}
+ uint32_t previousEndOfTransmissionTimestamp = 0;
+ if (prev_EOT) {
+ if (*prev_EOT) {
+ previousEndOfTransmissionTimestamp = *prev_EOT;
+ } else {
+ previousEndOfTransmissionTimestamp = timestamp;
+ }
+ }
+ EndOfTransmissionTimestamp = timestamp + duration;
+ if (prev_EOT) *prev_EOT = EndOfTransmissionTimestamp;
+
int num_lines = MIN((data_len - 1)/16 + 1, 16);
for (int j = 0; j < num_lines ; j++) {
if (j == 0) {
- PrintAndLog(" %10" PRIu32 " | %10" PRIu32 " | %s |%-64s | %s| %s",
- (timestamp - first_timestamp),
- (EndOfTransmissionTimestamp - first_timestamp),
- (isResponse ? "Tag" : "Rdr"),
- line[j],
- (j == num_lines-1) ? crc : " ",
- (j == num_lines-1) ? explanation : "");
+ uint32_t time1 = timestamp - first_timestamp;
+ uint32_t time2 = EndOfTransmissionTimestamp - first_timestamp;
+ if (prev_EOT) {
+ time1 = timestamp - previousEndOfTransmissionTimestamp;
+ time2 = duration;
+ }
+ if (times_in_us) {
+ PrintAndLog(" %10.1f | %10.1f | %s |%-64s | %s| %s",
+ (float)time1/13.56,
+ (float)time2/13.56,
+ isResponse ? "Tag" : "Rdr",
+ line[j],
+ (j == num_lines-1) ? crc : " ",
+ (j == num_lines-1) ? explanation : "");
+ } else {
+ PrintAndLog(" %10" PRIu32 " | %10" PRIu32 " | %s |%-64s | %s| %s",
+ time1,
+ time2,
+ isResponse ? "Tag" : "Rdr",
+ line[j],
+ (j == num_lines-1) ? crc : " ",
+ (j == num_lines-1) ? explanation : "");
+ }
} else {
PrintAndLog(" | | |%-64s | %s| %s",
line[j],
}
-int CmdHFList(const char *Cmd)
-{
- bool showWaitCycles = false;
- bool markCRCBytes = false;
- bool loadFromFile = false;
- bool PCSCtrace = false;
- bool saveToFile = false;
- char param1 = '\0';
- char param2 = '\0';
- char param3 = '\0';
- char param4 = '\0';
- char type[40] = {0};
- char filename[FILE_PATH_SIZE] = {0};
- uint8_t protocol = 0;
-
- // parse command line
- int tlen = param_getstr(Cmd, 0, type, sizeof(type));
- if (param_getlength(Cmd, 1) == 1) {
- param1 = param_getchar(Cmd, 1);
- } else {
- param_getstr(Cmd, 1, filename, sizeof(filename));
- }
- if (param_getlength(Cmd, 2) == 1) {
- param2 = param_getchar(Cmd, 2);
- } else if (strlen(filename) == 0) {
- param_getstr(Cmd, 2, filename, sizeof(filename));
- }
- if (param_getlength(Cmd, 3) == 1) {
- param3 = param_getchar(Cmd, 3);
- } else if (strlen(filename) == 0) {
- param_getstr(Cmd, 3, filename, sizeof(filename));
- }
- if (param_getlength(Cmd, 4) == 1) {
- param4 = param_getchar(Cmd, 4);
- } else if (strlen(filename) == 0) {
- param_getstr(Cmd, 4, filename, sizeof(filename));
- }
-
- // Validate params
- bool errors = false;
-
- if(tlen == 0) {
- errors = true;
- }
-
- if(param1 == 'h'
- || (param1 != 0 && param1 != 'f' && param1 != 'c' && param1 != 'l' && param1 != 'p')
- || (param2 != 0 && param2 != 'f' && param2 != 'c' && param2 != 'l' && param1 != 'p')
- || (param3 != 0 && param3 != 'f' && param3 != 'c' && param3 != 'l' && param1 != 'p')
- || (param4 != 0 && param4 != 'f' && param4 != 'c' && param4 != 'l' && param4 != 'p')) {
- errors = true;
- }
-
- if(!errors) {
- if (strcmp(type, "iclass") == 0) protocol = ICLASS;
- else if(strcmp(type, "14a") == 0) protocol = ISO_14443A;
- else if(strcmp(type, "mf") == 0) protocol = PROTO_MIFARE;
- else if(strcmp(type, "14b") == 0) protocol = ISO_14443B;
- else if(strcmp(type, "topaz") == 0) protocol = TOPAZ;
- else if(strcmp(type, "7816") == 0) protocol = ISO_7816_4;
- else if(strcmp(type, "14-4") == 0) protocol = ISO_14443_4;
- else if(strcmp(type, "15") == 0) protocol = ISO_15693;
- else if(strcmp(type, "raw") == 0) protocol = -1;//No crc, no annotations
- else if (strcmp(type, "save") == 0) saveToFile = true;
- else errors = true;
- }
-
- if (param1 == 'f' || param2 == 'f' || param3 == 'f' || param4 == 'f') {
- showWaitCycles = true;
- }
+int CmdHFList(const char *Cmd) {
+
+ CLIParserInit("hf list", "\nList or save protocol data.",
+ "examples: hf list 14a -f -- interpret as ISO14443A communication and display Frame Delay Times\n"\
+ " hf list iclass -- interpret as iClass trace\n"\
+ " hf list -s myCardTrace.trc -- save trace for later use\n"\
+ " hf list 14a -l myCardTrace.trc -- load trace and interpret as ISO14443A communication\n");
+ void* argtable[] = {
+ arg_param_begin,
+ arg_lit0("f", "fdt", "display fdt (frame delay times)"),
+ arg_lit0("r", "relative", "show relative times (gap and duration)"),
+ arg_lit0("c", "crc" , "mark CRC bytes"),
+ arg_lit0("p", "pcsc", "show trace buffer from PCSC card reader instead of PM3"),
+ arg_str0("l", "load", "<filename>", "load trace from file"),
+ arg_str0("s", "save", "<filename>", "save trace to file"),
+ arg_lit0("u", "us", "display times in microseconds instead of clock cycles"),
+ arg_str0(NULL, NULL, "<protocol>", "protocol to interpret. Possible values:\n"\
+ "\traw - just show raw data without annotations (default)\n"\
+ "\t14a - interpret data as ISO14443A communications\n"\
+ "\tmf - interpret data as ISO14443A communications and decrypt Mifare Crypto1 stream\n"\
+ "\t14b - interpret data as ISO14443B communications\n"\
+ "\t15 - interpret data as ISO15693 communications\n"\
+ "\ticlass - interpret data as iClass communications\n"\
+ "\ttopaz - interpret data as Topaz communications\n"\
+ "\t7816 - interpret data as 7816-4 APDU communications\n"\
+ "\t14-4 - interpret data as ISO14443-4 communications"),
+ arg_param_end
+ };
- if (param1 == 'c' || param2 == 'c' || param3 == 'c' || param4 == 'c') {
- markCRCBytes = true;
+ if (CLIParserParseString(Cmd, argtable, arg_getsize(argtable), true)){
+ CLIParserFree();
+ return 0;
}
- if (param1 == 'l' || param2 == 'l' || param3 == 'l' || param4 == 'l') {
- loadFromFile = true;
+ bool showWaitCycles = arg_get_lit(1);
+ bool relative_times = arg_get_lit(2);
+ bool markCRCBytes = arg_get_lit(3);
+ bool PCSCtrace = arg_get_lit(4);
+ bool loadFromFile = arg_get_str_len(5);
+ bool saveToFile = arg_get_str_len(6);
+ bool times_in_us = arg_get_lit(7);
+
+ uint32_t previous_EOT = 0;
+ uint32_t *prev_EOT = NULL;
+ if (relative_times) {
+ prev_EOT = &previous_EOT;
}
-
- if (param1 == 'p' || param2 == 'p' || param3 == 'p' || param4 == 'p') {
- PCSCtrace = true;
+
+ char load_filename[FILE_PATH_SIZE] = {0};
+ if (loadFromFile) {
+ strncpy(load_filename, arg_get_str(5)->sval[0], FILE_PATH_SIZE);
}
-
- if ((loadFromFile || saveToFile) && strlen(filename) == 0) {
- errors = true;
+ char save_filename[FILE_PATH_SIZE] = {0};
+ if (saveToFile) {
+ strncpy(save_filename, arg_get_str(6)->sval[0], FILE_PATH_SIZE);
}
-
- if (loadFromFile && saveToFile) {
- errors = true;
+
+ uint8_t protocol = -1;
+ if (arg_get_str_len(8)) {
+ if (strcmp(arg_get_str(8)->sval[0], "iclass") == 0) protocol = ICLASS;
+ else if(strcmp(arg_get_str(8)->sval[0], "14a") == 0) protocol = ISO_14443A;
+ else if(strcmp(arg_get_str(8)->sval[0], "mf") == 0) protocol = PROTO_MIFARE;
+ else if(strcmp(arg_get_str(8)->sval[0], "14b") == 0) protocol = ISO_14443B;
+ else if(strcmp(arg_get_str(8)->sval[0], "topaz") == 0) protocol = TOPAZ;
+ else if(strcmp(arg_get_str(8)->sval[0], "7816") == 0) protocol = ISO_7816_4;
+ else if(strcmp(arg_get_str(8)->sval[0], "14-4") == 0) protocol = ISO_14443_4;
+ else if(strcmp(arg_get_str(8)->sval[0], "15") == 0) protocol = ISO_15693;
+ else if(strcmp(arg_get_str(8)->sval[0], "raw") == 0) protocol = -1;//No crc, no annotations
+ else {
+ PrintAndLog("hf list: invalid argument \"%s\"\nTry 'hf list --help' for more information.", arg_get_str(8)->sval[0]);
+ CLIParserFree();
+ return 0;
+ }
}
- if (errors) {
- PrintAndLog("List or save protocol data.");
- PrintAndLog("Usage: hf list <protocol> [f] [c] [p] [l <filename>]");
- PrintAndLog(" hf list save <filename>");
- PrintAndLog(" f - show frame delay times as well");
- PrintAndLog(" c - mark CRC bytes");
- PrintAndLog(" p - use trace buffer from PCSC card reader instead of PM3");
- PrintAndLog(" l - load data from file instead of trace buffer");
- PrintAndLog(" save - save data to file");
- PrintAndLog("Supported <protocol> values:");
- PrintAndLog(" raw - just show raw data without annotations");
- PrintAndLog(" 14a - interpret data as iso14443a communications");
- PrintAndLog(" mf - interpret data as iso14443a communications and decrypt crypto1 stream");
- PrintAndLog(" 14b - interpret data as iso14443b communications");
- PrintAndLog(" 15 - interpret data as iso15693 communications");
- PrintAndLog(" iclass - interpret data as iclass communications");
- PrintAndLog(" topaz - interpret data as topaz communications");
- PrintAndLog(" 7816 - interpret data as 7816-4 APDU communications");
- PrintAndLog(" 14-4 - interpret data as ISO14443-4 communications");
- PrintAndLog("");
- PrintAndLog("example: hf list 14a f");
- PrintAndLog("example: hf list iclass");
- PrintAndLog("example: hf list save myCardTrace.trc");
- PrintAndLog("example: hf list 14a l myCardTrace.trc");
- return 0;
- }
+ CLIParserFree();
uint8_t *trace;
uint32_t tracepos = 0;
uint32_t traceLen = 0;
-
+
if (loadFromFile) {
#define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions
FILE *tracefile = NULL;
PrintAndLog("Cannot allocate memory for trace");
return 2;
}
- if ((tracefile = fopen(filename,"rb")) == NULL) {
- PrintAndLog("Could not open file %s", filename);
+ if ((tracefile = fopen(load_filename,"rb")) == NULL) {
+ PrintAndLog("Could not open file %s", load_filename);
free(trace);
return 0;
}
trace = malloc(USB_CMD_DATA_SIZE);
// Query for the size of the trace
UsbCommand response;
- GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false);
+ if (!(GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, 500, false))) {
+ return 1;
+ }
traceLen = response.arg[2];
if (traceLen > USB_CMD_DATA_SIZE) {
uint8_t *p = realloc(trace, traceLen);
return 2;
}
trace = p;
- GetFromBigBuf(trace, traceLen, 0, NULL, -1, false);
+ if (!(GetFromBigBuf(trace, traceLen, 0, NULL, 500, false))) {
+ return 1;
+ }
}
}
if (saveToFile) {
FILE *tracefile = NULL;
- if ((tracefile = fopen(filename,"wb")) == NULL) {
- PrintAndLog("Could not create file %s", filename);
+ if ((tracefile = fopen(save_filename,"wb")) == NULL) {
+ PrintAndLog("Could not create file %s", save_filename);
return 1;
}
fwrite(trace, 1, traceLen, tracefile);
- PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename);
+ PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, save_filename);
fclose(tracefile);
} else {
PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen);
PrintAndLog("");
- PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
- PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)");
- PrintAndLog("iClass - Timings are not as accurate");
+ if (relative_times) {
+ PrintAndLog("Gap = time between transfers. Duration = duration of data transfer. Src = Source of transfer");
+ } else {
+ PrintAndLog("Start = Start of Frame, End = End of Frame. Src = Source of transfer");
+ }
+ if (times_in_us) {
+ PrintAndLog("All times are in microseconds");
+ } else {
+ PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
+ }
PrintAndLog("");
- PrintAndLog(" Start | End | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation |");
+ if (relative_times) {
+ PrintAndLog(" Gap | Duration | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation |");
+ } else {
+ PrintAndLog(" Start | End | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation |");
+ }
PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|");
ClearAuthData();
- while(tracepos < traceLen)
- {
- tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes);
+ while(tracepos < traceLen) {
+ tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes, prev_EOT, times_in_us);
}
}