From: Martin Holst Swende Date: Sun, 4 Jan 2015 20:22:54 +0000 (+0100) Subject: Reworked how 'hf 14a list' and 'hf iclass list' works, to use the same method. Now... X-Git-Tag: v2.0.0-rc1~67 X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/4c3de57ad2c0ac268c9eccaf46a2dbf58fb0d313 Reworked how 'hf 14a list' and 'hf iclass list' works, to use the same method. Now. use 'hf list 14a' and 'hf list iclass' instead. Plus, the output is now annotated (although the annotation-engine could use a bit more love from someone more familiar with the available commands --- diff --git a/client/cmdhf.c b/client/cmdhf.c index d955fc83..9e8a2105 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include +#include //#include "proxusb.h" #include "proxmark3.h" #include "graph.h" @@ -31,6 +32,279 @@ int CmdHFTune(const char *Cmd) SendCommand(&c); return 0; } +// for the time being. Need better Bigbuf handling. +#define TRACE_SIZE 3000 + +#define ICLASS_CMD_ACTALL 0x0A +#define ICLASS_CMD_IDENTIFY 0x0C +#define ICLASS_CMD_READ 0x0C +#define ICLASS_CMD_SELECT 0x81 +#define ICLASS_CMD_PAGESEL 0x84 +#define ICLASS_CMD_READCHECK 0x88 +#define ICLASS_CMD_CHECK 0x05 +#define ICLASS_CMD_SOF 0x0F +#define ICLASS_CMD_HALT 0x00 + +#define iso14443_CMD_WUPA 0x52 +#define iso14443_CMD_SELECT 0x93 +#define iso14443_CMD_SELECT_2 0x95 +#define iso14443_CMD_REQ 0x26 +#define iso14443_CMD_READBLOCK 0x30 +#define iso14443_CMD_WRITEBLOCK 0xA0 +#define iso14443_CMD_INC 0xC0 +#define iso14443_CMD_DEC 0xC1 +#define iso14443_CMD_RESTORE 0xC2 +#define iso14443_CMD_TRANSFER 0xB0 +#define iso14443_CMD_HALT 0x50 +#define iso14443_CMD_RATS 0xE0 + + +void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch(cmd[0]) + { + case iso14443_CMD_WUPA: snprintf(exp,size,"WUPA"); break; + case iso14443_CMD_SELECT:{ + if(cmdsize > 2) + { + snprintf(exp,size,"SELECT_UID"); break; + }else + { + snprintf(exp,size,"SELECT_ALL"); break; + } + } + case iso14443_CMD_SELECT_2: snprintf(exp,size,"SELECT_2"); break; + case iso14443_CMD_REQ: snprintf(exp,size,"REW"); break; + case iso14443_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case iso14443_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case iso14443_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break; + case iso14443_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; + case iso14443_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; + case iso14443_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break; + case iso14443_CMD_HALT: snprintf(exp,size,"HALT"); break; + case iso14443_CMD_RATS: snprintf(exp,size,"RATS"); break; + default: snprintf(exp,size,"?"); break; + } + return; +} + +void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + + if(cmdsize > 1 && cmd[0] == ICLASS_CMD_READ) + { + snprintf(exp,size,"READ(%d)",cmd[1]); + return; + } + + switch(cmd[0]) + { + case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break; + case ICLASS_CMD_IDENTIFY: snprintf(exp,size,"IDENTIFY"); break; + case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; + case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL"); break; + case ICLASS_CMD_READCHECK: snprintf(exp,size,"READCHECK"); break; + case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; + case ICLASS_CMD_SOF: snprintf(exp,size,"SOF"); break; + case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; + default: snprintf(exp,size,"?"); break; + } + return; +} + + + +uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles) +{ + bool isResponse; + uint16_t duration, data_len,parity_len; + + uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp; + char explanation[30] = {0}; + + first_timestamp = *((uint32_t *)(trace)); + timestamp = *((uint32_t *)(trace + tracepos)); + // Break and stick with current result if buffer was not completely full + if (timestamp == 0x44444444) return TRACE_SIZE; + + tracepos += 4; + duration = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + data_len = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + + if (data_len & 0x8000) { + data_len &= 0x7fff; + isResponse = true; + } else { + isResponse = false; + } + parity_len = (data_len-1)/8 + 1; + + if (tracepos + data_len + parity_len >= TRACE_SIZE) { + return TRACE_SIZE; + } + + uint8_t *frame = trace + tracepos; + tracepos += data_len; + uint8_t *parityBytes = trace + tracepos; + tracepos += parity_len; + + //--- Draw the data column + char line[16][110]; + for (int j = 0; j < data_len; j++) { + int oddparity = 0x01; + int k; + + for (k=0 ; k<8 ; k++) { + oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); + } + + uint8_t parityBits = parityBytes[j>>3]; + + if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]); + } else { + sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]); + } + } + //--- Draw the CRC column + bool crcError = false; + + if (data_len > 2) { + uint8_t b1, b2; + if(iclass) + { + if(!isResponse && data_len == 4 ) { + // Rough guess that this is a command from the reader + // For iClass the command byte is not part of the CRC + ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2); + } + else { + // For other data.. CRC might not be applicable (UPDATE commands etc.) + ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2); + } + + if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { + crcError = true; + } + + }else{//Iso 14443a + + ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); + + if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { + if(!(isResponse & (data_len < 6))) + { + crcError = true; + } + } + } + + } + char *crc = crcError ? "!crc" :" "; + + EndOfTransmissionTimestamp = timestamp + duration; + + if(!isResponse) + { + if(iclass) annotateIclass(explanation,sizeof(explanation),frame,data_len); + else annotateIso14443a(explanation,sizeof(explanation),frame,data_len); + } + + int num_lines = (data_len - 1)/16 + 1; + for (int j = 0; j < num_lines; j++) { + if (j == 0) { + PrintAndLog(" %9d | %9d | %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 : ""); + } else { + PrintAndLog(" | | | %-64s| %s| %s", + line[j], + (j == num_lines-1)?crc:" ", + (j == num_lines-1) ? explanation : ""); + } + } + + bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; + + if (showWaitCycles && !isResponse && next_isResponse) { + uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); + if (next_timestamp != 0x44444444) { + PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", + (EndOfTransmissionTimestamp - first_timestamp), + (next_timestamp - first_timestamp), + " ", + (next_timestamp - EndOfTransmissionTimestamp)); + } + } + return tracepos; +} + +int CmdHFList(const char *Cmd) +{ + bool showWaitCycles = false; + char type[40] = {0}; + int tlen = param_getstr(Cmd,0,type); + char param = param_getchar(Cmd, 1); + bool errors = false; + bool iclass = false; + //Validate params + if(tlen == 0 || (strcmp(type, "iclass") != 0 && strcmp(type,"14a") != 0)) + { + errors = true; + } + if(param == 'h' || (param !=0 && param != 'f')) + { + errors = true; + } + + if (errors) { + PrintAndLog("List protocol data in trace buffer."); + PrintAndLog("Usage: hf list [14a|iclass] [f]"); + PrintAndLog(" - interpret data as iso14443a communications"); + PrintAndLog(" iclass - interpret data as iclass communications"); + PrintAndLog(" f - show frame delay times as well"); + PrintAndLog(""); + PrintAndLog("example: hf list 14a f"); + PrintAndLog("example: hf list iclass"); + return 0; + } + if(strcmp(type, "iclass") == 0) + { + iclass = true; + } + + if (param == 'f') { + showWaitCycles = true; + } + + + uint8_t trace[TRACE_SIZE]; + uint16_t tracepos = 0; + GetFromBigBuf(trace, TRACE_SIZE, 0); + WaitForResponse(CMD_ACK, NULL); + + PrintAndLog("Recorded Activity"); + 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"); + PrintAndLog(""); + PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); + PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------|-----|--------------------|"); + + while(tracepos < TRACE_SIZE) + { + tracepos = printTraceLine(tracepos, trace, iclass, showWaitCycles); + } + return 0; +} + static command_t CommandTable[] = { @@ -41,9 +315,10 @@ static command_t CommandTable[] = {"epa", CmdHFEPA, 1, "{ German Identification Card... }"}, {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, - {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, + {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, - {NULL, NULL, 0, NULL} + {"list", CmdHFList, 1, "List protocol data in trace buffer"}, + {NULL, NULL, 0, NULL} }; int CmdHF(const char *Cmd) diff --git a/client/cmdhf.h b/client/cmdhf.h index ff20a950..026357b5 100644 --- a/client/cmdhf.h +++ b/client/cmdhf.h @@ -13,5 +13,5 @@ int CmdHF(const char *Cmd); int CmdHFTune(const char *Cmd); - +int CmdHFList(const char *Cmd); #endif diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index c9976076..36ffe1b8 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -29,145 +29,7 @@ static void waitCmd(uint8_t iLen); int CmdHF14AList(const char *Cmd) { - bool ShowWaitCycles = false; - char param = param_getchar(Cmd, 0); - - if (param == 'h' || (param != 0 && param != 'f')) { - PrintAndLog("List data in trace buffer."); - PrintAndLog("Usage: hf 14a list [f]"); - PrintAndLog("f - show frame delay times as well"); - PrintAndLog("sample: hf 14a list f"); - return 0; - } - - if (param == 'f') { - ShowWaitCycles = true; - } - -// for the time being. Need better Bigbuf handling. -#define TRACE_SIZE 3000 - - uint8_t trace[TRACE_SIZE]; - GetFromBigBuf(trace, TRACE_SIZE, 0); - WaitForResponse(CMD_ACK, NULL); - - PrintAndLog("Recorded Activity"); - PrintAndLog(""); - PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); - PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC "); - PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------"); - - uint16_t tracepos = 0; - uint16_t duration; - uint16_t data_len; - uint16_t parity_len; - bool isResponse; - uint32_t timestamp; - uint32_t first_timestamp; - uint32_t EndOfTransmissionTimestamp; - - for (;;) { - - if(tracepos >= TRACE_SIZE) { - break; - } - - timestamp = *((uint32_t *)(trace + tracepos)); - if(tracepos == 0) { - first_timestamp = timestamp; - } - - // Break and stick with current result if buffer was not completely full - if (timestamp == 0x44444444) break; - - tracepos += 4; - duration = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - data_len = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - - if (data_len & 0x8000) { - data_len &= 0x7fff; - isResponse = true; - } else { - isResponse = false; - } - - parity_len = (data_len-1)/8 + 1; - - if (tracepos + data_len + parity_len >= TRACE_SIZE) { - break; - } - - uint8_t *frame = trace + tracepos; - tracepos += data_len; - uint8_t *parityBytes = trace + tracepos; - tracepos += parity_len; - - char line[16][110]; - for (int j = 0; j < data_len; j++) { - int oddparity = 0x01; - int k; - - for (k=0;k<8;k++) { - oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); - } - - uint8_t parityBits = parityBytes[j>>3]; - if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]); - } else { - sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]); - } - - } - - char crc[5] = ""; - if (data_len > 2) { - uint8_t b1, b2; - ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - sprintf(crc, (isResponse & (data_len < 6)) ? "" : "!crc"); - } else { - sprintf(crc, ""); - } - } - - EndOfTransmissionTimestamp = timestamp + duration; - - int num_lines = (data_len - 1)/16 + 1; - for (int j = 0; j < num_lines; j++) { - if (j == 0) { - PrintAndLog(" %9d | %9d | %s | %-64s| %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (isResponse ? "Tag" : "Rdr"), - line[j], - (j == num_lines-1)?crc:""); - } else { - PrintAndLog(" | | | %-64s| %s", - line[j], - (j == num_lines-1)?crc:""); - } - } - - bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; - - if (ShowWaitCycles && !isResponse && next_isResponse) { - uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); - if (next_timestamp != 0x44444444) { - PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", - (EndOfTransmissionTimestamp - first_timestamp), - (next_timestamp - first_timestamp), - " ", - (next_timestamp - EndOfTransmissionTimestamp)); - } - } - - } - + PrintAndLog("Deprecated command, use 'hf list 14a' instead"); return 0; } @@ -510,7 +372,7 @@ int CmdHF14ASnoop(const char *Cmd) { if (param_getchar(Cmd, 0) == 'h') { PrintAndLog("It get data from the field and saves it into command buffer."); - PrintAndLog("Buffer accessible from command hf 14a list."); + PrintAndLog("Buffer accessible from command hf list 14a."); PrintAndLog("Usage: hf 14a snoop [c][r]"); PrintAndLog("c - triggered by first data from card"); PrintAndLog("r - triggered by first 7-bit request from reader (REQ,WUP,...)"); @@ -671,7 +533,7 @@ static void waitCmd(uint8_t iSelect) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"list", CmdHF14AList, 0, "List ISO 14443a history"}, + {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"}, {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index f6261f33..5146401b 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -80,151 +80,7 @@ void explain(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) int CmdHFiClassList(const char *Cmd) { - bool ShowWaitCycles = false; - char param = param_getchar(Cmd, 0); - - if (param != 0) { - PrintAndLog("List data in trace buffer."); - PrintAndLog("Usage: hf iclass list"); - PrintAndLog("h - help"); - PrintAndLog("sample: hf iclass list"); - return 0; - } - -// for the time being. Need better Bigbuf handling. -#define TRACE_SIZE 3000 - - uint8_t trace[TRACE_SIZE]; - GetFromBigBuf(trace, TRACE_SIZE, 0); - WaitForResponse(CMD_ACK, NULL); - - PrintAndLog("Recorded Activity"); - PrintAndLog(""); - PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); - PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Explanation|"); - PrintAndLog("-----------|-----------|-----|-------------------------------------------------------------------------------------"); - - uint16_t tracepos = 0; - uint16_t duration; - uint16_t data_len; - uint16_t parity_len; - bool isResponse; - uint32_t timestamp; - uint32_t first_timestamp; - uint32_t EndOfTransmissionTimestamp; - char explanation[20] = {0}; - for (;;) { - - if(tracepos >= TRACE_SIZE) { - break; - } - - timestamp = *((uint32_t *)(trace + tracepos)); - if(tracepos == 0) { - first_timestamp = timestamp; - } - - // Break and stick with current result if buffer was not completely full - if (timestamp == 0x44444444) break; - - tracepos += 4; - duration = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - data_len = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - - if (data_len & 0x8000) { - data_len &= 0x7fff; - isResponse = true; - } else { - isResponse = false; - } - - parity_len = (data_len-1)/8 + 1; - - if (tracepos + data_len + parity_len >= TRACE_SIZE) { - break; - } - - uint8_t *frame = trace + tracepos; - tracepos += data_len; - uint8_t *parityBytes = trace + tracepos; - tracepos += parity_len; - - char line[16][110]; - for (int j = 0; j < data_len; j++) { - int oddparity = 0x01; - int k; - - for (k=0;k<8;k++) { - oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); - } - - uint8_t parityBits = parityBytes[j>>3]; - if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - sprintf(line[j/16]+((j%16)*4), "%02x! ", frame[j]); - } else { - sprintf(line[j/16]+((j%16)*4), "%02x ", frame[j]); - } - - } - - char *crc = " "; - if (data_len > 2) { - uint8_t b1, b2; - if(!isResponse && data_len == 4 ) { - // Rough guess that this is a command from the reader - // For iClass the command byte is not part of the CRC - ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2); - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - crc = "!crc"; - } - } - else { - // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2); - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - crc = "!crc"; - } - } - } - - EndOfTransmissionTimestamp = timestamp + duration; - explain(explanation,sizeof(explanation),frame,data_len); - int num_lines = (data_len - 1)/16 + 1; - for (int j = 0; j < num_lines; j++) { - if (j == 0) { - PrintAndLog(" %9d | %9d | %s | %-64s| %s| %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (isResponse ? "Tag" : "Rdr"), - line[j], - (j == num_lines-1)?crc:" ", - explanation); - } else { - PrintAndLog(" | | | %-64s| %s", - line[j], - (j == num_lines-1)?crc:" "); - } - } - - bool next_isResponse = *((uint16_t *)(trace + tracepos + 6)) & 0x8000; - - if (ShowWaitCycles && !isResponse && next_isResponse) { - uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); - if (next_timestamp != 0x44444444) { - PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d", - (EndOfTransmissionTimestamp - first_timestamp), - (next_timestamp - first_timestamp), - " ", - (next_timestamp - EndOfTransmissionTimestamp)); - } - } - - } - + PrintAndLog("Deprecated command, use 'hf list iclass' instead"); return 0; } @@ -619,7 +475,7 @@ int CmdHFiClass_iso14443A_write(const char *Cmd) static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"list", CmdHFiClassList, 0, "List iClass history"}, + {"list", CmdHFiClassList, 0, "[Deprecated] List iClass history"}, {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"}, {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"}, {"reader",CmdHFiClassReader, 0, "Read an iClass tag"},