mirror of
https://github.com/Proxmark/proxmark3.git
synced 2024-09-20 23:06:25 +08:00
mod 'hf list' (#881)
* switch to argtable command line parsing (i.e. options must now be preceded by '-') * add option '-r' to display relative times * add option '-u' to display times in microseconds * fix: graceful exit if trace is requested from offline PM3
This commit is contained in:
parent
496bb4be33
commit
d3bcdbdabf
|
@ -18,6 +18,7 @@
|
|||
#include <stdbool.h>
|
||||
#include "util.h"
|
||||
#include "ui.h"
|
||||
#include "cliparser/cliparser.h"
|
||||
#include "comms.h"
|
||||
#include "iso14443crc.h"
|
||||
#include "iso15693tools.h"
|
||||
|
@ -317,7 +318,7 @@ void annotateIso7816(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){
|
||||
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) {
|
||||
|
@ -364,8 +365,7 @@ void annotateIso14443_4(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){
|
|||
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;
|
||||
|
@ -383,8 +383,7 @@ void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
|
|||
|
||||
}
|
||||
|
||||
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:
|
||||
|
@ -802,22 +801,18 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo
|
|||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
@ -855,13 +850,13 @@ bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -982,8 +977,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
|
|||
//--- 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);
|
||||
|
||||
|
@ -1000,16 +993,43 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
|
|||
}
|
||||
}
|
||||
|
||||
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],
|
||||
|
@ -1047,129 +1067,88 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
int CmdHFList(const char *Cmd) {
|
||||
|
||||
// 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));
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (param1 == 'c' || param2 == 'c' || param3 == 'c' || param4 == 'c') {
|
||||
markCRCBytes = true;
|
||||
}
|
||||
|
||||
if (param1 == 'l' || param2 == 'l' || param3 == 'l' || param4 == 'l') {
|
||||
loadFromFile = true;
|
||||
}
|
||||
|
||||
if (param1 == 'p' || param2 == 'p' || param3 == 'p' || param4 == 'p') {
|
||||
PCSCtrace = true;
|
||||
}
|
||||
|
||||
if ((loadFromFile || saveToFile) && strlen(filename) == 0) {
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (loadFromFile && saveToFile) {
|
||||
errors = true;
|
||||
}
|
||||
|
||||
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");
|
||||
if (CLIParserParseString(Cmd, argtable, arg_getsize(argtable), true)){
|
||||
CLIParserFree();
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char load_filename[FILE_PATH_SIZE] = {0};
|
||||
if (loadFromFile) {
|
||||
strncpy(load_filename, arg_get_str(5)->sval[0], FILE_PATH_SIZE);
|
||||
}
|
||||
char save_filename[FILE_PATH_SIZE] = {0};
|
||||
if (saveToFile) {
|
||||
strncpy(save_filename, arg_get_str(6)->sval[0], FILE_PATH_SIZE);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1179,8 +1158,8 @@ int CmdHFList(const char *Cmd)
|
|||
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;
|
||||
}
|
||||
|
@ -1206,7 +1185,9 @@ int CmdHFList(const char *Cmd)
|
|||
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);
|
||||
|
@ -1216,33 +1197,45 @@ int CmdHFList(const char *Cmd)
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue