From 3bc3598e880b68870cfcc55fbdda443d77395809 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Dec 2014 15:14:05 +0100 Subject: [PATCH] added the changes from PM3 master. added some code for the AWID26 --- armsrc/iso14443a.c | 17 ++- client/cmdhf14a.c | 5 + client/cmdhficlass.c | 308 ++++++++++++++----------------------------- client/cmdlf.c | 2 +- client/cmdlfawid26.c | 117 ++++++++++++++-- client/cmdlfawid26.h | 2 + client/cmdlft55xx.c | 3 + client/util.c | 99 ++++++++++++++ client/util.h | 10 ++ 9 files changed, 343 insertions(+), 220 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index d8edc209..269a00c5 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1715,6 +1715,10 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) * fills the uid pointer unless NULL * fills resp_data unless NULL */ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { + + iso14a_set_timeout(10500); // 10ms default 10*105 = + + //uint8_t deselect[] = {0xc2}; //DESELECT //uint8_t halt[] = { 0x50, 0x00, 0x57, 0xCD }; // HALT uint8_t wupa[] = { 0x52 }; // WAKE-UP //uint8_t reqa[] = { 0x26 }; // REQUEST A @@ -1731,8 +1735,8 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u int len; // test for the SKYLANDERS TOY. - //ReaderTransmit(halt,sizeof(halt), NULL); - //len = ReaderReceive(resp, resp_par); + // ReaderTransmit(deselect,sizeof(deselect), NULL); + // len = ReaderReceive(resp, resp_par); // Broadcast for a card, WUPA (0x52) will force response from all cards in the field ReaderTransmitBitsPar(wupa,7,0, NULL); @@ -1836,7 +1840,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u p_hi14a_card->sak = sak; p_hi14a_card->ats_len = 0; } - + if( (sak & 0x20) == 0) { return 2; // non iso14443a compliant tag } @@ -1845,8 +1849,13 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); + len = ReaderReceive(resp, resp_par); - if(!len) return 0; + Dbprintf("RATS Reponse: %d", len); + if(!len) { + Dbprintf("RATS: %02x %02x %02x", resp[0], resp[1], resp[2]); + return 0; + } if(p_hi14a_card) { memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 97d102be..bfa7bfbf 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -181,6 +181,11 @@ int CmdHF14AReader(const char *Cmd) if(select_status == 0) { PrintAndLog("iso14443a card select failed"); + // disconnect + c.arg[0] = 0; + c.arg[1] = 0; + c.arg[2] = 0; + SendCommand(&c); return 0; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index e033422a..75c6e2c9 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -43,7 +43,6 @@ int xorbits_8(uint8_t val) int CmdHFiClassList(const char *Cmd) { - bool ShowWaitCycles = false; char param = param_getchar(Cmd, 0); @@ -55,8 +54,11 @@ int CmdHFiClassList(const char *Cmd) return 0; } - uint8_t got[TRACE_BUFFER_SIZE]; - GetFromBigBuf(got,sizeof(got),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"); @@ -64,155 +66,58 @@ int CmdHFiClassList(const char *Cmd) 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"); - PrintAndLog("-----------|-----------|-----|--------"); - - int i; - uint32_t first_timestamp = 0; + 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; - bool tagToReader; - uint32_t parityBits; - uint8_t len; - uint8_t *frame; - uint32_t EndOfTransmissionTimestamp = 0; + uint32_t first_timestamp; + uint32_t EndOfTransmissionTimestamp; + + for (;;) { + if(tracepos >= TRACE_SIZE) { + break; + } - for( i=0; i < TRACE_BUFFER_SIZE;) - { - //First 32 bits contain - // isResponse (1 bit) - // timestamp (remaining) - //Then paritybits - //Then length - timestamp = *((uint32_t *)(got+i)); - parityBits = *((uint32_t *)(got+i+4)); - len = got[i+8]; - frame = (got+i+9); - uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff; - - tagToReader = timestamp & 0x80000000; - timestamp &= 0x7fffffff; - - if(i==0) { + timestamp = *((uint32_t *)(trace + tracepos)); + if(tracepos == 0) { first_timestamp = timestamp; } - // Break and stick with current result idf buffer was not completely full - if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break; - - char line[1000] = ""; - - if(len)//We have some data to display - { - int j,oddparity; - - for(j = 0; j < len ; j++) - { - oddparity = 0x01 ^ xorbits_8(frame[j] & 0xFF); - - if (tagToReader && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } else { - sprintf(line+(j*4), "%02x ", frame[j]); - } - } - }else - { - if (ShowWaitCycles) { - sprintf(line, "fdt (Frame Delay Time): %d", (next_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; } - char *crc = ""; - - if(len > 2) - { - uint8_t b1, b2; - if(!tagToReader && 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], len-3, &b1, &b2); - } - else { - // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2); - } + parity_len = (data_len-1)/8 + 1; - if (b1 != frame[len-2] || b2 != frame[len-1]) { - crc = (tagToReader & (len < 8)) ? "" : " !crc"; - } + if (tracepos + data_len + parity_len >= TRACE_SIZE) { + break; } - - i += (len + 9); - EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff; - - // Not implemented for iclass on the ARM-side - //if (!ShowWaitCycles) i += 9; - - PrintAndLog(" %9d | %9d | %s | %s %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (len?(tagToReader ? "Tag" : "Rdr"):" "), - line, crc); - } - return 0; -} - -int CmdHFiClassListOld(const char *Cmd) -{ - uint8_t got[1920]; - GetFromBigBuf(got,sizeof(got),0); - - PrintAndLog("recorded activity:"); - PrintAndLog(" ETU :rssi: who bytes"); - PrintAndLog("---------+----+----+-----------"); - - int i = 0; - int prev = -1; - - for (;;) { - if(i >= 1900) { - break; - } - - bool isResponse; - int timestamp = *((uint32_t *)(got+i)); - if (timestamp & 0x80000000) { - timestamp &= 0x7fffffff; - isResponse = 1; - } else { - isResponse = 0; - } - - - int metric = 0; - - int parityBits = *((uint32_t *)(got+i+4)); - // 4 bytes of additional information... - // maximum of 32 additional parity bit information - // - // TODO: - // at each quarter bit period we can send power level (16 levels) - // or each half bit period in 256 levels. - - - int len = got[i+8]; - - if (len > 100) { - break; - } - if (i + len >= 1900) { - break; - } - - uint8_t *frame = (got+i+9); - - // Break and stick with current result if buffer was not completely full - if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; } - - char line[1000] = ""; - int j; - for (j = 0; j < len; j++) { + + 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; @@ -220,79 +125,68 @@ int CmdHFiClassListOld(const char *Cmd) oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); } - //if((parityBits >> (len - j - 1)) & 0x01) { - if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } - else { - sprintf(line+(j*4), "%02x ", frame[j]); - } - } + 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; - crc = ""; - if (len > 2) { - uint8_t b1, b2; - for (j = 0; j < (len - 1); j++) { - // gives problems... search for the reason.. - /*if(frame[j] == 0xAA) { - switch(frame[j+1]) { - case 0x01: - crc = "[1] Two drops close after each other"; - break; - case 0x02: - crc = "[2] Potential SOC with a drop in second half of bitperiod"; - break; - case 0x03: - crc = "[3] Segment Z after segment X is not possible"; - break; - case 0x04: - crc = "[4] Parity bit of a fully received byte was wrong"; - break; - default: - crc = "[?] Unknown error"; - break; - } - break; - }*/ - } + } - if (strlen(crc)==0) { - if(!isResponse && len == 4) { + 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], len-3, &b1, &b2); + 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, len-2, &b1, &b2); - } - //printf("%1x %1x",(unsigned)b1,(unsigned)b2); - if (b1 != frame[len-2] || b2 != frame[len-1]) { - crc = (isResponse & (len < 8)) ? "" : " !crc"; - } else { - crc = ""; - } - } - } else { - crc = ""; // SHORT - } - - char metricString[100]; - if (isResponse) { - sprintf(metricString, "%3d", metric); - } else { - strcpy(metricString, " "); - } - - PrintAndLog(" +%7d: %s: %s %s %s", - (prev < 0 ? 0 : (timestamp - prev)), - metricString, - (isResponse ? "TAG" : " "), line, crc); + ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2); + if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { + crc = "!crc"; + } + } + } - prev = timestamp; - i += (len + 9); - } + 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)); + } + } + + } + return 0; } diff --git a/client/cmdlf.c b/client/cmdlf.c index 2f55cd22..faf95ccd 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -581,7 +581,7 @@ static command_t CommandTable[] = {"simman", CmdLFSimManchester, 0, " [GAP] Simulate arbitrary Manchester LF tag"}, {"snoop", CmdLFSnoop, 0, "['l'|'h'|] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"}, - {"avid", CmdLFAWID26, 1, "{ AWID26 tags }"}, + {"awid26", CmdLFAWID26, 1, "{ AWID26 tags }"}, {"em4x", CmdLFEM4X, 1, "{ EM4X tags }"}, {"hid", CmdLFHID, 1, "{ HID tags }"}, {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders }"}, diff --git a/client/cmdlfawid26.c b/client/cmdlfawid26.c index 63b35fdd..0e1fca8e 100644 --- a/client/cmdlfawid26.c +++ b/client/cmdlfawid26.c @@ -12,14 +12,14 @@ #include #include "proxmark3.h" #include "ui.h" -#include "graph.h" +//#include "graph.h" #include "cmdmain.h" #include "cmdparser.h" -#include "cmddata.h" +//#include "cmddata.h" #include "cmdlf.h" #include "cmdlfawid26.h" #include "util.h" -#include "data.h" +//#include "data.h" static int CmdHelp(const char *Cmd); @@ -29,11 +29,10 @@ int CmdClone(const char *Cmd) char cmdp = param_getchar(Cmd, 0); if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: lf awid26 write []"); + PrintAndLog("Usage: lf awid26 clone "); PrintAndLog(" [], "); PrintAndLog(""); - PrintAndLog(" sample: lf awid26 write 26 2233"); - PrintAndLog(" : lf awid26 write 26 15 2233"); + PrintAndLog(" sample: lf awid26 clone 15 2233"); return 0; } @@ -50,6 +49,108 @@ int CmdClone(const char *Cmd) return 0; } + +// convert 96 bit AWID FSK data to 8 digit BCD UID +bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26) +{ + // uint8_t i, tmp[96], tmp1[7]; + // int site; + // int id; + + // if(!hextobinarray(tmp, awid26)) + // return false; + + // // data is in blocks of 4 bits - every 4th bit is parity, except the first + // // block which is all zeros + // for(i= 0 ; i < 4 ; ++i) + // if(tmp[i] != 0x00) + // return false; + + // // discard 1st block + // memcpy(tmp, tmp + 4, 92); + + // // check and strip parity on the rest + // for(i= 1 ; i < 23 ; ++i) + // if(tmp[(i * 4) - 1] != parity(tmp + (i - 1) * 4, ODD, 3)) + // return false; + // else + // memcpy((tmp + (i - 1) * 3), tmp + (i - 1) * 4, 3); + + // // discard the rest of the header - 1 more 3 bit block + // memcpy(tmp, tmp + 3, 66); + + // // next 8 bits is data length - should be 26: 0x1A + // binarraytohex(tmp1, tmp, 8); + // if(strcmp(tmp1, "1A") != 0) + // return false; + // memcpy(tmp, tmp +8, 58); + + // // standard wiegand parity check - even for 1st 12 bits, odd for 2nd 12 + // if(tmp[0] != parity(tmp + 1, EVEN, 12)) + // return false; + // if(tmp[25] != parity(tmp + 13, ODD, 12)) + // return false; + + // // convert to hex, ignoring parity bits + // if(!binarraytohex(tmp1, tmp + 1, 24)) + // return false; + + // // convert hex to site/id + // sscanf(tmp1,"%2X%4X", &site, &id); + + // // final output 8 byte BCD + // sprintf(response,"%03d%05d", site, id); + + return true; +} + +// convert null-terminated BCD UID (8 digits) to 96 bit awid26 encoded binary array +bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd) +{ + // char i, p, tmp1[8], tmp2[26]; + // int tmpint; + + // if(strlen(bcd) != 8) + // return false; + + // // convert BCD site code to HEX + // sscanf(bcd, "%03d", &tmpint); + // sprintf(tmp2, "%02x", tmpint); + // memcpy(tmp1, tmp2, 2); + + // // convert BCD ID to HEX + // sscanf(bcd + 3, "%05d", &tmpint);; + // sprintf(tmp2, "%04x", tmpint); + + // // copy with trailing NULL + // memcpy(tmp1 + 2, tmp2, 5); + + // // convert full HEX to binary, leaving room for parity prefix + // hextobinarray(tmp2 + 1, tmp1); + + // wiegand_add_parity(tmp2, tmp2 + 1, 24); + + // memset(awid26, '\x0', 96); + + // // magic 18 bit awid26 header (we will overwrite the last two bits) + // hextobinarray(awid26, "011D8"); + + // // copy to target leaving space for parity bits + // for(i= 0, p= 18 ; i < 26 ; ++i, ++p) + // { + // // skip target bit if this is a parity location + // if(!((p + 1) % 4)) + // p += 1; + // awid26[p]= tmp2[i]; + // } + + // // add parity bits + // for(i= 1 ; i < 24 ; ++i) + // awid26[((i + 1) * 4) - 1]= parity(&awid26[i * 4], ODD, 3); + + return false; +} + // int CmdReadTrace(const char *Cmd) // { @@ -84,8 +185,8 @@ int CmdClone(const char *Cmd) static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"clone", CmdClone, 0, " -- clone to a t55xx tag"}, + {"help", CmdHelp, 1, "This help"}, + {"clone", CmdClone, 1, " -- clone AWID26 to t55xx tag"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfawid26.h b/client/cmdlfawid26.h index c0facf51..cb1cd9e2 100644 --- a/client/cmdlfawid26.h +++ b/client/cmdlfawid26.h @@ -13,4 +13,6 @@ int CmdLFAWID26(const char *Cmd); int CmdClone(const char *Cmd); +bool awid26_hex_to_uid(unsigned char *response, unsigned char *awid26); +bool bcd_to_awid26_bin(unsigned char *awid26, unsigned char *bcd); #endif diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 78d90e7c..6ea9d2d3 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -468,6 +468,9 @@ uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits){ int i = start; int j = len-1; + if (len > 32) { + return 0; + } uint32_t tmp = 0; for (; j >= 0; --j, ++i){ tmp |= bits[i] << j; diff --git a/client/util.c b/client/util.c index 56c4998d..0418dd98 100644 --- a/client/util.c +++ b/client/util.c @@ -292,3 +292,102 @@ int param_getstr(const char *line, int paramnum, char * str) return en - bg + 1; } + +/* +The following methods comes from Rfidler sourcecode. +https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/src/ +*/ + +// convert hex to sequence of 0/1 bit values +// returns number of bits converted +int hextobinarray(char *target, char *source) +{ + int length, i, count= 0; + char x; + + length = strlen(source); + // process 4 bits (1 hex digit) at a time + while(length--) + { + x= *(source++); + // capitalize + if (x >= 'a' && x <= 'f') + x -= 32; + // convert to numeric value + if (x >= '0' && x <= '9') + x -= '0'; + else if (x >= 'A' && x <= 'F') + x -= 'A' - 10; + else + return 0; + // output + for(i= 0 ; i < 4 ; ++i, ++count) + *(target++)= (x >> (3 - i)) & 1; + } + + return count; +} + +// convert hex to human readable binary string +int hextobinstring(char *target, char *source) +{ + int length; + + if(!(length= hextobinarray(target, source))) + return 0; + binarraytobinstring(target, target, length); + return length; +} + +// convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source) +// return number of bits converted +int binarraytohex(char *target, char *source, int length) +{ + unsigned char i, x; + int j = length; + + if(j % 4) + return 0; + + while(j) + { + for(i= x= 0 ; i < 4 ; ++i) + x += ( source[i] << (3 - i)); + sprintf(target,"%X", x); + ++target; + source += 4; + j -= 4; + } + return length; +} + +// convert binary array to human readable binary +void binarraytobinstring(char *target, char *source, int length) +{ + int i; + + for(i= 0 ; i < length ; ++i) + *(target++)= *(source++) + '0'; + *target= '\0'; +} + +// return parity bit required to match type +uint8_t parity( char *bits, uint8_t type, int length) +{ + int x; + + for(x= 0 ; length > 0 ; --length) + x += bits[length - 1]; + x %= 2; + + return x ^ type; +} + +// add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half +void wiegand_add_parity(char *target, char *source, char length) +{ + *(target++)= parity(source, EVEN, length / 2); + memcpy(target, source, length); + target += length; + *(target)= parity(source + length / 2, ODD, length / 2); +} diff --git a/client/util.h b/client/util.h index 54562a07..10bafba9 100644 --- a/client/util.h +++ b/client/util.h @@ -23,6 +23,10 @@ #ifndef MAX # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#define TRUE 1 +#define FALSE 0 +#define EVEN 0 +#define ODD 1 int ukbhit(void); @@ -48,4 +52,10 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base); int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt); int param_getstr(const char *line, int paramnum, char * str); + int hextobinarray( char *target, char *source); + int hextobinstring( char *target, char *source); + int binarraytohex( char *target, char *source, int length); +void binarraytobinstring(char *target, char *source, int length); +uint8_t parity( char *string, uint8_t type, int length); +void wiegand_add_parity(char *target, char *source, char length); -- 2.39.5