From 9a2a0116e41d48e5fd5bb87ba55c041748a295bb Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 8 Sep 2019 23:19:06 +0200 Subject: [PATCH] fix: 'hf iclass clone' - last block write fails, see (https://github.com/RfidResearchGroup/proxmark3/issues/183) chg: 'hf iclass clone' - now tries ten times, behavies better, obey verbose nicer, drop field constant. Uses NG. chg: 'hf iclass dump' - now tries ten times, in general nice outputs.. --- armsrc/appmain.c | 8 +- armsrc/iclass.c | 24 +++--- client/cmdhficlass.c | 200 +++++++++++++++++++++++++++---------------- 3 files changed, 145 insertions(+), 87 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index cb5dbe8a2..990ac1c56 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1271,7 +1271,13 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ICLASS_CLONE: { - iClass_Clone(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + struct p { + uint8_t startblock; + uint8_t endblock; + uint8_t data[]; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + iClass_Clone(payload->startblock, payload->endblock, payload->data); break; } #endif diff --git a/armsrc/iclass.c b/armsrc/iclass.c index fa90f0881..c87bade4b 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -2520,23 +2520,19 @@ void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { int total_block = (endblock - startblock) + 1; for (i = 0; i < total_block; i++) { // block number - if (iClass_WriteBlock_ext(i + startblock, data + (i * 12))) { - Dbprintf("Write block [%02x] successful", i + startblock); + if (iClass_WriteBlock_ext(startblock + i, data + (i * 12))) { + Dbprintf("Write block [%02x] successful", startblock + i); written++; } else { - if (iClass_WriteBlock_ext(i + startblock, data + (i * 12))) { - Dbprintf("Write block [%02x] successful", i + startblock); - written++; - } else { - Dbprintf("Write block [%02x] failed", i + startblock); - } + Dbprintf("Write block [%02x] failed", startblock + i); } } - if (written == total_block) - DbpString("Clone complete"); - else - DbpString("Clone incomplete"); - - reply_mix(CMD_ACK, 1, 0, 0, 0, 0); + switch_off(); + + uint8_t isOK = 0; + if (written == total_block) + isOK = 1; + + reply_ng(CMD_HF_ICLASS_CLONE, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 5ac3a8925..4f9a34113 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -1118,6 +1118,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { cmdp += 2; break; case 'e': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo")); elite = true; cmdp++; break; @@ -1149,6 +1150,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { cmdp += 2; break; case 'r': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("raw mode")); rawkey = true; cmdp++; break; @@ -1180,7 +1182,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { PrintAndLogEx(WARNING, "command execute timeout"); DropField(); - return 0; + return PM3_ESOFT; } DropField(); @@ -1189,7 +1191,8 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { if (readStatus == 0) { PrintAndLogEx(FAILED, "no tag found"); - return 0; + DropField(); + return PM3_ESOFT; } if (readStatus & (FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC)) { @@ -1202,14 +1205,16 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { } // authenticate debit key and get div_key - later store in dump block 3 - if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) { - //try twice - for some reason it sometimes fails the first time... - PrintAndLogEx(SUCCESS, "retry to select card"); - if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) { - PrintAndLogEx(WARNING, "failed authenticating with debit key"); - DropField(); - return 0; - } + int numberAuthRetries = ICLASS_AUTH_RETRY; + do { + if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) + break; + } while (numberAuthRetries--); + + if ( numberAuthRetries <= 0) { + PrintAndLogEx(WARNING, "failed authenticating with debit key"); + DropField(); + return PM3_ESOFT; } // begin dump @@ -1233,7 +1238,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { uint8_t isOK = resp.oldarg[0] & 0xff; if (!isOK && !blocksRead) { PrintAndLogEx(WARNING, "read block failed"); - return 0; + return PM3_ESOFt; } uint32_t startindex = resp.oldarg[2]; @@ -1245,7 +1250,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { // response ok - now get bigbuf content of the dump if (!GetFromDevice(BIG_BUF, tag_data + (blockno * 8), blocksRead * 8, startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); - return 0; + return PM3_ETIMEOUT; } size_t gotBytes = blocksRead * 8 + blockno * 8; @@ -1254,16 +1259,22 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { if (have_credit_key) { //turn off hf field before authenticating with different key DropField(); + memset(MAC, 0, 4); + // AA2 authenticate credit key and git c_div_key - later store in dump block 4 - if (!select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose)) { - //try twice - for some reason it sometimes fails the first time... - if (!select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose)) { - PrintAndLogEx(WARNING, "failed authenticating with credit key"); - DropField(); - return 0; - } + numberAuthRetries = ICLASS_AUTH_RETRY; + do { + if (select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose)) + break; + } while (numberAuthRetries--); + + if ( numberAuthRetries <= 0) { + PrintAndLogEx(WARNING, "failed authenticating with credit key"); + DropField(); + return PM3_ESOFT; } + // do we still need to read more block? (aa2 enabled?) if (maxBlk > blockno + numblks + 1) { // setup dump and start @@ -1271,13 +1282,13 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { SendCommandMIX(CMD_HF_ICLASS_DUMP, blockno + blocksRead, maxBlk - (blockno + blocksRead), 0, NULL, 0); if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { PrintAndLogEx(WARNING, "command execute timeout 2"); - return 0; + return PM3_ETIMEOUT; } isOK = resp.oldarg[0] & 0xff; blocksRead = resp.oldarg[1]; if (!isOK && !blocksRead) { PrintAndLogEx(WARNING, "read block failed 2"); - return 0; + return PM3_ESOFT; } startindex = resp.oldarg[2]; @@ -1288,7 +1299,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { // get dumped data from bigbuf if (!GetFromDevice(BIG_BUF, tag_data + gotBytes, blocksRead * 8, startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); - return 0; + return PM3_ETIMEOUT; } gotBytes += blocksRead * 8; @@ -1298,16 +1309,20 @@ static int CmdHFiClassReader_Dump(const char *Cmd) { DropField(); // add diversified keys to dump - if (have_debit_key) memcpy(tag_data + (3 * 8), div_key, 8); - if (have_credit_key) memcpy(tag_data + (4 * 8), c_div_key, 8); + if (have_debit_key) + memcpy(tag_data + (3 * 8), div_key, 8); + + if (have_credit_key) + memcpy(tag_data + (4 * 8), c_div_key, 8); + // print the dump - PrintAndLogEx(NORMAL, "------+--+-------------------------+\n"); - PrintAndLogEx(NORMAL, "CSN |00| %s|\n", sprint_hex(tag_data, 8)); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "------+--+-------------------------+"); + PrintAndLogEx(NORMAL, "CSN |00| %s|", sprint_hex(tag_data, 8)); printIclassDumpContents(tag_data, 1, (gotBytes / 8), gotBytes); if (filename[0] == 0) { - //Use the first block (CSN) for filename strcat(filename, "hf-iclass-"); FillFileNameByUID(filename, tag_data, "-data", 8); @@ -1469,6 +1484,7 @@ static int CmdHFiClassCloneTag(const char *Cmd) { uint8_t startblock = 0; uint8_t endblock = 0; uint8_t dataLen = 0; + bool got_startblk = false, got_endblk = false; bool use_credit_key = false; bool elite = false; bool rawkey = false; @@ -1480,17 +1496,17 @@ static int CmdHFiClassCloneTag(const char *Cmd) { case 'h': return usage_hf_iclass_clone(); case 'b': - if (param_gethex(Cmd, cmdp + 1, &startblock, 2)) { - PrintAndLogEx(WARNING, "start block No must include 2 HEX symbols\n"); - errors = true; - } + startblock = param_get8ex(Cmd, cmdp + 1, 07, 16); + got_startblk = true; cmdp += 2; break; case 'c': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("CREDIT")); use_credit_key = true; cmdp++; break; case 'e': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("elite algo")); elite = true; cmdp++; break; @@ -1509,6 +1525,7 @@ static int CmdHFiClassCloneTag(const char *Cmd) { } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp + 1); if (keyNbr < ICLASS_KEYS_MAX) { + PrintAndLogEx(SUCCESS, "Using key[%d] %s", keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8 )); memcpy(KEY, iClass_Key_Table[keyNbr], 8); } else { PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); @@ -1521,13 +1538,12 @@ static int CmdHFiClassCloneTag(const char *Cmd) { cmdp += 2; break; case 'l': - if (param_gethex(Cmd, cmdp + 1, &endblock, 2)) { - PrintAndLogEx(WARNING, "start Block No must include 2 HEX symbols\n"); - errors = true; - } + endblock = param_get8ex(Cmd, cmdp + 1, 07, 16); + got_endblk = true; cmdp += 2; break; case 'r': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("raw mode")); rawkey = true; cmdp++; break; @@ -1541,53 +1557,66 @@ static int CmdHFiClassCloneTag(const char *Cmd) { break; } } + if ( got_endblk == false || got_startblk == false) + errors = true; if (errors || cmdp < 8) return usage_hf_iclass_clone(); - FILE *f; - - iclass_block_t tag_data[PM3_CMD_DATA_SIZE / 12]; - - if ((endblock - startblock + 1) * 12 > PM3_CMD_DATA_SIZE) { - PrintAndLogEx(NORMAL, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE / 8); + if (startblock < 5) { + PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4"); + return PM3_EINVARG; } + + int total_bytes = (((endblock - startblock) + 1) * 12); + + if (total_bytes > PM3_CMD_DATA_SIZE - 2) { + PrintAndLogEx(NORMAL, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE / 8); + return PM3_EINVARG; + } + // file handling and reading - f = fopen(filename, "rb"); + FILE *f = fopen(filename, "rb"); if (!f) { PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", filename); return PM3_EFILE; } - if (startblock < 5) { - PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4"); - fclose(f); - return 0; - } - // now read data from the file from block 6 --- 19 - // ok we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data - // then copy to usbcommand->asbytes; the max is 32 - 6 = 24 block 12 bytes each block 288 bytes then we can only accept to clone 21 blocks at the time, - // else we have to create a share memory + iclass_block_t tag_data[PM3_CMD_DATA_SIZE / 12]; + + // read data from file from block 6 --- 19 + // we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data + // then copy to usbcommand->asbytes; + // max is 32 - 6 = 28 block. 28 x 12 bytes gives 336 bytes int i; fseek(f, startblock * 8, SEEK_SET); size_t bytes_read = fread(tag_data, sizeof(iclass_block_t), endblock - startblock + 1, f); + fclose(f); + if (bytes_read == 0) { PrintAndLogEx(ERR, "file reading error."); - fclose(f); - return 2; + return PM3_EFILE; } - fclose(f); - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) { - return 0; + + int numberAuthRetries = ICLASS_AUTH_RETRY; + do { + if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) + break; + } while (numberAuthRetries--); + + if ( numberAuthRetries <= 0 ) { + PrintAndLogEx(ERR, "failed to authenticate"); + DropField(); + return PM3_ESOFT; } - uint8_t data[(endblock - startblock) * 12]; + uint8_t data[total_bytes]; + // calculate all mac for every the block we will write for (i = startblock; i <= endblock; i++) { + Calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC); // usb command d start pointer = d + (i - 6) * 12 // memcpy(pointer,tag_data[i - 6],8) 8 bytes @@ -1597,22 +1626,49 @@ static int CmdHFiClassCloneTag(const char *Cmd) { memcpy(ptr, &(tag_data[i - startblock].d[0]), 8); memcpy(ptr + 8, MAC, 4); } - uint8_t p[12]; - for (i = 0; i <= endblock - startblock; i++) { - memcpy(p, data + (i * 12), 12); - PrintAndLogEx(NORMAL, "Block |%02x|", i + startblock); - PrintAndLogEx(NORMAL, " %02x%02x%02x%02x%02x%02x%02x%02x |", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - PrintAndLogEx(NORMAL, " MAC |%02x%02x%02x%02x|\n", p[8], p[9], p[10], p[11]); + + if ( verbose ) { + PrintAndLogEx(NORMAL,"------+--------------------------+-------------"); + PrintAndLogEx(NORMAL,"block | data | mac"); + PrintAndLogEx(NORMAL,"------+--------------------------+-------------"); + uint8_t p[12]; + for (i = 0; i <= endblock - startblock; i++) { + memcpy(p, data + (i * 12), 12); + char *s = calloc(70, sizeof(uint8_t)); + sprintf(s, "| %s ", sprint_hex(p, 8)); + sprintf(s + strlen(s), "| %s", sprint_hex(p + 8, 4)); + PrintAndLogEx(NORMAL, " %02X %s", i + startblock, s ); + free(s); + } } + struct p { + uint8_t startblock; + uint8_t endblock; + uint8_t data[PM3_CMD_DATA_SIZE - 2]; + } PACKED payload; + + payload.startblock = startblock; + payload.endblock = endblock; + memcpy(payload.data, data, total_bytes); + PacketResponseNG resp; clearCommandBuffer(); - SendCommandOLD(CMD_HF_ICLASS_CLONE, startblock, endblock, 0, data, (endblock - startblock) * 12); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + SendCommandNG(CMD_HF_ICLASS_CLONE, (uint8_t*)&payload, total_bytes + 2 ); + + if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 4500) == 0) { PrintAndLogEx(WARNING, "command execute timeout"); - return 0; + DropField(); + return PM3_ETIMEOUT; } - return PM3_SUCCESS; + + if (resp.status == PM3_SUCCESS) { + if ( resp.data.asBytes[0] == 1 ) + PrintAndLogEx(SUCCESS, "Clone successful"); + else + PrintAndLogEx(WARNING, "Clone failed"); + } + return resp.status; } static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth) { @@ -1809,13 +1865,13 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e //PrintAndLog ("startblock: %d, endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d",startblock, endblock,filesize, maxmemcount, filemaxblock); int i = startblock; - PrintAndLogEx(NORMAL, "------+--+-------------------------+\n"); + PrintAndLogEx(NORMAL, "------+--+-------------------------+"); while (i <= endblock) { uint8_t *blk = iclass_dump + (i * 8); - PrintAndLogEx(NORMAL, " |%02X| %s\n", i, sprint_hex_ascii(blk, 8)); + PrintAndLogEx(NORMAL, " |%02X| %s", i, sprint_hex_ascii(blk, 8)); i++; } - PrintAndLogEx(NORMAL, "------+--+-------------------------+\n"); + PrintAndLogEx(NORMAL, "------+--+-------------------------+"); } static int CmdHFiClassReadTagFile(const char *Cmd) {