diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 1c9bd26ea2..59d9fcb093 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -1282,7 +1282,16 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) { goto read_end; } - int pageNum = 0; + + if (payload->page >= tag.max_page) { + DBG Dbprintf("Warning, read page "_YELLOW_("%d") " > max page("_YELLOW_("%d") ") ", payload->page, tag.max_page); + } + + int page_addr = payload->page; + int page_index = 0; + lf_hts_read_response_t card = {0}; + + memcpy(card.config_page.asBytes, tag.data.pages[HITAGS_CONFIG_PADR], HITAGS_PAGE_SIZE); while ((BUTTON_PRESS() == false) && (data_available() == false)) { @@ -1294,7 +1303,7 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) { size_t txlen = 0; uint8_t cmd = HITAGS_READ_PAGE; txlen = concatbits(tx, txlen, &cmd, 0, 4); - uint8_t addr = pageNum; + uint8_t addr = page_addr; txlen = concatbits(tx, txlen, &addr, 0, 8); uint8_t crc = CRC8Hitag1Bits(tx, txlen); txlen = concatbits(tx, txlen, &crc, 0, 8); @@ -1303,33 +1312,37 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) { if (rxlen != 40) { DBG Dbprintf("Read page failed!"); - status = PM3_ERFTRANS; - goto read_end; + card.pages_reason[page_index] = -4; + // status = PM3_ERFTRANS; + // goto read_end; + page_addr++; + page_index++; + continue; } //save received data - 40 bits - for (int i = 0; i < 4 && i < rxlen; i++) { // set page bytes from received bits - tag.data.pages[pageNum][i] = rx[i]; - } + memcpy(card.pages[page_index], rx, HITAGS_PAGE_SIZE); if (g_dbglevel >= DBG_EXTENDED) { - if (tag.data.s.auth && tag.data.s.LKP && pageNum == 1) { - DBG Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, pwdh0, - tag.data.pages[pageNum][2], - tag.data.pages[pageNum][1], - tag.data.pages[pageNum][0]); - } else { - DBG Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, - tag.data.pages[pageNum][3], - tag.data.pages[pageNum][2], - tag.data.pages[pageNum][1], - tag.data.pages[pageNum][0]); + if (page_addr == 1 && (payload->cmd == HTSF_KEY || payload->cmd == HTSF_CHALLENGE) && card.config_page.s.auth == 1) { + DBG Dbprintf("Page[%2d]: %02X %02X %02X %02X", page_addr, + card.pages[page_index][0], + card.pages[page_index][1], + card.pages[page_index][2], + pwdh0); + } else { // HTSF_PLAIN or HTSF_82xx can read the full page + DBG Dbprintf("Page[%2d]: %02X %02X %02X %02X", page_addr, + card.pages[page_index][0], + card.pages[page_index][1], + card.pages[page_index][2], + card.pages[page_index][3]); } } - pageNum++; + page_addr++; + page_index++; //display key and password if possible - if (pageNum == 2 && tag.data.s.auth == 1 && tag.data.s.LKP) { + if (page_addr == 2 && card.config_page.s.auth == 1 && card.config_page.s.LKP) { if (payload->cmd == HTSF_KEY) { DBG Dbprintf("Page[ 2]: %02X %02X %02X %02X", payload->key[1], @@ -1343,16 +1356,22 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) { payload->key[3], payload->key[2] ); + card.pages_reason[page_index++] = 1; + card.pages_reason[page_index++] = 1; } else { //if the authentication is done with a challenge the key and password are unknown DBG Dbprintf("Page[ 2]: __ __ __ __"); DBG Dbprintf("Page[ 3]: __ __ __ __"); + card.pages_reason[page_index++] = -4; + card.pages_reason[page_index++] = -4; } // since page 2+3 are not accessible when LKP == 1 and AUT == 1 fastforward to next readable page - pageNum = 4; + page_addr = 4; } - if (pageNum >= tag.max_page) { + if (payload->page_count == 0) { + if (page_addr > tag.max_page) break; + } else if (page_addr > 255 || page_addr >= payload->page + payload->page_count) { break; } } @@ -1361,7 +1380,7 @@ void hts_read(const lf_hitag_data_t *payload, bool ledcontrol) { hts_stop_clock(); set_tracing(false); lf_finalize(ledcontrol); - reply_reason(CMD_LF_HITAGS_READ, status, reason,(uint8_t *)tag.data.pages, sizeof(tag.data.pages)); + reply_reason(CMD_LF_HITAGS_READ, status, reason, (uint8_t *)&card, sizeof(card)); } /* diff --git a/client/src/cmdlfhitaghts.c b/client/src/cmdlfhitaghts.c index b24c424747..3be9d67392 100644 --- a/client/src/cmdlfhitaghts.c +++ b/client/src/cmdlfhitaghts.c @@ -236,7 +236,8 @@ static int CmdLFHitagSRead(const char *Cmd) { arg_str0(NULL, "nrar", "", "nonce / answer writer, 8 hex bytes"), arg_lit0(NULL, "crypto", "crypto mode"), arg_str0("k", "key", "", "pwd or key, 4 or 6 hex bytes"), - arg_int1("p", "page", "", "page address to read from"), + arg_int0("p", "page", "", "page address to read from"), + arg_int0("c", "count", "", "how many pages to read. '0' reads all pages up to the s page (default: 1)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -245,10 +246,25 @@ static int CmdLFHitagSRead(const char *Cmd) { if (process_hitags_common_args(ctx, &packet) < 0) return PM3_EINVARG; - // int page = arg_get_int_def(ctx, 5, 0); // not implemented yet + uint32_t page = arg_get_int_def(ctx, 5, 0); + + if (page > 255) { + PrintAndLogEx(WARNING, "Page address Invalid."); + return PM3_EINVARG; + } + + uint32_t count = arg_get_int_def(ctx, 6, 1); + + if (count > HITAGS_MAX_PAGES) { + PrintAndLogEx(WARNING, "No more than 64 pages can be read at once."); + return PM3_EINVARG; + } CLIParserFree(ctx); + packet.page = page; + packet.page_count = count; + clearCommandBuffer(); SendCommandNG(CMD_LF_HITAGS_READ, (uint8_t *) &packet, sizeof(packet)); @@ -264,9 +280,9 @@ static int CmdLFHitagSRead(const char *Cmd) { return PM3_ESOFT; } - uint8_t *data = resp.data.asBytes; + lf_hts_read_response_t *card = (lf_hts_read_response_t *)resp.data.asBytes; - hitags_config_t config = hitags_config_unpack(&data[HITAGS_PAGE_SIZE * HITAGS_CONFIG_PADR]); + hitags_config_t config = hitags_config_unpack(card->config_page.asBytes); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); @@ -275,11 +291,28 @@ static int CmdLFHitagSRead(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Data") " ----------------------------------"); + PrintAndLogEx(INFO, "adr| 00 01 02 03 | ascii"); + PrintAndLogEx(INFO, "---+-------------+-------"); + + const int hts_mem_sizes[] = {1, 8, 64, 64}; + + if (count == 0) { + count = hts_mem_sizes[config.memory_type] - page; + } - const int hts_mem_sizes[] = {4, 32, 256, 256}; - uint32_t size = hts_mem_sizes[config.memory_type]; + // int page_end = page + count; + // page_end = MIN(page_end, 255); - print_hex_break(data, size, HITAGS_PAGE_SIZE); + for (int i = 0; i < count; ++i) { + int page_addr = page + i; + if (page_addr > 255) { + break; + } + if (card->pages_reason[i] >= 0) + PrintAndLogEx(SUCCESS, "%02u | %s", page_addr, sprint_hex_ascii(card->pages[i], HITAGS_PAGE_SIZE)); + else + PrintAndLogEx(INFO, "%02u | -- -- -- -- | read failed reason: " _YELLOW_("%d"), page_addr, card->pages_reason[i]); + } return PM3_SUCCESS; } diff --git a/include/hitag.h b/include/hitag.h index 4e64a0dc6b..cdc1fcb03f 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -67,7 +67,8 @@ typedef enum { typedef struct { hitag_function cmd; - int16_t page; + uint8_t page; + uint8_t page_count; uint8_t data[HITAGS_PAGE_SIZE]; uint8_t NrAr[HITAG_NRAR_SIZE]; // unaligned access to key as uint64_t will abort. @@ -165,4 +166,34 @@ struct hitagS_tag { } PACKED; +typedef struct { + union { + uint8_t asBytes[HITAGS_PAGE_SIZE]; + struct { + // page 1 + uint8_t CON0; + // con1 + bool LKP : 1; // 0 = page2/3 read write 1 =page2/3 read only in Plain mode and no access in authenticate mode + bool LCON : 1; // 0 = con1/2 read write 1 =con1 read only and con2 OTP + int TTFM : 2; // the number of pages that are sent to the RWD + int TTFDR : 2; // data rate in TTF Mode + bool TTFC : 1; // Transponder Talks first coding. 0 = Manchester 1 = Biphase + bool auth : 1; // 0 = Plain 1 = Auth + // con2 + // 0 = read write 1 = read only + bool LCK0 : 1; // page48-63 + bool LCK1 : 1; // page32-47 + bool LCK2 : 1; // page24-31 + bool LCK3 : 1; // page16-23 + bool LCK4 : 1; // page12-15 + bool LCK5 : 1; // page8-11 + bool LCK6 : 1; // page6/7 + bool LCK7 : 1; // page4/5 + // reserved/pwdh0 + uint8_t pwdh0; + }s; + } config_page; + int8_t pages_reason[HITAGS_MAX_PAGES]; + uint8_t pages[HITAGS_MAX_PAGES][HITAGS_PAGE_SIZE]; +} PACKED lf_hts_read_response_t; #endif