diff --git a/CHANGELOG.md b/CHANGELOG.md index ceaea4f56..6bc91ec89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added `hf 14b raw --pico` - now supports picopass anticollision over ISO14443-B (@iceman1001) + - Changed `hf 14b *` - worked apdu and comms. Improved output. Uses NG packets (@iceman1001) + - Fixed `data manrawdecode` - now copy to demodbuf even if em4100 decode fails (@iceman1001) + - Changed `nfc decode` - now supports Android Managed Provision NDEF message decoding (@iceman1001) + - Changed `hf_cardhopper` - Allow button presses to break, handle non-zero CID from reader by relaying RATS and improving PPS and WTX handling, more reliably cook ATS, ignore client packets on serial line (@nvx) + - Fixed `data diff` - client no longer crashes when using short widths on long filenames (@iceman1001) + - Added `hf 15 wipe` - fills card memory with zeros (@iceman1001) + - Changed `hf xerox info` - now prints some part info (@iceman1001) + - Added `hf xerox view` - view dump files of fuji/xerox tags (@iceman1001) + - Changed `hf 15 findafi` - improved the params (@iceman1001) + - Changed `hf 15 rdbl/rdmulti/dump` - should handle 4 vs 8 bytes block sizes in cards (@iceman1001) + - Changed `hf 15 *` - all 15 commands now uses NG packets (@iceman1001) + - Changed `hf 15 raw` - now supports "-k" keep field on and "-s" select (@iceman1001) - Changed `prefs set client.debug` - now also toggles the client side APDU logging (@iceman1001) - Changed `hf 14b sriwrbl` - now supports --force to override block checks. Thanks @gentilkiwi for the idea! (@iceman1001) - Changed `hf 14b sriwrbl` - now tries to verify the write (@iceman1001) diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 4f99ae756..0949558f3 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -92,9 +92,9 @@ uint32_t BigBuf_get_size(void) { // get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done uint8_t *BigBuf_get_EM_addr(void) { // not yet allocated - if (emulator_memory == NULL) - emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE); - + if (emulator_memory == NULL) { + emulator_memory = BigBuf_calloc(CARD_MEMORY_SIZE); + } return emulator_memory; } @@ -366,8 +366,9 @@ void tosend_stuffbit(int b) { } dmabuf16_t *get_dma16(void) { - if (dma_16.buf == NULL) + if (dma_16.buf == NULL) { dma_16.buf = (uint16_t *)BigBuf_malloc(DMA_BUFFER_SIZE * sizeof(uint16_t)); + } return &dma_16; } diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index e496ce2f7..7eb8fa2ce 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -26,7 +26,7 @@ #define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC #define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these #define CARD_MEMORY_SIZE 4096 -#define DMA_BUFFER_SIZE 512 +#define DMA_BUFFER_SIZE (512 + 256) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits #define TOSEND_BUFFER_SIZE (9 * MAX_FRAME_SIZE + 1 + 1 + 2) diff --git a/armsrc/Standalone/hf_cardhopper.c b/armsrc/Standalone/hf_cardhopper.c index b589542c4..45181b0d9 100644 --- a/armsrc/Standalone/hf_cardhopper.c +++ b/armsrc/Standalone/hf_cardhopper.c @@ -78,7 +78,9 @@ void RunMod(void) { // Ensure debug logs don't polute stream #ifdef CARDHOPPER_USB g_reply_via_usb = false; + g_reply_via_fpc = true; #else + g_reply_via_usb = true; g_reply_via_fpc = false; #endif @@ -100,6 +102,11 @@ void RunMod(void) { packet_t modeRx = { 0 }; read_packet(&modeRx); + if (BUTTON_PRESS()) { + DbpString(_CYAN_("[@]") " Button pressed - Breaking from mode loop"); + break; + } + if (memcmp(magicREAD, modeRx.dat, sizeof(magicREAD)) == 0) { DbpString(_CYAN_("[@]") " I am a READER. I talk to a CARD."); become_reader(); @@ -137,6 +144,20 @@ static void become_reader(void) { read_packet(rx); if (memcmp(magicRSRT, rx->dat, sizeof(magicRSRT)) == 0) break; + if (rx->dat[0] == ISO14443A_CMD_RATS && rx->len == 4) { + // got RATS from reader, reset the card + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(40); + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + + // re-select the card without RATS to allow replaying the real RATS + int ret = iso14443a_select_card(NULL, NULL, NULL, true, 0, true); + if (ret && ret != 1) { + Dbprintf(_RED_("[!]") " Error selecting card: %d", ret); + continue; + } + } + memcpy(toCard, rx->dat, rx->len); AddCrc14A(toCard, rx->len); ReaderTransmit(toCard, rx->len + 2, NULL); @@ -212,9 +233,12 @@ static void become_card(void) { if (cardhopper_data_available()) { read_packet(rx); if (memcmp(magicRSRT, rx->dat, sizeof(magicRSRT)) == 0) { - DbpString(_CYAN_("[@]") " Breaking from reader loop"); + DbpString(_CYAN_("[@]") " Breaking from emulation loop"); break; } + } else if (BUTTON_PRESS()) { + DbpString(_CYAN_("[@]") " Button pressed - Breaking from emulation loop"); + break; } continue; } @@ -223,9 +247,13 @@ static void become_card(void) { if (try_use_canned_response(fromReaderDat, fromReaderLen, canned)) continue; // Option 2: Reply with our cooked ATS + bool no_reply = false; if (fromReaderDat[0] == ISO14443A_CMD_RATS && fromReaderLen == 4) { reply_with_packet(&ats); - continue; + + // fallthrough to still send the RATS to the card so it can learn the CID + // but don't send the reply since we've already sent our cooked ATS + no_reply = true; } // Option 3: Relay the message @@ -234,7 +262,9 @@ static void become_card(void) { write_packet(tx); read_packet(rx); - reply_with_packet(rx); + if (!no_reply && rx->len > 0) { + reply_with_packet(rx); + } } } @@ -286,28 +316,71 @@ static void cook_ats(packet_t *ats, uint8_t fwi, uint8_t sfgi) { return; } - // If the ATS is too short (unusual), pad it to length with hopefully-sensible data - // Might be better for the phone side to do this tbh - if (ats->len == 1) { - ats->len = 4; - ats->dat[0] = 0x04; - ats->dat[1] = 0x78; - ats->dat[2] = 0x77; - // ats->dat[3] = 0x80; - } else if (ats->len == 2) { - ats->len = 4; - ats->dat[0] = 0x04; - ats->dat[2] = 0x77; - // ats->dat[3] = 0x80; - } else if (ats->len == 3) { - ats->len = 4; - ats->dat[0] = 0x04; - // ats->dat[3] = 0x80; + uint8_t t0 = 0x70; // TA, TB, and TC transmitted, FSCI nibble set later + uint8_t ta = 0x80; // only 106kbps rate supported, and must be same in both directions - PM3 doesn't support any other rates + uint8_t tb = (fwi << 4) | sfgi; // cooked value + uint8_t tc = 0; + + uint8_t historical_len = 0; + uint8_t *historical_bytes; + if (ats->len > 1) { + // T0 byte exists when ats length > 1 + + uint8_t orig_t0 = ats->dat[1]; + // Update FSCI in T0 from the received ATS + t0 |= orig_t0 & 0x0F; + + uint8_t len = ats->len - 2; + uint8_t *orig_ats_ptr = &ats->dat[2]; + if (orig_t0 & 0x10) { + // TA present + if (len < 1) { + DbpString(_RED_("[!]") " Malformed ATS - unable to cook; things may go wrong!"); + return; + } + orig_ats_ptr++; + len--; + } + if (orig_t0 & 0x20) { + // TB present + if (len < 1) { + DbpString(_RED_("[!]") " Malformed ATS - unable to cook; things may go wrong!"); + return; + } + orig_ats_ptr++; + len--; + } + if (orig_t0 & 0x40) { + // TC present, extract protocol parameters + if (len < 1) { + DbpString(_RED_("[!]") " Malformed ATS - unable to cook; things may go wrong!"); + return; + } + tc = *orig_ats_ptr; + orig_ats_ptr++; + len--; + } + + historical_bytes = orig_ats_ptr; + historical_len = len; + } else { + // T0 byte missing, update FSCI in T0 to the default value of 2 + t0 |= 0x02; } - // Set the SFGI as well as the FWI - needed for some older readers (firmware revs?) - uint8_t cookedTB0 = (fwi << 4) | sfgi; - ats->dat[3] = cookedTB0; + packet_t cooked_ats = { 0 }; + cooked_ats.len = 5 + historical_len; + cooked_ats.dat[0] = cooked_ats.len; + cooked_ats.dat[1] = t0; + cooked_ats.dat[2] = ta; + cooked_ats.dat[3] = tb; + cooked_ats.dat[4] = tc; + + if (historical_len > 0) { + memcpy(cooked_ats.dat + 5, historical_bytes, historical_len); + } + + memcpy(ats, &cooked_ats, sizeof(packet_t)); } @@ -343,17 +416,18 @@ static bool try_use_canned_response(const uint8_t *dat, int len, tag_response_in } } - if (dat[0] == ISO14443A_CMD_PPS) { + // high nibble of PPS is PPS CMD, low nibble of PPS is CID + if ((dat[0] & 0xF0) == ISO14443A_CMD_PPS) { EmSendPrecompiledCmd(canned + RESP_INDEX_PPS); return true; } // No response is expected to these 14a commands - if ((dat[0] == 0xf2 && len == 4) || dat[0] == 0xfa) return true; + if ((dat[0] & 0xF7) == ISO14443A_CMD_WTX) return true; // bit 0x08 indicates CID following if (dat[0] == ISO14443A_CMD_HALT && len == 4) return true; // Ignore Apple ECP2 polling - if (dat[0] == 0x6a) return true; + if (dat[0] == ECP_HEADER) return true; return false; } @@ -380,15 +454,38 @@ static void read_packet(packet_t *packet) { while (!cardhopper_data_available()) { WDT_HIT(); SpinDelayUs(100); + if (BUTTON_PRESS()) { + DbpString(_CYAN_("[@]") " Button pressed while waiting for packet - aborting"); + return; + } } cardhopper_read((uint8_t *) &packet->len, 1); uint32_t dataReceived = 0; while (dataReceived != packet->len) { - while (!cardhopper_data_available()) WDT_HIT(); + while (!cardhopper_data_available()) { + WDT_HIT(); + if (BUTTON_PRESS()) { + DbpString(_CYAN_("[@]") " Button pressed while reading packet - aborting"); + return; + } + } dataReceived += cardhopper_read(packet->dat + dataReceived, packet->len - dataReceived); + + if (packet->len == 0x50 && dataReceived >= sizeof(PacketResponseNGPreamble) && packet->dat[0] == 0x4D && packet->dat[1] == 0x33 && packet->dat[2] == 0x61) { + // PM3 NG packet magic + DbpString(_CYAN_("[@]") " PM3 NG packet recieved - ignoring"); + + // clear any remaining buffered data + while (cardhopper_data_available()) { + cardhopper_read(packet->dat, 255); + } + + packet->len = 0; + return; + } } cardhopper_write(magicACK, sizeof(magicACK)); } @@ -414,7 +511,7 @@ static bool GetIso14443aCommandFromReaderInterruptible(uint8_t *received, uint8_ WDT_HIT(); if (flip == 3) { - if (cardhopper_data_available()) + if (cardhopper_data_available() || BUTTON_PRESS()) return false; flip = 0; diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 520b445d6..1e4a1ca15 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -815,14 +815,21 @@ static void PacketReceived(PacketCommandNG *packet) { bool off; } PACKED; struct p *payload = (struct p *)packet->data.asBytes; - if (payload->on && payload->off) + if (payload->on && payload->off) { reply_ng(CMD_SET_TEAROFF, PM3_EINVARG, NULL, 0); - if (payload->on) + } + + if (payload->on) { g_tearoff_enabled = true; - if (payload->off) + } + + if (payload->off) { g_tearoff_enabled = false; - if (payload->delay_us > 0) + } + + if (payload->delay_us > 0) { g_tearoff_delay_us = payload->delay_us; + } reply_ng(CMD_SET_TEAROFF, PM3_SUCCESS, NULL, 0); break; } @@ -1269,11 +1276,16 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ISO15693_COMMAND: { - DirectTag15693Command(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + iso15_raw_cmd_t *payload = (iso15_raw_cmd_t *)packet->data.asBytes; + SendRawCommand15693(payload); break; } case CMD_HF_ISO15693_FINDAFI: { - BruteforceIso15693Afi(packet->oldarg[0]); + struct p { + uint32_t flags; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + BruteforceIso15693Afi(payload->flags); break; } case CMD_HF_ISO15693_READER: { @@ -1443,7 +1455,7 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_HF_ISO14443B_COMMAND: { iso14b_raw_cmd_t *payload = (iso14b_raw_cmd_t *)packet->data.asBytes; - SendRawCommand14443B_Ex(payload); + SendRawCommand14443B(payload); break; } case CMD_HF_CRYPTORF_SIM : { diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 283577e3a..ca63c5c93 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -43,11 +43,6 @@ uint8_t get_pagemap(const picopass_hdr_t *hdr) { return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; } -// The length of a received command will in most cases be no more than 18 bytes. -// we expect max 34 (32+2) bytes as tag answer (response to READ4) -#ifndef ICLASS_BUFFER_SIZE -#define ICLASS_BUFFER_SIZE 34 + 2 -#endif #ifndef ICLASS_16KS_SIZE #define ICLASS_16KS_SIZE 0x100 * 8 diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 30846ff36..4a71780bb 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -36,6 +36,13 @@ #define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms #define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us +// The length of a received command will in most cases be no more than 18 bytes. +// we expect max 34 (32+2) bytes as tag answer (response to READ4) +#ifndef ICLASS_BUFFER_SIZE +#define ICLASS_BUFFER_SIZE 34 + 2 +#endif + + #define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1) void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 512976d30..1890faec2 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -34,6 +34,7 @@ #include "dbprint.h" #include "ticks.h" #include "iso14b.h" // defines for ETU conversions +#include "iclass.h" // picopass buffer defines /* * Current timing issues with ISO14443-b implementation @@ -111,9 +112,6 @@ * */ - - - #ifndef MAX_14B_TIMEOUT // FWT(max) = 4949 ms or 4.95 seconds. // SSP_CLK = 4949000 * 3.39 = 16777120 @@ -195,9 +193,11 @@ static void iso14b_set_maxframesize(uint16_t size); static void iso14b_set_fwt(uint8_t fwt); // the block number for the ISO14443-4 PCB (used with APDUs) -static uint8_t iso14b_pcb_blocknum = 0; -static uint8_t iso14b_fwt = 9; -static uint32_t iso14b_timeout = FWT_TIMEOUT_14B; +static uint8_t s_iso14b_pcb_blocknum = 0; +static uint8_t s_iso14b_fwt = 9; +static uint32_t s_iso14b_timeout = MAX_14B_TIMEOUT; + +static bool s_field_on = false; /* * ISO 14443-B communications @@ -350,7 +350,6 @@ static uint32_t iso14b_timeout = FWT_TIMEOUT_14B; // them yet, just leaves them ready to send in ToSend[]. //----------------------------------------------------------------------------- static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { - int i; tosend_reset(); @@ -362,6 +361,7 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { // 80/fs < TR1 < 200/fs // 10 ETU < TR1 < 24 ETU + int i; // Send TR1. // 10-11 ETU * 4times samples ONES for (i = 0; i < 10; i++) { @@ -458,15 +458,18 @@ static void iso14b_set_timeout(uint32_t timeout_etu) { ssp = MAX_14B_TIMEOUT; } - iso14b_timeout = ssp; + s_iso14b_timeout = ssp; if (g_dbglevel >= DBG_DEBUG) { - Dbprintf("ISO14443B Timeout set to %ld fwt", iso14b_timeout); + Dbprintf("ISO14443B Timeout set to %ld fwt", s_iso14b_timeout); } } // keep track of FWT, also updates the timeout static void iso14b_set_fwt(uint8_t fwt) { - iso14b_fwt = fwt; + s_iso14b_fwt = fwt; + if (g_dbglevel >= DBG_DEBUG) { + Dbprintf("ISO14443B FWT Timeout set to %ld fwt", s_iso14b_fwt); + } iso14b_set_timeout(32 << fwt); } @@ -819,7 +822,7 @@ void SimulateIso14443bTag(const uint8_t *pupi) { // WUP in HALTED state if (len == 5) { if ((receivedCmd[0] == ISO14443B_REQB && (receivedCmd[2] & 0x8) == 0x8 && cardSTATE == SIM_HALTED) || - receivedCmd[0] == ISO14443B_REQB) { + receivedCmd[0] == ISO14443B_REQB) { LogTrace(receivedCmd, len, 0, 0, NULL, true); cardSTATE = SIM_SELECTING; @@ -1323,6 +1326,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t // The DMA buffer, used to stream samples from the FPGA dmabuf16_t *dma = get_dma16(); + if (dma == NULL) { + return PM3_EMALLOC; + } if (FpgaSetupSscDma((uint8_t *) dma->buf, DMA_BUFFER_SIZE) == false) { if (g_dbglevel > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting"); @@ -1407,9 +1413,10 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, uint32_t if (Demod.len > 0) { uint32_t sof_time = *eof_time - HF14_ETU_TO_SSP( (Demod.len * (8 + 2)) // time for byte transfers -// + (10) // time for TR1 + (10 + 2) // time for SOF transfer - + (10)); // time for EOF transfer + + (10) // time for EOF transfer + ) + ; LogTrace(Demod.output, Demod.len, sof_time, *eof_time, NULL, false); } @@ -1583,7 +1590,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t /* Sends an APDU to the tag * TODO: check CRC and preamble */ -int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int *reponselen) { +int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *response_byte, uint16_t *reponselen) { uint8_t real_cmd[msg_len + 4]; @@ -1596,12 +1603,12 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void } // put block number into the PCB - real_cmd[0] |= iso14b_pcb_blocknum; + real_cmd[0] |= s_iso14b_pcb_blocknum; memcpy(real_cmd + 1, msg, msg_len); } else { // R-block. ACK real_cmd[0] = 0xA2; // r-block + ACK - real_cmd[0] |= iso14b_pcb_blocknum; + real_cmd[0] |= s_iso14b_pcb_blocknum; } AddCrc14B(real_cmd, msg_len + 1); @@ -1618,26 +1625,25 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void // SSP_CLK = 4833 µS * 3.39 = 16384 uint16_t len = 0; - if (Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) { - return PM3_ECARDEXCHANGE; + int status = Get14443bAnswerFromTag(rxdata, rxmaxlen, s_iso14b_timeout, &eof_time, &len); + if (status != PM3_SUCCESS) { + return status; } - FpgaDisableTracing(); - uint8_t *data_bytes = (uint8_t *) rxdata; if (len) { // S-Block WTX while (len && ((data_bytes[0] & 0xF2) == 0xF2)) { - uint32_t save_iso14b_timeout_spp = iso14b_timeout; + uint32_t save_iso14b_timeout_spp = s_iso14b_timeout; // 2 high bits mandatory set to 0b // byte1 - WTXM [1..59]. uint8_t wtxm = data_bytes[1] & 0x3F; // command FWT = FWT * WTXM - uint32_t fwt_temp = iso14b_fwt * wtxm; + uint32_t fwt_temp = (s_iso14b_fwt * wtxm); // temporarily increase timeout iso14b_set_timeout((32 << fwt_temp)); @@ -1653,41 +1659,41 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void // retrieve the result again (with increased timeout) eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; - - if (Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) { - FpgaDisableTracing(); + + if (Get14443bAnswerFromTag(rxdata, rxmaxlen, s_iso14b_timeout, &eof_time, &len) != PM3_SUCCESS) { return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); data_bytes = rxdata; // restore timeout - iso14b_timeout = save_iso14b_timeout_spp; + s_iso14b_timeout = save_iso14b_timeout_spp; } // if we received an I- or R(ACK)-Block with a block number equal to the // current block number, toggle the current block number if ((len >= 3) && // PCB + CRC = 3 bytes - (((data_bytes[0] & 0xC0) == 0) || (data_bytes[0] & 0xD0) == 0x80) && // I-Block OR R-Block with ACK bit set to 0 - ((data_bytes[0] & 0x01) == iso14b_pcb_blocknum)) { // equal block numbers + (((data_bytes[0] & 0xC0) == 0) || (data_bytes[0] & 0xD0) == 0x80) && // I-Block OR R-Block with ACK bit set to 0 + ((data_bytes[0] & 0x01) == s_iso14b_pcb_blocknum)) { // equal block numbers - iso14b_pcb_blocknum ^= 1; + s_iso14b_pcb_blocknum ^= 1; } // if we received I-block with chaining we need to send ACK and receive another block of data - if (res) { - *res = data_bytes[0]; + if (response_byte) { + *response_byte = data_bytes[0]; } // crc check if (len >= 3 && (check_crc(CRC_14443_B, data_bytes, len) == false)) { return PM3_ECRC; } + } - // cut frame byte + // cut frame byte + if (len) { len -= 1; for (int i = 0; i < len; i++) { @@ -1722,11 +1728,9 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) { eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; uint16_t retlen = 0; - if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } - - FpgaDisableTracing(); if (retlen != 4) { return PM3_ELENGTH; @@ -1745,10 +1749,9 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) { CodeAndTransmit14443bAsReader(cmdMSBUID, sizeof(cmdMSBUID), &start_time, &eof_time, true); eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; - if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); if (retlen != 4) { return PM3_ELENGTH; @@ -1765,10 +1768,9 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) { CodeAndTransmit14443bAsReader(cmdLSBUID, sizeof(cmdLSBUID), &start_time, &eof_time, true); eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; - if (Get14443bAnswerFromTag(r, sizeof(r), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(r, sizeof(r), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); if (retlen != 4) { return PM3_ELENGTH; @@ -1782,9 +1784,6 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) { } return PM3_SUCCESS; -out: - FpgaDisableTracing(); - return PM3_ECARDEXCHANGE; } /** * SRx Initialise. @@ -1802,11 +1801,9 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) { eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; uint16_t retlen = 0; - if (Get14443bAnswerFromTag(r_init, sizeof(r_init), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - FpgaDisableTracing(); + if (Get14443bAnswerFromTag(r_init, sizeof(r_init), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); // Randomly generated Chip ID if (card) { @@ -1823,12 +1820,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) { CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx), &start_time, &eof_time, true); eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; - if (Get14443bAnswerFromTag(r_select, sizeof(r_select), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(r_select, sizeof(r_select), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); - if (retlen != 3) { return PM3_ELENGTH; } @@ -1850,12 +1845,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) { CodeAndTransmit14443bAsReader(select_srx, 3, &start_time, &eof_time, true); // Only first three bytes for this one eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; - if (Get14443bAnswerFromTag(r_papid, sizeof(r_papid), iso14b_timeout, &eof_time, & retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(r_papid, sizeof(r_papid), s_iso14b_timeout, &eof_time, & retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); - if (retlen != 10) { return PM3_ELENGTH; } @@ -1869,9 +1862,6 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) { memcpy(card->uid, r_papid, 8); } return PM3_SUCCESS; -out: - FpgaDisableTracing(); - return PM3_ECARDEXCHANGE; } // Xerox tag connect function: wup, anticoll, attrib, password @@ -1907,12 +1897,11 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) { for (slot = 0; slot < 4; slot++) { start_time = eof_time + HF14_ETU_TO_SSP(30); //(24); // next slot after 24 ETU - if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { if (retlen > 0) { Dbprintf("unexpected data %d", retlen); - Dbprintf("crc %s", check_crc(CRC_14443_B, x_atqb, retlen) ? "OK" : "BAD"); } - goto out; + return PM3_ECARDEXCHANGE; } // tx unframed slot-marker @@ -1930,8 +1919,6 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) { } if (4 == slot) { - FpgaDisableTracing(); - if (g_dbglevel >= DBG_DEBUG) { DbpString("no answer to anticollision"); } @@ -1939,8 +1926,8 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) { } } - if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } if (g_dbglevel >= DBG_DEBUG) { @@ -1984,10 +1971,9 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) { CodeAndTransmit14443bAsReader(txbuf + 1, 15, &start_time, &eof_time, true); eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; - if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); if (retlen < 3) { return PM3_ELENGTH; @@ -2018,8 +2004,8 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) { CodeAndTransmit14443bAsReader(txbuf, 17, &start_time, &eof_time, true); eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; - if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(x_atqb, sizeof(x_atqb), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } if (retlen < 4) { @@ -2035,10 +2021,6 @@ static int iso14443b_select_xrx_card(iso14b_card_select_t *card) { } return PM3_SUCCESS; - -out: - FpgaDisableTracing(); - return PM3_ECARDEXCHANGE; } /* Perform the ISO 14443 B Card Selection procedure @@ -2066,12 +2048,10 @@ int iso14443b_select_card(iso14b_card_select_t *card) { eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; uint16_t retlen = 0; - if (Get14443bAnswerFromTag(r_pupid, sizeof(r_pupid), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(r_pupid, sizeof(r_pupid), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); - // ATQB too short? if (retlen < 14) { return PM3_ELENGTH; @@ -2098,10 +2078,9 @@ int iso14443b_select_card(iso14b_card_select_t *card) { CodeAndTransmit14443bAsReader(attrib, sizeof(attrib), &start_time, &eof_time, true); eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; - if (Get14443bAnswerFromTag(r_attrib, sizeof(r_attrib), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - goto out; + if (Get14443bAnswerFromTag(r_attrib, sizeof(r_attrib), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); // Answer to ATTRIB too short? if (retlen < 3) { @@ -2135,12 +2114,134 @@ int iso14443b_select_card(iso14b_card_select_t *card) { } } // reset PCB block number - iso14b_pcb_blocknum = 0; + s_iso14b_pcb_blocknum = 0; return PM3_SUCCESS; +} -out: - FpgaDisableTracing(); - return PM3_ECARDEXCHANGE; +static int iso14443b_select_picopass_card(picopass_hdr_t *hdr) { + + static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; + static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY }; + static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; + uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t read_aia[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; + + uint32_t start_time = 0; + uint32_t eof_time = 0; + uint16_t retlen = 0; + + // first, wake up the tag 0x0A + CodeAndTransmit14443bAsReader(act_all, sizeof(act_all), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // 0x0C + // start_time = eof_time + ISO14B_TR2; + start_time = eof_time + US_TO_SSP(330); // 330ms before next cmd + CodeAndTransmit14443bAsReader(identify, sizeof(identify), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + // copy the Anti-collision CSN to our select-packet + memcpy(&select[1], resp, 8); + + // select the card + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(select, sizeof(select), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect a 10-byte response here, 8 byte CSN and 2 byte CRC + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + // save CSN + memcpy(hdr->csn, resp, sizeof(hdr->csn)); + + // card selected, now read config (block1) (only 8 bytes no CRC) + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(read_conf, sizeof(read_conf), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect a 10-byte response here, 8 bytes CONFIGURATION and 2 byte CRC) + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + // save CONF + memcpy((uint8_t *)&hdr->conf, resp, sizeof(hdr->conf)); + + uint8_t pagemap = get_pagemap(hdr); + if (pagemap != PICOPASS_NON_SECURE_PAGEMODE) { + + // read App Issuer Area block 5 + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(read_aia, sizeof(read_aia), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect AIA, a 10-byte response here + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + memcpy(hdr->app_issuer_area, resp, sizeof(hdr->app_issuer_area)); + + // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect EPURSE, a 8 byte response here + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 8) { + return PM3_ELENGTH; + } + + memcpy(hdr->epurse, resp, sizeof(hdr->epurse)); + + } else { + + // on NON_SECURE_PAGEMODE cards, AIA is on block2.. + + // read App Issuer Area block 2 + read_aia[1] = 0x02; + read_aia[2] = 0x61; + read_aia[3] = 0x10; + + start_time = eof_time + ISO14B_TR2; + CodeAndTransmit14443bAsReader(read_aia, sizeof(read_aia), &start_time, &eof_time, true); + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + + // expect AIA, a 10-byte response here + if (Get14443bAnswerFromTag(resp, sizeof(resp), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { + return PM3_ECARDEXCHANGE; + } + if (retlen != 10) { + return PM3_ELENGTH; + } + + memcpy(hdr->epurse, resp, sizeof(hdr->epurse)); + } + return PM3_SUCCESS; } // Set up ISO 14443 Type B communication (similar to iso14443a_setup) @@ -2180,6 +2281,8 @@ void iso14443b_setup(void) { // reset timeout iso14b_set_fwt(8); + s_field_on = true; + LED_D_ON(); } @@ -2194,7 +2297,6 @@ void iso14443b_setup(void) { //----------------------------------------------------------------------------- static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) { -// iceman: todo add static CRC uint8_t cmd[] = {ISO14443B_READ_BLK, blocknr, 0x00, 0x00}; AddCrc14B(cmd, 2); @@ -2206,20 +2308,16 @@ static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) { eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; uint16_t retlen = 0; - if (Get14443bAnswerFromTag(r_block, sizeof(r_block), iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { - FpgaDisableTracing(); + if (Get14443bAnswerFromTag(r_block, sizeof(r_block), s_iso14b_timeout, &eof_time, &retlen) != PM3_SUCCESS) { return PM3_ECARDEXCHANGE; } - FpgaDisableTracing(); // Check if we got an answer from the tag if (retlen != 6) { - Dbprintf("expected 6 bytes from tag, got %u", retlen); return PM3_EWRONGANSWER; } // The check the CRC of the answer if (check_crc(CRC_14443_B, r_block, retlen) == false) { - DbpString("CRC fail"); return PM3_ECRC; } @@ -2227,14 +2325,6 @@ static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) { memcpy(block, r_block, ISO14B_BLOCK_SIZE); } - if (g_dbglevel >= DBG_DEBUG) { - Dbprintf("Address=%02x, Contents=%08x, CRC=%04x", - blocknr, - (r_block[3] << 24) + (r_block[2] << 16) + (r_block[1] << 8) + r_block[0], - (r_block[4] << 8) + r_block[5] - ); - } - return PM3_SUCCESS; } @@ -2457,7 +2547,7 @@ static void iso14b_set_trigger(bool enable) { g_trigger = enable; } -void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) { +void SendRawCommand14443B(iso14b_raw_cmd_t *p) { // turn on trigger (LED_A) if ((p->flags & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) { @@ -2476,6 +2566,7 @@ void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) { clear_trace(); BigBuf_Clear_ext(false); } + set_tracing(true); // receive buffer @@ -2512,51 +2603,75 @@ void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p) { sendlen = sizeof(iso14b_cts_card_select_t); status = iso14443b_select_cts_card(cts); reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)cts, sendlen); - if (status > PM3_SUCCESS) goto out; + if (status != PM3_SUCCESS) goto out; + } + + if ((p->flags & ISO14B_SELECT_PICOPASS) == ISO14B_SELECT_PICOPASS) { + picopass_hdr_t *hdr = (picopass_hdr_t *)buf; + memset(hdr, 0, sizeof(picopass_hdr_t)); + sendlen = sizeof(picopass_hdr_t); + status = iso14443b_select_picopass_card(hdr); + reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t *)hdr, sendlen); + if (status != PM3_SUCCESS) goto out; + } + + // if field is off... + if ( + ((p->flags & ISO14B_APDU) == ISO14B_APDU) || + ((p->flags & ISO14B_RAW) == ISO14B_RAW) + ) { + if (s_field_on == false) { + DbpString("Field is off"); + reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ERFTRANS, NULL, 0); + goto out; + } } if ((p->flags & ISO14B_APDU) == ISO14B_APDU) { - int responselen = 0; + uint16_t responselen = 0; uint8_t response_byte = 0; - status = iso14443b_apdu(p->raw, p->rawlen, (p->flags & ISO14B_SEND_CHAINING), buf, sizeof(buf), &response_byte, &responselen); + bool chaining = ((p->flags & ISO14B_SEND_CHAINING) == ISO14B_SEND_CHAINING); + status = iso14443b_apdu(p->raw, p->rawlen, chaining, buf, sizeof(buf), &response_byte, &responselen); if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ETEAROFF, NULL, 0); } else { - responselen = MIN(responselen, PM3_CMD_DATA_SIZE); - - iso14b_raw_apdu_response_t *payload = (iso14b_raw_apdu_response_t *)BigBuf_calloc( sizeof(iso14b_raw_apdu_response_t) + responselen); + uint8_t packet[responselen + 1 + 2]; + iso14b_raw_apdu_response_t *payload = (iso14b_raw_apdu_response_t *)packet; payload->response_byte = response_byte; payload->datalen = responselen; memcpy(payload->data, buf, payload->datalen); - - reply_ng(CMD_HF_ISO14443B_COMMAND, status, (uint8_t*)payload, sizeof(iso14b_raw_apdu_response_t) + responselen); - BigBuf_free_keep_EM(); + reply_ng(CMD_HF_ISO14443B_COMMAND, status, packet, sizeof(packet)); } } if ((p->flags & ISO14B_RAW) == ISO14B_RAW) { - uint8_t *raw = BigBuf_calloc(p->rawlen + 2); - memcpy(raw, p->raw, p->rawlen); - if ( - ((p->flags & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) && (p->rawlen)) { - AddCrc14B(raw, p->rawlen); + if (((p->flags & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) && (p->rawlen)) { + + // Picopass uses different CRC algo + // it also excludes the first instruction byte + if ((p->flags & ISO14B_SELECT_PICOPASS) == ISO14B_SELECT_PICOPASS) { + AddCrc15(p->raw + 1, p->rawlen - 1); + } else { + AddCrc14B(p->raw, p->rawlen); + } p->rawlen += 2; } uint32_t start_time = 0; uint32_t eof_time = 0; - CodeAndTransmit14443bAsReader(raw, p->rawlen, &start_time, &eof_time, true); + CodeAndTransmit14443bAsReader(p->raw, p->rawlen, &start_time, &eof_time, true); - FpgaDisableTracing(); if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred reply_ng(CMD_HF_ISO14443B_COMMAND, PM3_ETEAROFF, NULL, 0); } else { + eof_time += DELAY_ISO14443B_PCD_TO_PICC_READER; + uint16_t retlen = 0; - status = Get14443bAnswerFromTag(buf, sizeof(buf), iso14b_timeout, &eof_time, &retlen); + status = Get14443bAnswerFromTag(buf, sizeof(buf), s_iso14b_timeout, &eof_time, &retlen); if (status == PM3_SUCCESS) { sendlen = MIN(retlen, PM3_CMD_DATA_SIZE); reply_ng(CMD_HF_ISO14443B_COMMAND, status, Demod.output, sendlen); @@ -2578,5 +2693,6 @@ out: switch_off(); // disconnect raw SpinDelay(20); BigBuf_free_keep_EM(); + s_field_on = false; } } diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h index 14da377d3..83f617831 100644 --- a/armsrc/iso14443b.h +++ b/armsrc/iso14443b.h @@ -34,8 +34,12 @@ # define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1) #endif +#ifndef AddCrc15 +#define AddCrc15(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1) +#endif + void iso14443b_setup(void); -int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int * responselen); +int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, uint16_t *responselen); int iso14443b_select_card(iso14b_card_select_t *card); @@ -43,8 +47,7 @@ void SimulateIso14443bTag(const uint8_t *pupi); void AcquireRawAdcSamplesIso14443b(uint32_t parameter); void read_14b_st_block(uint8_t blocknr); void SniffIso14443b(void); -void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); -void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p); +void SendRawCommand14443B(iso14b_raw_cmd_t *p); // States for 14B SIM command #define SIM_NOFIELD 0 diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index da2f9255e..868b1f6f4 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1739,7 +1739,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla } // no need to try decoding reader data if the tag is sending - if (!tag_is_active) { + if (tag_is_active == false) { int extra_8s = 1; if (Handle15693SampleFromReader((sniffdata & 0x02) >> 1, &dreader) || @@ -1756,7 +1756,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla // sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true); - if (!iclass) { // Those flags don't exist in iClass + if (iclass == false) { // Those flags don't exist in iClass expect_fsk_answer = dreader.output[0] & ISO15_REQ_SUBCARRIER_TWO; expect_fast_answer = dreader.output[0] & ISO15_REQ_DATARATE_HIGH; } @@ -1774,17 +1774,19 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla } // no need to try decoding tag data if the reader is currently sending or no answer expected yet - if (!reader_is_active && expect_tag_answer) { + if ((reader_is_active == false) && expect_tag_answer) { - if (!expect_fsk_answer) { + if (expect_fsk_answer == false) { // single subcarrier tag response if (Handle15693SamplesFromTag((sniffdata >> 4) << 2, &dtag, expect_fast_answer)) { // sof/eof_times are in ssp_clk, which is 13.56MHz / 4 uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF + if (dtag.lastBit == SOF_PART2) { eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) } + uint32_t sof_time = eof_time - dtag.len * 1024 // time for byte transfers (4096/fc / 4) - 512 // time for SOF transfer (2048/fc / 4) @@ -1802,18 +1804,22 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla } else { tag_is_active = (dtag.state >= STATE_TAG_RECEIVING_DATA); } + } else { // dual subcarrier tag response - if (FREQ_IS_0((sniffdata >> 2) & 0x3)) // tolerate 1 00 + if (FREQ_IS_0((sniffdata >> 2) & 0x3)) { // tolerate 1 00 sniffdata = sniffdata_prev; + } if (Handle15693FSKSamplesFromTag((sniffdata >> 2) & 0x3, &dtagfsk, expect_fast_answer)) { if (dtagfsk.len > 0) { // sof/eof_times are in ssp_clk, which is 13.56MHz / 4 uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF + if (dtagfsk.lastBit == SOF) { eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS) } + uint32_t sof_time = eof_time - dtagfsk.len * 1016 // time for byte transfers (4064/fc / 4) - FSK is slightly different - 512 // time for SOF transfer (2048/fc / 4) @@ -1937,8 +1943,8 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *eof_time = start_time + 32 * ((8 * ts->max) - 4); // subtract the 4 padding bits after EOF LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true); if (recv != NULL) { - bool fsk = send[0] & ISO15_REQ_SUBCARRIER_TWO; - bool recv_speed = send[0] & ISO15_REQ_DATARATE_HIGH; + bool fsk = ((send[0] & ISO15_REQ_SUBCARRIER_TWO) == ISO15_REQ_SUBCARRIER_TWO); + bool recv_speed = ((send[0] & ISO15_REQ_DATARATE_HIGH) == ISO15_REQ_DATARATE_HIGH); res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time, fsk, recv_speed, resp_len); } return res; @@ -2087,7 +2093,7 @@ void ReaderIso15693(iso15_card_select_t *p_card) { reply_ng(CMD_HF_ISO15693_READER, PM3_SUCCESS, uid, sizeof(uid)); if (g_dbglevel >= DBG_EXTENDED) { - Dbprintf("[+] %d octets read from IDENTIFY request:", recvlen); + Dbprintf("[+] %d bytes read from IDENTIFY request:", recvlen); DbdecodeIso15693Answer(recvlen, answer); Dbhexdump(recvlen, answer, true); } @@ -2360,16 +2366,20 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { // Since there is no standardized way of reading the AFI out of a tag, we will brute force it // (some manufactures offer a way to read the AFI, though) -void BruteforceIso15693Afi(uint32_t speed) { +void BruteforceIso15693Afi(uint32_t flags) { + + clear_trace(); - uint8_t data[7] = {0}; - uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH]; Iso15693InitReader(); + bool speed = ((flags & ISO15_HIGH_SPEED) == ISO15_HIGH_SPEED); + // first without AFI // Tags should respond without AFI and with AFI=0 even when AFI is active + uint8_t data[7] = {0}; + uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH] = {0}; - data[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + data[0] = (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1); data[1] = ISO15693_INVENTORY; data[2] = 0; // AFI AddCrc15(data, 3); @@ -2434,16 +2444,31 @@ void BruteforceIso15693Afi(uint32_t speed) { // Allows to directly send commands to the tag via the client // OBS: doesn't turn off rf field afterwards. -void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data) { +void SendRawCommand15693(iso15_raw_cmd_t *packet) { LED_A_ON(); - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - uint16_t timeout; - uint32_t eof_time = 0; + uint16_t timeout = ISO15693_READER_TIMEOUT; + if ((packet->flags & ISO15_LONG_WAIT) == ISO15_LONG_WAIT) { + timeout = ISO15693_READER_TIMEOUT_WRITE; + } + + bool speed = ((packet->flags & ISO15_HIGH_SPEED) == ISO15_HIGH_SPEED); + bool keep_field_on = ((packet->flags & ISO15_NO_DISCONNECT) == ISO15_NO_DISCONNECT); + bool read_respone = ((packet->flags & ISO15_READ_RESPONSE) == ISO15_READ_RESPONSE); + bool init = ((packet->flags & ISO15_CONNECT) == ISO15_CONNECT); + + // This is part of ISO15693 protocol definitions where the following commands needs to request option. + // note: + // it seem like previous we just guessed and never followed the fISO145_REQ_OPTION flag if it was set / not set from client side. + // this is a problem. Since without this the response from the tag is one byte shorter. And a lot of client side functions has been + // hardcoded to assume for the extra byte in the response. + bool request_answer = false; - switch (data[1]) { + switch (packet->raw[1]) { + case ISO15693_SET_PASSWORD: + case ISO15693_ENABLE_PRIVACY: case ISO15693_WRITEBLOCK: case ISO15693_LOCKBLOCK: case ISO15693_WRITE_MULTI_BLOCK: @@ -2453,42 +2478,54 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint case ISO15693_WRITE_PASSWORD: case ISO15693_PASSWORD_PROTECT_EAS: case ISO15693_LOCK_DSFID: - timeout = ISO15693_READER_TIMEOUT_WRITE; - request_answer = data[0] & ISO15_REQ_OPTION; + request_answer = ((packet->raw[0] & ISO15_REQ_OPTION) == ISO15_REQ_OPTION); break; default: - timeout = ISO15693_READER_TIMEOUT; + break; } + uint32_t eof_time = 0; uint32_t start_time = 0; uint16_t recvlen = 0; - int res = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time, &recvlen); + + uint8_t buf[ISO15693_MAX_RESPONSE_LENGTH] = {0x00}; + + int res = SendDataTag(packet->raw, packet->rawlen, init, speed, (read_respone ? buf : NULL), sizeof(buf), start_time, timeout, &eof_time, &recvlen); + if (res == PM3_ETEAROFF) { // tearoff occurred reply_ng(CMD_HF_ISO15693_COMMAND, res, NULL, 0); } else { - bool fsk = data[0] & ISO15_REQ_SUBCARRIER_TWO; - bool recv_speed = data[0] & ISO15_REQ_DATARATE_HIGH; + // if tag answers with an error code, it don't care about EOF packet + if (recvlen) { + recvlen = MIN(recvlen, ISO15693_MAX_RESPONSE_LENGTH); + reply_ng(CMD_HF_ISO15693_COMMAND, res, buf, recvlen); + } + + // looking at the first byte of the RAW bytes to determine Subcarrier, datarate, request option + bool fsk = ((packet->raw[0] & ISO15_REQ_SUBCARRIER_TWO) == ISO15_REQ_SUBCARRIER_TWO); + bool recv_speed = ((packet->raw[0] & ISO15_REQ_DATARATE_HIGH) == ISO15_REQ_DATARATE_HIGH); // send a single EOF to get the tag response if (request_answer) { start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - res = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time, fsk, recv_speed, &recvlen); + res = SendDataTagEOF((read_respone ? buf : NULL), sizeof(buf), start_time, ISO15693_READER_TIMEOUT, &eof_time, fsk, recv_speed, &recvlen); } - if (recv) { + if (read_respone) { recvlen = MIN(recvlen, ISO15693_MAX_RESPONSE_LENGTH); - reply_ng(CMD_HF_ISO15693_COMMAND, res, recvbuf, recvlen); + reply_ng(CMD_HF_ISO15693_COMMAND, res, buf, recvlen); } else { reply_ng(CMD_HF_ISO15693_COMMAND, PM3_SUCCESS, NULL, 0); } } + if (keep_field_on == false) { + switch_off(); // disconnect raw + SpinDelay(20); + } - // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway - // also prevents hf 15 raw -k keep_field on ... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); + LED_A_OFF(); } /* @@ -2611,10 +2648,9 @@ void LockPassSlixIso15693(uint32_t pass_id, uint32_t password) { void SetTag15693Uid(const uint8_t *uid) { LED_A_ON(); - uint8_t cmd[4][9] = { - {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3e, 0x00, 0x00, 0x00, 0x00}, - {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3f, 0x69, 0x96, 0x00, 0x00}, + {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x8F}, + {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3f, 0x69, 0x96, 0x00, 0x00, 0x8A, 0xBB}, {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x38}, {ISO15_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x39} }; @@ -2631,29 +2667,31 @@ void SetTag15693Uid(const uint8_t *uid) { cmd[3][5] = uid[1]; cmd[3][6] = uid[0]; - AddCrc15(cmd[0], 7); - AddCrc15(cmd[1], 7); AddCrc15(cmd[2], 7); AddCrc15(cmd[3], 7); - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + uint8_t buf[ISO15693_MAX_RESPONSE_LENGTH] = {0x00}; uint32_t start_time = 0; uint32_t eof_time = 0; uint16_t recvlen = 0; + int res = PM3_SUCCESS; + for (int i = 0; i < 4; i++) { res = SendDataTag( cmd[i], sizeof(cmd[i]), (i == 0) ? true : false, true, - recvbuf, - sizeof(recvbuf), + buf, + sizeof(buf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time, - &recvlen); + &recvlen + ); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; } diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 8a9e2fe82..a3cb5174a 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -48,8 +48,8 @@ void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader void EmlClearIso15693(void); void SimTagIso15693(uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag -void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag -void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI +void BruteforceIso15693Afi(uint32_t flags); // find an AFI of a tag +void SendRawCommand15693(iso15_raw_cmd_t *packet); // send arbitrary commands from CLI void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool iclass); diff --git a/client/deps/hardnested/hardnested_bruteforce.c b/client/deps/hardnested/hardnested_bruteforce.c index f55d8885a..655ef9dbb 100644 --- a/client/deps/hardnested/hardnested_bruteforce.c +++ b/client/deps/hardnested/hardnested_bruteforce.c @@ -493,6 +493,8 @@ float brute_force_benchmark(void) { if (!read_bench_data(test_candidates)) { PrintAndLogEx(NORMAL, "Couldn't read benchmark data. Assuming brute force rate of %1.0f states per second", DEFAULT_BRUTE_FORCE_RATE); + free(test_candidates[0].states[ODD_STATE]); + free(test_candidates[0].states[EVEN_STATE]); return DEFAULT_BRUTE_FORCE_RATE; } @@ -515,5 +517,3 @@ float brute_force_benchmark(void) { test_candidates[0].len[EVEN_STATE] = 0; return bf_rate; } - - diff --git a/client/luascripts/hf_mf_uid_downgrade.lua b/client/luascripts/hf_mf_uid_downgrade.lua index a8d243888..97988fd1b 100644 --- a/client/luascripts/hf_mf_uid_downgrade.lua +++ b/client/luascripts/hf_mf_uid_downgrade.lua @@ -11,6 +11,9 @@ author = "Adam Foster (evildaemond)" version = 'v0.0.1' desc = [[ Convert a facility code and card number to a Mifare Classic UID, which can be used as part of a downgrade attack. +This abuses the fact that some controllers interpret the UID for Mifare Classic cards as a CN and FN, it requires the controller to interpret the wiegand payload in this way. + +The example of FC 146 CN 5 would be read by the reader and send as a payload like 0920005, where 9200 is dec 146 and 05 is interpreted as 5 Working on HID Readers with any of the following enabled - Generic 14333A diff --git a/client/src/cmddata.c b/client/src/cmddata.c index 8654c8476..ff0257f6d 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -608,11 +608,14 @@ static int Cmdmandecoderaw(const char *Cmd) { uint64_t id = 0; uint32_t hi = 0; size_t idx = 0; - int res = Em410xDecode(bits, &size, &idx, &hi, &id); + size_t tmpsize = 0; + int res = Em410xDecode(bits, &tmpsize, &idx, &hi, &id); if (res > 0) { //need to adjust to set bitstream back to manchester encoded data //setDemodBuff(bits, size, idx); printEM410x(hi, id, false, res); + + size = tmpsize; } } setDemodBuff(bits, size, 0); @@ -2025,7 +2028,7 @@ int CmdTuneSamples(const char *Cmd) { // Q measure with Vlr=Q*(2*Vdd/pi) double lfq2 = (double)package->peak_v * 3.14 / 2 / vdd; - PrintAndLogEx(SUCCESS, "Peak voltage............ " _YELLOW_("%.1lf") , lfq2); + PrintAndLogEx(SUCCESS, "Peak voltage............ " _YELLOW_("%.1lf"), lfq2); // cross-check results if (lfq1 > 3) { double approx_vdd = (double)package->peak_v * 3.14 / 2 / lfq1; @@ -2073,7 +2076,7 @@ int CmdTuneSamples(const char *Cmd) { if (package->v_hf >= HF_UNUSABLE_V) { // Q measure with Vlr=Q*(2*Vdd/pi) double hfq = (double)package->v_hf * 3.14 / 2 / vdd; - PrintAndLogEx(SUCCESS, "peak voltage............ " _YELLOW_("%.1lf") , hfq); + PrintAndLogEx(SUCCESS, "peak voltage............ " _YELLOW_("%.1lf"), hfq); } if (package->v_hf < HF_UNUSABLE_V) @@ -2098,13 +2101,13 @@ int CmdTuneSamples(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------- " _CYAN_("LF tuning graph") " ---------"); PrintAndLogEx(SUCCESS, "Blue line Divisor %d / %.2f kHz" - , LF_DIVISOR_134 - , LF_DIV2FREQ(LF_DIVISOR_134) - ); + , LF_DIVISOR_134 + , LF_DIV2FREQ(LF_DIVISOR_134) + ); PrintAndLogEx(SUCCESS, "Red line Divisor %d / %.2f kHz\n\n" - , LF_DIVISOR_125 - , LF_DIV2FREQ(LF_DIVISOR_125) - ); + , LF_DIVISOR_125 + , LF_DIV2FREQ(LF_DIVISOR_125) + ); g_GraphTraceLen = 256; g_CursorCPos = LF_DIVISOR_125; g_CursorDPos = LF_DIVISOR_134; @@ -3192,7 +3195,7 @@ static int CmdDiff(const char *Cmd) { // dump magic card memory /* if (use_c) { - PrintAndLogEx(WARNING, "not implemented yet, feel free to contribute!"); + PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); return PM3_ENOTIMPL; } */ @@ -3200,21 +3203,41 @@ static int CmdDiff(const char *Cmd) { size_t biggest = (datalenA > datalenB) ? datalenA : datalenB; PrintAndLogEx(DEBUG, "data len: %zu A %zu B %zu", biggest, datalenA, datalenB); - if (inA == NULL) + if (inA == NULL) { PrintAndLogEx(INFO, "inA null"); + } - if (inB == NULL) + if (inB == NULL) { PrintAndLogEx(INFO, "inB null"); + } + + + char hdr0[400] = {0}; int hdr_sln = (width * 4) + 2; - char hdr0[300] = {0}; + int max_fn_space = (width * 4); - int max_fn_space = (width * 5); + if (max_fn_space < fnlenA) { + truncate_filename(filenameA, max_fn_space); + fnlenA = strlen(filenameA); + } + + if (max_fn_space < fnlenB) { + truncate_filename(filenameB, max_fn_space); + fnlenB = strlen(filenameB); + } + + if (fnlenA && fnlenB) { - if (fnlenA && fnlenB && (max_fn_space > fnlenA) && (max_fn_space > fnlenB)) { snprintf(hdr0, sizeof(hdr0) - 1, " # | " _CYAN_("%.*s"), max_fn_space, filenameA); - memset(hdr0 + strlen(hdr0), ' ', hdr_sln - strlen(filenameA) - 1); + + // add space if needed + int padding_len = (hdr_sln - fnlenA - 1); + if (padding_len > 0) { + memset(hdr0 + strlen(hdr0), ' ', padding_len); + } snprintf(hdr0 + strlen(hdr0), sizeof(hdr0) - 1 - strlen(hdr0), "| " _CYAN_("%.*s"), max_fn_space, filenameB); + } else { strcat(hdr0, " # | " _CYAN_("a")); memset(hdr0 + strlen(hdr0), ' ', hdr_sln - 2); @@ -3334,7 +3357,6 @@ static int CmdNumCon(const char *Cmd) { memset(dec, 0, sizeof(dec)); int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)dec, sizeof(dec), &dlen); - int hlen = 256; char hex[256]; memset(hex, 0, sizeof(hex)); @@ -3363,13 +3385,13 @@ static int CmdNumCon(const char *Cmd) { mbedtls_mpi N; mbedtls_mpi_init(&N); - // hex if (hlen > 0) { if (data_verify_hex((uint8_t *)hex, hlen) == false) { return PM3_EINVARG; } MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16, hex)); + PrintAndLogEx(INFO, "Input hex len... %d", hlen); } // decimal @@ -3382,6 +3404,7 @@ static int CmdNumCon(const char *Cmd) { if (blen > 0) { // should have bianry string check here too MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 2, bin)); + PrintAndLogEx(INFO, "Input bin len... %d", blen); } mbedtls_mpi base; diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 361e4deae..690196ace 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -205,11 +205,11 @@ static const manufactureName_t manufactureMapping[] = { // returns description of the best match const char *getTagInfo(uint8_t uid) { - int i; - - for (i = 0; i < ARRAYLEN(manufactureMapping); ++i) - if (uid == manufactureMapping[i].uid) + for (int i = 0; i < ARRAYLEN(manufactureMapping); ++i) { + if (uid == manufactureMapping[i].uid) { return manufactureMapping[i].desc; + } + } //No match, return default return manufactureMapping[ARRAYLEN(manufactureMapping) - 1].desc; @@ -832,7 +832,7 @@ int CmdHF14ASim(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; + PacketResponseNG resp = {0}; sector_t *k_sector = NULL; size_t k_sectors_cnt = MIFARE_4K_MAXSECTOR; @@ -1254,54 +1254,59 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea // ISO14443-4. 7. Half-duplex block transmission protocol static int CmdHF14AAPDU(const char *Cmd) { - uint8_t data[PM3_CMD_DATA_SIZE]; - int datalen = 0; - uint8_t header[PM3_CMD_DATA_SIZE]; - int headerlen = 0; - bool activateField = false; - bool leaveSignalON = false; - bool decodeTLV = false; - bool decodeAPDU = false; - bool makeAPDU = false; - bool extendedAPDU = false; - int le = 0; - CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a apdu", - "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013", - "hf 14a apdu -st 00A404000E325041592E5359532E444446303100\n" - "hf 14a apdu -sd 00A404000E325041592E5359532E444446303100 -> decode apdu\n" - "hf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n" - "hf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n"); + "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL).\n" + "Works with all APDU types from ISO 7816-4:2013\n" + "\n" + "note:\n" + " `-m` and `-d` goes hand in hand\n" + " -m -d 325041592E5359532E4444463031\n" + "\n" + " OR\n" + "\n" + " use `-d` with complete APDU data\n" + " -d 00A404000E325041592E5359532E444446303100", + "hf 14a apdu -st -d 00A404000E325041592E5359532E444446303100\n" + "hf 14a apdu -sd -d 00A404000E325041592E5359532E444446303100 -> decode apdu\n" + "hf 14a apdu -sm 00A40400 -d 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n" + "hf 14a apdu -sm 00A40400 -d 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n"); void *argtable[] = { arg_param_begin, arg_lit0("s", "select", "activate field and select card"), arg_lit0("k", "keep", "keep signal field ON after receive"), - arg_lit0("t", "tlv", "executes TLV decoder if it possible"), - arg_lit0("d", "decapdu", "decode apdu request if it possible"), - arg_str0("m", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), + arg_lit0("t", "tlv", "decode TLV"), + arg_lit0("d", "decapdu", "decode APDU request"), + arg_str0("m", "make", "", "APDU header, 4 bytes "), arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"), - arg_int0("l", "le", "", "Le apdu parameter if `m` parameter included"), - arg_strx1(NULL, NULL, "", "data if `m` parameter included"), + arg_int0("l", "le", "", "Le APDU parameter if `m` parameter included"), + arg_strx1("d", "data", "", "full APDU package or data if `m` parameter included"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - activateField = arg_get_lit(ctx, 1); - leaveSignalON = arg_get_lit(ctx, 2); - decodeTLV = arg_get_lit(ctx, 3); - decodeAPDU = arg_get_lit(ctx, 4); + bool activateField = arg_get_lit(ctx, 1); + bool leaveSignalON = arg_get_lit(ctx, 2); + bool decodeTLV = arg_get_lit(ctx, 3); + bool decodeAPDU = arg_get_lit(ctx, 4); + uint8_t header[PM3_CMD_DATA_SIZE]; + int headerlen = 0; CLIGetHexWithReturn(ctx, 5, header, &headerlen); - makeAPDU = headerlen > 0; + + bool makeAPDU = (headerlen > 0); + if (makeAPDU && headerlen != 4) { PrintAndLogEx(ERR, "header length must be 4 bytes instead of %d", headerlen); CLIParserFree(ctx); return PM3_EINVARG; } - extendedAPDU = arg_get_lit(ctx, 6); - le = arg_get_int_def(ctx, 7, 0); + bool extendedAPDU = arg_get_lit(ctx, 6); + int le = arg_get_int_def(ctx, 7, 0); + + uint8_t data[PM3_CMD_DATA_SIZE]; + int datalen = 0; if (makeAPDU) { uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0}; @@ -1386,35 +1391,35 @@ static int CmdHF14ACmdRaw(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_lit0("a", NULL, "active signal field ON without select"), - arg_int0("b", NULL, "", "number of bits to send. Useful for send partial byte"), - arg_lit0("c", NULL, "calculate and append CRC"), - arg_lit0("k", NULL, "keep signal field ON after receive"), - arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"), - arg_lit0("r", NULL, "do not read response"), - arg_lit0("s", NULL, "active signal field ON with select"), - arg_int0("t", "timeout", "", "timeout in milliseconds"), - arg_lit0("v", "verbose", "Verbose output"), - arg_lit0(NULL, "topaz", "use Topaz protocol to send command"), - arg_lit0(NULL, "ecp", "use enhanced contactless polling"), - arg_lit0(NULL, "mag", "use Apple magsafe polling"), - arg_strx1(NULL, NULL, "", "raw bytes to send"), + arg_lit0("a", NULL, "Active signal field ON without select"), + arg_lit0("c", NULL, "Calculate and append CRC"), + arg_lit0("k", NULL, "Keep signal field ON after receive"), + arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"), + arg_lit0("r", NULL, "Do not read response"), + arg_lit0("s", NULL, "Active signal field ON with select"), + arg_int0("t", "timeout", "", "Timeout in milliseconds"), + arg_int0("b", NULL, "", "Number of bits to send. Useful for send partial byte"), + arg_lit0("v", "verbose", "Verbose output"), + arg_lit0(NULL, "ecp", "Use enhanced contactless polling"), + arg_lit0(NULL, "mag", "Use Apple magsafe polling"), + arg_lit0(NULL, "topaz", "Use Topaz protocol to send command"), + arg_strx1(NULL, NULL, "", "Raw bytes to send"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); bool active = arg_get_lit(ctx, 1); - uint16_t numbits = (uint16_t)arg_get_int_def(ctx, 2, 0); - bool crc = arg_get_lit(ctx, 3); - bool keep_field_on = arg_get_lit(ctx, 4); - bool no_rats = arg_get_lit(ctx, 5); - bool reply = (arg_get_lit(ctx, 6) == false); - bool active_select = arg_get_lit(ctx, 7); - uint32_t timeout = (uint32_t)arg_get_int_def(ctx, 8, 0); + bool crc = arg_get_lit(ctx, 2); + bool keep_field_on = arg_get_lit(ctx, 3); + bool no_rats = arg_get_lit(ctx, 4); + bool reply = (arg_get_lit(ctx, 5) == false); + bool active_select = arg_get_lit(ctx, 6); + uint32_t timeout = (uint32_t)arg_get_int_def(ctx, 7, 0); + uint16_t numbits = (uint16_t)arg_get_int_def(ctx, 8, 0); bool verbose = arg_get_lit(ctx, 9); - bool topazmode = arg_get_lit(ctx, 10); - bool use_ecp = arg_get_lit(ctx, 11); - bool use_magsafe = arg_get_lit(ctx, 12); + bool use_ecp = arg_get_lit(ctx, 10); + bool use_magsafe = arg_get_lit(ctx, 11); + bool topazmode = arg_get_lit(ctx, 12); int datalen = 0; uint8_t data[PM3_CMD_DATA_SIZE_MIX] = {0}; diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 7c416fb86..9ad2e7c00 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -20,19 +20,20 @@ #include #include "iso14b.h" #include "fileutils.h" -#include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN -#include "comms.h" // clearCommandBuffer -#include "emv/emvcore.h" // TLVPrintFromBuffer +#include "cmdparser.h" // command_t +#include "commonutil.h" // ARRAYLEN +#include "comms.h" // clearCommandBuffer +#include "emv/emvcore.h" // TLVPrintFromBuffer #include "cmdtrace.h" #include "cliparser.h" #include "crc16.h" #include "cmdhf14a.h" -#include "protocols.h" // definitions of ISO14B/7816 protocol -#include "iso7816/apduinfo.h" // GetAPDUCodeDescription -#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint +#include "protocols.h" // definitions of ISO14B/7816 protocol +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription +#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint #include "aidsearch.h" -#include "fileutils.h" // saveFile +#include "fileutils.h" // saveFile +#include "iclass_cmd.h" // picopass defines #define MAX_14B_TIMEOUT_MS (4949U) @@ -54,9 +55,6 @@ #define ST25_SIZE_2K 4 #define ST25_SIZE_4K 5 - - - // iso14b apdu input frame length static uint16_t apdu_frame_length = 0; //static uint16_t ats_fsc[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; @@ -76,6 +74,17 @@ static int switch_off_field_14b(void) { return PM3_SUCCESS; } +static int clear_trace_14b(void) { + iso14b_raw_cmd_t packet = { + .flags = ISO14B_CLEARTRACE, + .timeout = 0, + .rawlen = 0, + }; + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); + return PM3_SUCCESS; +} + static void hf14b_aid_search(bool verbose) { json_t *root = AIDSearchInit(verbose); @@ -99,7 +108,7 @@ static void hf14b_aid_search(bool verbose) { uint8_t vaid[200] = {0}; int vaidlen = 0; - if ((AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) == false) || (vaidlen == 0 )) { + if ((AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) == false) || (vaidlen == 0)) { continue; } @@ -210,7 +219,7 @@ static bool wait_14b_response(bool only_first, uint8_t *datalen, uint8_t *data) return false; } - // treat first reponse as same. + // treat first reponse as same. if (only_first) { if (datalen) { @@ -219,7 +228,7 @@ static bool wait_14b_response(bool only_first, uint8_t *datalen, uint8_t *data) if (data) { memcpy(data, resp.data.asBytes, resp.length); - } + } return true; } @@ -258,8 +267,14 @@ static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) { } if (is_select) { + if (resp.status == PM3_ECARDEXCHANGE) { + PrintAndLogEx(INFO, "no response from tag"); + return false; + } if (resp.status != PM3_SUCCESS) { - PrintAndLogEx(INFO, "failed status value... %d", resp.status); + if (verbose) { + PrintAndLogEx(INFO, "failed status value... %d", resp.status); + } return false; } } @@ -295,226 +310,6 @@ static bool wait_cmd_14b(bool verbose, bool is_select, uint32_t timeout) { return true; } -static int CmdHF14BList(const char *Cmd) { - return CmdTraceListAlias(Cmd, "hf 14b", "14b -c"); -} - -static int CmdHF14BSim(const char *Cmd) { - - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf 14b sim", - "Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI", - "hf 14b sim -u 11AA33BB" - ); - - void *argtable[] = { - arg_param_begin, - arg_str1("u", "uid", "hex", "4byte UID/PUPI"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, false); - - uint8_t pupi[4]; - int n = 0; - int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n); - CLIParserFree(ctx); - - if (res) { - PrintAndLogEx(FAILED, "failed to read pupi"); - return PM3_EINVARG; - } - - PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi))); - PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation"); - clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); - return PM3_SUCCESS; -} - -static int CmdHF14BSniff(const char *Cmd) { - - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf 14b sniff", - "Sniff the communication reader and tag", - "hf 14b sniff" - ); - - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - PacketResponseNG resp; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0); - - WaitForResponse(CMD_HF_ISO14443B_SNIFF, &resp); - - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14b list") "` to view captured tracelog"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing"); - return PM3_SUCCESS; -} - -static int CmdHF14BCmdRaw(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf 14b raw", - "Sends raw bytes to card", - "hf 14b raw -cks --data 0200a40400 -> standard select, apdu 0200a4000 (7816)\n" - "hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n" - "hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_lit0("k", "keep", "leave the signal field ON after receive response"), - arg_lit0("s", "std", "activate field, use ISO14B select"), - arg_lit0(NULL, "sr", "activate field, use SRx ST select"), - arg_lit0(NULL, "cts", "activate field, use ASK C-ticket select"), - arg_lit0(NULL, "xrx", "activate field, use Fuji/Xerox select"), - arg_lit0("c", "crc", "calculate and append CRC"), - arg_lit0("r", NULL, "do not read response from card"), - arg_int0("t", "timeout", "", "timeout in ms"), - arg_lit0("v", "verbose", "verbose output"), - arg_str0("d", "data", "", "data, bytes to send"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, false); - - bool keep_field_on = arg_get_lit(ctx, 1); - bool select_std = arg_get_lit(ctx, 2); - bool select_sr = arg_get_lit(ctx, 3); - bool select_cts = arg_get_lit(ctx, 4); - bool select_xrx = arg_get_lit(ctx, 5); - bool add_crc = arg_get_lit(ctx, 6); - bool read_reply = (arg_get_lit(ctx, 7) == false); - int user_timeout = arg_get_int_def(ctx, 8, -1); - bool verbose = arg_get_lit(ctx, 9); - - uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; - int datalen = 0; - int res = CLIParamHexToBuf(arg_get_str(ctx, 10), data, sizeof(data), &datalen); - if (res && verbose) { - PrintAndLogEx(INFO, "called with no raw bytes"); - } - CLIParserFree(ctx); - - // FLAGS for device side - uint32_t flags = ISO14B_CONNECT; - if (add_crc) { - flags |= ISO14B_APPEND_CRC; - } - - if (select_std) { - flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE); - if (verbose) { - PrintAndLogEx(INFO, "using ISO14443-B select"); - } - } else if (select_sr) { - flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE); - if (verbose) { - PrintAndLogEx(INFO, "using ST/SRx select"); - } - } else if (select_cts) { - flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE); - if (verbose) { - PrintAndLogEx(INFO, "using ASK/C-ticket select"); - } - } else if (select_xrx) { - flags |= (ISO14B_SELECT_XRX | ISO14B_CLEARTRACE); - if (verbose) { - PrintAndLogEx(INFO, "using Fuji/Xerox select"); - } - } - - uint32_t time_wait = 0; - if (user_timeout > 0) { - - flags |= ISO14B_SET_TIMEOUT; - - if (user_timeout > MAX_14B_TIMEOUT_MS) { - user_timeout = MAX_14B_TIMEOUT_MS; - PrintAndLogEx(INFO, "set timeout to 4.9 seconds. The max we can wait for response"); - } - - // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) - time_wait = (uint32_t)((13560 / 128) * user_timeout); - if (verbose) - PrintAndLogEx(INFO, " new raw timeout : %u ETU ( %u ms )", time_wait, user_timeout); - } - - if (keep_field_on == false) { - flags |= ISO14B_DISCONNECT; - } - - if (datalen > 0) { - flags |= ISO14B_RAW; - } - - // Max buffer is PM3_CMD_DATA_SIZE - datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; - - - iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + datalen); - if (packet == NULL) { - PrintAndLogEx(FAILED, "failed to allocate memory"); - return PM3_EMALLOC; - } - - packet->flags = flags; - packet->timeout = time_wait; - packet->rawlen = datalen; - memcpy(packet->raw, data, datalen); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen); - free(packet); - - if (read_reply == false) { - clearCommandBuffer(); - return PM3_SUCCESS; - } - - bool success = true; - - // Select, device will send back iso14b_card_select_t, don't print it. - if (select_std) { - success = wait_cmd_14b(verbose, true, user_timeout); - if (verbose && success) { - PrintAndLogEx(SUCCESS, "Got response for standard select"); - } - } - - if (select_sr) { - success = wait_cmd_14b(verbose, true, user_timeout); - if (verbose && success) { - PrintAndLogEx(SUCCESS, "Got response for ST/SRx select"); - } - } - - if (select_cts) { - success = wait_cmd_14b(verbose, true, user_timeout); - if (verbose && success) { - PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select"); - } - } - - if (select_xrx) { - success = wait_cmd_14b(verbose, true, user_timeout); - if (verbose && success) { - PrintAndLogEx(SUCCESS, "Got response for Fuji/Xerox select"); - } - } - - // get back response from the raw bytes you sent. - if (success && datalen > 0) { - wait_cmd_14b(true, false, user_timeout); - } - - return PM3_SUCCESS; -} - static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) { // sanity checks @@ -579,6 +374,30 @@ static bool get_14b_UID(uint8_t *d, iso14b_type_t *found_type) { return false; } +/* extract uid from filename + * filename must match '^hf-14b-[0-9A-F]{16}' + */ +uint8_t *get_uid_from_filename(const char *filename) { + static uint8_t uid[8] ; + memset(uid, 0, 8) ; + char uidinhex[17] ; + if (strlen(filename) < 23 || strncmp(filename, "hf-14b-", 7)) { + PrintAndLogEx(ERR, "can't get uid from filename '%s'. Expected format is hf-14b-...", filename); + return uid ; + } + // extract uid part from filename + strncpy(uidinhex, filename + 7, 16) ; + uidinhex[16] = '\0' ; + int len = hex_to_bytes(uidinhex, uid, 8); + if (len == 8) + return SwapEndian64(uid, 8, 8); + else { + PrintAndLogEx(ERR, "get_uid_from_filename failed: hex_to_bytes returned %d", len); + memset(uid, 0, 8); + } + return uid ; +} + // print full atqb info // bytes // 0,1,2,3 = application data @@ -659,7 +478,7 @@ static const char *get_st25_chip_model(uint8_t id) { return "ST25TB512-AC"; case 0x33: return "ST25TB512-AT"; - case 0x3F: + case 0x3F: return "ST25TB02K"; case 0x1F: return "ST25TB04K"; @@ -846,7 +665,7 @@ static uint8_t get_st_cardsize(const uint8_t *uid) { switch (chipid) { case 0x0: case 0x3: - case 0x7: + case 0x7: return SR_SIZE_4K; case 0x4: case 0x6: @@ -858,6 +677,7 @@ static uint8_t get_st_cardsize(const uint8_t *uid) { } /* + static uint8_t get_st25_cardsize(const uint8_t *uid) { uint8_t chipid = get_st25_chipid(uid); switch (chipid) { @@ -979,6 +799,247 @@ static void print_sr_blocks(uint8_t *data, size_t len, const uint8_t *uid) { // 0200a404000ca000000063504b43532d313500 (resp 02 6a 82 [4b 4c]) // 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c]) +static int CmdHF14BList(const char *Cmd) { + return CmdTraceListAlias(Cmd, "hf 14b", "14b -c"); +} + +static int CmdHF14BSim(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14b sim", + "Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI", + "hf 14b sim -u 11AA33BB" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("u", "uid", "hex", "4byte UID/PUPI"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + uint8_t pupi[4]; + int n = 0; + int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n); + CLIParserFree(ctx); + + if (res) { + PrintAndLogEx(FAILED, "failed to read pupi"); + return PM3_EINVARG; + } + + PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi))); + PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation"); + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); + return PM3_SUCCESS; +} + +static int CmdHF14BSniff(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14b sniff", + "Sniff the communication reader and tag", + "hf 14b sniff" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0); + + WaitForResponse(CMD_HF_ISO14443B_SNIFF, &resp); + + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14b list") "` to view captured tracelog"); + PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing"); + return PM3_SUCCESS; +} + +static int CmdHF14BRaw(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14b raw", + "Sends raw bytes to card. Activates field by default", + "hf 14b raw -cks --data 0200a40400 -> standard select, apdu 0200a4000 (7816)\n" + "hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n" + "hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", NULL, "active signal field ON without select"), + arg_lit0("c", "crc", "calculate and append CRC"), + arg_lit0("k", "keep", "leave the signal field ON after receive response"), + + arg_str0("d", "data", "", "data, bytes to send"), + arg_lit0("r", NULL, "do not read response from card"), + arg_int0("t", "timeout", "", "timeout in ms"), + + arg_lit0("s", "std", "use ISO14B select"), + arg_lit0(NULL, "sr", "use SRx ST select"), + arg_lit0(NULL, "cts", "use ASK C-ticket select"), + arg_lit0(NULL, "xrx", "use Fuji/Xerox select"), + arg_lit0(NULL, "pico", "use Picopass select"), + + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool activate_field = arg_get_lit(ctx, 1); + bool add_crc = arg_get_lit(ctx, 2); + bool keep_field_on = arg_get_lit(ctx, 3); + + uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; + int datalen = 0; + CLIParamHexToBuf(arg_get_str(ctx, 4), data, sizeof(data), &datalen); + + bool read_reply = (arg_get_lit(ctx, 5) == false); + int user_timeout = arg_get_int_def(ctx, 6, -1); + bool select_std = arg_get_lit(ctx, 7); + bool select_sr = arg_get_lit(ctx, 8); + bool select_cts = arg_get_lit(ctx, 9); + bool select_xrx = arg_get_lit(ctx, 10); + bool select_pico = arg_get_lit(ctx, 11); + bool verbose = arg_get_lit(ctx, 12); + CLIParserFree(ctx); + + // FLAGS for device side + uint32_t flags = 0; + + if (activate_field) { + flags |= ISO14B_CONNECT; + } + + if (add_crc) { + flags |= ISO14B_APPEND_CRC; + } + + if (select_std) { + flags |= (ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_CLEARTRACE); + if (verbose) { + PrintAndLogEx(INFO, "using ISO14443-B select"); + } + } else if (select_sr) { + flags |= (ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_CLEARTRACE); + if (verbose) { + PrintAndLogEx(INFO, "using ST/SRx select"); + } + } else if (select_cts) { + flags |= (ISO14B_CONNECT | ISO14B_SELECT_CTS | ISO14B_CLEARTRACE); + if (verbose) { + PrintAndLogEx(INFO, "using ASK/C-ticket select"); + } + } else if (select_xrx) { + flags |= (ISO14B_CONNECT | ISO14B_SELECT_XRX | ISO14B_CLEARTRACE); + if (verbose) { + PrintAndLogEx(INFO, "using Fuji/Xerox select"); + } + } else if (select_pico) { + flags |= (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_CLEARTRACE); + if (verbose) { + PrintAndLogEx(INFO, "using Picopass select"); + } + } + + uint32_t time_wait = 0; + if (user_timeout > 0) { + + flags |= ISO14B_SET_TIMEOUT; + + if (user_timeout > MAX_14B_TIMEOUT_MS) { + user_timeout = MAX_14B_TIMEOUT_MS; + PrintAndLogEx(INFO, "set timeout to 4.9 seconds. The max we can wait for response"); + } + + // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) + time_wait = (uint32_t)((13560 / 128) * user_timeout); + if (verbose) + PrintAndLogEx(INFO, " new raw timeout : %u ETU ( %u ms )", time_wait, user_timeout); + } + + if (keep_field_on == false) { + flags |= ISO14B_DISCONNECT; + } + + if (datalen > 0) { + flags |= ISO14B_RAW; + } + + // Max buffer is PM3_CMD_DATA_SIZE + datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; + + iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + datalen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + packet->flags = flags; + packet->timeout = time_wait; + packet->rawlen = datalen; + memcpy(packet->raw, data, datalen); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen); + free(packet); + + if (read_reply == false) { + clearCommandBuffer(); + return PM3_SUCCESS; + } + + bool success = true; + + // Select, device will send back iso14b_card_select_t, don't print it. + if (select_std) { + success = wait_cmd_14b(verbose, true, user_timeout); + if (verbose && success) { + PrintAndLogEx(SUCCESS, "Got response for standard select"); + } + } + + if (select_sr) { + success = wait_cmd_14b(verbose, true, user_timeout); + if (verbose && success) { + PrintAndLogEx(SUCCESS, "Got response for ST/SRx select"); + } + } + + if (select_cts) { + success = wait_cmd_14b(verbose, true, user_timeout); + if (verbose && success) { + PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select"); + } + } + + if (select_xrx) { + success = wait_cmd_14b(verbose, true, user_timeout); + if (verbose && success) { + PrintAndLogEx(SUCCESS, "Got response for Fuji/Xerox select"); + } + } + + if (select_pico) { + success = wait_cmd_14b(verbose, true, user_timeout); + if (verbose && success) { + PrintAndLogEx(SUCCESS, "Got response for Picopass select"); + } + } + + // get back response from the raw bytes you sent. + if (success && datalen > 0) { + wait_cmd_14b(true, false, user_timeout); + } + + return PM3_SUCCESS; +} + // 14b get and print Full Info (as much as we know) static bool HF14B_Std_Info(bool verbose, bool do_aid_search) { // 14b get and print UID only (general info) @@ -1137,9 +1198,9 @@ static int write_sr_block(uint8_t blockno, uint8_t datalen, uint8_t *data) { free(packet); if (wait_14b_response(true, NULL, NULL) == false) { - PrintAndLogEx(FAILED, "SRx write block ( " _RED_("failed") " )" ); + PrintAndLogEx(FAILED, "SRx write block ( " _RED_("failed") " )"); return PM3_ESOFT; - } + } return PM3_SUCCESS; } @@ -1163,7 +1224,7 @@ static bool HF14B_st_reader(bool verbose) { } switch (resp.status) { - case PM3_SUCCESS:{ + case PM3_SUCCESS: { iso14b_card_select_t card; memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); @@ -1278,6 +1339,53 @@ static bool HF14B_ask_ct_reader(bool verbose) { return false; } +static bool HF14B_picopass_reader(bool verbose) { + + iso14b_raw_cmd_t packet = { + .flags = (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_DISCONNECT), + .timeout = 0, + .rawlen = 0, + }; + + // 14b get and print UID only (general info) + clearCommandBuffer(); + PacketResponseNG resp; + SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); + return false; + } + + switch (resp.status) { + case PM3_SUCCESS: { + + picopass_hdr_t *card = calloc(1, sizeof(picopass_hdr_t)); + if (card == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return false; + } + memcpy(card, resp.data.asBytes, sizeof(picopass_hdr_t)); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn))); + free(card); + return true; + } + case PM3_ELENGTH: { + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 wrong length"); + break; + } + case PM3_ECRC: { + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); + break; + } + default: { + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b Picopass select failed"); + break; + } + } + return false; +} + // test for other 14b type tags (mimic another reader - don't have tags to identify) static bool HF14B_other_reader(bool verbose) { @@ -1297,7 +1405,7 @@ static bool HF14B_other_reader(bool verbose) { SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen); // wait for the select message and wait for response - if (wait_14b_response(false, NULL, NULL) ) { + if (wait_14b_response(false, NULL, NULL)) { PrintAndLogEx(SUCCESS, "\n14443-3b tag found:"); PrintAndLogEx(SUCCESS, "unknown tag type answered to a " _YELLOW_("0x000b3f80") " command"); switch_off_field_14b(); @@ -1357,6 +1465,8 @@ static int CmdHF14BReader(const char *Cmd) { PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); } + clear_trace_14b(); + return readHF14B(cm, verbose); } @@ -1406,7 +1516,7 @@ static int CmdHF14BSriRdBl(const char *Cmd) { } // New command to write a SRI512/SRIX4K tag. -static int CmdHF14BWriteSri(const char *Cmd) { +static int CmdHF14BSriWrbl(const char *Cmd) { /* * For SRIX4K blocks 00 - 7F * hf 14b raw --sr -c --data [09 $srix4kwblock $srix4kwdata @@ -1419,13 +1529,14 @@ static int CmdHF14BWriteSri(const char *Cmd) { */ CLIParserContext *ctx; - CLIParserInit(&ctx, "hf 14b sriwrite", + CLIParserInit(&ctx, "hf 14b wrbl", "Write data to a SRI512 or SRIX4K block\n" - "If writing to a block out-of-range, use --force to override checks", - "hf 14b sriwrite --4k -b 100 -d 11223344\n" - "hf 14b sriwrite --4k --sb -d 11223344 --> special block write\n" - "hf 14b sriwrite --512 -b 15 -d 11223344\n" - "hf 14b sriwrite --512 --sb -d 11223344 --> special block write\n" + "If writing to a block out-of-range, use `--force` to override checks\n" + "Special block at end denots OTP and lock bits among others", + "hf 14b wrbl --4k -b 100 -d 11223344\n" + "hf 14b wrbl --4k --sb -d 11223344 --> special block write\n" + "hf 14b wrbl --512 -b 15 -d 11223344\n" + "hf 14b wrbl --512 --sb -d 11223344 --> special block write\n" ); void *argtable[] = { @@ -1508,7 +1619,7 @@ static int CmdHF14BWriteSri(const char *Cmd) { status = read_sr_block(blockno, out); if (status == PM3_SUCCESS) { if (memcmp(data, out, 4) == 0) { - PrintAndLogEx(SUCCESS, "SRx write block ( " _GREEN_("ok") " )" ); + PrintAndLogEx(SUCCESS, "SRx write block ( " _GREEN_("ok") " )"); } } else { PrintAndLogEx(INFO, "Verifying block ( " _RED_("failed") " )"); @@ -1713,16 +1824,38 @@ static uint32_t srix4kEncode(uint32_t value) { uint8_t block = (value & 0xFF); uint8_t i = 0; uint8_t valuebytes[] = {0, 0, 0}; + Uint3byteToMemBe(valuebytes, value >> 8); - num_to_bytes(value, 3, valuebytes); + uint32_t value_x = (value >> 8); + PrintAndLogEx(INFO, "value...... %08x %06x", value, value_x); + PrintAndLogEx(INFO, "3b value... %s", sprint_hex_inrow(valuebytes, sizeof(valuebytes))); + PrintAndLogEx(INFO, "block no... %02x", block); // Scrambled part // Crumb swapping of value. - uint8_t temp[] = {0, 0}; - temp[0] = (CRUMB(value, 22) << 4 | CRUMB(value, 14) << 2 | CRUMB(value, 6)) << 4; - temp[0] |= CRUMB(value, 20) << 4 | CRUMB(value, 12) << 2 | CRUMB(value, 4); - temp[1] = (CRUMB(value, 18) << 4 | CRUMB(value, 10) << 2 | CRUMB(value, 2)) << 4; - temp[1] |= CRUMB(value, 16) << 4 | CRUMB(value, 8) << 2 | CRUMB(value, 0); + uint32_t foo = 0; + foo |= CRUMB(value_x, 22) << 28; + foo |= CRUMB(value_x, 14) << 26; + foo |= CRUMB(value_x, 6) << 24; + + foo |= CRUMB(value_x, 20) << 20; + foo |= CRUMB(value_x, 12) << 18; + foo |= CRUMB(value_x, 4) << 16; + + foo |= CRUMB(value_x, 18) << 12; + foo |= CRUMB(value_x, 10) << 10; + foo |= CRUMB(value_x, 2) << 8; + + foo |= CRUMB(value_x, 16) << 4; + foo |= CRUMB(value_x, 8) << 2; + foo |= CRUMB(value_x, 0) << 0; + + PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 22), CRUMB(value_x, 14), CRUMB(value_x, 6)); + PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 20), CRUMB(value_x, 12), CRUMB(value_x, 4)); + PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 18), CRUMB(value_x, 10), CRUMB(value_x, 2)); + PrintAndLogEx(INFO, "hex........ %02x %02x %02x", CRUMB(value_x, 16), CRUMB(value_x, 8), CRUMB(value_x, 0)); + + PrintAndLogEx(INFO, "hex........ %08x", foo); // chksum part uint32_t chksum = 0xFF - block; @@ -1740,9 +1873,11 @@ static uint32_t srix4kEncode(uint32_t value) { base4[i--] = (chksum % 4 << 2); chksum /= 4; } + PrintAndLogEx(INFO, "%s", sprint_hex_inrow(base4, sizeof(base4))); // merge scambled and chksum parts - uint32_t encvalue = + uint32_t encvalue = 0; + (NIBBLE_LOW(base4[0]) << 28) | (NIBBLE_HIGH(temp[0]) << 24) | @@ -1758,7 +1893,14 @@ static uint32_t srix4kEncode(uint32_t value) { PrintAndLogEx(NORMAL, "ICE encoded | %08X -> %08X", value, encvalue); return encvalue; } +*/ +static uint32_t srix4k_decode_counter(uint32_t num) { + uint32_t value = ~num; + ++value; + return value; +} +/* static uint32_t srix4kDecode(uint32_t value) { switch (value) { case 0xC04F42C5: @@ -1770,19 +1912,16 @@ static uint32_t srix4kDecode(uint32_t value) { } return 0; } +*/ -static uint32_t srix4kDecodeCounter(uint32_t num) { - uint32_t value = ~num; - ++value; - return value; -} - -static uint32_t srix4kGetMagicbytes(uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19) { +static uint32_t srix4k_get_magicbytes(uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19) { #define MASK 0xFFFFFFFF; uint32_t uid32 = uid & MASK; - uint32_t counter = srix4kDecodeCounter(block6); - uint32_t decodedBlock18 = srix4kDecode(block18); - uint32_t decodedBlock19 = srix4kDecode(block19); + uint32_t counter = srix4k_decode_counter(block6); + uint32_t decodedBlock18 = 0; + uint32_t decodedBlock19 = 0; +// uint32_t decodedBlock18 = srix4kDecode(block18); +// uint32_t decodedBlock19 = srix4kDecode(block19); uint32_t doubleBlock = (decodedBlock18 << 16 | decodedBlock19) + 1; uint32_t result = (uid32 * doubleBlock * counter) & MASK; @@ -1790,8 +1929,19 @@ static uint32_t srix4kGetMagicbytes(uint64_t uid, uint32_t block6, uint32_t bloc return result; } -static int srix4kValid(const char *Cmd) { - (void)Cmd; // Cmd is not used so far +static int CmdSRIX4kValid(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14b valid", + "SRIX checksum test", + "hf 14b valid\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIParserFree(ctx); uint64_t uid = 0xD00202501A4532F9; uint32_t block6 = 0xFFFFFFFF; @@ -1799,23 +1949,22 @@ static int srix4kValid(const char *Cmd) { uint32_t block19 = 0xC1484807; uint32_t block21 = 0xD1BCABA4; - uint32_t test_b18 = 0x00313918; - uint32_t test_b18_enc = srix4kEncode(test_b18); - //uint32_t test_b18_dec = srix4kDecode(test_b18_enc); + uint32_t test_b18 = 0x001A2001; // 0x00313918; + uint32_t test_b18_enc = 0; + // uint32_t test_b18_enc = srix4kEncode(test_b18); + // uint32_t test_b18_dec = srix4kDecode(test_b18_enc); PrintAndLogEx(SUCCESS, "ENCODE & CHECKSUM | %08X -> %08X (%s)", test_b18, test_b18_enc, ""); - uint32_t magic = srix4kGetMagicbytes(uid, block6, block18, block19); + uint32_t magic = srix4k_get_magicbytes(uid, block6, block18, block19); PrintAndLogEx(SUCCESS, "BLOCK 21 | %08X -> %08X (no XOR)", block21, magic ^ block21); - return 0; + return PM3_SUCCESS; } -*/ int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { if (card) { memset(card, 0, sizeof(iso14b_card_select_t)); } - SetAPDULogging(true); switch_off_field_14b(); iso14b_raw_cmd_t packet = { @@ -1827,14 +1976,14 @@ int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { PacketResponseNG resp; SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { - PrintAndLogEx(INFO, "Trying 14B Select SRx"); + PrintAndLogEx(INFO, "Trying 14B Select SRx"); // Anticollision + SELECT SR card packet.flags = (ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_CLEARTRACE); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { - PrintAndLogEx(INFO, "Trying 14B Select CTS"); + PrintAndLogEx(INFO, "Trying 14B Select CTS"); // Anticollision + SELECT ASK C-Ticket card packet.flags = (ISO14B_CONNECT | ISO14B_SELECT_CTS | ISO14B_CLEARTRACE); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); @@ -1891,7 +2040,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, PrintAndLogEx(FAILED, "APDU: failed to allocate memory"); return PM3_EMALLOC; } - packet->flags = (ISO14B_CONNECT | ISO14B_APDU); + packet->flags = (ISO14B_APDU); packet->timeout = 0; packet->rawlen = 0; @@ -1927,7 +2076,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, return PM3_ETIMEOUT; } - if ( resp.status != PM3_SUCCESS) { + if (resp.status != PM3_SUCCESS) { PrintAndLogEx(ERR, "APDU: no APDU response"); return resp.status; } @@ -1959,7 +2108,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, PrintAndLogEx(ERR, "APDU: small APDU response, len " _RED_("%d"), apdu->datalen); return PM3_ESOFT; } - + // copy to output array memcpy(dataout, apdu->data, dlen); @@ -2020,7 +2169,6 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, } while (clen < datainlen); } else { - res = handle_14b_apdu(false, datain, datainlen, activate_field, dataout, maxdataoutlen, dataoutlen, &chaining, user_timeout); if (res != PM3_SUCCESS) { if (leave_signal_on == false) { @@ -2050,18 +2198,6 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, // ISO14443-4. 7. Half-duplex block transmission protocol static int CmdHF14BAPDU(const char *Cmd) { - uint8_t data[PM3_CMD_DATA_SIZE]; - int datalen = 0; - uint8_t header[PM3_CMD_DATA_SIZE]; - int headerlen = 0; - bool activate_field = false; - bool leave_signal_on = false; - bool decode_TLV = false; - bool decode_APDU = false; - bool make_APDU = false; - bool extended_APDU = false; - int le = 0; - CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b apdu", "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL).\n" @@ -2087,21 +2223,27 @@ static int CmdHF14BAPDU(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - activate_field = arg_get_lit(ctx, 1); - leave_signal_on = arg_get_lit(ctx, 2); - decode_TLV = arg_get_lit(ctx, 3); - decode_APDU = arg_get_lit(ctx, 4); + bool activate_field = arg_get_lit(ctx, 1); + bool leave_signal_on = arg_get_lit(ctx, 2); + bool decode_TLV = arg_get_lit(ctx, 3); + bool decode_APDU = arg_get_lit(ctx, 4); + uint8_t header[PM3_CMD_DATA_SIZE] = {0x00}; + int headerlen = 0; CLIGetHexWithReturn(ctx, 5, header, &headerlen); - make_APDU = headerlen > 0; + + bool make_APDU = (headerlen > 0); if (make_APDU && headerlen != 4) { - PrintAndLogEx(ERR, "header length must be 4 bytes instead of %d", headerlen); + PrintAndLogEx(ERR, "header length must be 4 bytes, got " _RED_("%d"), headerlen); CLIParserFree(ctx); return PM3_EINVARG; } - extended_APDU = arg_get_lit(ctx, 6); - le = arg_get_int_def(ctx, 7, 0); + bool extended_APDU = arg_get_lit(ctx, 6); + int le = arg_get_int_def(ctx, 7, 0); + + uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; + int datalen = 0; if (make_APDU) { uint8_t apdudata[PM3_CMD_DATA_SIZE] = {0}; @@ -2145,10 +2287,10 @@ static int CmdHF14BAPDU(const char *Cmd) { int user_timeout = arg_get_int_def(ctx, 9, -1); CLIParserFree(ctx); - PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", + PrintAndLogEx(INFO, ">>>> %s%s%s >>>> " _YELLOW_("%s"), activate_field ? "sel" : "", - leave_signal_on ? " keep" : "", - decode_TLV ? " TLV" : "", + leave_signal_on ? "| keep" : "", + decode_TLV ? "| TLV" : "", sprint_hex(data, datalen) ); @@ -2165,8 +2307,12 @@ static int CmdHF14BAPDU(const char *Cmd) { return res; } - PrintAndLogEx(NORMAL, "<<<< %s", sprint_hex(data, datalen)); - PrintAndLogEx(SUCCESS, "APDU response: " _YELLOW_("%02x %02x") " - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])); + PrintAndLogEx(INFO, "<<<< %s", sprint_hex(data, datalen)); + PrintAndLogEx(SUCCESS, "APDU response: " _YELLOW_("%02x %02x") " - %s" + , data[datalen - 2] + , data[datalen - 1] + , GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]) + ); // TLV decoder if (decode_TLV && datalen > 4) { @@ -2293,30 +2439,6 @@ out: return res; } -/* extract uid from filename - * filename must match '^hf-14b-[0-9A-F]{16}' - */ -uint8_t *get_uid_from_filename(const char *filename) { - static uint8_t uid[8] ; - memset(uid, 0, 8) ; - char uidinhex[17] ; - if (strlen(filename) < 23 || strncmp(filename, "hf-14b-", 7)) { - PrintAndLogEx(ERR, "can't get uid from filename '%s'. Expected format is hf-14b-...", filename); - return uid ; - } - // extract uid part from filename - strncpy(uidinhex, filename + 7, 16) ; - uidinhex[16] = '\0' ; - int len = hex_to_bytes(uidinhex, uid, 8); - if (len == 8) - return SwapEndian64(uid, 8, 8); - else { - PrintAndLogEx(ERR, "get_uid_from_filename failed: hex_to_bytes returned %d", len); - memset(uid, 0, 8); - } - return uid ; -} - static int CmdHF14BView(const char *Cmd) { CLIParserContext *ctx; @@ -2342,8 +2464,8 @@ static int CmdHF14BView(const char *Cmd) { // read dump file uint8_t *dump = NULL; - size_t bytes_read = 0; - int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (ST25TB_SR_BLOCK_SIZE * 0xFF)); + size_t bytes_read = (ST25TB_SR_BLOCK_SIZE * 0x100); + int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (ST25TB_SR_BLOCK_SIZE * 0x100)); if (res != PM3_SUCCESS) { return res; } @@ -2351,7 +2473,6 @@ static int CmdHF14BView(const char *Cmd) { uint16_t block_cnt = bytes_read / ST25TB_SR_BLOCK_SIZE; if (verbose) { - PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename); PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt); } @@ -2366,21 +2487,22 @@ static int CmdHF14BView(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"}, - {"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO-14443-B tag, save to file"}, - {"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"}, - {"list", CmdHF14BList, AlwaysAvailable, "List ISO-14443-B history"}, - {"ndefread", CmdHF14BNdefRead, IfPm3Iso14443b, "Read NDEF file on tag"}, - {"raw", CmdHF14BCmdRaw, IfPm3Iso14443b, "Send raw hex data to tag"}, - {"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a ISO-14443-B reader to identify a tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"list", CmdHF14BList, AlwaysAvailable, "List ISO-14443-B history"}, + {"---------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("general") " -----------------------"}, + {"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"}, + {"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO-14443-B tag, save to file"}, + {"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"}, + {"ndefread", CmdHF14BNdefRead, IfPm3Iso14443b, "Read NDEF file on tag"}, + {"raw", CmdHF14BRaw, IfPm3Iso14443b, "Send raw hex data to tag"}, + {"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4 block"}, + {"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a ISO-14443-B reader to identify a tag"}, // {"restore", CmdHF14BRestore, IfPm3Iso14443b, "Restore from file to all memory pages of an ISO-14443-B tag"}, - {"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO ISO-14443-B tag"}, - {"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO-14443-B"}, - {"rdbl", CmdHF14BSriRdBl, IfPm3Iso14443b, "Read SRI512/SRIX4x block"}, - {"sriwrite", CmdHF14BWriteSri, IfPm3Iso14443b, "Write data to a SRI512 or SRIX4K tag"}, - {"view", CmdHF14BView, AlwaysAvailable, "Display content from tag dump file"}, -// {"valid", srix4kValid, AlwaysAvailable, "srix4k checksum test"}, + {"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO ISO-14443-B tag"}, + {"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO-14443-B"}, + {"wrbl", CmdHF14BSriWrbl, IfPm3Iso14443b, "Write data to a SRI512/SRIX4 tag"}, + {"view", CmdHF14BView, AlwaysAvailable, "Display content from tag dump file"}, + {"valid", CmdSRIX4kValid, AlwaysAvailable, "SRIX4 checksum test"}, {NULL, NULL, NULL, NULL} }; @@ -2432,6 +2554,13 @@ int readHF14B(bool loop, bool verbose) { else if (found) return PM3_SUCCESS; + // Picopass + found |= HF14B_picopass_reader(verbose) ; + if (found && loop) + continue; + else if (found) + return PM3_SUCCESS; + // try ASK CT 14b found |= HF14B_ask_ct_reader(verbose); if (found && loop) diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 6072c57b7..8095d4732 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -29,19 +29,20 @@ // variant, but offers the possibility to analyze the waveforms directly. #include "cmdhf15.h" #include -#include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN -#include "comms.h" // clearCommandBuffer +#include "cmdparser.h" // command_t +#include "commonutil.h" // ARRAYLEN +#include "comms.h" // clearCommandBuffer #include "cmdtrace.h" -#include "iso15693tools.h" // ISO15693 error codes etc -#include "protocols.h" // ISO15693 command set +#include "iso15693tools.h" // ISO15693 error codes etc +#include "protocols.h" // ISO15693 command set #include "crypto/libpcrypto.h" #include "graph.h" -#include "crc16.h" // iso15 crc -#include "cmddata.h" // getsamples -#include "fileutils.h" // pm3_save_dump +#include "crc16.h" // iso15 crc +#include "cmddata.h" // getsamples +#include "fileutils.h" // pm3_save_dump #include "cliparser.h" -#include "util_posix.h" // msleep +#include "util_posix.h" // msleep +#include "iso15.h" // typedef structs / enum #define FrameSOF Iso15693FrameSOF #define Logic0 Iso15693Logic0 @@ -60,6 +61,42 @@ #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) #endif +#ifndef ISO15_RAW_LEN +#define ISO15_RAW_LEN(x) (sizeof(iso15_raw_cmd_t) + (x)) +#endif + + +#ifndef ISO15_ERROR_HANDLING_RESPONSE +#define ISO15_ERROR_HANDLING_RESPONSE { \ + if (resp.status == PM3_ETEAROFF) { \ + return resp.status; \ + } \ + if (resp.length < 2) { \ + PrintAndLogEx(ERR, "iso15693 command failed"); \ + return PM3_EWRONGANSWER; \ + } \ +} +#endif + +#ifndef ISO15_ERROR_HANDLING_CARD_RESPONSE +#define ISO15_ERROR_HANDLING_CARD_RESPONSE(data, len) { \ + if ((check_crc(CRC_15693, (data), (len))) == false) { \ + PrintAndLogEx(FAILED, "crc ( " _RED_("fail") " )"); \ + return PM3_ECRC; \ + } \ + \ + if ((d[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { \ + \ + if (data[1] == 0x0F || data[1] == 0x10) { \ + return PM3_EOUTOFBOUND; \ + } \ + \ + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", d[0], TagErrorStr(d[0])); \ + return PM3_EWRONGANSWER; \ + } \ +} +#endif + typedef struct { uint8_t lock; uint8_t block[8]; @@ -168,6 +205,7 @@ static const productName_t uidmapping[] = { { 0xE016240000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 09] 23,5pF CustomerID-102"}, { 0xE016280000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 10] 23,5pF (1Kb flash memory - not provide High Security mode and QuietStorage feature)" }, { 0xE0163C0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 15] 23,5pF"}, + { 0xE016780000000000LL, 24, "EM-Marin SA (Skidata); EM4425 Echo V (dual tech)"}, { 0xE0167C0000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 31] 95pF"}, { 0xE016940000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 37] 95pF 51x64bit "}, { 0xE0169c0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 39] 95pF (Read/Write)" }, @@ -278,7 +316,7 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { }; */ - uint8_t revuid[8] = {0}; + uint8_t revuid[HF15_UID_LENGTH] = {0}; reverse_array_copy(uid, sizeof(revuid), revuid); uint8_t revsign[32] = {0}; @@ -420,24 +458,29 @@ static const char *TagErrorStr(uint8_t error) { // fast method to just read the UID of a tag (collision detection not supported) // *buf should be large enough to fit the 64bit uid // returns 1 if succeeded -static int getUID(bool loop, uint8_t *buf) { +static int getUID(bool verbose, bool loop, uint8_t *buf) { - uint8_t data[5]; - data[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; - data[1] = ISO15693_INVENTORY; - data[2] = 0; // mask length - - AddCrc15(data, 3); + uint8_t approxlen = 5; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } // params - uint8_t fast = 1; - uint8_t reply = 1; + packet->raw[packet->rawlen++] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + packet->raw[packet->rawlen++] = ISO15693_INVENTORY; + packet->raw[packet->rawlen++] = 0; // mask length + + AddCrc15(packet->raw, 3); + packet->rawlen += 2; + + packet->flags = (ISO15_CONNECT | ISO15_HIGH_SPEED | ISO15_READ_RESPONSE); int res = PM3_ESOFT; - do { clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, sizeof(data), fast, reply, data, sizeof(data)); + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000)) { @@ -447,12 +490,11 @@ static int getUID(bool loop, uint8_t *buf) { memcpy(buf, resp.data.asBytes + 2, 8); } - DropField(); - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL, buf)); - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("%s"), getTagInfo_15(buf)); - + if (verbose) { + PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%s"), iso15693_sprintUID(NULL, buf)); + PrintAndLogEx(SUCCESS, "TYPE... " _YELLOW_("%s"), getTagInfo_15(buf)); + PrintAndLogEx(NORMAL, ""); + } res = PM3_SUCCESS; if (loop == false) { @@ -462,15 +504,17 @@ static int getUID(bool loop, uint8_t *buf) { } } while (loop && kbd_enter_pressed() == false); - DropField(); + free(packet); return res; } // used with 'hf search' bool readHF15Uid(bool loop, bool verbose) { - uint8_t uid[8] = {0}; - if (getUID(loop, uid) != PM3_SUCCESS) { - if (verbose) PrintAndLogEx(WARNING, "no tag found"); + uint8_t uid[HF15_UID_LENGTH] = {0}; + if (getUID(verbose, loop, uid) != PM3_SUCCESS) { + if (verbose) { + PrintAndLogEx(WARNING, "no tag found"); + } return false; } return true; @@ -479,7 +523,7 @@ bool readHF15Uid(bool loop, bool verbose) { // adds 6 static uint8_t arg_add_default(void *at[]) { at[0] = arg_param_begin; - at[1] = arg_str0("u", "uid", "", "full UID, 8 bytes"); + at[1] = arg_str0("u", "uid", "", "full UID (8 hex bytes)"); at[2] = arg_lit0(NULL, "ua", "unaddressed mode"); at[3] = arg_lit0("*", NULL, "scan for tag"); at[4] = arg_lit0("2", NULL, "use slower '1 out of 256' mode"); @@ -526,7 +570,7 @@ static int CmdHF15Demod(const char *Cmd) { int skip = 4; if (g_GraphTraceLen < 1000) { - PrintAndLogEx(FAILED, "Too few samples in GraphBuffer. Need more than 1000"); + PrintAndLogEx(FAILED, "Too few samples in GraphBuffer"); PrintAndLogEx(HINT, "Run " _YELLOW_("`hf 15 samples`") " to collect and download data"); return PM3_ESOFT; } @@ -547,17 +591,22 @@ static int CmdHF15Demod(const char *Cmd) { i = maxPos + ARRAYLEN(FrameSOF) / skip; int k = 0; + uint8_t mask = 0x01; + uint8_t outBuf[2048] = {0}; memset(outBuf, 0, sizeof(outBuf)); - uint8_t mask = 0x01; + for (;;) { + int corr0 = 0, corr1 = 0, corrEOF = 0; for (j = 0; j < ARRAYLEN(Logic0); j += skip) { corr0 += Logic0[j] * g_GraphBuffer[i + (j / skip)]; } + for (j = 0; j < ARRAYLEN(Logic1); j += skip) { corr1 += Logic1[j] * g_GraphBuffer[i + (j / skip)]; } + for (j = 0; j < ARRAYLEN(FrameEOF); j += skip) { corrEOF += FrameEOF[j] * g_GraphBuffer[i + (j / skip)]; } @@ -593,7 +642,7 @@ static int CmdHF15Demod(const char *Cmd) { } if (mask != 0x01) { - PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)"); + PrintAndLogEx(WARNING, "Warning, discarding extra bits!"); PrintAndLogEx(INFO, " mask = %02x", mask); } @@ -603,7 +652,7 @@ static int CmdHF15Demod(const char *Cmd) { i = 0; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Got %d octets, decoded as following", k); + PrintAndLogEx(INFO, "Got %d bytes, decoded as following", k); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, " idx | data"); PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------"); @@ -648,88 +697,110 @@ static int CmdHF15Samples(const char *Cmd) { getSamples(0, true); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 15 demod") "` to decode signal"); + PrintAndLogEx(INFO, "Done!"); return PM3_SUCCESS; } static int NxpTestEAS(uint8_t *uid) { - uint8_t fast = 1; - uint8_t reply = 1; - PacketResponseNG resp; - uint16_t reqlen = 0; - uint8_t req[PM3_CMD_DATA_SIZE] = {0}; - req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; - req[reqlen++] = ISO15693_EAS_ALARM; - req[reqlen++] = 0x04; // IC manufacturer code - memcpy(req + 3, uid, 8); // add UID - reqlen += 8; + if (uid == NULL) { + return PM3_EINVARG; + } - AddCrc15(req, reqlen); - reqlen += 2; + uint8_t approxlen = 3 + 8 + 2; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + // params + packet->raw[packet->rawlen++] = (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS); + packet->raw[packet->rawlen++] = ISO15693_EAS_ALARM; + packet->raw[packet->rawlen++] = 0x04; // IC manufacturer code + + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); // add UID + packet->rawlen += HF15_UID_LENGTH; + + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; + + packet->flags = (ISO15_CONNECT | ISO15_HIGH_SPEED | ISO15_READ_RESPONSE); clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen); - + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + free(packet); + PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { PrintAndLogEx(DEBUG, "iso15693 timeout"); - } else { - PrintAndLogEx(INFO, ""); - if (resp.length < 2) { - PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is not active"); - } else { - uint8_t *recv = resp.data.asBytes; + return PM3_ETIMEOUT; + } - if (!(recv[0] & ISO15_RES_ERROR)) { - PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is active."); - PrintAndLogEx(INFO, " EAS sequence: %s", sprint_hex(recv + 1, 32)); - } + PrintAndLogEx(INFO, ""); + if (resp.length < 2) { + PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is not active"); + } else { + uint8_t *d = resp.data.asBytes; + if ((d[0] & ISO15_RES_ERROR) != ISO15_RES_ERROR) { + PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is active."); + PrintAndLogEx(INFO, " EAS sequence: %s", sprint_hex(d + 1, 32)); } } return PM3_SUCCESS; } static int NxpCheckSig(uint8_t *uid) { - uint8_t fast = 1; - uint8_t reply = 1; - PacketResponseNG resp; - uint16_t reqlen = 0; - uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + if (uid == NULL) { + return PM3_EINVARG; + } + + uint8_t approxlen = 13; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + // params // Check if we can also read the signature - req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; - req[reqlen++] = ISO15693_READ_SIGNATURE; - req[reqlen++] = 0x04; // IC manufacturer code - memcpy(req + 3, uid, 8); // add UID - reqlen += 8; + packet->raw[packet->rawlen++] = (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS); + packet->raw[packet->rawlen++] = ISO15693_READ_SIGNATURE; + packet->raw[packet->rawlen++] = 0x04; // IC manufacturer code - AddCrc15(req, reqlen); - reqlen += 2; + memcpy(packet->raw + 3, uid, HF15_UID_LENGTH); // add UID + packet->rawlen += HF15_UID_LENGTH; + + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; + + packet->flags = (ISO15_CONNECT | ISO15_HIGH_SPEED | ISO15_READ_RESPONSE); clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen); + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + free(packet); + PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { PrintAndLogEx(DEBUG, "iso15693 timeout"); - DropField(); return PM3_ETIMEOUT; } - DropField(); + if (resp.status == PM3_ETEAROFF) { + return resp.status; + } if (resp.length < 2) { PrintAndLogEx(WARNING, "iso15693 card doesn't answer to READ SIGNATURE command"); return PM3_EWRONGANSWER; } - uint8_t *recv = resp.data.asBytes; + uint8_t *d = resp.data.asBytes; - if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { - PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return PM3_EWRONGANSWER; - } + ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length) uint8_t signature[32] = {0x00}; - memcpy(signature, recv + 1, sizeof(signature)); + memcpy(signature, d + 1, sizeof(signature)); nxp_15693_print_signature(uid, signature); return PM3_SUCCESS; @@ -742,30 +813,34 @@ static int NxpSysInfo(uint8_t *uid) { return PM3_EINVARG; } - uint8_t req[PM3_CMD_DATA_SIZE] = {0}; - uint8_t fast = 1; - uint8_t reply = 1; - uint16_t reqlen = 0; - - req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; - req[reqlen++] = ISO15693_GET_NXP_SYSTEM_INFO; - req[reqlen++] = 0x04; // IC manufacturer code - memcpy(req + 3, uid, 8); // add UID - reqlen += 8; - - AddCrc15(req, reqlen); - reqlen += 2; - - PacketResponseNG resp; - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, reply, req, reqlen); - if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { - PrintAndLogEx(DEBUG, "iso15693 timeout"); - DropField(); - return PM3_ETIMEOUT; + uint8_t approxlen = 13; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; } - DropField(); + // params + packet->raw[packet->rawlen++] = (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS); + packet->raw[packet->rawlen++] = ISO15693_GET_NXP_SYSTEM_INFO; + packet->raw[packet->rawlen++] = 0x04; // IC manufacturer code + + memcpy(packet->raw + 3, uid, 8); // add UID + packet->rawlen += HF15_UID_LENGTH; + + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; + + packet->flags = (ISO15_CONNECT | ISO15_HIGH_SPEED | ISO15_READ_RESPONSE); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + free(packet); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { + PrintAndLogEx(DEBUG, "iso15693 timeout"); + return PM3_ETIMEOUT; + } if (resp.status == PM3_ETEAROFF) { return resp.status; @@ -776,52 +851,49 @@ static int NxpSysInfo(uint8_t *uid) { return PM3_EWRONGANSWER; } - uint8_t *recv = resp.data.asBytes; + uint8_t *d = resp.data.asBytes; - if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { - PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return PM3_EWRONGANSWER; - } + ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length) - bool support_signature = (recv[5] & 0x01); - bool support_easmode = (recv[4] & 0x04); + bool support_signature = (d[5] & 0x01); + bool support_easmode = (d[4] & 0x04); PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "--- " _CYAN_("NXP Sysinfo")); - PrintAndLogEx(INFO, " raw... %s", sprint_hex(recv, 8)); + PrintAndLogEx(INFO, " raw... %s", sprint_hex(d, 8)); PrintAndLogEx(INFO, " " _CYAN_("Password protection configuration:")); - PrintAndLogEx(INFO, " * Page L read%s password protected", ((recv[2] & 0x01) ? "" : _GREEN_(" not"))); - PrintAndLogEx(INFO, " * Page L write%s password protected", ((recv[2] & 0x02) ? "" : _GREEN_(" not"))); - PrintAndLogEx(INFO, " * Page H read%s password protected", ((recv[2] & 0x10) ? "" : _GREEN_(" not"))); - PrintAndLogEx(INFO, " * Page H write%s password protected", ((recv[2] & 0x20) ? "" : _GREEN_(" not"))); + PrintAndLogEx(INFO, " * Page L read%s password protected", ((d[2] & 0x01) ? "" : _GREEN_(" not"))); + PrintAndLogEx(INFO, " * Page L write%s password protected", ((d[2] & 0x02) ? "" : _GREEN_(" not"))); + PrintAndLogEx(INFO, " * Page H read%s password protected", ((d[2] & 0x10) ? "" : _GREEN_(" not"))); + PrintAndLogEx(INFO, " * Page H write%s password protected", ((d[2] & 0x20) ? "" : _GREEN_(" not"))); - PrintAndLogEx(INFO, " " _CYAN_("Lock bits:")); + PrintAndLogEx(INFO, " " _CYAN_("Lock bits")); // AFI lock bit - PrintAndLogEx(INFO, " * AFI%s locked", ((recv[3] & 0x01) ? "" : _GREEN_(" not"))); + PrintAndLogEx(INFO, " * AFI%s locked", ((d[3] & 0x01) ? "" : _GREEN_(" not"))); // EAS lock bit - PrintAndLogEx(INFO, " * EAS%s locked", ((recv[3] & 0x02) ? "" : _GREEN_(" not"))); + PrintAndLogEx(INFO, " * EAS%s locked", ((d[3] & 0x02) ? "" : _GREEN_(" not"))); // DSFID lock bit - PrintAndLogEx(INFO, " * DSFID%s locked", ((recv[3] & 0x03) ? "" : _GREEN_(" not"))); + PrintAndLogEx(INFO, " * DSFID%s locked", ((d[3] & 0x03) ? "" : _GREEN_(" not"))); // Password protection pointer address and access conditions lock bit - PrintAndLogEx(INFO, " * Password protection configuration%s locked", ((recv[3] & 0x04) ? "" : _GREEN_(" not"))); + PrintAndLogEx(INFO, " * Password protection configuration%s locked", ((d[3] & 0x04) ? "" : _GREEN_(" not"))); - PrintAndLogEx(INFO, " " _CYAN_("Features:")); - PrintAndLogEx(INFO, " * User memory password protection%s supported", ((recv[4] & 0x01) ? "" : " not")); - PrintAndLogEx(INFO, " * Counter feature%s supported", ((recv[4] & 0x02) ? "" : " not")); + PrintAndLogEx(INFO, " " _CYAN_("Features")); + PrintAndLogEx(INFO, " * User memory password protection%s supported", ((d[4] & 0x01) ? "" : " not")); + PrintAndLogEx(INFO, " * Counter feature%s supported", ((d[4] & 0x02) ? "" : " not")); PrintAndLogEx(INFO, " * EAS ID%s supported by EAS ALARM command", support_easmode ? "" : " not"); - PrintAndLogEx(INFO, " * EAS password protection%s supported", ((recv[4] & 0x08) ? "" : " not")); - PrintAndLogEx(INFO, " * AFI password protection%s supported", ((recv[4] & 0x10) ? "" : " not")); - PrintAndLogEx(INFO, " * Extended mode%s supported by INVENTORY READ command", ((recv[4] & 0x20) ? "" : " not")); - PrintAndLogEx(INFO, " * EAS selection%s supported by extended mode in INVENTORY READ command", ((recv[4] & 0x40) ? "" : " not")); + PrintAndLogEx(INFO, " * EAS password protection%s supported", ((d[4] & 0x08) ? "" : " not")); + PrintAndLogEx(INFO, " * AFI password protection%s supported", ((d[4] & 0x10) ? "" : " not")); + PrintAndLogEx(INFO, " * Extended mode%s supported by INVENTORY READ command", ((d[4] & 0x20) ? "" : " not")); + PrintAndLogEx(INFO, " * EAS selection%s supported by extended mode in INVENTORY READ command", ((d[4] & 0x40) ? "" : " not")); PrintAndLogEx(INFO, " * READ SIGNATURE command%s supported", support_signature ? "" : " not"); - PrintAndLogEx(INFO, " * Password protection for READ SIGNATURE command%s supported", ((recv[5] & 0x02) ? "" : " not")); - PrintAndLogEx(INFO, " * STAY QUIET PERSISTENT command%s supported", ((recv[5] & 0x04) ? "" : " not")); - PrintAndLogEx(INFO, " * ENABLE PRIVACY command%s supported", ((recv[5] & 0x10) ? "" : " not")); - PrintAndLogEx(INFO, " * DESTROY command%s supported", ((recv[5] & 0x20) ? "" : " not")); - PrintAndLogEx(INFO, " * Additional 32 bits feature flags are%s transmitted", ((recv[7] & 0x80) ? "" : " not")); + PrintAndLogEx(INFO, " * Password protection for READ SIGNATURE command%s supported", ((d[5] & 0x02) ? "" : " not")); + PrintAndLogEx(INFO, " * STAY QUIET PERSISTENT command%s supported", ((d[5] & 0x04) ? "" : " not")); + PrintAndLogEx(INFO, " * ENABLE PRIVACY command%s supported", ((d[5] & 0x10) ? "" : " not")); + PrintAndLogEx(INFO, " * DESTROY command%s supported", ((d[5] & 0x20) ? "" : " not")); + PrintAndLogEx(INFO, " * Additional 32 bits feature flags are%s transmitted", ((d[7] & 0x80) ? "" : " not")); if (support_easmode) { NxpTestEAS(uid); @@ -855,12 +927,12 @@ static int CmdHF15Info(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t uid[8]; + uint8_t uid[HF15_UID_LENGTH]; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); bool unaddressed = arg_get_lit(ctx, 2); bool scan = arg_get_lit(ctx, 3); - int fast = (arg_get_lit(ctx, 4) == false); + bool fast = (arg_get_lit(ctx, 4) == false); bool add_option = arg_get_lit(ctx, 5); CLIParserFree(ctx); @@ -872,108 +944,122 @@ static int CmdHF15Info(const char *Cmd) { } // default fallback to scan for tag. - if (unaddressed == false && uidlen != 8) { + if (unaddressed == false && uidlen != HF15_UID_LENGTH) { scan = true; } // request to be sent to device/card - uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - uint8_t req[PM3_CMD_DATA_SIZE] = {flags, ISO15693_GET_SYSTEM_INFO}; - uint16_t reqlen = 2; + // don't know if it has uid added or not. + // cmd uid crc + uint8_t approxlen = 2 + 8 + 2; + + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + // ISO15693 protocol params + packet->raw[packet->rawlen++] = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); + packet->raw[packet->rawlen++] = ISO15693_GET_SYSTEM_INFO; if (scan) { - if (getUID(false, uid) != PM3_SUCCESS) { + if (getUID(true, false, uid) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "no tag found"); + free(packet); return PM3_EINVARG; } - uidlen = 8; + uidlen = HF15_UID_LENGTH; } - if (uidlen == 8) { + if (uidlen == HF15_UID_LENGTH) { // add UID (scan, uid) - memcpy(req + reqlen, uid, sizeof(uid)); - reqlen += sizeof(uid); + memcpy(packet->raw + packet->rawlen, uid, uidlen); + packet->rawlen += uidlen; } - PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; - AddCrc15(req, reqlen); - reqlen += 2; + // PM3 flags + packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE); + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } - uint8_t read_response = 1; - PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_response, req, reqlen); + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + free(packet); + PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { - PrintAndLogEx(WARNING, "iso15693 timeout"); - DropField(); + PrintAndLogEx(DEBUG, "iso15693 timeout"); return PM3_ETIMEOUT; } - DropField(); - if (resp.status == PM3_ETEAROFF) { return resp.status; } + if (resp.length < 2) { PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", resp.length); return PM3_EWRONGANSWER; } - uint8_t *data = resp.data.asBytes; + uint8_t *d = resp.data.asBytes; - if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { - PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0])); - return PM3_EWRONGANSWER; - } + ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length) + + memcpy(uid, d + 2, sizeof(uid)); - memcpy(uid, data + 2, sizeof(uid)); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); - PrintAndLogEx(SUCCESS, " TYPE: " _YELLOW_("%s"), getTagInfo_15(data + 2)); - PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); - PrintAndLogEx(SUCCESS, " SYSINFO: %s", sprint_hex(data, resp.length - 2)); + PrintAndLogEx(SUCCESS, " TYPE... " _YELLOW_("%s"), getTagInfo_15(d + 2)); + PrintAndLogEx(SUCCESS, " UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, " SYSINFO... %s", sprint_hex(d, resp.length - 2)); // DSFID - if (data[1] & 0x01) - PrintAndLogEx(SUCCESS, " - DSFID supported [0x%02X]", data[10]); + if (d[1] & 0x01) + PrintAndLogEx(SUCCESS, " - DSFID supported [0x%02X]", d[10]); else PrintAndLogEx(SUCCESS, " - DSFID not supported"); // AFI - if (data[1] & 0x02) - PrintAndLogEx(SUCCESS, " - AFI supported [0x%02X]", data[11]); + if (d[1] & 0x02) + PrintAndLogEx(SUCCESS, " - AFI supported [0x%02X]", d[11]); else PrintAndLogEx(SUCCESS, " - AFI not supported"); // IC reference - if (data[1] & 0x08) - PrintAndLogEx(SUCCESS, " - IC reference supported [0x%02X]", data[14]); + if (d[1] & 0x08) + PrintAndLogEx(SUCCESS, " - IC reference supported [0x%02X]", d[14]); else PrintAndLogEx(SUCCESS, " - IC reference not supported"); // memory - if (data[1] & 0x04) { + if (d[1] & 0x04) { PrintAndLogEx(SUCCESS, " - Tag provides info on memory layout (vendor dependent)"); - uint8_t blocks = data[12] + 1; - uint8_t size = (data[13] & 0x1F); + uint8_t blocks = d[12] + 1; + uint8_t size = (d[13] & 0x1F); PrintAndLogEx(SUCCESS, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks); } else { PrintAndLogEx(SUCCESS, " - Tag does not provide information on memory layout"); } // Check if SLIX2 and attempt to get NXP System Information - PrintAndLogEx(DEBUG, "Byte 6 :: %02x Byte 7 :: %02x Byte 8 :: %02x", data[6], data[7], data[8]); - // SLIX2 uses xxx0 1xxx format on data[6] of UID - uint8_t nxp_version = data[6] & 0x18; + PrintAndLogEx(DEBUG, "Byte 6 :: %02x Byte 7 :: %02x Byte 8 :: %02x", d[6], d[7], d[8]); + // SLIX2 uses xxx0 1xxx format on d[6] of UID + uint8_t nxp_version = d[6] & 0x18; PrintAndLogEx(DEBUG, "NXP Version: %02x", nxp_version); - if (data[8] == 0x04 && data[7] == 0x01 && nxp_version == 0x08) { + + if (d[8] == 0x04 && d[7] == 0x01 && nxp_version == 0x08) { PrintAndLogEx(DEBUG, "SLIX2 Detected, getting NXP System Info"); return NxpSysInfo(uid); - } else if (data[8] == 0x04 && data[7] == 0x01 && nxp_version == 0x18) { //If it is an NTAG 5 + + } else if (d[8] == 0x04 && d[7] == 0x01 && nxp_version == 0x18) { // If it is an NTAG 5 PrintAndLogEx(DEBUG, "NTAG 5 Detected, getting NXP System Info"); return NxpSysInfo(uid); - } else if (data[8] == 0x04 && (data[7] == 0x01 || data[7] == 0x02 || data[7] == 0x03)) { //If SLI, SLIX, SLIX-l, or SLIX-S check EAS status + + } else if (d[8] == 0x04 && (d[7] == 0x01 || d[7] == 0x02 || d[7] == 0x03)) { // If SLI, SLIX, SLIX-l, or SLIX-S check EAS status PrintAndLogEx(DEBUG, "SLI, SLIX, SLIX-L, or SLIX-S Detected checking EAS status"); return NxpTestEAS(uid); } @@ -1004,6 +1090,7 @@ static int CmdHF15Sniff(const char *Cmd) { PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 15 list") "` to view captured tracelog"); PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -h") "` to save tracelog for later analysing"); + PrintAndLogEx(INFO, "Done!"); return PM3_SUCCESS; } @@ -1067,12 +1154,12 @@ static int CmdHF15ELoad(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 15 eload", - "Load memory image from file to be used with 'hf 15 sim'", + "Load memory dump from file to be used with 'hf 15 sim'", "hf 15 eload -f hf-15-01020304.bin\n" ); void *argtable[] = { arg_param_begin, - arg_str1("f", "file", "", "filename of image"), + arg_str1("f", "file", "", "filename of dump"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -1150,8 +1237,8 @@ static int CmdHF15ESave(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str1("f", "file", "", "Specify a filename for dump file"), - arg_int0(NULL, "bsize", "", "block size, defaults to 4"), - arg_int0("c", "count", "", "number of blocks to export, defaults to all"), + arg_int0(NULL, "bsize", "", "block size (def 4)"), + arg_int0("c", "count", "", "number of blocks to export (def all)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1163,6 +1250,12 @@ static int CmdHF15ESave(const char *Cmd) { int count = arg_get_int_def(ctx, 3, -1); CLIParserFree(ctx); + // sanity checks + if (blocksize < 4) { + PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); + blocksize = 4; + } + int bytes = CARD_MEMORY_SIZE; if (count > 0 && count * blocksize <= bytes) { bytes = count * blocksize; @@ -1197,23 +1290,30 @@ static void print_hrule(int blocksize) { PrintAndLogEx(INFO, "-----+%.*s-+-%.*s-", 3 * blocksize, dashes, blocksize, dashes); } +// for emaulator and dump files we don't have lock info byte available. static void print_blocks_15693(uint8_t *data, uint16_t bytes, int blocksize) { int blocks = bytes / blocksize; + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "----------- " _CYAN_("Tag Memory") " ---------------"); + PrintAndLogEx(NORMAL, ""); print_hrule(blocksize); + char spaces[] = " "; PrintAndLogEx(INFO, " blk | data %.*s| ascii", MAX(0, 3 * blocksize - 5), spaces); print_hrule(blocksize); for (int i = 0; i < blocks; i++) { PrintAndLogEx(INFO, "%4d | %s ", i, sprint_hex_ascii(data + (i * blocksize), blocksize)); - } + if (bytes % blocksize != 0) { // If there is something left over print it too // This will have a broken layout, but should not happen anyway PrintAndLogEx(INFO, "%4d | %s ", blocks, sprint_hex_ascii(data + (blocks * blocksize), bytes % blocksize)); } + print_hrule(blocksize); PrintAndLogEx(NORMAL, ""); } @@ -1228,8 +1328,8 @@ static int CmdHF15EView(const char *Cmd) { ); void *argtable[] = { arg_param_begin, - arg_int0("b", "blocksize", "", "block size, defaults to 4"), - arg_int0("c", "count", "", "number of blocks to display, defaults to all"), + arg_int0("b", "blocksize", "", "block size (def 4)"), + arg_int0("c", "count", "", "number of blocks to display (def all)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1237,6 +1337,12 @@ static int CmdHF15EView(const char *Cmd) { int count = arg_get_int_def(ctx, 2, -1); CLIParserFree(ctx); + // santity checks + if (blocksize < 4) { + PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); + blocksize = 4; + } + int bytes = CARD_MEMORY_SIZE; if (count > 0 && count * blocksize <= bytes) { bytes = count * blocksize; @@ -1248,7 +1354,7 @@ static int CmdHF15EView(const char *Cmd) { return PM3_EMALLOC; } - PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes); + PrintAndLogEx(INFO, "Downloading " _YELLOW_("%u") " bytes from emulator memory...", bytes); if (GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false) == false) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); free(dump); @@ -1271,21 +1377,21 @@ static int CmdHF15Sim(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"), - arg_int0("b", "blocksize", "", "block size, defaults to 4"), + arg_str1("u", "uid", "", "UID, 8 hex bytes"), + arg_int0("b", "blocksize", "", "block size (def 4)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); struct { - uint8_t uid[8]; + uint8_t uid[HF15_UID_LENGTH]; uint8_t block_size; } PACKED payload; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen); - if (uidlen != 8) { - PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); + if (uidlen != HF15_UID_LENGTH) { + PrintAndLogEx(WARNING, "UID must include 8 hex bytes"); CLIParserFree(ctx); return PM3_EINVARG; } @@ -1293,6 +1399,12 @@ static int CmdHF15Sim(const char *Cmd) { payload.block_size = arg_get_int_def(ctx, 2, 4); CLIParserFree(ctx); + // santity checks + if (payload.block_size < 4) { + PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); + payload.block_size = 4; + } + PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid)); PrintAndLogEx(INFO, "Press " _YELLOW_("`pm3-button`") " to abort simulation"); @@ -1316,15 +1428,27 @@ static int CmdHF15FindAfi(const char *Cmd) { void *argtable[] = { arg_param_begin, + arg_lit0("2", NULL, "use slower '1 out of 256' mode"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + bool fast = (arg_get_lit(ctx, 1) == false); CLIParserFree(ctx); PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or press " _GREEN_("") " to exit"); + + struct p { + uint32_t flags; + } PACKED packet; + + packet.flags = 0; + if (fast) { + packet.flags |= ISO15_HIGH_SPEED; + } + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO15693_FINDAFI, (uint8_t *)&packet, sizeof(struct p)); PacketResponseNG resp; - SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0); uint32_t timeout = 0; for (;;) { @@ -1352,7 +1476,7 @@ static int CmdHF15FindAfi(const char *Cmd) { } DropField(); - PrintAndLogEx(INFO, "Done"); + PrintAndLogEx(INFO, "Done!"); return PM3_SUCCESS; } @@ -1367,7 +1491,7 @@ static int CmdHF15WriteAfi(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("u", "uid", "", "full UID, 8 bytes"), + arg_str0("u", "uid", "", "full UID, 8 hex bytes"), arg_int1(NULL, "afi", "", "AFI number (0-255)"), arg_str0("p", "pwd", "", "optional AFI/EAS password"), arg_param_end @@ -1378,7 +1502,7 @@ static int CmdHF15WriteAfi(const char *Cmd) { struct { uint8_t pwd[4]; bool use_pwd; - uint8_t uid[8]; + uint8_t uid[HF15_UID_LENGTH]; bool use_uid; uint8_t afi; } PACKED payload; @@ -1399,13 +1523,13 @@ static int CmdHF15WriteAfi(const char *Cmd) { } payload.use_uid = false; - if (uidlen == 8) { + if (uidlen == HF15_UID_LENGTH) { payload.use_uid = true; } // sanity checks if (uidlen != 0 && uidlen != 8) { - PrintAndLogEx(WARNING, "uid must be 8 hex bytes if provided"); + PrintAndLogEx(WARNING, "uid must be 8 hex bytes, got ( " _RED_("%d") " )", uidlen); return PM3_EINVARG; } @@ -1429,11 +1553,11 @@ static int CmdHF15WriteAfi(const char *Cmd) { break; } case PM3_EWRONGANSWER: { - PrintAndLogEx(WARNING, "error writing AFI"); + PrintAndLogEx(WARNING, "Writing AFI ( " _RED_("fail") " )"); break; } case PM3_SUCCESS: { - PrintAndLogEx(SUCCESS, "Wrote AFI 0x%02X", payload.afi); + PrintAndLogEx(SUCCESS, "Wrote AFI 0x%02X ( " _GREEN_("ok") " )", payload.afi); break; } } @@ -1449,22 +1573,25 @@ static int CmdHF15WriteDsfid(const char *Cmd) { "hf 15 writedsfid -u E011223344556677 --dsfid 12" ); - void *argtable[6 + 2] = {0}; + void *argtable[6 + 3] = {0}; uint8_t arglen = arg_add_default(argtable); argtable[arglen++] = arg_int1(NULL, "dsfid", "", "DSFID number (0-255)"); + argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t uid[8]; + uint8_t uid[HF15_UID_LENGTH] = {0}; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); + bool unaddressed = arg_get_lit(ctx, 2); bool scan = arg_get_lit(ctx, 3); - int fast = (arg_get_lit(ctx, 4) == false); + bool fast = (arg_get_lit(ctx, 4) == false); bool add_option = arg_get_lit(ctx, 5); int dsfid = arg_get_int_def(ctx, 6, 0); + bool verbose = arg_get_lit(ctx, 7); CLIParserFree(ctx); // sanity checks @@ -1473,68 +1600,73 @@ static int CmdHF15WriteDsfid(const char *Cmd) { return PM3_EINVARG; } + // enforcing add_option since we are writing. + if (add_option == false) { + if (verbose) { + PrintAndLogEx(INFO, "Overriding OPTION param since we are writing (ENFORCE)"); + } + add_option = true; + } + // request to be sent to device/card - uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - uint8_t req[16] = {flags, ISO15693_WRITE_DSFID}; - // enforce, since we are writing - req[0] |= ISO15_REQ_OPTION; - uint16_t reqlen = 2; + uint8_t approxlen = 2 + 8 + 1 + 2; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + // params + packet->raw[packet->rawlen++] = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); + packet->raw[packet->rawlen++] = ISO15693_WRITE_DSFID; if (unaddressed == false) { if (scan) { - if (getUID(false, uid) != PM3_SUCCESS) { + if (getUID(verbose, false, uid) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "no tag found"); + free(packet); return PM3_EINVARG; } - uidlen = 8; + uidlen = HF15_UID_LENGTH; } - if (uidlen == 8) { + if (uidlen == HF15_UID_LENGTH) { // add UID (scan, uid) - memcpy(req + reqlen, uid, sizeof(uid)); - reqlen += sizeof(uid); + memcpy(packet->raw + packet->rawlen, uid, uidlen); + packet->rawlen += uidlen; } - PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); + } else { + PrintAndLogEx(SUCCESS, "Using unaddressed mode"); } // dsfid - req[reqlen++] = (uint8_t)dsfid; + packet->raw[packet->rawlen++] = (uint8_t)dsfid; - AddCrc15(req, reqlen); - reqlen += 2; + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; + packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE); + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } - // arg: len, speed, recv? - // arg0 (datalen, cmd len? .arg0 == crc?) - // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) - // arg2 (recv == 1 == expect a response) - uint8_t read_respone = 1; - - PrintAndLogEx(DEBUG, "cmd %s", sprint_hex(req, reqlen)); - PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen); - + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + free(packet); + PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { - PrintAndLogEx(ERR, "iso15693 timeout"); - DropField(); + PrintAndLogEx(DEBUG, "iso15693 timeout"); return PM3_ETIMEOUT; } - DropField(); - if (resp.status == PM3_ETEAROFF) { - return resp.status; - } + ISO15_ERROR_HANDLING_RESPONSE - uint8_t *data = resp.data.asBytes; + uint8_t *d = resp.data.asBytes; - if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { - PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0])); - return PM3_EWRONGANSWER; - } + ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length) PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Wrote DSFID 0x%02X", dsfid); + PrintAndLogEx(SUCCESS, "Wrote DSFID 0x%02X ( " _GREEN_("ok") " )", dsfid); return PM3_SUCCESS; } @@ -1549,25 +1681,32 @@ static int CmdHF15Dump(const char *Cmd) { "hf 15 dump -u E011223344556677 -f hf-15-my-dump.bin" ); - void *argtable[6 + 2] = {0}; + void *argtable[6 + 5] = {0}; uint8_t arglen = arg_add_default(argtable); argtable[arglen++] = arg_str0("f", "file", "", "Specify a filename for dump file"), - argtable[arglen++] = arg_param_end; + argtable[arglen++] = arg_int0(NULL, "bs", "", "block size (def 4)"), + argtable[arglen++] = arg_lit0(NULL, "ns", "no save to file"), + argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); + argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t uid[8]; + uint8_t uid[HF15_UID_LENGTH]; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); + bool unaddressed = arg_get_lit(ctx, 2); bool scan = arg_get_lit(ctx, 3); - int fast = (arg_get_lit(ctx, 4) == false); + bool fast = (arg_get_lit(ctx, 4) == false); bool add_option = arg_get_lit(ctx, 5); int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + int blocksize = arg_get_int_def(ctx, 7, 4); + bool no_save = arg_get_lit(ctx, 8); + bool verbose = arg_get_lit(ctx, 9); CLIParserFree(ctx); // sanity checks @@ -1576,94 +1715,138 @@ static int CmdHF15Dump(const char *Cmd) { return PM3_EINVARG; } + if (blocksize < 4) { + PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); + blocksize = 4; + } + // default fallback to scan for tag. // overriding unaddress parameter :) - if (uidlen != 8) { + if (uidlen != HF15_UID_LENGTH) { scan = true; } // request to be sent to device/card - uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - uint8_t req[13] = {flags, ISO15693_READBLOCK}; - uint16_t reqlen = 2; + uint8_t approxlen = 2 + 8 + 1 + 2; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } - if (scan) { - if (getUID(false, uid) != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "no tag found"); - return PM3_EINVARG; + // ISO15693 Protocol params + packet->raw[packet->rawlen++] = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); + packet->raw[packet->rawlen++] = ISO15693_READBLOCK; + + bool used_uid = false; + if (unaddressed == false) { + // default fallback to scan for tag. Overriding unaddress parameter + if (scan) { + if (getUID(verbose, false, uid) != PM3_SUCCESS) { + free(packet); + PrintAndLogEx(WARNING, "no tag found"); + return PM3_EINVARG; + } + } else { + reverse_array(uid, HF15_UID_LENGTH); } - uidlen = 8; - } - - if (uidlen == 8) { // add UID (scan, uid) - memcpy(req + reqlen, uid, sizeof(uid)); - reqlen += sizeof(uid); + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; + used_uid = true; + } else { + PrintAndLogEx(SUCCESS, "Using unaddressed mode"); } - PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); - // detect blocksize from card :) + if (verbose) { + PrintAndLogEx(INFO, "Using block size... " _YELLOW_("%d"), blocksize); + } - PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, uid)); + // PM3 params + packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT); + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } + + // add CRC length (2) to packet and blockno (1) + packet->rawlen += 3; + + PrintAndLogEx(SUCCESS, "Reading memory"); int blocknum = 0; // memory. t15memory_t mem[256]; - uint8_t data[256 * 8] = {0}; + uint8_t data[256 * 4]; memset(data, 0, sizeof(data)); // keep track of which block length tag returned? - uint8_t blklen = 4; + uint8_t blklen = blocksize; - for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) { - req[10] = blocknum; - AddCrc15(req, 11); + for (int retry = 0; (retry < 2 && blocknum < 0x100); retry++) { + + if (blocknum > 0) { + packet->flags = (ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT); + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } + } + + if (used_uid) { + packet->raw[10] = (uint8_t)blocknum & 0xFF; + AddCrc15(packet->raw, 11); + } else { + packet->raw[2] = (uint8_t)blocknum & 0xFF; + AddCrc15(packet->raw, 3); + } - // arg: len, speed, recv? - // arg0 (datalen, cmd len? .arg0 == crc?) - // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) - // arg2 (recv == 1 == expect a response) - uint8_t read_respone = 1; - PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, sizeof(req), fast, read_respone, req, sizeof(req)); - + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000)) { - if (resp.status == PM3_ETEAROFF) { - continue; - } if (resp.length < 2) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "iso15693 command failed"); continue; } - uint8_t *recv = resp.data.asBytes; + uint8_t *d = resp.data.asBytes; - if (CheckCrc15(recv, resp.length) == false) { + if (CheckCrc15(d, resp.length) == false) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "crc ( " _RED_("fail") " )"); continue; } - if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { + if ((d[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { + + // heuristic determine end of available memory + if (d[1] == 0x0F || d[1] == 0x10) { + break; + } + PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(FAILED, "Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1])); + PrintAndLogEx(FAILED, "Tag returned Error %i: %s", d[1], TagErrorStr(d[1])); break; } - // lock byte value - mem[blocknum].lock = resp.data.asBytes[0]; - // is tag responding with 4 or 8 bytes? - if (resp.length == 11) { + if (resp.length > 8) { blklen = 8; } - memcpy(mem[blocknum].block, resp.data.asBytes + 1, blklen); - memcpy(data + (blocknum * 4), resp.data.asBytes + 1, blklen); + + uint8_t offset = 0; + if (add_option) { + offset = 1; + } + // lock byte value + mem[blocknum].lock = d[0 + offset]; + + // copy read data + memcpy(mem[blocknum].block, d + 1 + offset, blklen); + memcpy(data + (blocknum * 4), d + 1 + offset, 4); retry = 0; blocknum++; @@ -1672,23 +1855,30 @@ static int CmdHF15Dump(const char *Cmd) { } } + free(packet); DropField(); - if (blklen == 8) { - PrintAndLogEx(INFO, "8 byte block length detected"); + if (blklen != blocksize) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, _YELLOW_("%u") " byte block length detected, called with " _YELLOW_("%d"), blklen, blocksize); } - PrintAndLogEx(NORMAL, "\n"); - PrintAndLogEx(INFO, "block# | data |lck| ascii"); - PrintAndLogEx(INFO, "---------+--------------+---+----------"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "----------- " _CYAN_("Tag Memory") " ---------------"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "block# | data |lck| ascii"); + PrintAndLogEx(INFO, "---------+-------------+---+-------"); + for (int i = 0; i < blocknum; i++) { + char lck[16] = {0}; if (mem[i].lock) { snprintf(lck, sizeof(lck), _RED_("%d"), mem[i].lock); } else { snprintf(lck, sizeof(lck), "%d", mem[i].lock); } - PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s" + + PrintAndLogEx(INFO, "%3d/0x%02X | %s| %s | %s" , i , i , sprint_hex(mem[i].block, blklen) @@ -1696,8 +1886,15 @@ static int CmdHF15Dump(const char *Cmd) { , sprint_ascii(mem[i].block, blklen) ); } + PrintAndLogEx(INFO, "---------+-------------+---+-------"); PrintAndLogEx(NORMAL, ""); + if (no_save) { + PrintAndLogEx(INFO, "Called with no save option"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; + } + // user supplied filename ? if (strlen(filename) < 1) { char *fptr = filename; @@ -1715,61 +1912,105 @@ static int CmdHF15Dump(const char *Cmd) { } static int CmdHF15List(const char *Cmd) { - return CmdTraceListAlias(Cmd, "hf 15", "15"); + return CmdTraceListAlias(Cmd, "hf 15", "15 -c"); } static int CmdHF15Raw(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 15 raw", "Sends raw bytes over ISO-15693 to card", - "hf 15 raw -c -d 260100 --> add crc\n" - "hf 15 raw -krc -d 260100 --> add crc, keep field on, skip response" + "hf 15 raw -ac -d 260100 --> activate, add crc\n" + "hf 15 raw -akrc -d 260100 --> activate, add crc, keep field on, skip response" ); void *argtable[] = { arg_param_begin, + arg_lit0("a", NULL, "activate field"), + arg_lit0("c", "crc", "calculate and append CRC"), + arg_lit0("k", NULL, "keep signal field ON after receive"), arg_lit0("2", NULL, "use slower '1 out of 256' mode"), - arg_lit0("c", "crc", "calculate and append CRC"), - arg_lit0("k", NULL, "keep signal field ON after receive"), - arg_lit0("r", NULL, "do not read response"), + arg_lit0("r", NULL, "do not read response"), arg_str1("d", "data", "", "raw bytes to send"), + arg_lit0("w", "wait", "wait longer for response. For writes etc."), arg_param_end }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - int fast = (arg_get_lit(ctx, 1) == false); + + bool activate = arg_get_lit(ctx, 1); bool crc = arg_get_lit(ctx, 2); bool keep_field_on = arg_get_lit(ctx, 3); - bool read_respone = (arg_get_lit(ctx, 4) == false); + bool fast = (arg_get_lit(ctx, 4) == false); + bool read_respone = (arg_get_lit(ctx, 5) == false); + int datalen = 0; - uint8_t data[300]; - CLIGetHexWithReturn(ctx, 5, data, &datalen); + uint8_t data[PM3_CMD_DATA_SIZE] = { 0x00 }; + CLIGetHexWithReturn(ctx, 6, data, &datalen); + + bool wait = arg_get_lit(ctx, 7); CLIParserFree(ctx); + datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; + if (crc) { - AddCrc15(data, datalen); - datalen += 2; + + if ((datalen - 2) < PM3_CMD_DATA_SIZE) { + AddCrc15(data, datalen); + datalen += 2; + } else { + PrintAndLogEx(FAILED, "raw data too long to add CRC."); + return PM3_ECRC; + } } - // arg: len, speed, recv? - // arg0 (datalen, cmd len? .arg0 == crc?) - // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) - // arg2 (recv == 1 == expect a response) - PacketResponseNG resp; - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, datalen, fast, read_respone, data, datalen); + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + datalen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } + + // track that RF field is UP. + if (keep_field_on) { + packet->flags |= ISO15_NO_DISCONNECT; + } if (read_respone) { + packet->flags |= ISO15_READ_RESPONSE; + } + + if (wait) { + packet->flags |= ISO15_LONG_WAIT; + } + + if (activate) { + packet->flags |= ISO15_CONNECT; + SetISODEPState(ISODEP_NFCV); + } + + packet->rawlen = datalen; + memcpy(packet->raw, data, datalen); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(datalen)); + free(packet); + + if (read_respone) { + PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000)) { if (resp.status == PM3_ETEAROFF) { - DropField(); return resp.status; } + if (resp.length < 2) { PrintAndLogEx(WARNING, "command failed"); } else { - PrintAndLogEx(SUCCESS, "received %i octets", resp.length); - PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, resp.length)); + PrintAndLogEx(SUCCESS, "(%u) %s", resp.length, sprint_hex(resp.data.asBytes, resp.length)); } + } else { PrintAndLogEx(WARNING, "timeout while waiting for reply"); } @@ -1793,32 +2034,35 @@ static int CmdHF15Readmulti(const char *Cmd) { "hf 15 rdmulti -u E011223344556677 -b 12 --cnt 3 -> read three blocks" ); - void *argtable[6 + 3] = {0}; + void *argtable[6 + 5] = {0}; uint8_t arglen = arg_add_default(argtable); argtable[arglen++] = arg_int1("b", NULL, "", "first page number (0-255)"); argtable[arglen++] = arg_int1(NULL, "cnt", "", "number of pages (1-6)"); + argtable[arglen++] = arg_int0(NULL, "bs", "", "block size (def 4)"), + argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t uid[HF15_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH] = {0x00}; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); bool uid_set = (uidlen == HF15_UID_LENGTH) ? true : false; bool unaddressed = arg_get_lit(ctx, 2); bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; //Default fallback to scan for tag. Overriding unaddressed parameter. - int fast = (arg_get_lit(ctx, 4) == false); + bool fast = (arg_get_lit(ctx, 4) == false); bool add_option = arg_get_lit(ctx, 5); - int block = arg_get_int_def(ctx, 6, 0); + int blockno = arg_get_int_def(ctx, 6, 0); int blockcnt = arg_get_int_def(ctx, 7, 0); - + int blocksize = arg_get_int_def(ctx, 8, 4); + bool verbose = arg_get_lit(ctx, 9); CLIParserFree(ctx); // sanity checks if (blockcnt > 6) { - PrintAndLogEx(WARNING, "Page count must be 6 or less (%d)", blockcnt); + PrintAndLogEx(WARNING, "Page count must be 6 or less, got ( " _RED_("%d") " )", blockcnt); return PM3_EINVARG; } @@ -1827,14 +2071,35 @@ static int CmdHF15Readmulti(const char *Cmd) { return PM3_EINVARG; } + if (blocksize < 4) { + PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); + blocksize = 4; + } + + // enforcing add_option in order to get lock-info + if (add_option == false) { + if (verbose) { + PrintAndLogEx(INFO, "Overriding OPTION param in order to get lock-info response (ENFORCE)"); + } + add_option = true; + } + // request to be sent to device/card - uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - uint8_t req[PM3_CMD_DATA_SIZE] = {flags, ISO15693_READ_MULTI_BLOCK}; - uint16_t reqlen = 2; + uint8_t approxlen = 2 + 8 + 2 + 2; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + // ISO15693 Protocol params + packet->raw[packet->rawlen++] = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); + packet->raw[packet->rawlen++] = ISO15693_READ_MULTI_BLOCK; if (unaddressed == false) { if (scan) { - if (getUID(false, uid) != PM3_SUCCESS) { + if (getUID(verbose, false, uid) != PM3_SUCCESS) { + free(packet); PrintAndLogEx(WARNING, "no tag found"); return PM3_EINVARG; } @@ -1842,75 +2107,73 @@ static int CmdHF15Readmulti(const char *Cmd) { reverse_array(uid, HF15_UID_LENGTH); } // add UID (scan, uid) - memcpy(req + reqlen, uid, HF15_UID_LENGTH); - reqlen += HF15_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; - PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); + } else { + PrintAndLogEx(SUCCESS, "Using unaddressed mode"); + } + + if (verbose) { + PrintAndLogEx(INFO, "Using block size... " _YELLOW_("%d"), blocksize); } - // add OPTION flag, in order to get lock-info - req[0] |= ISO15_REQ_OPTION; // 0 means 1 page, // 1 means 2 pages, ... if (blockcnt > 0) blockcnt--; - req[reqlen++] = block; - req[reqlen++] = blockcnt; + packet->raw[packet->rawlen++] = blockno; + packet->raw[packet->rawlen++] = blockcnt; - AddCrc15(req, reqlen); - reqlen += 2; + // crc + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; + + packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE); + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } - uint8_t read_respone = 1; - PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen); - + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + free(packet); + PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { PrintAndLogEx(FAILED, "iso15693 card timeout"); - DropField(); return PM3_ETIMEOUT; } - DropField(); + ISO15_ERROR_HANDLING_RESPONSE - if (resp.status == PM3_ETEAROFF) { - return resp.status; - } + uint8_t *d = resp.data.asBytes; - if (resp.length < 2) { - PrintAndLogEx(FAILED, "iso15693 card readmulti failed"); - return PM3_EWRONGANSWER; - } + ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length) - uint8_t *data = resp.data.asBytes; - - if (CheckCrc15(data, resp.length) == false) { - PrintAndLogEx(FAILED, "crc ( " _RED_("fail") " )"); - return PM3_ESOFT; - } - - if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { - PrintAndLogEx(FAILED, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0])); - return PM3_EWRONGANSWER; + // 1 byte cmd, 1 lock byte, 4 / 8 bytes block size, 2 crc + if (resp.length > (1 + (blockcnt * (blocksize + 1)) + 2)) { + PrintAndLogEx(WARNING, "got longer response. Check block size!"); } // skip status byte int start = 1; - int stop = (blockcnt + 1) * 5; - int currblock = block; + int stop = ((blockcnt + 1) * (blocksize + 1)); + int currblock = blockno; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, " # | data |lck| ascii"); PrintAndLogEx(INFO, "---------+--------------+---+----------"); - for (int i = start; i < stop; i += 5) { + for (int i = start; i < stop; i += (blocksize + 1)) { + char lck[16] = {0}; - if (data[i]) { - snprintf(lck, sizeof(lck), _RED_("%d"), data[i]); + if (d[i]) { + snprintf(lck, sizeof(lck), _RED_("%d"), d[i]); } else { - snprintf(lck, sizeof(lck), "%d", data[i]); + snprintf(lck, sizeof(lck), "%d", d[i]); } - PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s", currblock, currblock, sprint_hex(data + i + 1, 4), lck, sprint_ascii(data + i + 1, 4)); + + PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s", currblock, currblock, sprint_hex(d + i + 1, blocksize), lck, sprint_ascii(d + i + 1, blocksize)); + currblock++; } PrintAndLogEx(NORMAL, ""); @@ -1929,9 +2192,11 @@ static int CmdHF15Readblock(const char *Cmd) { "hf 15 rdbl -u E011223344556677 -b 12" ); - void *argtable[6 + 2] = {0}; + void *argtable[6 + 4] = {0}; uint8_t arglen = arg_add_default(argtable); argtable[arglen++] = arg_int1("b", "blk", "", "page number (0-255)"); + argtable[arglen++] = arg_int0(NULL, "bs", "", "block size (def 4)"), + argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -1942,11 +2207,14 @@ static int CmdHF15Readblock(const char *Cmd) { bool uid_set = (uidlen == HF15_UID_LENGTH) ? true : false; bool unaddressed = arg_get_lit(ctx, 2); - bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; //Default fallback to scan for tag. Overriding unaddressed parameter. - int fast = (arg_get_lit(ctx, 4) == false); + bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; // Default fallback to scan for tag. Overriding unaddressed parameter. + bool fast = (arg_get_lit(ctx, 4) == false); bool add_option = arg_get_lit(ctx, 5); - int block = arg_get_int_def(ctx, 6, 0); + int blockno = arg_get_int_def(ctx, 6, 0); + int blocksize = arg_get_int_def(ctx, 7, 4); + + bool verbose = arg_get_lit(ctx, 8); CLIParserFree(ctx); // sanity checks @@ -1955,16 +2223,36 @@ static int CmdHF15Readblock(const char *Cmd) { return PM3_EINVARG; } + if (blocksize < 4) { + PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); + blocksize = 4; + } + + // enforcing add_option in order to get lock-info + if (add_option == false) { + if (verbose) { + PrintAndLogEx(INFO, "Overriding OPTION param in order to get lock-info response (ENFORCE)"); + } + add_option = true; + } + // request to be sent to device/card - uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - uint8_t req[PM3_CMD_DATA_SIZE] = {flags, ISO15693_READBLOCK}; - uint16_t reqlen = 2; + uint8_t approxlen = 2 + 8 + 1 + 2; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + // ISO15693 Protocol params + packet->raw[packet->rawlen++] = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); + packet->raw[packet->rawlen++] = ISO15693_READBLOCK; if (unaddressed == false) { - // default fallback to scan for tag. - // overriding unaddress parameter :) + // default fallback to scan for tag. Overriding unaddress parameter if (scan) { - if (getUID(false, uid) != PM3_SUCCESS) { + if (getUID(verbose, false, uid) != PM3_SUCCESS) { + free(packet); PrintAndLogEx(WARNING, "no tag found"); return PM3_EINVARG; } @@ -1972,110 +2260,137 @@ static int CmdHF15Readblock(const char *Cmd) { reverse_array(uid, HF15_UID_LENGTH); } // add UID (scan, uid) - memcpy(req + reqlen, uid, HF15_UID_LENGTH); - reqlen += HF15_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; - PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); + } else { + PrintAndLogEx(SUCCESS, "Using unaddressed mode"); } - // add OPTION flag, in order to get lock-info - req[0] |= ISO15_REQ_OPTION; - req[reqlen++] = (uint8_t)block; + if (verbose) { + PrintAndLogEx(INFO, "Using block size... " _YELLOW_("%d"), blocksize); + } - AddCrc15(req, reqlen); - reqlen += 2; + // block no + packet->raw[packet->rawlen++] = (uint8_t)blockno; + + // crc + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; + + packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE); + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } - // arg: len, speed, recv? - // arg0 (datalen, cmd len? .arg0 == crc?) - // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) - // arg2 (recv == 1 == expect a response) - uint8_t read_respone = 1; - PacketResponseNG resp; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_respone, req, reqlen); - + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + free(packet); + PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { - PrintAndLogEx(ERR, "iso15693 timeout"); - DropField(); + PrintAndLogEx(DEBUG, "iso15693 timeout"); return PM3_ETIMEOUT; } - DropField(); + ISO15_ERROR_HANDLING_RESPONSE - if (resp.status == PM3_ETEAROFF) { - return resp.status; - } - if (resp.length < 2) { - PrintAndLogEx(ERR, "iso15693 command failed"); - return PM3_EWRONGANSWER; - } - - uint8_t *data = resp.data.asBytes; - - if (CheckCrc15(data, resp.length) == false) { - PrintAndLogEx(FAILED, "crc ( " _RED_("fail") " )"); - return PM3_ESOFT; - } - - if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { - PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", data[0], TagErrorStr(data[0])); - return PM3_EWRONGANSWER; - } + uint8_t *d = resp.data.asBytes; + ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length) // print response char lck[16] = {0}; - if (data[1]) { - snprintf(lck, sizeof(lck), _RED_("%02X"), data[1]); + if (d[1]) { + snprintf(lck, sizeof(lck), _RED_("%d"), d[1]); } else { - snprintf(lck, sizeof(lck), "%02X", data[1]); + snprintf(lck, sizeof(lck), "%d", d[1]); } + PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "#%3d |lck| ascii", block); - PrintAndLogEx(INFO, "------------+---+------"); - PrintAndLogEx(INFO, "%s| %s | %s", sprint_hex(data + 2, resp.length - 4), lck, sprint_ascii(data + 2, resp.length - 4)); + + uint8_t offset = 2; + + bool got_blocksize8 = (resp.length > 8); + + if (got_blocksize8) { + PrintAndLogEx(INFO, "#%3d |lck| ascii", blockno); + PrintAndLogEx(INFO, "------------+---+------"); + PrintAndLogEx(INFO, "%s| %s | %s" + , sprint_hex(d + offset, 8) + , lck + , sprint_ascii(d + offset, 8) + ); + PrintAndLogEx(INFO, "------------+---+------"); + + } else { + PrintAndLogEx(INFO, "#%3d |lck| ascii", blockno); + PrintAndLogEx(INFO, "------------+---+------"); + PrintAndLogEx(INFO, "%s| %s | %s" + , sprint_hex(d + offset, 4) + , lck + , sprint_ascii(d + offset, 4) + ); + PrintAndLogEx(INFO, "------------+---+------"); + } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int hf_15_write_blk(bool verbose, bool fast, uint8_t *req, uint8_t reqlen) { +static int hf_15_write_blk(uint8_t *pm3flags, uint16_t flags, uint8_t *uid, bool fast, uint8_t blockno, uint8_t *data, uint8_t dlen) { + + // request to be sent to device/card + // 2 + 8 + 1 + (4|8) + 2 + uint8_t approxlen = 21; + iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + // ISO15693 protocol params + packet->raw[packet->rawlen++] = flags; + packet->raw[packet->rawlen++] = ISO15693_WRITEBLOCK; + + // add UID + if (uid) { + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; + } + + packet->raw[packet->rawlen++] = blockno; + + memcpy(packet->raw + packet->rawlen, data, dlen); + packet->rawlen += dlen; + + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; + + // PM3 params + if (pm3flags) { + packet->flags = *pm3flags; + } else { + packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE | ISO15_LONG_WAIT); + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } + } - uint8_t read_response = 1; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO15693_COMMAND, reqlen, fast, read_response, req, reqlen); + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + free(packet); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { PrintAndLogEx(FAILED, "iso15693 card timeout, data may be written anyway"); - DropField(); return PM3_ETIMEOUT; } - DropField(); - if (resp.status == PM3_ETEAROFF) { - return resp.status; - } + ISO15_ERROR_HANDLING_RESPONSE - if (resp.length < 2) { - if (verbose) { - PrintAndLogEx(FAILED, "iso15693 command failed"); - } - return PM3_EWRONGANSWER; - } + uint8_t *d = resp.data.asBytes; - uint8_t *recv = resp.data.asBytes; - if (CheckCrc15(recv, resp.length) == false) { - if (verbose) { - PrintAndLogEx(FAILED, "crc ( " _RED_("fail") " )"); - } - return PM3_ESOFT; - } + ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length) - if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { - if (verbose) { - PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - } - return PM3_EWRONGANSWER; - } return PM3_SUCCESS; } @@ -2105,12 +2420,12 @@ static int CmdHF15Write(const char *Cmd) { bool uid_set = (uidlen == HF15_UID_LENGTH) ? true : false; bool unaddressed = arg_get_lit(ctx, 2); - bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; //Default fallback to scan for tag. Overriding unaddressed parameter. - int fast = (arg_get_lit(ctx, 4) == false); + bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; // Default fallback to scan for tag. Overriding unaddressed parameter. + bool fast = (arg_get_lit(ctx, 4) == false); bool add_option = arg_get_lit(ctx, 5); - int block = arg_get_int_def(ctx, 6, 0); - uint8_t d[4]; + int blockno = arg_get_int_def(ctx, 6, 0); + uint8_t d[8]; int dlen = 0; CLIGetHexWithReturn(ctx, 7, d, &dlen); @@ -2123,54 +2438,44 @@ static int CmdHF15Write(const char *Cmd) { return PM3_EINVARG; } - if (dlen != 4) { - PrintAndLogEx(WARNING, "expected data, 4 bytes, got %d", dlen); + if ((dlen != 4) && (dlen != 8)) { + PrintAndLogEx(WARNING, "expected data, 4 or 8 bytes, got " _RED_("%d"), dlen); return PM3_EINVARG; } // default fallback to scan for tag. // overriding unaddress parameter :) - - // request to be sent to device/card - uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - uint8_t req[17] = {flags, ISO15693_WRITEBLOCK}; - - // enforce, since we are writing - req[0] |= ISO15_REQ_OPTION; - uint16_t reqlen = 2; - if (unaddressed == false) { if (scan) { - if (getUID(false, uid) != PM3_SUCCESS) { + if (getUID(verbose, false, uid) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "no tag found"); return PM3_EINVARG; } } else { reverse_array(uid, HF15_UID_LENGTH); } - // add UID (scan, uid) - memcpy(req + reqlen, uid, HF15_UID_LENGTH); - reqlen += HF15_UID_LENGTH; - - PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); + } else { + PrintAndLogEx(SUCCESS, "Using unaddressed mode"); } - req[reqlen++] = (uint8_t)block; - memcpy(req + reqlen, d, sizeof(d)); - reqlen += sizeof(d); + // TI needs OPTION + if (uid[7] == 0xE0 && uid[6] == 0x07) { + if (verbose) { + PrintAndLogEx(INFO, "Overriding OPTION param, writing to TI tag"); + } + add_option = true; + } - AddCrc15(req, reqlen); - reqlen += 2; + uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data [ %s ] ", block, block, sprint_hex(req, reqlen)); + int res = hf_15_write_blk(NULL, flags, ((unaddressed) ? NULL : uid), fast, (uint8_t)blockno, d, dlen); - int res = hf_15_write_blk(verbose, fast, req, reqlen); if (res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )"); + PrintAndLogEx(SUCCESS, "Writing to page %02d (0x%02X) | %s ( " _GREEN_("ok") " )", blockno, blockno, sprint_hex(d, dlen)); else - PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )"); + PrintAndLogEx(FAILED, "Writing to page %02d (0x%02X) | %s ( " _RED_("fail") " )", blockno, blockno, sprint_hex(d, dlen)); - return PM3_SUCCESS; + return res; } static int CmdHF15Restore(const char *Cmd) { @@ -2191,17 +2496,19 @@ static int CmdHF15Restore(const char *Cmd) { argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t uid[8]; + uint8_t uid[HF15_UID_LENGTH]; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); + bool unaddressed = arg_get_lit(ctx, 2); bool scan = arg_get_lit(ctx, 3); - int fast = (arg_get_lit(ctx, 4) == false); + bool fast = (arg_get_lit(ctx, 4) == false); bool add_option = arg_get_lit(ctx, 5); int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + uint32_t retries = arg_get_u32_def(ctx, 7, 3); int blocksize = arg_get_int_def(ctx, 8, 4); bool verbose = arg_get_lit(ctx, 9); @@ -2212,50 +2519,51 @@ static int CmdHF15Restore(const char *Cmd) { PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid"); return PM3_EINVARG; } + if (fnlen == 0) { PrintAndLogEx(WARNING, "please provide a filename"); return PM3_EINVARG; } + if (blocksize < 4) { + PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); + blocksize = 4; + } + // default fallback to scan for tag. // overriding unaddress parameter :) - if (uidlen != 8) { + if (uidlen != HF15_UID_LENGTH) { scan = true; } - // request to be sent to device/card - uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - uint8_t req[17] = {flags, ISO15693_WRITEBLOCK}; - // enforce, since we are writing - req[0] |= ISO15_REQ_OPTION; - uint16_t reqlen = 2; - if (unaddressed == false) { if (scan) { - if (getUID(false, uid) != PM3_SUCCESS) { + if (getUID(verbose, false, uid) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "no tag found"); return PM3_EINVARG; } - uidlen = 8; + } else { + reverse_array(uid, HF15_UID_LENGTH); } - - if (uidlen == 8) { - // add UID (scan, uid) - memcpy(req + reqlen, uid, sizeof(uid)); - reqlen += sizeof(uid); - } - PrintAndLogEx(SUCCESS, "Using UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); } else { PrintAndLogEx(SUCCESS, "Using unaddressed mode"); } - PrintAndLogEx(INFO, "Using block size... %d", blocksize); + PrintAndLogEx(INFO, "Using block size... " _YELLOW_("%d"), blocksize); + + // TI needs OPTION + if (uid[7] == 0xE0 && uid[6] == 0x07) { + if (verbose) { + PrintAndLogEx(INFO, "Overriding OPTION param, writing to TI tag"); + } + add_option = true; + } // read dump file uint8_t *dump = NULL; size_t bytes_read = 0; - // 4bytes * 256 blocks. Should be enough.. - int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (4 * 256)); + // blocksize bytes * 256 blocks. Should be enough + int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (blocksize * 256)); if (res != PM3_SUCCESS) { return res; } @@ -2266,27 +2574,43 @@ static int CmdHF15Restore(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(INFO, "restoring data blocks"); - PrintAndLogEx(INFO, "." NOLF); - fflush(stdout); + PrintAndLogEx(INFO, "Restoring data blocks"); + + uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); + + uint8_t pm3flags = (ISO15_CONNECT | ISO15_READ_RESPONSE | ISO15_LONG_WAIT | ISO15_NO_DISCONNECT); + if (fast) { + pm3flags |= ISO15_HIGH_SPEED; + } int retval = PM3_SUCCESS; size_t bytes = 0; uint16_t i = 0; while (bytes < bytes_read) { - req[reqlen] = i; + uint8_t data[blocksize]; + // copy over the data to the request - memcpy(req + reqlen + 1, dump + bytes, blocksize); - AddCrc15(req, reqlen + 1 + blocksize); + memcpy(data, dump + bytes, blocksize); uint32_t tried = 0; for (tried = 0; tried < retries; tried++) { - retval = hf_15_write_blk(verbose, fast, req, (reqlen + 1 + blocksize + 2)); + retval = hf_15_write_blk(&pm3flags, flags, uid, fast, i, data, blocksize); if (retval == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "." NOLF); - fflush(stdout); + + PrintAndLogEx(INPLACE, "blk %3d", i); + + if (i == 0) { + pm3flags = (ISO15_READ_RESPONSE | ISO15_LONG_WAIT | ISO15_NO_DISCONNECT); + if (fast) { + pm3flags |= ISO15_HIGH_SPEED; + } + } + break; + } else if (retval == PM3_EOUTOFBOUND) { + // we only get this when we reached end of tag memory + // break out of retry loop break; } } @@ -2294,17 +2618,27 @@ static int CmdHF15Restore(const char *Cmd) { if (tried >= retries) { free(dump); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(FAILED, "restore failed. Too many retries."); + PrintAndLogEx(FAILED, "Too many retries (" _RED_("fail") " )"); + DropField(); return retval; } + bytes += blocksize; i++; + + if (retval == PM3_EOUTOFBOUND) { + // we only get this when we reached end of tag memory + // break out of while loop + break; + } } + free(dump); + DropField(); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "done"); - PrintAndLogEx(HINT, "try `" _YELLOW_("hf 15 dump") "` to read your card to verify"); + PrintAndLogEx(HINT, "try `" _YELLOW_("hf 15 dump --ns") "` to verify"); + PrintAndLogEx(INFO, "Done!"); return PM3_SUCCESS; } @@ -2321,21 +2655,21 @@ static int CmdHF15CSetUID(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"), + arg_str1("u", "uid", "", "UID, 8 hex bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); struct { - uint8_t uid[8]; + uint8_t uid[HF15_UID_LENGTH]; } PACKED payload; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen); CLIParserFree(ctx); - if (uidlen != 8) { - PrintAndLogEx(WARNING, "UID must include 16 HEX symbols got "); + if (uidlen != HF15_UID_LENGTH) { + PrintAndLogEx(WARNING, "UID must include 8 hex bytes, got " _RED_("%i"), uidlen); return PM3_EINVARG; } @@ -2344,17 +2678,17 @@ static int CmdHF15CSetUID(const char *Cmd) { return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "reverse input UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid)); + PrintAndLogEx(DEBUG, "Reverse input UID... " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid)); - PrintAndLogEx(INFO, "getting current card details..."); - uint8_t carduid[8] = {0x00}; - if (getUID(false, carduid) != PM3_SUCCESS) { + PrintAndLogEx(INFO, "Get current tag"); + + uint8_t carduid[HF15_UID_LENGTH] = {0x00}; + if (getUID(true, false, carduid) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "no tag found"); return PM3_ESOFT; } - PrintAndLogEx(INFO, "updating tag uid..."); - + PrintAndLogEx(INFO, "Writing..."); PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_CSETUID, (uint8_t *)&payload, sizeof(payload)); @@ -2364,24 +2698,26 @@ static int CmdHF15CSetUID(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(INFO, "getting updated card details..."); + PrintAndLogEx(INFO, "Verifying..."); - if (getUID(false, carduid) != PM3_SUCCESS) { + if (getUID(true, false, carduid) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "no tag found"); return PM3_ESOFT; } // reverse cardUID to compare - uint8_t revuid[8] = {0}; + uint8_t revuid[HF15_UID_LENGTH] = {0}; reverse_array_copy(carduid, sizeof(carduid), revuid); - if (memcmp(revuid, payload.uid, 8) != 0) { - PrintAndLogEx(FAILED, "setting new UID ( " _RED_("fail") " )"); - return PM3_ESOFT; - } else { - PrintAndLogEx(SUCCESS, "setting new UID ( " _GREEN_("ok") " )"); - return PM3_SUCCESS; + if (memcmp(revuid, payload.uid, HF15_UID_LENGTH) == 0) { + PrintAndLogEx(SUCCESS, "Setting new UID ( " _GREEN_("ok") " )"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS;; } + + PrintAndLogEx(FAILED, "Setting new UID ( " _RED_("fail") " )"); + PrintAndLogEx(NORMAL, ""); + return PM3_ESOFT; } static int CmdHF15SlixEASEnable(const char *Cmd) { @@ -2393,7 +2729,7 @@ static int CmdHF15SlixEASEnable(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("p", "pwd", "", "optional password, 8 hex bytes"), + arg_str0("p", "pwd", "", "optional password, 4 hex bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -2439,14 +2775,14 @@ static int CmdHF15SlixEASEnable(const char *Cmd) { } case PM3_EWRONGANSWER: { if (pwdlen > 0) { - PrintAndLogEx(WARNING, "the password provided was not accepted"); + PrintAndLogEx(WARNING, "Password provided was not accepted ( " _RED_("fail") " )"); } else { - PrintAndLogEx(WARNING, "either a password is required or EAS mode is locked"); + PrintAndLogEx(WARNING, "Either password is required or EAS mode is locked ( " _RED_("fail") " )"); } break; } case PM3_SUCCESS: { - PrintAndLogEx(SUCCESS, "EAS mode is now enabled ( " _GREEN_("ok") " ) "); + PrintAndLogEx(SUCCESS, "EAS mode is enabled ( " _GREEN_("ok") " ) "); break; } } @@ -2462,7 +2798,7 @@ static int CmdHF15SlixEASDisable(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("p", "pwd", "", "optional password, 8 hex bytes"), + arg_str0("p", "pwd", "", "optional password, 4 hex bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -2508,14 +2844,14 @@ static int CmdHF15SlixEASDisable(const char *Cmd) { } case PM3_EWRONGANSWER: { if (pwdlen > 0) { - PrintAndLogEx(WARNING, "the password provided was not accepted"); + PrintAndLogEx(WARNING, "Password provided was not accepted ( " _RED_("fail") " )"); } else { - PrintAndLogEx(WARNING, "either a password is required or EAS mode is locked"); + PrintAndLogEx(WARNING, "Either password is required or EAS mode is locked ( " _RED_("fail") " )"); } break; } case PM3_SUCCESS: { - PrintAndLogEx(SUCCESS, "EAS mode is now disabled ( " _GREEN_("ok") " ) "); + PrintAndLogEx(SUCCESS, "EAS mode is disabled ( " _GREEN_("ok") " ) "); break; } } @@ -2531,7 +2867,7 @@ static int CmdHF15SlixDisable(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("p", "pwd", "", "password, 8 hex bytes"), + arg_str1("p", "pwd", "", "password, 4 hex bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -2561,11 +2897,11 @@ static int CmdHF15SlixDisable(const char *Cmd) { break; } case PM3_EWRONGANSWER: { - PrintAndLogEx(WARNING, "password was not accepted"); + PrintAndLogEx(WARNING, "Password was not accepted ( " _RED_("fail") " )"); break; } case PM3_SUCCESS: { - PrintAndLogEx(SUCCESS, "privacy mode is now disabled ( " _GREEN_("ok") " ) "); + PrintAndLogEx(SUCCESS, "Privacy mode is disabled ( " _GREEN_("ok") " ) "); break; } } @@ -2581,7 +2917,7 @@ static int CmdHF15SlixEnable(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("p", "pwd", "", "password, 8 hex bytes"), + arg_str1("p", "pwd", "", "password, 4 hex bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -2611,11 +2947,11 @@ static int CmdHF15SlixEnable(const char *Cmd) { break; } case PM3_EWRONGANSWER: { - PrintAndLogEx(WARNING, "password was not accepted"); + PrintAndLogEx(WARNING, "Password was not accepted ( " _RED_("fail") " )"); break; } case PM3_SUCCESS: { - PrintAndLogEx(SUCCESS, "privacy mode is now enabled ( " _GREEN_("ok") " ) "); + PrintAndLogEx(SUCCESS, "Privacy mode is enabled ( " _GREEN_("ok") " ) "); break; } } @@ -2632,8 +2968,8 @@ static int CmdHF15SlixWritePassword(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str1("t", "type", "", "which password field to write to"), - arg_str0("o", "old", "", "old password (if present), 8 hex bytes"), - arg_str1("n", "new", "", "new password, 8 hex bytes"), + arg_str0("o", "old", "", "old password (if present), 4 hex bytes"), + arg_str1("n", "new", "", "new password, 4 hex bytes"), arg_param_end }; @@ -2707,11 +3043,11 @@ static int CmdHF15SlixWritePassword(const char *Cmd) { break; } case PM3_EWRONGANSWER: { - PrintAndLogEx(WARNING, "password was not accepted"); + PrintAndLogEx(WARNING, "Password was not accepted ( " _RED_("fail") " )"); break; } case PM3_SUCCESS: { - PrintAndLogEx(SUCCESS, "password written ( " _GREEN_("ok") " ) "); + PrintAndLogEx(SUCCESS, "Password written ( " _GREEN_("ok") " ) "); break; } } @@ -2728,7 +3064,7 @@ static int CmdHF15AFIPassProtect(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("p", "pwd", "", "EAS/AFI password, 8 hex bytes"), + arg_str1("p", "pwd", "", "EAS/AFI password, 4 hex bytes"), arg_lit0(NULL, "force", "Force execution of command (irreversible) "), arg_param_end }; @@ -2772,7 +3108,7 @@ static int CmdHF15AFIPassProtect(const char *Cmd) { break; } case PM3_EWRONGANSWER: { - PrintAndLogEx(WARNING, "error enabling AFI password protection"); + PrintAndLogEx(WARNING, "Enabling AFI password protection ( " _RED_("fail") " )"); break; } case PM3_SUCCESS: { @@ -2794,7 +3130,7 @@ static int CmdHF15EASPassProtect(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("p", "pwd", "", "EAS/AFI password, 8 hex bytes"), + arg_str1("p", "pwd", "", "EAS/AFI password, 4 hex bytes"), arg_lit0(NULL, "force", "Force execution of command (irreversible) "), arg_param_end }; @@ -2838,7 +3174,7 @@ static int CmdHF15EASPassProtect(const char *Cmd) { break; } case PM3_EWRONGANSWER: { - PrintAndLogEx(WARNING, "error enabling EAS password protection"); + PrintAndLogEx(WARNING, "Enabling EAS password protection ( " _RED_("fail") " )"); break; } case PM3_SUCCESS: { @@ -2877,13 +3213,106 @@ static int CmdHF15View(const char *Cmd) { return res; } - PrintAndLogEx(NORMAL, ""); print_blocks_15693(dump, bytes_read, 4); free(dump); return PM3_SUCCESS; } +static int CmdHF15Wipe(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 wipe", + "Wipe a ISO-15693 tag by filled memory with zeros", + "hf 15 wipe\n" + ); + void *argtable[6 + 3] = {0}; + uint8_t arglen = arg_add_default(argtable); + argtable[arglen++] = arg_int0(NULL, "bs", "", "block size (def 4)"), + argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); + argtable[arglen++] = arg_param_end; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + uint8_t uid[HF15_UID_LENGTH]; + int uidlen = 0; + CLIGetHexWithReturn(ctx, 1, uid, &uidlen); + bool uid_set = (uidlen == HF15_UID_LENGTH) ? true : false; + + bool unaddressed = arg_get_lit(ctx, 2); + bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; // Default fallback to scan for tag. Overriding unaddressed parameter. + bool fast = (arg_get_lit(ctx, 4) == false); + bool add_option = arg_get_lit(ctx, 5); + + int blocksize = arg_get_int_def(ctx, 6, 4); + bool verbose = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + + // sanity checks + if ((scan + unaddressed + uid_set) > 1) { + PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid"); + return PM3_EINVARG; + } + + if (blocksize < 4) { + PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); + blocksize = 4; + } + + // default fallback to scan for tag. + // overriding unaddress parameter :) + if (unaddressed == false) { + if (scan) { + if (getUID(verbose, false, uid) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "no tag found"); + return PM3_EINVARG; + } + } else { + reverse_array(uid, HF15_UID_LENGTH); + } + } else { + PrintAndLogEx(SUCCESS, "Using unaddressed mode"); + } + + // TI needs OPTION + if (uid[7] == 0xE0 && uid[6] == 0x07) { + if (verbose) { + PrintAndLogEx(INFO, "Overriding OPTION param, writing to TI tag"); + } + add_option = true; + } + + PrintAndLogEx(INFO, "Wiping tag..."); + + uint16_t flags = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); + uint8_t empty[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + uint8_t pm3flags = (ISO15_CONNECT | ISO15_READ_RESPONSE | ISO15_LONG_WAIT | ISO15_NO_DISCONNECT); + if (fast) { + pm3flags |= ISO15_HIGH_SPEED; + } + + for (uint16_t i = 0; i < 0x100; i++) { + + PrintAndLogEx(INPLACE, "blk %3d", i); + + int res = hf_15_write_blk(&pm3flags, flags, ((unaddressed) ? NULL : uid), fast, i, empty, blocksize); + if (res == PM3_SUCCESS) { + if (i == 0) { + pm3flags = (ISO15_READ_RESPONSE | ISO15_LONG_WAIT | ISO15_NO_DISCONNECT); + if (fast) { + pm3flags |= ISO15_HIGH_SPEED; + } + } + } else { + break; + } + } + + DropField(); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Done!"); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHF15Help, AlwaysAvailable, "This help"}, {"list", CmdHF15List, AlwaysAvailable, "List ISO-15693 history"}, @@ -2899,6 +3328,7 @@ static command_t CommandTable[] = { {"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO-15693 tag"}, {"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire samples as reader (enables carrier, sends inquiry)"}, {"view", CmdHF15View, AlwaysAvailable, "Display content from tag dump file"}, + {"wipe", CmdHF15Wipe, IfPm3Iso15693, "Wipe card to zeros"}, {"wrbl", CmdHF15Write, IfPm3Iso15693, "Write a block"}, {"-----------", CmdHF15Help, IfPm3Iso15693, "--------------------- " _CYAN_("simulation") " ----------------------"}, {"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO-15693 tag"}, diff --git a/client/src/cmdhfcryptorf.c b/client/src/cmdhfcryptorf.c index 1f2a18229..f35d18fbd 100644 --- a/client/src/cmdhfcryptorf.c +++ b/client/src/cmdhfcryptorf.c @@ -281,12 +281,12 @@ static int CmdHFCryptoRFDump(const char *Cmd) { bool m512 = arg_get_lit(ctx, 3); CLIParserFree(ctx); - if (m512 + m64 > 1) { + if (m512 + m64 != 1) { PrintAndLogEx(INFO, "Select only one card memory size"); return PM3_EINVARG; } - uint16_t cardsize = 0; + uint16_t cardsize; uint8_t blocks = 0; if (m64) { cardsize = (512 / 8) + 4; @@ -550,4 +550,3 @@ int CmdHFCryptoRF(const char *Cmd) { clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); } - diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 0933217cd..94623de5e 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -200,9 +200,8 @@ static bool emrtd_exchange_commands(sAPDU_t apdu, bool include_le, uint16_t le, } static int emrtd_exchange_commands_noout(sAPDU_t apdu, bool activate_field, bool keep_field_on) { - uint8_t response[PM3_CMD_DATA_SIZE]; + uint8_t response[PM3_CMD_DATA_SIZE] = {0}; size_t resplen = 0; - return emrtd_exchange_commands(apdu, false, 0, response, 0, &resplen, activate_field, keep_field_on); } @@ -987,7 +986,8 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA // Select EF_COM if (emrtd_select_file_by_ef(dg_table[EF_COM].fileid) == false) { *BAC = true; - PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication."); + PrintAndLogEx(INFO, "Authentication is enforced"); + PrintAndLogEx(INFO, "Switching to external authentication..."); } else { *BAC = false; // Select EF_DG1 @@ -997,7 +997,8 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false) == false) { *BAC = true; - PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication."); + PrintAndLogEx(INFO, "Authentication is enforced"); + PrintAndLogEx(INFO, "Switching to external authentication..."); } else { *BAC = false; } @@ -1006,9 +1007,9 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA // Do Basic Access Control if (*BAC) { // If BAC isn't available, exit out and warn user. - if (!BAC_available) { + if (BAC_available == false) { PrintAndLogEx(ERR, "This eMRTD enforces authentication, but you didn't supply MRZ data. Cannot proceed."); - PrintAndLogEx(HINT, "Check out hf emrtd info/dump --help, supply data with -n -d and -e."); + PrintAndLogEx(HINT, "Check out `hf emrtd info/dump --h`, supply data with `-n` `-d` and `-e`"); return false; } @@ -1034,19 +1035,19 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Dump EF_CardAccess (if available) - if (!emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, path)) { + if (emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, path) == false) { PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE"); PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about"); } // Authenticate with the eMRTD - if (!emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac)) { + if (emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac) == false) { DropField(); return PM3_ESOFT; } // Select EF_COM - if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC)) { + if (emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC) == false) { PrintAndLogEx(ERR, "Failed to read EF_COM"); DropField(); return PM3_ESOFT; @@ -1884,10 +1885,10 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab DropField(); return PM3_ESOFT; } - bool use14b = GetISODEPState() == ISODEP_NFCB; + bool use14b = (GetISODEPState() == ISODEP_NFCB); // Read EF_CardAccess - if (!emrtd_select_and_read(response, &resplen, dg_table[EF_CardAccess].fileid, ks_enc, ks_mac, ssc, BAC)) { + if (emrtd_select_and_read(response, &resplen, dg_table[EF_CardAccess].fileid, ks_enc, ks_mac, ssc, BAC) == false) { PACE_available = false; PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE."); } @@ -2044,6 +2045,7 @@ int infoHF_EMRTD_offline(const char *path) { // coverity scan CID 395630, if (data == NULL) { + free(filepath); return PM3_ESOFT; } diff --git a/client/src/cmdhffelica.c b/client/src/cmdhffelica.c index 5ba3e8116..c2f8743b3 100644 --- a/client/src/cmdhffelica.c +++ b/client/src/cmdhffelica.c @@ -263,28 +263,32 @@ static const char *felica_model_name(uint8_t rom_type, uint8_t ic_type) { * @param verbose prints out the response received. */ static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) { - if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) { - uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff); - if (verbose) { - PrintAndLogEx(SUCCESS, "client received %i octets", len); - if (len == 0 || len == 1) { - PrintAndLogEx(ERR, "Could not receive data correctly!"); - return false; - } - PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp->data.asBytes, len)); - if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) { - PrintAndLogEx(WARNING, "wrong or no CRC bytes"); - } - if (resp->data.asBytes[0] != 0xB2 && resp->data.asBytes[1] != 0x4D) { - PrintAndLogEx(ERR, "received incorrect frame format!"); - return false; - } - } - return true; - } else { + if (WaitForResponseTimeout(CMD_ACK, resp, 2000) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return false; } - return false; + + uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff); + + if (verbose) { + + if (len == 0 || len == 1) { + PrintAndLogEx(ERR, "Could not receive data correctly!"); + return false; + } + + PrintAndLogEx(SUCCESS, "(%u) %s", len, sprint_hex(resp->data.asBytes, len)); + + if (check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2) == false) { + PrintAndLogEx(WARNING, "CRC ( " _RED_("fail") " )"); + } + + if (resp->data.asBytes[0] != 0xB2 && resp->data.asBytes[1] != 0x4D) { + PrintAndLogEx(ERR, "received incorrect frame format!"); + return false; + } + } + return true; } @@ -2186,13 +2190,13 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"}, {"list", CmdHFFelicaList, AlwaysAvailable, "List ISO 18092/FeliCa history"}, - {"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"}, + {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"}, {"info", CmdHFFelicaInfo, IfPm3Felica, "Tag information"}, - {"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"}, {"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"}, {"rdbl", CmdHFFelicaReadPlain, IfPm3Felica, "read block data from authentication-not-required Service."}, + {"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"}, + {"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"}, {"wrbl", CmdHFFelicaWritePlain, IfPm3Felica, "write block data to an authentication-not-required Service."}, {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("FeliCa Standard") " -----------------------"}, //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"}, diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 340af551a..cf4b4f314 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1009,7 +1009,7 @@ int read_iclass_csn(bool loop, bool verbose, bool shallow_mod) { } else { if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) { - if (verbose) PrintAndLogEx(WARNING, "iCLASS / Picopass card select failed ( %d )", r->status); + if (verbose) PrintAndLogEx(WARNING, "iCLASS / Picopass card select failed ( %d , %d)", r->status, resp.status); res = PM3_EOPABORTED; break; } @@ -1059,7 +1059,7 @@ static int CmdHFiClassReader(const char *Cmd) { PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); } - return read_iclass_csn(cm, true, shallow_mod); + return read_iclass_csn(cm, false, shallow_mod); } static int CmdHFiClassELoad(const char *Cmd) { diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 6673491b5..96607d4db 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -819,7 +819,6 @@ static int mfLoadKeys(uint8_t **pkeyBlock, uint32_t *pkeycnt, uint8_t *userkey, *pkeycnt += loaded_numKeys; free(keyBlock_tmp); } - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%u") " keys from dictionary", loaded_numKeys); } return PM3_SUCCESS; } @@ -1563,6 +1562,7 @@ out: free(keyB); PrintAndLogEx(INFO, "-----+-------------------------------------------------+----------------"); PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf dump --ns") "` to verify"); PrintAndLogEx(INFO, "Done!"); return PM3_SUCCESS; } diff --git a/client/src/cmdhfmfhard.c b/client/src/cmdhfmfhard.c index f8f894e3c..78971eb01 100644 --- a/client/src/cmdhfmfhard.c +++ b/client/src/cmdhfmfhard.c @@ -1690,7 +1690,7 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_ } if (acquisition_completed) { - field_off = true; // switch off field with next SendCommandOLD and then finish + field_off = true; // switch off field with next SendCommandMIX and then finish } if (initialize == false) { diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 60a7130fe..b573daf35 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -829,9 +829,9 @@ static int ulev1_print_configuration(uint64_t tagtype, uint8_t *data, uint8_t st break; } PrintAndLogEx(INFO, " mirror start page %02X | byte pos %02X - %s" - , mirror_page, mirror_byte - , (mirror_page >= 0x4 && ((mirror_user_mem_start_byte + bytes_required_for_mirror_data) <= 144)) ? _GREEN_("ok") : _YELLOW_("Invalid value") - ); + , mirror_page, mirror_byte + , (mirror_page >= 0x4 && ((mirror_user_mem_start_byte + bytes_required_for_mirror_data) <= 144)) ? _GREEN_("ok") : _YELLOW_("Invalid value") + ); } } else if (tagtype & (MFU_TT_NTAG_213_F | MFU_TT_NTAG_216_F)) { @@ -2743,7 +2743,6 @@ static int CmdHF14AMfUDump(const char *Cmd) { if (is_partial) { PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size); } - return PM3_SUCCESS; } @@ -3108,7 +3107,8 @@ static int CmdHF14AMfURestore(const char *Cmd) { DropField(); free(dump); - PrintAndLogEx(INFO, "Restore finished"); + PrintAndLogEx(HINT, "try `" _YELLOW_("hf mfu dump --ns") "` to verify"); + PrintAndLogEx(INFO, "Done!"); return PM3_SUCCESS; } // diff --git a/client/src/cmdhfwaveshare.c b/client/src/cmdhfwaveshare.c index cc220b55d..c4ede2b3c 100644 --- a/client/src/cmdhfwaveshare.c +++ b/client/src/cmdhfwaveshare.c @@ -81,11 +81,11 @@ static model_t models[] = { static int CmdHelp(const char *Cmd); -static uint8_t * map8to1(gdImagePtr img, int color) { +static uint8_t *map8to1(gdImagePtr img, int color) { // Calculate width rounding up uint16_t width8 = (gdImageSX(img) + 7) / 8; - uint8_t * colormap8 = calloc(width8 * gdImageSY(img), sizeof(uint8_t)); + uint8_t *colormap8 = calloc(width8 * gdImageSY(img), sizeof(uint8_t)); if (!colormap8) { return NULL; } @@ -668,14 +668,14 @@ static int CmdHF14AWSLoad(const char *Cmd) { } } - uint8_t * black_plane = map8to1(pal_img, 1); + uint8_t *black_plane = map8to1(pal_img, 1); if (!black_plane) { PrintAndLogEx(WARNING, "Could not convert image to bit plane"); gdImageDestroy(pal_img); return PM3_EMALLOC; } - uint8_t * red_plane = NULL; + uint8_t *red_plane = NULL; if (model_has_red) { red_plane = map8to1(pal_img, 2); if (!red_plane) { diff --git a/client/src/cmdhfxerox.c b/client/src/cmdhfxerox.c index 88f910dfa..5a918d61b 100644 --- a/client/src/cmdhfxerox.c +++ b/client/src/cmdhfxerox.c @@ -5,15 +5,16 @@ #include "cmdhfxerox.h" #include "fileutils.h" - -#include "cmdparser.h" // command_t +#include "cmdtrace.h" +#include "cmdparser.h" // command_t #include "cliparser.h" #include "comms.h" #include "iso14b.h" #include "crc16.h" +#include "commonutil.h" // ARRAYLEN #define TIMEOUT 2000 - +#define XEROX_BLOCK_SIZE 4 #define c2l(c,l) (l = ((unsigned long)(*((c)++))), \ l |= ((unsigned long)(*((c)++))) << 8L, \ @@ -381,20 +382,21 @@ static int switch_off_field(void) { return PM3_SUCCESS; } -static int findXerox(iso14b_card_select_t *card, bool disconnect) { +static int xerox_select_card(iso14b_card_select_t *card) { if (card == NULL) { return PM3_EINVARG; } - int8_t retry = 3; + int8_t retry = 2; while (retry--) { iso14b_raw_cmd_t packet = { - .flags = (ISO14B_CONNECT | ISO14B_SELECT_XRX | (disconnect ? ISO14B_DISCONNECT : 0)), + .flags = (ISO14B_CONNECT | ISO14B_SELECT_XRX | ISO14B_DISCONNECT), .timeout = 0, .rawlen = 0, }; + clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); PacketResponseNG resp; @@ -403,23 +405,23 @@ static int findXerox(iso14b_card_select_t *card, bool disconnect) { if (resp.status == PM3_SUCCESS) { memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); } + return resp.length; } } // retry -// switch_off_field(); PrintAndLogEx(FAILED, "command execution timeout"); return PM3_ESOFT; } static uint8_t info_blocks[] = { 0x15, 0x16, 0x17, 0x18, 0x22 }; -static const char *c_type[] = { "drum", "yellow", "magenta", "cyan", "black" }; +static const char *xerox_c_type[] = { "drum", "yellow", "magenta", "cyan", "black" }; static inline char dec_digit(uint8_t dig) { return (dig <= 9) ? dig + '0' : '?'; } -static void gen_pn(const uint8_t *data, char *pn) { +static void xerox_generate_partno(const uint8_t *data, char *pn) { pn[0] = dec_digit(data[0] >> 4); pn[1] = dec_digit(data[0] & 0xF); pn[2] = dec_digit(data[1] >> 4); @@ -438,25 +440,110 @@ static void gen_pn(const uint8_t *data, char *pn) { pn[12] = 0; } +static void xerox_print_hdr(void) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "block# | data | ascii"); + PrintAndLogEx(INFO, "---------+--------------+----------"); +} + +static void xerox_print(uint8_t *data, uint16_t datalen) { + + uint16_t blockno = datalen / XEROX_BLOCK_SIZE; + + for (int i = 0; i < blockno; i++) { + PrintAndLogEx(INFO, + "%3d/0x%02X | %s | %s", + i, + i, + sprint_hex(data + (i * XEROX_BLOCK_SIZE), XEROX_BLOCK_SIZE), + sprint_ascii(data + (i * XEROX_BLOCK_SIZE), XEROX_BLOCK_SIZE) + ); + } +} + +static void xerox_print_footer(void) { + PrintAndLogEx(INFO, "---------+--------------+----------"); + PrintAndLogEx(NORMAL, ""); +} + + +// structure and database for uid -> tagtype lookups +typedef struct { + const char *color; + const char *partnumber; + const char *region; + const char *ms; +} xerox_part_t; + +// https://gist.github.com/JeroenSteen/4b45886b8d87fa0530af9b0364e6b277 +static const xerox_part_t xerox_part_mappings[] = { + {"cyan", "006R01532", "DMO", "sold"}, + {"cyan", "006R01660", "DMO", "sold"}, + {"cyan", "006R01739", "DMO", "sold"}, + {"cyan", "006R01524", "WW", "metered"}, + {"cyan", "006R01528", "NA/ESG", "sold"}, + {"cyan", "006R01656", "NA/ESG", "sold"}, + {"cyan", "006R01735", "NA/ESG", "sold"}, + + {"magenta", "006R01531", "DMO", "sold"}, + {"magenta", "006R01661", "DMO", "sold"}, + {"magenta", "006R01740", "DMO", "sold"}, + {"magenta", "006R01523", "WW", "metered"}, + {"magenta", "006R01527", "NA/ESG", "sold"}, + {"magenta", "006R01657", "NA/ESG", "sold"}, + {"magenta", "006R01736", "NA/ESG", "sold"}, + + {"yellow", "006R01530", "DMO", "sold"}, + {"yellow", "006R01662", "DMO", "sold"}, + {"yellow", "006R01741", "DMO", "sold"}, + {"yellow", "006R01522", "WW", "metered"}, + {"yellow", "006R01526", "NA/ESG", "sold"}, + {"yellow", "006R01658", "NA/ESG", "sold"}, + {"yellow", "006R01737", "NA/ESG", "sold"}, + + {"black", "006R01529", "DMO", "sold"}, + {"black", "006R01659", "DMO", "sold"}, + {"black", "006R01738", "DMO", "sold"}, + {"black", "006R01521", "WW", "metered"}, + {"black", "006R01525", "NA/ESG", "sold"}, + {"black", "006R01655", "NA/ESG", "sold"}, + {"black", "006R01734", "NA/ESG", "sold"}, + {"", "", "", ""} // must be the last entry +}; + +// get a product description based on the UID +// returns description of the best match +static const xerox_part_t *get_xerox_part_info(const char *pn) { + for (int i = 0; i < ARRAYLEN(xerox_part_mappings); ++i) { + if (str_startswith(pn, xerox_part_mappings[i].partnumber) == 0) { + return &xerox_part_mappings[i]; + } + } + //No match, return default + return &xerox_part_mappings[ARRAYLEN(xerox_part_mappings) - 1]; +} + int read_xerox_uid(bool loop, bool verbose) { do { iso14b_card_select_t card; - int status = findXerox(&card, true); + int status = xerox_select_card(&card); if (loop) { if (status != PM3_SUCCESS) { continue; } - } else { + } - if (status == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); - } else { - return PM3_ESOFT; + if (status == PM3_SUCCESS) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID..... %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, " ATQB.... %s", sprint_hex(card.atqb, sizeof(card.atqb))); + } else { + if (verbose) { + PrintAndLogEx(WARNING, "no tag found"); } + return PM3_ESOFT; } } while (loop && kbd_enter_pressed() == false); @@ -464,11 +551,80 @@ int read_xerox_uid(bool loop, bool verbose) { return PM3_SUCCESS; } +static int read_xerox_block(iso14b_card_select_t *card, uint8_t blockno, uint8_t *out) { + + if (card == NULL || out == NULL) { + return PM3_EINVARG; + } + + uint8_t approx_len = (2 + card->uidlen + 1); + iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + approx_len); + if (packet == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + } + + // set up the read command + packet->flags = (ISO14B_CONNECT | ISO14B_APPEND_CRC | ISO14B_RAW); + packet->raw[packet->rawlen++] = 0x02; + packet->raw[packet->rawlen++] = XEROX_READ_MEM; + + // uid + memcpy(packet->raw + packet->rawlen, card->uid, card->uidlen); + packet->rawlen += card->uidlen; + + // block to read + packet->raw[packet->rawlen++] = blockno; + + int res = PM3_ESOFT; + // read loop + for (int retry = 0; retry < 2; retry++) { + + if (retry) { + packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW); + } + + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000) == false) { + continue; + } + + // sanity checks + if (resp.length < 7) { + PrintAndLogEx(FAILED, "trying one more time, wrong length"); + continue; + } + + uint8_t *d = resp.data.asBytes; + + if (check_crc(CRC_14443_B, d, 7) == false) { + PrintAndLogEx(FAILED, "trying one more time, CRC ( " _RED_("fail") " )"); + continue; + } + + if (d[0] != 2) { + PrintAndLogEx(FAILED, "Tag returned Error %x %x", d[0], d[1]); + res = PM3_ERFTRANS; + break; + } + + memcpy(out + (blockno * XEROX_BLOCK_SIZE), d + 1, XEROX_BLOCK_SIZE); + res = PM3_SUCCESS; + break; + } + + switch_off_field(); + return res; +} + static int CmdHFXeroxReader(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf xerox reader", - "Act as a 14443B reader to identify a tag", + "Act as a 14443B reader to identify a Fuji Xerox based tag\n" + "ISO/IEC 14443 type B based communications", "hf xerox reader\n" "hf xerox reader -@ \n" ); @@ -494,7 +650,8 @@ static int CmdHFXeroxReader(const char *Cmd) { static int CmdHFXeroxInfo(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf xerox info", - "Tag information for ISO/IEC 14443 type B / XEROX based tags", + "Tag information for Fuji Xerox based tags\n" + "ISO/IEC 14443 type B based communications", "hf xerox info" ); @@ -508,9 +665,8 @@ static int CmdHFXeroxInfo(const char *Cmd) { CLIParserFree(ctx); iso14b_card_select_t card; - int status = findXerox(&card, false); + int status = xerox_select_card(&card); if (status != PM3_SUCCESS) { - switch_off_field(); if (verbose) { PrintAndLogEx(FAILED, "Fuji/Xerox tag select failed"); } @@ -518,86 +674,46 @@ static int CmdHFXeroxInfo(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(SUCCESS, " UID..... %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, " ATQB.... %s", sprint_hex(card.atqb, sizeof(card.atqb))); - iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11); - if (packet == NULL) { - PrintAndLogEx(FAILED, "failed to allocate memory"); - return PM3_EMALLOC; - } - int blocknum = 0; - uint8_t data[sizeof(info_blocks) * 4] = {0}; + uint8_t data[sizeof(info_blocks) * XEROX_BLOCK_SIZE] = {0}; - // set up the read command - packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW); - packet->rawlen = 11; - packet->raw[0] = 0x02; - packet->raw[1] = 0x20; // set command: read mem - memcpy(packet->raw + 2, card.uid, 8); // store uid + for (int i = 0; i < sizeof(i); i++) { - for (int retry = 0; (retry < 5 && blocknum < sizeof(info_blocks)); retry++) { - - packet->raw[10] = info_blocks[blocknum]; - - PacketResponseNG resp; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen); - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) { - /* - PrintAndLogEx(INFO, "%X %X %X %X %X %I64X %I64X %I64X %X %X %X %c", - resp.cmd, resp.length, resp.magic, resp.status, resp.crc, resp.oldarg[0], resp.oldarg[1], resp.oldarg[2], - resp.data.asBytes[0], resp.data.asBytes[1], resp.data.asBytes[2], resp.ng ? 't' : 'f'); - */ - - // 14b raw command send data_len instead of status - if (resp.length < 7) { - PrintAndLogEx(FAILED, "retrying one more time"); - continue; - } - - uint8_t *recv = resp.data.asBytes; - - if (check_crc(CRC_14443_B, recv, 7) == false) { - PrintAndLogEx(FAILED, "crc fail, retrying one more time"); - continue; - } - - if (recv[0] != 2) { - PrintAndLogEx(FAILED, "Tag returned Error %x %x", recv[0], recv[1]); - break; - } - - memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4); - - retry = 0; - blocknum++; + int res = read_xerox_block(&card, info_blocks[i], data + (i * XEROX_BLOCK_SIZE)); + if (res != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Fuji/Xerox tag read failed"); + break; } } switch_off_field(); - free(packet); - - if (blocknum != sizeof(info_blocks)) { - PrintAndLogEx(FAILED, "Fuji/Xerox tag read failed"); - return PM3_ERFTRANS; - } char pn[13]; - gen_pn(data, pn); - PrintAndLogEx(SUCCESS, " PartNo : %s", pn); - PrintAndLogEx(SUCCESS, " Date : %02d.%02d.%02d", data[8], data[9], data[10]); - PrintAndLogEx(SUCCESS, " Serial : %d", (data[14] << 16) | (data[13] << 8) | data[12]); - PrintAndLogEx(SUCCESS, " Type : %s", (data[18] <= 4) ? c_type[data[18]] : "Unknown"); + xerox_generate_partno(data, pn); + PrintAndLogEx(INFO, "-------- " _CYAN_("tag memory") " ---------"); + PrintAndLogEx(SUCCESS, " PartNo... %s", pn); + PrintAndLogEx(SUCCESS, " Date..... %02d.%02d.%02d", data[8], data[9], data[10]); + PrintAndLogEx(SUCCESS, " Serial... %d", (data[14] << 16) | (data[13] << 8) | data[12]); + PrintAndLogEx(SUCCESS, " Type..... %s", (data[18] <= 4) ? xerox_c_type[data[18]] : "Unknown"); + const xerox_part_t *item = get_xerox_part_info(pn); + if (strlen(item->partnumber) > 0) { + PrintAndLogEx(SUCCESS, "Color..... %s", item->color); + PrintAndLogEx(SUCCESS, "Region.... %s", item->region); + PrintAndLogEx(SUCCESS, "M/s....... %s", item->ms); + } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } static int CmdHFXeroxDump(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf xerox dump", - "Dump all memory from a Fuji/Xerox tag", + "Dump all memory from a Fuji/Xerox tag\n" + "ISO/IEC 14443 type B based communications", "hf xerox dump\n" ); @@ -605,6 +721,8 @@ static int CmdHFXeroxDump(const char *Cmd) { arg_param_begin, arg_str0("f", "file", "", "filename to save dump to"), arg_lit0("d", "decrypt", "decrypt secret blocks"), + arg_lit0(NULL, "ns", "no save to file"), + arg_lit0("v", "verbose", "verbose output"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -613,39 +731,48 @@ static int CmdHFXeroxDump(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); bool decrypt = arg_get_lit(ctx, 2); + bool nosave = arg_get_lit(ctx, 3); + bool verbose = arg_get_lit(ctx, 4); CLIParserFree(ctx); - iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11); + iso14b_card_select_t card; + int status = xerox_select_card(&card); + if (status != PM3_SUCCESS) { + if (verbose) { + PrintAndLogEx(FAILED, "Fuji/Xerox tag select failed"); + } + return status; + } + + PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); + + uint8_t approx_len = (2 + 8 + 1); + iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + approx_len); if (packet == NULL) { PrintAndLogEx(FAILED, "failed to allocate memory"); return PM3_EMALLOC; } - iso14b_card_select_t card; - int status = findXerox(&card, false); // remain RF on - if (status != PM3_SUCCESS) { - free(packet); - switch_off_field(); - return PM3_ERFTRANS; - } - - PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); - - int blocknum = 1; // block 0 all zeros - uint8_t data[256 * 4] = {0}; + int blockno = 1; // block 0 all zeros + uint8_t data[256 * XEROX_BLOCK_SIZE] = {0}; // set up the read command - packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW); - packet->rawlen = 11; - packet->raw[0] = 0x02; - memcpy(packet->raw + 2, card.uid, 8); // store uid + packet->flags = (ISO14B_CONNECT | ISO14B_APPEND_CRC | ISO14B_RAW); + packet->raw[packet->rawlen++] = 0x02; + + // add one for command byte + packet->rawlen++; + + // store uid + memcpy(packet->raw + packet->rawlen, card.uid, 8); + packet->rawlen += 8; PrintAndLogEx(INFO, "." NOLF); - for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) { + for (int retry = 0; (retry < 2 && blockno < 0x100); retry++) { - packet->raw[1] = (blocknum < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem - packet->raw[10] = blocknum & 0xFF; + packet->raw[1] = (blockno < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem + packet->raw[10] = blockno & 0xFF; PacketResponseNG resp; clearCommandBuffer(); @@ -656,29 +783,29 @@ static int CmdHFXeroxDump(const char *Cmd) { resp.cmd, resp.length, resp.magic, resp.status, resp.crc, resp.oldarg[0], resp.oldarg[1], resp.oldarg[2], resp.data.asBytes[0], resp.data.asBytes[1], resp.data.asBytes[2], resp.ng ? 't' : 'f'); */ - + if (resp.length < 7) { PrintAndLogEx(FAILED, "retrying one more time"); continue; } - uint8_t *recv = resp.data.asBytes; + uint8_t *d = resp.data.asBytes; - if (check_crc(CRC_14443_B, recv, 7) == false) { - PrintAndLogEx(FAILED, "crc fail, retrying one more time"); + if (check_crc(CRC_14443_B, d, 7) == false) { + PrintAndLogEx(FAILED, "retrying one more time, CRC ( " _RED_("fail") " )"); continue; } - if (recv[0] != 2) { + if (d[0] != 2) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(FAILED, "Tag returned Error %x %x", recv[0], recv[1]); + PrintAndLogEx(FAILED, "Tag returned Error %x %x", d[0], d[1]); break; } - memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4); + memcpy(data + (blockno * XEROX_BLOCK_SIZE), resp.data.asBytes + 1, XEROX_BLOCK_SIZE); retry = 0; - blocknum++; + blockno++; PrintAndLogEx(NORMAL, "." NOLF); fflush(stdout); @@ -691,8 +818,8 @@ static int CmdHFXeroxDump(const char *Cmd) { PrintAndLogEx(NORMAL, ""); - if (blocknum != 0x100) { - PrintAndLogEx(FAILED, "dump failed at block %d", blocknum); + if (blockno != 0x100) { + PrintAndLogEx(FAILED, "dump failed at block " _RED_("%d"), blockno); } if (decrypt) { @@ -705,9 +832,9 @@ static int CmdHFXeroxDump(const char *Cmd) { k1[1] = data[5]; k1[2] = data[6]; k1[3] = data[7]; - k1[4] = data[0x18 * 4 + 0]; - k1[5] = data[0x18 * 4 + 1]; - k1[6] = data[0x22 * 4 + 0]; + k1[4] = data[(0x18 * XEROX_BLOCK_SIZE) + 0]; + k1[5] = data[(0x18 * XEROX_BLOCK_SIZE) + 1]; + k1[6] = data[(0x22 * XEROX_BLOCK_SIZE) + 0]; k1[7] = 0; RC2_set_key(&exp_key, 8, k1, 64); @@ -721,8 +848,8 @@ static int CmdHFXeroxDump(const char *Cmd) { memcpy(k1, k2, sizeof(k1)); - k1[2] = k2[3] ^ data[0x22 * 4 + 0]; - k1[3] = k2[4] ^ data[0x22 * 4 + 1]; // first_key[7]; + k1[2] = k2[3] ^ data[(0x22 * XEROX_BLOCK_SIZE) + 0]; + k1[3] = k2[4] ^ data[(0x22 * XEROX_BLOCK_SIZE) + 1]; // first_key[7]; k1[5] = k2[1] ^ 0x01; // 01 = crypto method? rfid[23][2] RC2_set_key(&exp_key, 8, k1, 64); @@ -731,7 +858,7 @@ static int CmdHFXeroxDump(const char *Cmd) { uint8_t dadr = var_list[n]; - if (dadr + 1 >= blocknum) { + if (dadr + 1 >= blockno) { PrintAndLogEx(INFO, "secret block %02X skipped.", dadr); continue; } @@ -739,9 +866,9 @@ static int CmdHFXeroxDump(const char *Cmd) { memset(iv, 0, sizeof(iv)); iv[0] = dadr; - RC2_cbc_encrypt(&data[dadr * 4], decr, 8, &exp_key, iv, RC2_DECRYPT); + RC2_cbc_encrypt(&data[dadr * XEROX_BLOCK_SIZE], decr, 8, &exp_key, iv, RC2_DECRYPT); - memcpy(&data[dadr * 4], decr, 8); + memcpy(&data[dadr * XEROX_BLOCK_SIZE], decr, 8); int b; uint16_t cs, csd; @@ -750,6 +877,7 @@ static int CmdHFXeroxDump(const char *Cmd) { for (b = 0, cs = 0; b < sizeof(decr) - 2; b += 2) { cs += decr[b] | (decr[b + 1] << 8); } + cs = ~cs; csd = (decr[7] << 8) | decr[6]; @@ -759,37 +887,109 @@ static int CmdHFXeroxDump(const char *Cmd) { } } - PrintAndLogEx(INFO, "block# | data | ascii"); - PrintAndLogEx(INFO, "---------+--------------+----------"); + xerox_print_hdr(); + xerox_print(data, blockno * XEROX_BLOCK_SIZE); + xerox_print_footer(); - for (int i = 0; i < blocknum; i++) { - PrintAndLogEx(INFO, - "%3d/0x%02X | %s | %s", - i, - i, - sprint_hex(data + (i * 4), 4), - sprint_ascii(data + (i * 4), 4) - ); + if (nosave) { + PrintAndLogEx(INFO, "Called with no save option"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; } - PrintAndLogEx(INFO, "---------+--------------+----------"); - PrintAndLogEx(NORMAL, ""); if (0 == filename[0]) { // generate filename from uid char *fptr = filename; PrintAndLogEx(INFO, "Using UID as filename"); fptr += snprintf(fptr, sizeof(filename), "hf-xerox-"); - FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), decrypt ? "-dump-dec" : "-dump", card.uidlen); + FillFileNameByUID(fptr + , SwapEndian64(card.uid, card.uidlen, 8) + , (decrypt) ? "-dump-dec" : "-dump" + , card.uidlen + ); } - pm3_save_dump(filename, data, blocknum * 4, jsf14b_v2); + pm3_save_dump(filename, data, blockno * XEROX_BLOCK_SIZE, jsf14b_v2); return PM3_SUCCESS; } +static int CmdHFXeroxView(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf xerox view", + "Print a Fuji/Xerox dump file (bin/eml/json)\n" + "note:\n" + " - command expects the filename to contain a UID\n" + " which is needed to determine card memory type", + "hf xerox view -f hf-xerox-0102030405060708-dump.bin" + ); + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "Specify a filename for dump file"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + int fnlen = 0; + char filename[FILE_PATH_SIZE]; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + bool verbose = arg_get_lit(ctx, 2); + CLIParserFree(ctx); + + // read dump file + uint8_t *dump = NULL; + size_t bytes_read = (XEROX_BLOCK_SIZE * 0x100); + int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (XEROX_BLOCK_SIZE * 0x100)); + if (res != PM3_SUCCESS) { + return res; + } + + uint16_t blockno = bytes_read / XEROX_BLOCK_SIZE; + + if (verbose) { + PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, blockno, blockno); + } + + uint8_t tmp[5 * XEROX_BLOCK_SIZE] = {0}; + for (uint8_t i = 0; i < ARRAYLEN(info_blocks); i++) { + memcpy(tmp + (i * XEROX_BLOCK_SIZE), dump + (info_blocks[i] * XEROX_BLOCK_SIZE), XEROX_BLOCK_SIZE); + } + + char pn[13]; + xerox_generate_partno(tmp, pn); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------- " _CYAN_("tag memory") " ---------"); + PrintAndLogEx(SUCCESS, " PartNo... %s", pn); + PrintAndLogEx(SUCCESS, " Date..... %02d.%02d.%02d", tmp[8], tmp[9], tmp[10]); + PrintAndLogEx(SUCCESS, " Serial... %d", (tmp[14] << 16) | (tmp[13] << 8) | tmp[12]); + PrintAndLogEx(SUCCESS, " Type..... %s", (tmp[18] <= 4) ? xerox_c_type[tmp[18]] : "Unknown"); + + const xerox_part_t *item = get_xerox_part_info(pn); + if (strlen(item->partnumber) > 0) { + PrintAndLogEx(SUCCESS, "Color..... %s", item->color); + PrintAndLogEx(SUCCESS, "Region.... %s", item->region); + PrintAndLogEx(SUCCESS, "M/s....... %s", item->ms); + } + xerox_print_hdr(); + xerox_print(dump, bytes_read); + xerox_print_footer(); + + free(dump); + return PM3_SUCCESS; +} + +static int CmdHFXeroxList(const char *Cmd) { + return CmdTraceListAlias(Cmd, "hf 14b", "14b -c"); +} + static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"info", CmdHFXeroxInfo, IfPm3Iso14443b, "Short info on Fuji/Xerox tag"}, - {"reader", CmdHFXeroxReader, IfPm3Iso14443b, "Act like a Fuji/Xerox reader"}, - {"dump", CmdHFXeroxDump, IfPm3Iso14443b, "Read all memory pages of an Fuji/Xerox tag, save to file"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"list", CmdHFXeroxList, AlwaysAvailable, "List ISO-14443B history"}, + {"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("general") " -----------------------"}, + {"info", CmdHFXeroxInfo, IfPm3Iso14443b, "Short info on Fuji/Xerox tag"}, + {"dump", CmdHFXeroxDump, IfPm3Iso14443b, "Read all memory pages of an Fuji/Xerox tag, save to file"}, + {"reader", CmdHFXeroxReader, IfPm3Iso14443b, "Act like a Fuji/Xerox reader"}, + {"view", CmdHFXeroxView, AlwaysAvailable, "Display content from tag dump file"}, // {"rdbl", CmdHFXeroxRdBl, IfPm3Iso14443b, "Read Fuji/Xerox block"}, // {"wrbl", CmdHFXeroxWrBl, IfPm3Iso14443b, "Write Fuji/Xerox block"}, {NULL, NULL, NULL, NULL} diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 11b48d6b7..ab8c3a123 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -292,6 +292,7 @@ int CmdLFCommandRead(const char *Cmd) { payload.samples = samples; payload.keep_field_on = keep_field_on; payload.verbose = verbose; + memset(payload.symbol_extra, 0, sizeof(payload.symbol_extra)); if (add_crc_ht && (cmd_len <= 120)) { // Hitag 1, Hitag S, ZX8211 @@ -734,6 +735,7 @@ static int lf_read_internal(bool realtime, bool verbose, uint64_t samples) { int result = set_fpga_mode(FPGA_BITSTREAM_LF); if (result != PM3_SUCCESS) { PrintAndLogEx(FAILED, "failed to load LF bitstream to FPGA"); + free(realtimeBuf); return result; } @@ -860,6 +862,7 @@ int lf_sniff(bool realtime, bool verbose, uint64_t samples) { int result = set_fpga_mode(FPGA_BITSTREAM_LF); if (result != PM3_SUCCESS) { PrintAndLogEx(FAILED, "failed to load LF bitstream to FPGA"); + free(realtimeBuf); return result; } diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 894ad3b5d..7db520897 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -1853,7 +1853,7 @@ static int CmdT55xxReadTrace(const char *Cmd) { ct = localtime_r(&now, &tm_buf); #endif - if (data.year > ct->tm_year - 110) + if (ct != NULL && (data.year > ct->tm_year - 110)) data.year += 2000; else data.year += 2010; @@ -4419,4 +4419,3 @@ int CmdLFT55XX(const char *Cmd) { clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); } - diff --git a/client/src/cmdparser.c b/client/src/cmdparser.c index fe7243c5e..feafb2a4f 100644 --- a/client/src/cmdparser.c +++ b/client/src/cmdparser.c @@ -194,6 +194,9 @@ bool IfPm3Zx8211(void) { void CmdsHelp(const command_t Commands[]) { if (Commands[0].Name == NULL) return; + + PrintAndLogEx(NORMAL, ""); + int i = 0; while (Commands[i].Name) { if (Commands[i].IsAvailable()) { @@ -271,6 +274,14 @@ int CmdsParse(const command_t Commands[], const char *Cmd) { str_lower(cmd_name); + // iceman: I mistyped "list" so many times with "lsit". No more. + char *lsit = strstr(cmd_name, "lsit"); + if (lsit) { + lsit[1] = lsit[2] ^ lsit[1]; + lsit[2] = lsit[1] ^ lsit[2]; + lsit[1] = lsit[2] ^ lsit[1]; + } + // Comment if (cmd_name[0] == '#') return PM3_SUCCESS; diff --git a/client/src/cmdsmartcard.c b/client/src/cmdsmartcard.c index b8fbef3a7..2ef17e7c5 100644 --- a/client/src/cmdsmartcard.c +++ b/client/src/cmdsmartcard.c @@ -1091,6 +1091,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) { if (json_is_object(data) == false) { PrintAndLogEx(ERR, "\ndata %d is not an object\n", i + 1); json_decref(root); + free(buf); return PM3_ESOFT; } @@ -1098,6 +1099,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) { if (json_is_string(jaid) == false) { PrintAndLogEx(ERR, "\nAID data [%d] is not a string", i + 1); json_decref(root); + free(buf); return PM3_ESOFT; } @@ -1459,5 +1461,3 @@ bool smart_select(bool verbose, smart_card_atr_t *atr) { return true; } - - diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 9ee7b256a..b5e0d98db 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -760,6 +760,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr if (prev_eot) *prev_eot = end_of_transmission_timestamp; + + // Always annotate these protocols both reader/tag messages switch (protocol) { case ISO_14443A: @@ -836,6 +838,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr if (j == 0) { + uint32_t time1 = hdr->timestamp - first_hdr->timestamp; uint32_t time2 = end_of_transmission_timestamp - first_hdr->timestamp; if (prev_eot) { @@ -995,13 +998,14 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr static int download_trace(void) { if (IfPm3Present() == false) { - PrintAndLogEx(FAILED, "You requested a trace upload in offline mode, consider using parameter '-1' for working from Tracebuffer"); + PrintAndLogEx(FAILED, "You requested a trace upload in offline mode, consider using parameter `" _YELLOW_("-1") "` for working from Tracebuffer"); return PM3_EINVARG; } // reserve some space. - if (gs_trace) + if (gs_trace) { free(gs_trace); + } gs_traceLen = 0; @@ -1011,7 +1015,7 @@ static int download_trace(void) { return PM3_EMALLOC; } - PrintAndLogEx(INFO, "downloading tracelog data from device"); + PrintAndLogEx(DEBUG, "downloading tracelog data from device"); // Query for the size of the trace, downloading PM3_CMD_DATA_SIZE PacketResponseNG resp; @@ -1078,11 +1082,11 @@ static int CmdTraceExtract(const char *Cmd) { download_trace(); } else if (gs_traceLen == 0) { PrintAndLogEx(FAILED, "You requested a trace list in offline mode but there is no trace."); - PrintAndLogEx(FAILED, "Consider using " _YELLOW_("`trace load`") " or removing parameter " _YELLOW_("`-1`")); + PrintAndLogEx(FAILED, "Consider using `" _YELLOW_("trace load") "` or removing parameter `" _YELLOW_("-1") "`"); return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "Recorded activity (trace len = " _YELLOW_("%u") " bytes)", gs_traceLen); + PrintAndLogEx(SUCCESS, "Recorded activity ( " _YELLOW_("%u") " bytes )", gs_traceLen); if (gs_traceLen == 0) { return PM3_SUCCESS; } @@ -1092,10 +1096,10 @@ static int CmdTraceExtract(const char *Cmd) { while (tracepos < gs_traceLen) { tracepos = extractChallenges(tracepos, gs_traceLen, gs_trace); - if (kbd_enter_pressed()) + if (kbd_enter_pressed()) { break; + } } - return PM3_SUCCESS; } @@ -1312,11 +1316,11 @@ int CmdTraceList(const char *Cmd) { download_trace(); } else if (gs_traceLen == 0 || gs_trace == NULL) { PrintAndLogEx(FAILED, "You requested a trace list in offline mode but there is no trace."); - PrintAndLogEx(FAILED, "Consider using " _YELLOW_("`trace load`") " or removing parameter " _YELLOW_("`-1`")); + PrintAndLogEx(FAILED, "Consider using `" _YELLOW_("trace load") "` or removing parameter `" _YELLOW_("-1") "`"); return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "Recorded activity (trace len = " _YELLOW_("%u") " bytes)", gs_traceLen); + PrintAndLogEx(SUCCESS, "Recorded activity ( " _YELLOW_("%u") " bytes )", gs_traceLen); if (gs_traceLen == 0) { return PM3_SUCCESS; } @@ -1335,9 +1339,9 @@ int CmdTraceList(const char *Cmd) { } else { if (use_relative) { - PrintAndLogEx(INFO, _YELLOW_("gap") " = time between transfers. " _YELLOW_("duration") " = duration of data transfer. " _YELLOW_("src") " = source of transfer"); + PrintAndLogEx(INFO, _YELLOW_("gap") " = time between transfers. " _YELLOW_("duration") " = duration of data transfer. " _YELLOW_("src") " = source of transfer."); } else { - PrintAndLogEx(INFO, _YELLOW_("start") " = start of start frame " _YELLOW_("end") " = end of frame. " _YELLOW_("src") " = source of transfer"); + PrintAndLogEx(INFO, _YELLOW_("start") " = start of start frame. " _YELLOW_("end") " = end of frame. " _YELLOW_("src") " = source of transfer."); } if (protocol == ISO_14443A || protocol == PROTO_MIFARE || protocol == MFDES || protocol == PROTO_MFPLUS || protocol == TOPAZ || protocol == LTO) { diff --git a/client/src/cmdwiegand.c b/client/src/cmdwiegand.c index 0973a9beb..9fc06b6f9 100644 --- a/client/src/cmdwiegand.c +++ b/client/src/cmdwiegand.c @@ -145,7 +145,7 @@ int CmdWiegandDecode(const char *Cmd) { if (hlen) { res = hexstring_to_u96(&top, &mid, &bot, hex); if (res != hlen) { - PrintAndLogEx(ERR, "hex string contains none hex chars"); + PrintAndLogEx(ERR, "Hex string contains none hex chars"); return PM3_EINVARG; } } else if (blen) { @@ -154,8 +154,9 @@ int CmdWiegandDecode(const char *Cmd) { PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); return PM3_EINVARG; } + PrintAndLogEx(INFO, "Input bin len... %d", blen); } else { - PrintAndLogEx(ERR, "empty input"); + PrintAndLogEx(ERR, "Empty input"); return PM3_EINVARG; } diff --git a/client/src/emv/cmdemv.c b/client/src/emv/cmdemv.c index af7255575..107d97362 100644 --- a/client/src/emv/cmdemv.c +++ b/client/src/emv/cmdemv.c @@ -2890,7 +2890,7 @@ static int CmdEMVReader(const char *Cmd) { } while (continuous); DropFieldEx(channel); - + SetAPDULogging(old_logging); return PM3_SUCCESS; } diff --git a/client/src/fileutils.c b/client/src/fileutils.c index c4e915509..3e2a2b143 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -239,6 +239,22 @@ char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePath return fileName; } +// trunacate down a filename to LEN size +void truncate_filename(char *fn, uint16_t maxlen) { + if (fn == NULL || maxlen < 5) { + return; + } + + // Check if the filename is already shorter than or equal to the desired length + if (strlen(fn) <= maxlen) { + return; + } + + // If there's no extension or it's too long, just truncate the filename + fn[maxlen - 3] = '\0'; + strcat(fn, "..."); +} + // --------- SAVE FILES int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) { @@ -1336,11 +1352,12 @@ int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) { static int load_file_sanity(char *s, uint32_t datalen, int i, size_t len) { if (len == 0) { - PrintAndLogEx(WARNING, "WARNING: json %s block %d has zero-length data", s, i); - PrintAndLogEx(INFO, "file parsing stopped"); + PrintAndLogEx(DEBUG, "WARNING: json %s block %d has zero-length data", s, i); + PrintAndLogEx(INFO, "File parsing stopped"); return false; } else if (len != datalen) { - PrintAndLogEx(WARNING, "WARNING: json %s block %d only has %zu bytes, expected %d (will fill with zero data)", s, i, len, datalen); + PrintAndLogEx(WARNING, "WARNING: json %s block %d only has %zu bytes", s, i, len); + PrintAndLogEx(INFO, "Expected %d - padding with zeros", datalen); } return true; } diff --git a/client/src/fileutils.h b/client/src/fileutils.h index 1af72f28d..fa36fb89e 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -107,6 +107,8 @@ bool setDefaultPath(savePaths_t pathIndex, const char *path); char *newfilenamemcopy(const char *preferredName, const char *suffix); char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t save_path); +void truncate_filename(char *fn, uint16_t len); + /** * @brief Utility function to save data to a binary file. This method takes a preferred name, but if that diff --git a/client/src/imgutils.c b/client/src/imgutils.c index 4b396c0ac..09f70faf5 100644 --- a/client/src/imgutils.c +++ b/client/src/imgutils.c @@ -8,7 +8,7 @@ struct ycbcr_t { int cr; }; -static void rgb_to_ycbcr(int rgb, struct ycbcr_t * ycbcr) { +static void rgb_to_ycbcr(int rgb, struct ycbcr_t *ycbcr) { int r = gdTrueColorGetRed(rgb); int g = gdTrueColorGetGreen(rgb); int b = gdTrueColorGetBlue(rgb); @@ -25,7 +25,7 @@ static void rgb_to_ycbcr(int rgb, struct ycbcr_t * ycbcr) { ycbcr->cr = (r * 32768 + g * -27439 + b * -5329) / 65536 + 128; } -static inline void cap_comp(int * x) { +static inline void cap_comp(int *x) { if (*x < 0) { *x = 0; } else if (*x > 255) { @@ -33,7 +33,7 @@ static inline void cap_comp(int * x) { } } -gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size) { +gdImagePtr img_palettize(gdImagePtr rgb, int *palette, int palette_size) { assert(rgb != NULL); assert(palette != NULL); assert(palette_size >= 2 && palette_size < 256); @@ -45,7 +45,7 @@ gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size) { } // Allocate space for palette in YCbCr - struct ycbcr_t * pal_ycbcr = calloc(palette_size, sizeof(struct ycbcr_t)); + struct ycbcr_t *pal_ycbcr = calloc(palette_size, sizeof(struct ycbcr_t)); if (!pal_ycbcr) { gdImageDestroy(res); return NULL; @@ -60,7 +60,7 @@ gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size) { * To reduce shifts and increase accuracy, each entry is stored with 16x times the error, * and gets divided by that amount when it is read. */ - struct ycbcr_t * forward = calloc(gdImageSX(rgb) + 2, sizeof(struct ycbcr_t)); + struct ycbcr_t *forward = calloc(gdImageSX(rgb) + 2, sizeof(struct ycbcr_t)); if (!forward) { free(pal_ycbcr); gdImageDestroy(res); @@ -108,10 +108,10 @@ gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size) { }; int can_score = ( - can_err.y * can_err.y + - can_err.cb * can_err.cb + - can_err.cr * can_err.cr - ); + can_err.y * can_err.y + + can_err.cb * can_err.cb + + can_err.cr * can_err.cr + ); if (can_score < best_score) { best_idx = can_idx; diff --git a/client/src/imgutils.h b/client/src/imgutils.h index ff619a5e1..d38f02d04 100644 --- a/client/src/imgutils.h +++ b/client/src/imgutils.h @@ -28,7 +28,7 @@ * * A comparison can be found at https://twitter.com/Socram4x8/status/1733157380097995205/photo/1. */ -gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size); +gdImagePtr img_palettize(gdImagePtr rgb, int *palette, int palette_size); /* * This function scales and crops the image to the given size. diff --git a/client/src/iso7816/iso7816core.c b/client/src/iso7816/iso7816core.c index 71f2a8e49..9eafaa599 100644 --- a/client/src/iso7816/iso7816core.c +++ b/client/src/iso7816/iso7816core.c @@ -44,10 +44,11 @@ static isodep_state_t isodep_state = ISODEP_INACTIVE; void SetISODEPState(isodep_state_t state) { isodep_state = state; if (APDULogging) { - PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s" + PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s%s" , isodep_state == ISODEP_INACTIVE ? "inactive" : "" , isodep_state == ISODEP_NFCA ? _GREEN_("NFC-A") : "" , isodep_state == ISODEP_NFCB ? _GREEN_("NFC-B") : "" + , isodep_state == ISODEP_NFCV ? _GREEN_("NFC-V") : "" ); } } @@ -64,7 +65,6 @@ int Iso7816Connect(Iso7816CommandChannel channel) { // select with no disconnect and set frameLength int res = SelectCard14443A_4(false, false, NULL); if (res == PM3_SUCCESS) { - SetISODEPState(ISODEP_NFCA); return PM3_SUCCESS; } @@ -72,7 +72,6 @@ int Iso7816Connect(Iso7816CommandChannel channel) { // If not 14a, try to 14b res = select_card_14443b_4(false, NULL); if (res == PM3_SUCCESS) { - SetISODEPState(ISODEP_NFCB); return PM3_SUCCESS; } @@ -110,8 +109,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l return 201; } - if (APDULogging) + if (APDULogging) { PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen)); + } int res = 0; @@ -125,6 +125,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l case ISODEP_NFCB: res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000); break; + case ISODEP_NFCV: + PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); + break; case ISODEP_INACTIVE: if (activate_field == false) { PrintAndLogEx(FAILED, "Field currently inactive, cannot send an APDU"); @@ -133,11 +136,7 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l res = ExchangeAPDU14a(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len); if (res != PM3_SUCCESS) { res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000); - if (res == PM3_SUCCESS) { - PrintAndLogEx(INFO, "Testing ISO14443-B... ( " _GREEN_("ok") " )"); - } else { - PrintAndLogEx(INFO, "Testing ISO14443-B... ( " _RED_("fail") " )"); - } + PrintAndLogEx(INFO, "Testing ISO14443-B... ( %s )", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail")); } break; } @@ -160,8 +159,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l } } - if (APDULogging) + if (APDULogging) { PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len)); + } if (*result_len < 2) { return 200; @@ -177,9 +177,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l if (isw != ISO7816_OK) { if (APDULogging) { if (*sw >> 8 == 0x61) { - PrintAndLogEx(ERR, "APDU chaining len %02x", *sw & 0xFF); + PrintAndLogEx(ERR, "APDU chaining len " _RED_("%02x"), *sw & 0xFF); } else { - PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xFF)); + PrintAndLogEx(ERR, "APDU (%02x%02x) ERROR... " _RED_("%4X") " - %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xFF)); return 5; } } diff --git a/client/src/iso7816/iso7816core.h b/client/src/iso7816/iso7816core.h index eb49a58bb..b24be2dab 100644 --- a/client/src/iso7816/iso7816core.h +++ b/client/src/iso7816/iso7816core.h @@ -30,6 +30,7 @@ typedef enum { ISODEP_INACTIVE = 0, ISODEP_NFCA, ISODEP_NFCB, + ISODEP_NFCV, } isodep_state_t; typedef enum { diff --git a/client/src/nfc/ndef.c b/client/src/nfc/ndef.c index a8227ddc7..8163abe59 100644 --- a/client/src/nfc/ndef.c +++ b/client/src/nfc/ndef.c @@ -42,6 +42,8 @@ #define NDEF_BLUEAPPL_LE "application/vnd.bluetooth.le.oob" #define NDEF_BLUEAPPL_SECURE_LE "application/vnd.bluetooth.secure.le.oob" +#define NDEF_ANDROID_PROVISION "application/com.android.managedprovisioning" + static const char *TypeNameFormat_s[] = { "Empty Record", @@ -592,7 +594,6 @@ static int ndefDecodePayloadSmartPoster(uint8_t *ndef, size_t ndeflen, bool prin return PM3_SUCCESS; } - typedef struct ndef_wifi_type_s { const char *description; uint8_t bytes[2]; @@ -943,6 +944,17 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) { return PM3_SUCCESS; } +static int ndefDecodeMime_android_provision(NDEFHeader_t *ndef) { + if (ndef->PayloadLen == 0) { + PrintAndLogEx(INFO, "no payload"); + return PM3_SUCCESS; + } + PrintAndLogEx(INFO, _CYAN_("Android Managed Provision")); + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, "%.*s", (int)ndef->PayloadLen, ndef->Payload); + return PM3_SUCCESS; +} + // https://raw.githubusercontent.com/haldean/ndef/master/docs/NFCForum-TS-RTD_1.0.pdf static int ndefDecodeExternal_record(NDEFHeader_t *ndef) { @@ -1079,6 +1091,10 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) { ndefDecodeMime_json(ndef); } + if (str_startswith(begin, NDEF_ANDROID_PROVISION)) { + ndefDecodeMime_android_provision(ndef); + } + free(begin); begin = NULL; break; @@ -1297,7 +1313,6 @@ int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) { return PM3_SUCCESS; } - int NDEFGetTotalLength(uint8_t *ndef, size_t ndeflen, size_t *outlen) { size_t idx = 0; diff --git a/client/src/pm3line_vocabulary.h b/client/src/pm3line_vocabulary.h index aa845203d..73970c9ba 100644 --- a/client/src/pm3line_vocabulary.h +++ b/client/src/pm3line_vocabulary.h @@ -157,18 +157,19 @@ const static vocabulary_t vocabulary[] = { { 0, "hf 14a ndefread" }, { 0, "hf 14a ndefwrite" }, { 1, "hf 14b help" }, + { 1, "hf 14b list" }, { 0, "hf 14b apdu" }, { 0, "hf 14b dump" }, { 0, "hf 14b info" }, - { 1, "hf 14b list" }, { 0, "hf 14b ndefread" }, { 0, "hf 14b raw" }, + { 0, "hf 14b rdbl" }, { 0, "hf 14b reader" }, { 0, "hf 14b sim" }, { 0, "hf 14b sniff" }, - { 0, "hf 14b rdbl" }, - { 0, "hf 14b sriwrite" }, + { 0, "hf 14b wrbl" }, { 1, "hf 14b view" }, + { 1, "hf 14b valid" }, { 1, "hf 15 help" }, { 1, "hf 15 list" }, { 1, "hf 15 demod" }, @@ -182,6 +183,7 @@ const static vocabulary_t vocabulary[] = { { 0, "hf 15 restore" }, { 0, "hf 15 samples" }, { 1, "hf 15 view" }, + { 0, "hf 15 wipe" }, { 0, "hf 15 wrbl" }, { 0, "hf 15 sim" }, { 0, "hf 15 eload" }, @@ -223,11 +225,11 @@ const static vocabulary_t vocabulary[] = { { 1, "hf emrtd list" }, { 1, "hf felica help" }, { 1, "hf felica list" }, - { 0, "hf felica reader" }, { 0, "hf felica info" }, - { 0, "hf felica sniff" }, { 0, "hf felica raw" }, { 0, "hf felica rdbl" }, + { 0, "hf felica reader" }, + { 0, "hf felica sniff" }, { 0, "hf felica wrbl" }, { 0, "hf felica rqservice" }, { 0, "hf felica rqresponse" }, @@ -502,10 +504,14 @@ const static vocabulary_t vocabulary[] = { { 1, "hf vas help" }, { 0, "hf vas reader" }, { 1, "hf vas decrypt" }, + { 1, "hf waveshare help" }, + { 1, "hf waveshare load" }, { 1, "hf xerox help" }, + { 1, "hf xerox list" }, { 0, "hf xerox info" }, - { 0, "hf xerox reader" }, { 0, "hf xerox dump" }, + { 0, "hf xerox reader" }, + { 1, "hf xerox view" }, { 1, "hw help" }, { 0, "hw break" }, { 0, "hw bootloader" }, diff --git a/client/src/preferences.c b/client/src/preferences.c index 09521cab4..af0100148 100644 --- a/client/src/preferences.c +++ b/client/src/preferences.c @@ -391,7 +391,7 @@ static const char *pref_show_status_msg(prefShowOpt_t opt) { } } -static const char *pref_show_value(prefShowOpt_t opt, const char* msg) { +static const char *pref_show_value(prefShowOpt_t opt, const char *msg) { static char s[128] = {0}; switch (opt) { @@ -403,7 +403,7 @@ static const char *pref_show_value(prefShowOpt_t opt, const char* msg) { sprintf(s, _GREEN_("%s"), msg); return s; case prefShowNone: - if ((strncmp(msg, "off", 3) == 0) || (strncmp(msg, "normal", 6) ==0)) { + if ((strncmp(msg, "off", 3) == 0) || (strncmp(msg, "normal", 6) == 0)) { sprintf(s, _WHITE_("%s"), msg); } else { sprintf(s, _GREEN_("%s"), msg); @@ -446,9 +446,9 @@ static void showEmojiState(prefShowOpt_t opt) { static void showColorState(prefShowOpt_t opt) { PrintAndLogEx(INFO, " %s color................... %s " - , pref_show_status_msg(opt) - , (g_session.supports_colors) ? pref_show_value(opt, "ansi") : pref_show_value(opt, "off") - ); + , pref_show_status_msg(opt) + , (g_session.supports_colors) ? pref_show_value(opt, "ansi") : pref_show_value(opt, "off") + ); } static void showClientDebugState(prefShowOpt_t opt) { @@ -461,7 +461,7 @@ static void showClientDebugState(prefShowOpt_t opt) { PrintAndLogEx(INFO, " %s client debug............ %s", pref_show_status_msg(opt), pref_show_value(opt, "simple")); break; case cdbFULL: - PrintAndLogEx(INFO, " %s client debug............ %s", pref_show_status_msg(opt), pref_show_value(opt,"full")); + PrintAndLogEx(INFO, " %s client debug............ %s", pref_show_status_msg(opt), pref_show_value(opt, "full")); break; default: PrintAndLogEx(INFO, " %s client debug............ %s", pref_show_status_msg(opt), pref_show_value(prefShowUnknown, "unknown")); @@ -545,40 +545,40 @@ static void showOverlayPosState(void) { static void showHintsState(prefShowOpt_t opt) { PrintAndLogEx(INFO, " %s hints................... %s" - , pref_show_status_msg(opt) - , (g_session.show_hints) ? pref_show_value(opt,"on") : pref_show_value(opt,"off") - ); + , pref_show_status_msg(opt) + , (g_session.show_hints) ? pref_show_value(opt, "on") : pref_show_value(opt, "off") + ); } static void showPlotSliderState(prefShowOpt_t opt) { PrintAndLogEx(INFO, " %s show plot sliders....... %s" - , pref_show_status_msg(opt) - , (g_session.overlay_sliders) ? pref_show_value(opt,"on") : pref_show_value(opt,"off") - ); + , pref_show_status_msg(opt) + , (g_session.overlay_sliders) ? pref_show_value(opt, "on") : pref_show_value(opt, "off") + ); } static void showBarModeState(prefShowOpt_t opt) { switch (g_session.bar_mode) { case STYLE_BAR: - PrintAndLogEx(INFO, " %s barmode................. %s", pref_show_status_msg(opt), pref_show_value(opt,"bar")); + PrintAndLogEx(INFO, " %s barmode................. %s", pref_show_status_msg(opt), pref_show_value(opt, "bar")); break; case STYLE_MIXED: - PrintAndLogEx(INFO, " %s barmode................. %s", pref_show_status_msg(opt), pref_show_value(opt,"mixed")); + PrintAndLogEx(INFO, " %s barmode................. %s", pref_show_status_msg(opt), pref_show_value(opt, "mixed")); break; case STYLE_VALUE: - PrintAndLogEx(INFO, " %s barmode................. %s", pref_show_status_msg(opt), pref_show_value(opt,"value")); + PrintAndLogEx(INFO, " %s barmode................. %s", pref_show_status_msg(opt), pref_show_value(opt, "value")); break; default: - PrintAndLogEx(INFO, " %s barmode................. %s", pref_show_status_msg(opt), pref_show_value(prefShowUnknown,"unknown")); + PrintAndLogEx(INFO, " %s barmode................. %s", pref_show_status_msg(opt), pref_show_value(prefShowUnknown, "unknown")); } } static void showOutputState(prefShowOpt_t opt) { PrintAndLogEx(INFO, " %s output.................. %s" - , pref_show_status_msg(opt) - , (g_session.dense_output) ? pref_show_value(opt,"dense") : pref_show_value(opt,"normal") - ); + , pref_show_status_msg(opt) + , (g_session.dense_output) ? pref_show_value(opt, "dense") : pref_show_value(opt, "normal") + ); } static void showClientExeDelayState(void) { diff --git a/client/src/scripting.c b/client/src/scripting.c index 613562978..0896fd550 100644 --- a/client/src/scripting.c +++ b/client/src/scripting.c @@ -46,6 +46,7 @@ #include "cmdlfem4x05.h" // read 4305 #include "cmdlfem4x50.h" // read 4350 #include "em4x50.h" // 4x50 structs +#include "iso7816/iso7816core.h" // ISODEPSTATE static int returnToLuaWithError(lua_State *L, const char *fmt, ...) { char buffer[200]; @@ -1188,15 +1189,12 @@ static int l_em4x50_read(lua_State *L) { words[etd.addresses & 0xFF].byte[3] ); lua_pushinteger(L, word); - return 1; } // static int l_ndefparse(lua_State *L) { - size_t size; - //Check number of arguments int n = lua_gettop(L); if (n != 3) { @@ -1212,6 +1210,7 @@ static int l_ndefparse(lua_State *L) { } // data + size_t size; const char *p_data = luaL_checklstring(L, 3, &size); if (size) { if (size > (datalen << 1)) @@ -1256,11 +1255,39 @@ static int l_remark(lua_State *L) { return 1; } +static int l_set_iso_dep_state(lua_State *L) { + + //Check number of arguments + int n = lua_gettop(L); + if (n != 1) { + return returnToLuaWithError(L, "Only one value allowed"); + } + + size_t state = luaL_checknumber(L, 1); + switch (state) { + case 0: + SetISODEPState(ISODEP_INACTIVE); + break; + case 1: + SetISODEPState(ISODEP_NFCA); + break; + case 2: + SetISODEPState(ISODEP_NFCB); + break; + case 3: + SetISODEPState(ISODEP_NFCV); + break; + default: + return returnToLuaWithError(L, "Wrong ISODEP STATE value"); + } + return 1; +} + // 1. filename // 2. extension // output: full search path to file static int l_searchfile(lua_State *L) { - //Check number of arguments + // Check number of arguments int n = lua_gettop(L); if (n != 2) { return returnToLuaWithError(L, "Only filename and extension"); @@ -1306,11 +1333,12 @@ static int l_cwd(lua_State *L) { while (GetCurrentDir(cwd, path_len) == NULL) { if (errno == ERANGE) { // Need bigger buffer path_len += 10; // if buffer was too small add 10 characters and try again - cwd = realloc(cwd, path_len); - if (cwd == NULL) { + char *cwdNew = realloc(cwd, path_len); + if (cwdNew == NULL) { free(cwd); return returnToLuaWithError(L, "Failed to allocate memory"); } + cwd = cwdNew; } else { free(cwd); return returnToLuaWithError(L, "Failed to get current working directory"); @@ -1402,6 +1430,7 @@ int set_pm3_libraries(lua_State *L) { {"em4x05_read", l_em4x05_read}, {"em4x50_read", l_em4x50_read}, {"ul_read_uid", l_ul_read_uid}, + {"set_isodepstate", l_set_iso_dep_state}, {NULL, NULL} }; diff --git a/client/src/uart/uart_win32.c b/client/src/uart/uart_win32.c index 9f8e7bef6..ac3d73dc4 100644 --- a/client/src/uart/uart_win32.c +++ b/client/src/uart/uart_win32.c @@ -85,13 +85,14 @@ static int uart_reconfigure_timeouts_polling(serial_port sp) { serial_port uart_open(const char *pcPortName, uint32_t speed, bool slient) { char acPortName[255] = {0}; serial_port_windows_t *sp = calloc(sizeof(serial_port_windows_t), sizeof(uint8_t)); - sp->hSocket = INVALID_SOCKET; // default: serial port if (sp == 0) { PrintAndLogEx(WARNING, "UART failed to allocate memory\n"); return INVALID_SERIAL_PORT; } + sp->hSocket = INVALID_SOCKET; // default: serial port + sp->udpBuffer = NULL; rx_empty_counter = 0; g_conn.send_via_local_ip = false; diff --git a/client/src/ui.c b/client/src/ui.c index fc3f7908a..df9b27a6d 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -119,7 +119,7 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam pathlen += strlen(subdir); char *tmp = realloc(path, pathlen * sizeof(char)); if (tmp == NULL) { - //free(path); + free(path); return PM3_EMALLOC; } path = tmp; @@ -156,7 +156,7 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam pathlen += strlen(filename); char *tmp = realloc(path, pathlen * sizeof(char)); if (tmp == NULL) { - //free(path); + free(path); return PM3_EMALLOC; } diff --git a/common_arm/ticks.c b/common_arm/ticks.c index 342aa3cab..297e507a4 100644 --- a/common_arm/ticks.c +++ b/common_arm/ticks.c @@ -202,17 +202,22 @@ void ResetSspClk(void) { AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; while (AT91C_BASE_TC2->TC_CV > 0); } + uint32_t RAMFUNC GetCountSspClk(void) { uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV; - if ((tmp_count & 0x0000ffff) == 0) //small chance that we may have missed an increment in TC2 + + // small chance that we may have missed an increment in TC2 + if ((tmp_count & 0x0000ffff) == 0) { return (AT91C_BASE_TC2->TC_CV << 16); + } return tmp_count; } uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start) { uint32_t stop = GetCountSspClk(); - if (stop >= start) + if (stop >= start) { return stop - start; + } return (UINT32_MAX - start) + stop; } diff --git a/doc/commands.json b/doc/commands.json index a4c474801..b852f32fc 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -95,9 +95,9 @@ ], "usage": "analyse freq [-h] [-F ] [-L ] [-C ]" }, - "analyse lcr": { - "command": "analyse lcr", - "description": "Specifying the bytes of a UID with a known LRC will find the last byte value needed to generate that LRC with a rolling XOR. All bytes should be specified in HEX.", + "analyse help": { + "command": "analyse help", + "description": "help This help lcr Generate final byte for XOR LRC crc Stub method for CRC evaluations chksum Checksum with adding, masking and one's complement dates Look for datestamps in a given array of bytes lfsr LFSR tests a num bits test nuid create NUID from 7byte UID demodbuff Load binary string to DemodBuffer freq Calc wave lengths foo muxer units convert ETU <> US <> SSP_CLK (3.39MHz) --------------------------------------------------------------------------------------- analyse lcr available offline: yes Specifying the bytes of a UID with a known LRC will find the last byte value needed to generate that LRC with a rolling XOR. All bytes should be specified in HEX.", "notes": [ "analyse lcr -d 04008064BA -> Target (BA) requires final LRC XOR byte value: 5A" ], @@ -152,19 +152,6 @@ ], "usage": "analyse units [-ht] [--etu ] [--us ]" }, - "auto": { - "command": "auto", - "description": "Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE", - "notes": [ - "auto" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-c Continue searching even after a first hit" - ], - "usage": "auto [-hc]" - }, "clear": { "command": "clear", "description": "Clear the Proxmark3 client terminal screen", @@ -247,22 +234,6 @@ ], "usage": "data bin2hex [-h] -d " }, - "data biphaserawdecode": { - "command": "data biphaserawdecode", - "description": "Biphase decode binary stream in DemodBuffer Converts 10 or 01 -> 1 and 11 or 00 -> 0 - must have binary sequence in DemodBuffer (run `data rawdemod --ar` before) - invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester", - "notes": [ - "data biphaserawdecode -> decode biphase bitstream from the DemodBuffer", - "data biphaserawdecode -oi -> decode biphase bitstream from the DemodBuffer, adjust offset, and invert output" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-o, --offset set to adjust decode start position", - "-i, --inv invert output", - "--err set max errors tolerated (def 20)" - ], - "usage": "data biphaserawdecode [-hoi] [--err ]" - }, "data bitsamples": { "command": "data bitsamples", "description": "Get raw samples from device as bitstring", @@ -450,6 +421,22 @@ ], "usage": "data grid [-h] [-x ] [-y ]" }, + "data help": { + "command": "data help", + "description": "help This help ----------- ------------------------- Modulation------------------------- biphaserawdecode Biphase decode bin stream in DemodBuffer detectclock Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer fsktonrz Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk) manrawdecode Manchester decode binary stream in DemodBuffer modulation Identify LF signal for clock and modulation rawdemod Demodulate the data in the GraphBuffer and output binary ----------- ------------------------- Graph------------------------- askedgedetect Adjust Graph for manual ASK demod autocorr Autocorrelation over window dirthreshold Max rising higher up-thres/ Min falling lower down-thres decimate Decimate samples envelope Generate square envelope of samples undecimate Un-decimate samples hide Hide graph window hpf Remove DC offset from trace iir Apply IIR buttersworth filter on plot data grid overlay grid on graph window ltrim Trim samples from left of trace mtrim Trim out samples from the specified start to the specified stop norm Normalize max/min to +/-128 plot Show graph window cthreshold Average out all values between rtrim Trim samples from right of trace setgraphmarkers Set blue and orange marker in graph window shiftgraphzero Shift 0 for Graphed wave + or - shift value timescale Set cursor display timescale zerocrossings Count time between zero-crossings convertbitstream Convert GraphBuffer's 0/1 values to 127 / -127 getbitstream Convert GraphBuffer's >=1 values to 1 and <1 to 0 ----------- ------------------------- General------------------------- asn1 ASN1 decoder atr ATR lookup bin2hex Converts binary to hexadecimal bmap Convert hex value according a binary template clear Clears bigbuf on deviceside and graph window diff Diff of input files hex2bin Converts hexadecimal to binary load Load contents of file into graph window num Converts dec/hex/bin print Print the data in the DemodBuffer save Save signal trace data (from graph window) setdebugmode Set Debugging Level on client side --------------------------------------------------------------------------------------- data biphaserawdecode available offline: yes Biphase decode binary stream in DemodBuffer Converts 10 or 01 -> 1 and 11 or 00 -> 0 - must have binary sequence in DemodBuffer (run `data rawdemod --ar` before) - invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester", + "notes": [ + "data biphaserawdecode -> decode biphase bitstream from the DemodBuffer", + "data biphaserawdecode -oi -> decode biphase bitstream from the DemodBuffer, adjust offset, and invert output" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-o, --offset set to adjust decode start position", + "-i, --inv invert output", + "--err set max errors tolerated (def 20)" + ], + "usage": "data biphaserawdecode [-hoi] [--err ]" + }, "data hex2bin": { "command": "data hex2bin", "description": "This function converts hexadecimal to binary. It will ignore all non-hexadecimal characters but stop reading on whitespace", @@ -893,6 +880,27 @@ ], "usage": "emv gpo [-hkpmatw] []..." }, + "emv help": { + "command": "emv help", + "description": "----------- ----------------------- general ----------------------- help This help list List ISO7816 history test Crypto logic test --------------------------------------------------------------------------------------- emv list available offline: yes Alias of `trace list -t 7816` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "notes": [ + "emv list --frame -> show frame delay times", + "emv list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-1, --buffer use data from trace buffer", + "--frame show frame delay times", + "-c mark CRC bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into Wireshark using encapsulation type \"ISO 14443\"", + "-f, --file filename of dictionary" + ], + "usage": "emv list [-h1crux] [--frame] [-f ]" + }, "emv intauth": { "command": "emv intauth", "description": "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format . Needs a EMV applet to be selected and GPO to be executed.", @@ -914,27 +922,6 @@ ], "usage": "emv intauth [-hkpmatw] []..." }, - "emv list": { - "command": "emv list", - "description": "Alias of `trace list -t 7816` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", - "notes": [ - "emv list --frame -> show frame delay times", - "emv list -1 -> use trace buffer" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-1, --buffer use data from trace buffer", - "--frame show frame delay times", - "-c mark CRC bytes", - "-r show relative times (gap and duration)", - "-u display times in microseconds instead of clock cycles", - "-x show hexdump to convert to pcap(ng)", - "or to import into Wireshark using encapsulation type \"ISO 14443\"", - "-f, --file filename of dictionary" - ], - "usage": "emv list [-h1crux] [--frame] [-f ]" - }, "emv pse": { "command": "emv pse", "description": "Executes PSE/PPSE select command. It returns list of applet on the card:", @@ -1095,6 +1082,19 @@ ], "usage": "quit [-h]" }, + "help": { + "command": "help", + "description": "help Use ` help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program --------------------------------------------------------------------------------------- auto available offline: no Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE", + "notes": [ + "auto" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-c Continue searching even after a first hit" + ], + "usage": "auto [-hc]" + }, "hf 14a antifuzz": { "command": "hf 14a antifuzz", "description": "Tries to fuzz the ISO14443a anticollision phase", @@ -1112,26 +1112,26 @@ }, "hf 14a apdu": { "command": "hf 14a apdu", - "description": "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013", + "description": "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). Works with all APDU types from ISO 7816-4:2013 note: `-m` and `-d` goes hand in hand -m -d 325041592E5359532E4444463031 OR use `-d` with complete APDU data -d 00A404000E325041592E5359532E444446303100", "notes": [ - "hf 14a apdu -st 00A404000E325041592E5359532E444446303100", - "hf 14a apdu -sd 00A404000E325041592E5359532E444446303100 -> decode apdu", - "hf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 -> encode standard apdu", - "hf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 -> encode extended apdu" + "hf 14a apdu -st -d 00A404000E325041592E5359532E444446303100", + "hf 14a apdu -sd -d 00A404000E325041592E5359532E444446303100 -> decode apdu", + "hf 14a apdu -sm 00A40400 -d 325041592E5359532E4444463031 -l 256 -> encode standard apdu", + "hf 14a apdu -sm 00A40400 -d 325041592E5359532E4444463031 -el 65536 -> encode extended apdu" ], "offline": false, "options": [ "-h, --help This help", "-s, --select activate field and select card", "-k, --keep keep signal field ON after receive", - "-t, --tlv executes TLV decoder if it possible", - "-d, --decapdu decode apdu request if it possible", - "-m, --make make apdu with head from this field and data from data field. Must be 4 bytes length: ", + "-t, --tlv decode TLV", + "-d, --decapdu decode APDU request", + "-m, --make APDU header, 4 bytes ", "-e, --extended make extended length apdu if `m` parameter included", - "-l, --le Le apdu parameter if `m` parameter included", - " data if `m` parameter included" + "-l, --le Le APDU parameter if `m` parameter included", + "-d, --data full APDU package or data if `m` parameter included" ], - "usage": "hf 14a apdu [-hsktde] [-m ] [-l ] []..." + "usage": "hf 14a apdu [-hsktde] [-m ] [-l ] -d [-d ]..." }, "hf 14a apdufind": { "command": "hf 14a apdufind", @@ -1184,24 +1184,9 @@ ], "usage": "hf 14a cuids [-h] [-n ]" }, - "hf 14a info": { - "command": "hf 14a info", - "description": "This command makes more extensive tests against a ISO14443a tag in order to collect information", - "notes": [ - "hf 14a info -nsv -> shows full information about the card" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-v, --verbose adds some information to results", - "-n, --nacktest test for nack bug", - "-s, --aidsearch checks if AIDs from aidlist.json is present on the card and prints information about found AIDs" - ], - "usage": "hf 14a info [-hvns]" - }, - "hf 14a list": { - "command": "hf 14a list", - "description": "Alias of `trace list -t 14a -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "hf 14a help": { + "command": "hf 14a help", + "description": "----------- ----------------------- General ----------------------- help This help list List ISO 14443-a history --------------------------------------------------------------------------------------- hf 14a list available offline: yes Alias of `trace list -t 14a -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf 14a list --frame -> show frame delay times", "hf 14a list -1 -> use trace buffer" @@ -1220,6 +1205,21 @@ ], "usage": "hf 14a list [-h1crux] [--frame] [-f ]" }, + "hf 14a info": { + "command": "hf 14a info", + "description": "This command makes more extensive tests against a ISO14443a tag in order to collect information", + "notes": [ + "hf 14a info -nsv -> shows full information about the card" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-v, --verbose adds some information to results", + "-n, --nacktest test for nack bug", + "-s, --aidsearch checks if AIDs from aidlist.json is present on the card and prints information about found AIDs" + ], + "usage": "hf 14a info [-hvns]" + }, "hf 14a ndefformat": { "command": "hf 14a ndefformat", "description": "Format ISO14443-a Tag as a NFC tag with Data Exchange Format (NDEF)", @@ -1398,23 +1398,9 @@ ], "usage": "hf 14b dump [-h] [-f ] [--ns]" }, - "hf 14b info": { - "command": "hf 14b info", - "description": "Tag information for ISO/IEC 14443 type B based tags", - "notes": [ - "hf 14b info" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-s, --aidsearch checks if AIDs from aidlist.json is present on the card and prints information about found AIDs", - "-v, --verbose verbose output" - ], - "usage": "hf 14b info [-hsv]" - }, - "hf 14b list": { - "command": "hf 14b list", - "description": "Alias of `trace list -t 14b` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "hf 14b help": { + "command": "hf 14b help", + "description": "help This help list List ISO-14443-B history --------- ----------------------- general ----------------------- view Display content from tag dump file valid SRIX4 checksum test --------------------------------------------------------------------------------------- hf 14b list available offline: yes Alias of `trace list -t 14b -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf 14b list --frame -> show frame delay times", "hf 14b list -1 -> use trace buffer" @@ -1433,6 +1419,20 @@ ], "usage": "hf 14b list [-h1crux] [--frame] [-f ]" }, + "hf 14b info": { + "command": "hf 14b info", + "description": "Tag information for ISO/IEC 14443 type B based tags", + "notes": [ + "hf 14b info" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-s, --aidsearch checks if AIDs from aidlist.json is present on the card and prints information about found AIDs", + "-v, --verbose verbose output" + ], + "usage": "hf 14b info [-hsv]" + }, "hf 14b ndefread": { "command": "hf 14b ndefread", "description": "Print NFC Data Exchange Format (NDEF)", @@ -1525,29 +1525,21 @@ ], "usage": "hf 14b sniff [-h]" }, - "hf 14b sriwrite": { - "command": "hf 14b sriwrite", - "description": "Write data to a SRI512 or SRIX4K block", + "hf 14b valid": { + "command": "hf 14b valid", + "description": "SRIX checksum test", "notes": [ - "hf 14b sriwrite --4k -b 100 -d 11223344", - "hf 14b sriwrite --4k --sb -d 11223344 -> special block write", - "hf 14b sriwrite --512 -b 15 -d 11223344", - "hf 14b sriwrite --512 --sb -d 11223344 -> special block write" + "hf 14b valid" ], - "offline": false, + "offline": true, "options": [ - "-h, --help This help", - "-b, --block block number", - "-d, --data 4 hex bytes", - "--512 target SRI 512 tag", - "--4k target SRIX 4k tag", - "--sb special block write at end of memory (0xFF)" + "-h, --help This help" ], - "usage": "hf 14b sriwrite [-h] [-b ] -d [--512] [--4k] [--sb]" + "usage": "hf 14b valid [-h]" }, "hf 14b view": { "command": "hf 14b view", - "description": "Print a ISO14443-B dump file (bin/eml/json)", + "description": "Print a ISO14443-B dump file (bin/eml/json) note: - command expects the filename to contain a UID which is needed to determine card memory type", "notes": [ "hf 14b view -f hf-14b-01020304-dump.bin" ], @@ -1559,6 +1551,27 @@ ], "usage": "hf 14b view [-hv] -f " }, + "hf 14b wrbl": { + "command": "hf 14b wrbl", + "description": "Write data to a SRI512 or SRIX4K block If writing to a block out-of-range, use `--force` to override checks Special block at end denots OTP and lock bits among others", + "notes": [ + "hf 14b wrbl --4k -b 100 -d 11223344", + "hf 14b wrbl --4k --sb -d 11223344 -> special block write", + "hf 14b wrbl --512 -b 15 -d 11223344", + "hf 14b wrbl --512 --sb -d 11223344 -> special block write" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-b, --block block number", + "-d, --data 4 hex bytes", + "--512 target SRI 512 tag", + "--4k target SRIX 4k tag", + "--sb special block write at end of memory (0xFF)", + "--force overrides block range checks" + ], + "usage": "hf 14b wrbl [-h] [-b ] -d [--512] [--4k] [--sb] [--force]" + }, "hf 15 csetuid": { "command": "hf 15 csetuid", "description": "Set UID for magic Chinese card (only works with such cards)", @@ -1568,9 +1581,9 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid <8b hex> UID eg E011223344556677" + "-u, --uid UID, 8 hex bytes" ], - "usage": "hf 15 csetuid [-h] -u <8b hex>" + "usage": "hf 15 csetuid [-h] -u " }, "hf 15 demod": { "command": "hf 15 demod", @@ -1595,25 +1608,28 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid full UID, 8 bytes", + "-u, --uid full UID (8 hex bytes)", "--ua unaddressed mode", "-* scan for tag", "-2 use slower '1 out of 256' mode", "-o, --opt set OPTION Flag (needed for TI)", - "-f, --file Specify a filename for dump file" + "-f, --file Specify a filename for dump file", + "--bs block size (def 4)", + "--ns no save to file", + "-v, --verbose verbose output" ], - "usage": "hf 15 dump [-h*2o] [-u ] [--ua] [-f ]" + "usage": "hf 15 dump [-h*2ov] [-u ] [--ua] [-f ] [--bs ] [--ns]" }, "hf 15 eload": { "command": "hf 15 eload", - "description": "Load memory image from file to be used with 'hf 15 sim'", + "description": "Load memory dump from file to be used with 'hf 15 sim'", "notes": [ "hf 15 eload -f hf-15-01020304.bin" ], "offline": false, "options": [ "-h, --help This help", - "-f, --file filename of image" + "-f, --file filename of dump" ], "usage": "hf 15 eload [-h] -f " }, @@ -1627,8 +1643,8 @@ "options": [ "-h, --help This help", "-f, --file Specify a filename for dump file", - "--bsize block size, defaults to 4", - "-c, --count number of blocks to export, defaults to all" + "--bsize block size (def 4)", + "-c, --count number of blocks to export (def all)" ], "usage": "hf 15 esave [-h] -f [--bsize ] [-c ]" }, @@ -1642,8 +1658,8 @@ "offline": false, "options": [ "-h, --help This help", - "-b, --blocksize block size, defaults to 4", - "-c, --count number of blocks to display, defaults to all" + "-b, --blocksize block size (def 4)", + "-c, --count number of blocks to display (def all)" ], "usage": "hf 15 eview [-h] [-b ] [-c ]" }, @@ -1654,33 +1670,15 @@ "hf 15 findafi" ], "offline": false, - "options": [ - "-h, --help This help" - ], - "usage": "hf 15 findafi [-h]" - }, - "hf 15 info": { - "command": "hf 15 info", - "description": "Uses the optional command `get_systeminfo` 0x2B to try and extract information", - "notes": [ - "hf 15 info", - "hf 15 info -*", - "hf 15 info -u E011223344556677" - ], - "offline": false, "options": [ "-h, --help This help", - "-u, --uid full UID, 8 bytes", - "--ua unaddressed mode", - "-* scan for tag", - "-2 use slower '1 out of 256' mode", - "-o, --opt set OPTION Flag (needed for TI)" + "-2 use slower '1 out of 256' mode" ], - "usage": "hf 15 info [-h*2o] [-u ] [--ua]" + "usage": "hf 15 findafi [-h2]" }, - "hf 15 list": { - "command": "hf 15 list", - "description": "Alias of `trace list -t 15` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "hf 15 help": { + "command": "hf 15 help", + "description": "help This help list List ISO-15693 history ----------- ----------------------- general ----------------------- demod Demodulate ISO-15693 from tag view Display content from tag dump file --------------------------------------------------------------------------------------- hf 15 list available offline: yes Alias of `trace list -t 15 -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf 15 list --frame -> show frame delay times", "hf 15 list -1 -> use trace buffer" @@ -1699,6 +1697,25 @@ ], "usage": "hf 15 list [-h1crux] [--frame] [-f ]" }, + "hf 15 info": { + "command": "hf 15 info", + "description": "Uses the optional command `get_systeminfo` 0x2B to try and extract information", + "notes": [ + "hf 15 info", + "hf 15 info -*", + "hf 15 info -u E011223344556677" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-u, --uid full UID (8 hex bytes)", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set OPTION Flag (needed for TI)" + ], + "usage": "hf 15 info [-h*2o] [-u ] [--ua]" + }, "hf 15 passprotectafi": { "command": "hf 15 passprotectafi", "description": "This command enables the password protect of AFI. *** OBS! This action can not be undone! ***", @@ -1708,7 +1725,7 @@ "offline": false, "options": [ "-h, --help This help", - "-p, --pwd EAS/AFI password, 8 hex bytes", + "-p, --pwd EAS/AFI password, 4 hex bytes", "--force Force execution of command (irreversible)" ], "usage": "hf 15 passprotectafi [-h] -p [--force]" @@ -1722,7 +1739,7 @@ "offline": false, "options": [ "-h, --help This help", - "-p, --pwd EAS/AFI password, 8 hex bytes", + "-p, --pwd EAS/AFI password, 4 hex bytes", "--force Force execution of command (irreversible)" ], "usage": "hf 15 passprotecteas [-h] -p [--force]" @@ -1731,8 +1748,8 @@ "command": "hf 15 raw", "description": "Sends raw bytes over ISO-15693 to card", "notes": [ - "hf 15 raw -c -d 260100 -> add crc", - "hf 15 raw -krc -d 260100 -> add crc, keep field on, skip response" + "hf 15 raw -sc -d 260100 -> add crc", + "hf 15 raw -skrc -d 260100 -> add crc, keep field on, skip response" ], "offline": false, "options": [ @@ -1741,9 +1758,11 @@ "-c, --crc calculate and append CRC", "-k keep signal field ON after receive", "-r do not read response", - "-d, --data raw bytes to send" + "-d, --data raw bytes to send", + "-w, --wait wait longer for response. For writes etc.", + "-a activate field" ], - "usage": "hf 15 raw [-h2ckr] -d " + "usage": "hf 15 raw [-h2ckrwa] -d " }, "hf 15 rdbl": { "command": "hf 15 rdbl", @@ -1755,14 +1774,16 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid full UID, 8 bytes", + "-u, --uid full UID (8 hex bytes)", "--ua unaddressed mode", "-* scan for tag", "-2 use slower '1 out of 256' mode", "-o, --opt set OPTION Flag (needed for TI)", - "-b, --blk page number (0-255)" + "-b, --blk page number (0-255)", + "--bs block size (def 4)", + "-v, --verbose verbose output" ], - "usage": "hf 15 rdbl [-h*2o] [-u ] [--ua] -b " + "usage": "hf 15 rdbl [-h*2ov] [-u ] [--ua] -b [--bs ]" }, "hf 15 rdmulti": { "command": "hf 15 rdmulti", @@ -1774,15 +1795,17 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid full UID, 8 bytes", + "-u, --uid full UID (8 hex bytes)", "--ua unaddressed mode", "-* scan for tag", "-2 use slower '1 out of 256' mode", "-o, --opt set OPTION Flag (needed for TI)", "-b first page number (0-255)", - "--cnt number of pages (1-6)" + "--cnt number of pages (1-6)", + "--bs block size (def 4)", + "-v, --verbose verbose output" ], - "usage": "hf 15 rdmulti [-h*2o] [-u ] [--ua] -b --cnt " + "usage": "hf 15 rdmulti [-h*2ov] [-u ] [--ua] -b --cnt [--bs ]" }, "hf 15 reader": { "command": "hf 15 reader", @@ -1809,7 +1832,7 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid full UID, 8 bytes", + "-u, --uid full UID (8 hex bytes)", "--ua unaddressed mode", "-* scan for tag", "-2 use slower '1 out of 256' mode", @@ -1842,10 +1865,10 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid <8b hex> UID eg E011223344556677", - "-b, --blocksize block size, defaults to 4" + "-u, --uid UID, 8 hex bytes", + "-b, --blocksize block size (def 4)" ], - "usage": "hf 15 sim [-h] -u <8b hex> [-b ]" + "usage": "hf 15 sim [-h] -u [-b ]" }, "hf 15 slixeasdisable": { "command": "hf 15 slixeasdisable", @@ -1856,7 +1879,7 @@ "offline": false, "options": [ "-h, --help This help", - "-p, --pwd optional password, 8 hex bytes" + "-p, --pwd optional password, 4 hex bytes" ], "usage": "hf 15 slixeasdisable [-h] [-p ]" }, @@ -1869,7 +1892,7 @@ "offline": false, "options": [ "-h, --help This help", - "-p, --pwd optional password, 8 hex bytes" + "-p, --pwd optional password, 4 hex bytes" ], "usage": "hf 15 slixeasenable [-h] [-p ]" }, @@ -1877,12 +1900,12 @@ "command": "hf 15 slixprivacydisable", "description": "Disable privacy mode on SLIX ISO-15693 tag", "notes": [ - "hf 15 slixdisable -p 0F0F0F0F" + "hf 15 slixprivacydisable -p 0F0F0F0F" ], "offline": false, "options": [ "-h, --help This help", - "-p, --pwd password, 8 hex bytes" + "-p, --pwd password, 4 hex bytes" ], "usage": "hf 15 slixprivacydisable [-h] -p " }, @@ -1890,12 +1913,12 @@ "command": "hf 15 slixprivacyenable", "description": "Enable privacy mode on SLIX ISO-15693 tag", "notes": [ - "hf 15 slixenable -p 0F0F0F0F" + "hf 15 slixprivacyenable -p 0F0F0F0F" ], "offline": false, "options": [ "-h, --help This help", - "-p, --pwd password, 8 hex bytes" + "-p, --pwd password, 4 hex bytes" ], "usage": "hf 15 slixprivacyenable [-h] -p " }, @@ -1909,8 +1932,8 @@ "options": [ "-h, --help This help", "-t, --type which password field to write to", - "-o, --old old password (if present), 8 hex bytes", - "-n, --new new password, 8 hex bytes" + "-o, --old old password (if present), 4 hex bytes", + "-n, --new new password, 4 hex bytes" ], "usage": "hf 15 slixwritepwd [-h] -t [-o ] -n " }, @@ -1939,6 +1962,25 @@ ], "usage": "hf 15 view [-h] -f " }, + "hf 15 wipe": { + "command": "hf 15 wipe", + "description": "Wipe a ISO-15693 tag by filled memory with zeros", + "notes": [ + "hf 15 wipe" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-u, --uid full UID (8 hex bytes)", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set OPTION Flag (needed for TI)", + "--bs block size (def 4)", + "-v, --verbose verbose output" + ], + "usage": "hf 15 wipe [-h*2ov] [-u ] [--ua] [--bs ]" + }, "hf 15 wrbl": { "command": "hf 15 wrbl", "description": "Write block on ISO-15693 tag", @@ -1949,7 +1991,7 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid full UID, 8 bytes", + "-u, --uid full UID (8 hex bytes)", "--ua unaddressed mode", "-* scan for tag", "-2 use slower '1 out of 256' mode", @@ -1970,7 +2012,7 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid full UID, 8 bytes", + "-u, --uid full UID, 8 hex bytes", "--afi AFI number (0-255)", "-p, --pwd optional AFI/EAS password" ], @@ -1986,14 +2028,15 @@ "offline": false, "options": [ "-h, --help This help", - "-u, --uid full UID, 8 bytes", + "-u, --uid full UID (8 hex bytes)", "--ua unaddressed mode", "-* scan for tag", "-2 use slower '1 out of 256' mode", "-o, --opt set OPTION Flag (needed for TI)", - "--dsfid DSFID number (0-255)" + "--dsfid DSFID number (0-255)", + "-v, --verbose verbose output" ], - "usage": "hf 15 writedsfid [-h*2o] [-u ] [--ua] --dsfid " + "usage": "hf 15 writedsfid [-h*2ov] [-u ] [--ua] --dsfid " }, "hf cipurse aread": { "command": "hf cipurse aread", @@ -2162,13 +2205,13 @@ ], "usage": "hf cipurse formatall [-hav] [-n ] [-k ] [--sreq ] [--sresp ] [--no-auth]" }, - "hf cipurse info": { - "command": "hf cipurse info", - "description": "Get info from CIPURSE tags", + "hf cipurse help": { + "command": "hf cipurse help", + "description": "help This help. test Regression tests --------------------------------------------------------------------------------------- hf cipurse info available offline: no Get info from CIPURSE tags", "notes": [ "hf cipurse info" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help" ], @@ -2314,15 +2357,15 @@ ], "usage": "hf cipurse write [-hav] [-n ] [-k ] [--aid ] [--fid ] [-o ] [--noauth] [--sreq ] [--sresp ] [-d ] [--commit]" }, - "hf emrtd dump": { - "command": "hf emrtd dump", - "description": "Dump all files on an eMRTD", + "hf emrtd help": { + "command": "hf emrtd help", + "description": "help This help info Display info about an eMRTD list List ISO 14443A/7816 history --------------------------------------------------------------------------------------- hf emrtd dump available offline: no Dump all files on an eMRTD", "notes": [ "hf emrtd dump", "hf emrtd dump --dir ../dump", "hf emrtd dump -n 123456789 -d 890101 -e 250401" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "-n, --doc document number, up to 9 chars", @@ -2375,13 +2418,13 @@ ], "usage": "hf emrtd list [-h1crux] [--frame] [-f ]" }, - "hf epa cnonces": { - "command": "hf epa cnonces", - "description": "Tries to collect nonces when doing part of PACE protocol.", + "hf epa help": { + "command": "hf epa help", + "description": "help This help --------------------------------------------------------------------------------------- hf epa cnonces available offline: no Tries to collect nonces when doing part of PACE protocol.", "notes": [ "hf epa cnonces --size 4 --num 4 --delay 1" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "--size nonce size", @@ -2461,21 +2504,9 @@ ], "usage": "hf felica auth2 [-hv] [-i ] [-c ] [-k ]" }, - "hf felica info": { - "command": "hf felica info", - "description": "Reader for FeliCa based tags", - "notes": [ - "hf felica info" - ], - "offline": false, - "options": [ - "-h, --help This help" - ], - "usage": "hf felica info [-h]" - }, - "hf felica list": { - "command": "hf felica list", - "description": "Alias of `trace list -t felica` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "hf felica help": { + "command": "hf felica help", + "description": "help This help list List ISO 18092/FeliCa history ----------- ----------------------- General ----------------------- ----------- ----------------------- FeliCa Standard ----------------------- ----------- ----------------------- FeliCa Light ----------------------- --------------------------------------------------------------------------------------- hf felica list available offline: yes Alias of `trace list -t felica` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf felica list --frame -> show frame delay times", "hf felica list -1 -> use trace buffer" @@ -2494,6 +2525,18 @@ ], "usage": "hf felica list [-h1crux] [--frame] [-f ]" }, + "hf felica info": { + "command": "hf felica info", + "description": "Reader for FeliCa based tags", + "notes": [ + "hf felica info" + ], + "offline": false, + "options": [ + "-h, --help This help" + ], + "usage": "hf felica info [-h]" + }, "hf felica litedump": { "command": "hf felica litedump", "description": "Dump ISO/18092 FeliCa Lite tag. It will timeout after 200sec", @@ -2747,21 +2790,9 @@ ], "usage": "hf fido auth [-havuc] default mode: [-f ] [-k ] [--kh ] [--cp ] [--ap ] [--cpx ] [--apx ]" }, - "hf fido info": { - "command": "hf fido info", - "description": "Get info from Fido tags", - "notes": [ - "hf fido info" - ], - "offline": false, - "options": [ - "-h, --help This help" - ], - "usage": "hf fido info [-h]" - }, - "hf fido list": { - "command": "hf fido list", - "description": "Alias of `trace list -t 14a` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "hf fido help": { + "command": "hf fido help", + "description": "help This help. list List ISO 14443A history --------------------------------------------------------------------------------------- hf fido list available offline: yes Alias of `trace list -t 14a` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf fido list --frame -> show frame delay times", "hf fido list -1 -> use trace buffer" @@ -2780,6 +2811,18 @@ ], "usage": "hf fido list [-h1crux] [--frame] [-f ]" }, + "hf fido info": { + "command": "hf fido info", + "description": "Get info from Fido tags", + "notes": [ + "hf fido info" + ], + "offline": false, + "options": [ + "-h, --help This help" + ], + "usage": "hf fido info [-h]" + }, "hf fido make": { "command": "hf fido make", "description": "Execute a FIDO2 Make Credential command. Needs json file with parameters. Sample file `fido2_defparams.json` in `client/resources/`. - for yubikey there must be only one option `\"rk\": true` or false", @@ -2834,6 +2877,21 @@ ], "usage": "hf fudan dump [-h] [-f ]" }, + "hf fudan help": { + "command": "hf fudan help", + "description": "help This help view Display content from tag dump file --------------------------------------------------------------------------------------- hf fudan reader available offline: no Read a fudan tag", + "notes": [ + "hf fudan reader", + "hf fudan reader -@ -> continuous reader mode" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-v, --verbose verbose output", + "-@ optional - continuous reader mode" + ], + "usage": "hf fudan reader [-hv@]" + }, "hf fudan rdbl": { "command": "hf fudan rdbl", "description": "Read fudan block", @@ -2850,21 +2908,6 @@ ], "usage": "hf fudan rdbl [-hv] --blk [-k ]" }, - "hf fudan reader": { - "command": "hf fudan reader", - "description": "Read a fudan tag", - "notes": [ - "hf fudan reader", - "hf fudan reader -@ -> continuous reader mode" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-v, --verbose verbose output", - "-@ optional - continuous reader mode" - ], - "usage": "hf fudan reader [-hv@]" - }, "hf fudan view": { "command": "hf fudan view", "description": "Print a FUDAN dump file (bin/eml/json)", @@ -2968,14 +3011,14 @@ ], "usage": "hf gallagher diversify [-h] --aid [--keynum ] [--uid ] [--sitekey ] [--apdu]" }, - "hf gallagher reader": { - "command": "hf gallagher reader", - "description": "Read a Gallagher DESFire tag from the Card Application Directory, CAD Specify site key is required if using non-default key", + "hf gallagher help": { + "command": "hf gallagher help", + "description": "help This help diversifykey Diversify Gallagher key decode Decode Gallagher credential block --------------------------------------------------------------------------------------- hf gallagher reader available offline: no Read a Gallagher DESFire tag from the Card Application Directory, CAD Specify site key is required if using non-default key", "notes": [ "hf gallagher reader -@ -> continuous reader mode", "hf gallagher reader --aid 2081f4 --sitekey 00112233445566778899aabbccddeeff -> skip CAD" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "--aid Application ID to read (3 bytes). If specified, the CAD is not used", @@ -2986,6 +3029,27 @@ ], "usage": "hf gallagher reader [-h@v] [--aid ] [--sitekey ] [--apdu]" }, + "hf help": { + "command": "hf help", + "description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } jooki { Jooki RFIDs... } iclass { ICLASS RFIDs... } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service } waveshare { Waveshare NFC ePaper... } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "notes": [ + "hf list --frame -> show frame delay times", + "hf list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-1, --buffer use data from trace buffer", + "--frame show frame delay times", + "-c mark CRC bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into Wireshark using encapsulation type \"ISO 14443\"", + "-f, --file filename of dictionary" + ], + "usage": "hf list [-h1crux] [--frame] [-f ]" + }, "hf iclass calcnewkey": { "command": "hf iclass calcnewkey", "description": "Calculate new keys for updating (blocks 3 & 4)", @@ -3218,22 +3282,9 @@ ], "usage": "hf iclass eview [-hvz] [-s <256|2048>]" }, - "hf iclass info": { - "command": "hf iclass info", - "description": "Act as a iCLASS reader. Reads / fingerprints a iCLASS tag.", - "notes": [ - "hf iclass info" - ], - "offline": false, - "options": [ - "-h, --help This help", - "--shallow use shallow (ASK) reader modulation instead of OOK" - ], - "usage": "hf iclass info [-h] [--shallow]" - }, - "hf iclass list": { - "command": "hf iclass list", - "description": "Alias of `trace list -t iclass -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "hf iclass help": { + "command": "hf iclass help", + "description": "help This help list List iclass history ----------- --------------------- general --------------------- view Display content from tag dump file ----------- --------------------- recovery -------------------- loclass Use loclass to perform bruteforce reader attack lookup Uses authentication trace to check for key in dictionary file ----------- ---------------------- utils ---------------------- calcnewkey Calc diversified keys (blocks 3 & 4) to write new keys encode Encode binary wiegand to block 7 encrypt Encrypt given block data decrypt Decrypt given block data or tag dump file managekeys Manage keys to use with iclass commands permutekey Permute function from 'heart of darkness' paper --------------------------------------------------------------------------------------- hf iclass list available offline: yes Alias of `trace list -t iclass -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf iclass list --frame -> show frame delay times", "hf iclass list -1 -> use trace buffer" @@ -3252,6 +3303,19 @@ ], "usage": "hf iclass list [-h1crux] [--frame] [-f ]" }, + "hf iclass info": { + "command": "hf iclass info", + "description": "Act as a iCLASS reader. Reads / fingerprints a iCLASS tag.", + "notes": [ + "hf iclass info" + ], + "offline": false, + "options": [ + "-h, --help This help", + "--shallow use shallow (ASK) reader modulation instead of OOK" + ], + "usage": "hf iclass info [-h] [--shallow]" + }, "hf iclass loclass": { "command": "hf iclass loclass", "description": "Execute the offline part of loclass attack An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses The binary format of the file is expected to be as follows: <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC> <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC> <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC> ... totalling N*24 bytes", @@ -3475,22 +3539,6 @@ ], "usage": "hf iclass wrbl [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow]" }, - "hf jooki clone": { - "command": "hf jooki clone", - "description": "Write a Jooki token to a Ultralight or NTAG tag", - "notes": [ - "hf jooki clone -d -> where hex is raw NDEF", - "hf jooki clone --b64 7WzlgEzqLgwTnWNy -> using base64 url parameter" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-b, --b64 base64 url parameter", - "-d, --data raw NDEF bytes", - "-p, --pwd password for authentication (EV1/NTAG 4 bytes)" - ], - "usage": "hf jooki clone [-h] [-b ] [-d ] [-p ]" - }, "hf jooki decode": { "command": "hf jooki decode", "description": "Decode a base64-encode Jooki token in NDEF URI format", @@ -3539,6 +3587,22 @@ ], "usage": "hf jooki encode [-hrtv] [-u ] [--dragon] [--fox] [--ghost] [--knight] [--whale] [--blackdragon] [--blackfox] [--blackknight] [--blackwhale] [--whitedragon] [--whitefox] [--whiteknight] [--whitewhale] [--tid ] [--fid ]" }, + "hf jooki help": { + "command": "hf jooki help", + "description": "help This help decode Decode Jooki token encode Encode Jooki token --------------------------------------------------------------------------------------- hf jooki clone available offline: no Write a Jooki token to a Ultralight or NTAG tag", + "notes": [ + "hf jooki clone -d -> where hex is raw NDEF", + "hf jooki clone --b64 7WzlgEzqLgwTnWNy -> using base64 url parameter" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-b, --b64 base64 url parameter", + "-d, --data raw NDEF bytes", + "-p, --pwd password for authentication (EV1/NTAG 4 bytes)" + ], + "usage": "hf jooki clone [-h] [-b ] [-d ] [-p ]" + }, "hf jooki sim": { "command": "hf jooki sim", "description": "Simulate a Jooki token. Either `hf mfu eload` before or use `-d` param", @@ -3567,6 +3631,19 @@ ], "usage": "hf ksx6924 balance [-hka]" }, + "hf ksx6924 help": { + "command": "hf ksx6924 help", + "description": "help This help --------------------------------------------------------------------------------------- hf ksx6924 select available offline: no Selects KS X 6924 application, and leaves field up", + "notes": [ + "hf ksx6924 select" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-a, --apdu Show APDU requests and responses" + ], + "usage": "hf ksx6924 select [-ha]" + }, "hf ksx6924 info": { "command": "hf ksx6924 info", "description": "Get info about a KS X 6924 transit card. This application is used by T-Money (South Korea) and Snapper+ (Wellington, New Zealand).", @@ -3609,19 +3686,6 @@ ], "usage": "hf ksx6924 prec [-hka] " }, - "hf ksx6924 select": { - "command": "hf ksx6924 select", - "description": "Selects KS X 6924 application, and leaves field up", - "notes": [ - "hf ksx6924 select" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-a, --apdu Show APDU requests and responses" - ], - "usage": "hf ksx6924 select [-ha]" - }, "hf legic crc": { "command": "hf legic crc", "description": "Calculates the legic crc8/crc16 on the given data", @@ -3638,22 +3702,6 @@ ], "usage": "hf legic crc [-h] -d [--mcc ] [-t ]" }, - "hf legic dump": { - "command": "hf legic dump", - "description": "Read all memory from LEGIC Prime tags and saves to (bin/json) dump file It autodetects card type (MIM22, MIM256, MIM1024)", - "notes": [ - "hf legic dump -> use UID as filename", - "hf legic dump -f myfile", - "hf legic dump --de -> use UID as filename and deobfuscate data" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-f, --file Dump filename", - "--de deobfuscate dump data (xor with MCC)" - ], - "usage": "hf legic dump [-h] [-f ] [--de]" - }, "hf legic einfo": { "command": "hf legic einfo", "description": "It decodes and displays emulator memory", @@ -3721,6 +3769,22 @@ ], "usage": "hf legic eview [-hv] [--22] [--256] [--1024]" }, + "hf legic help": { + "command": "hf legic help", + "description": "----------- --------------------- operations --------------------- help This help list List LEGIC history ----------- --------------------- simulation --------------------- ----------- --------------------- utils --------------------- crc Calculate Legic CRC over given bytes view Display deobfuscated and decoded content from tag dump file --------------------------------------------------------------------------------------- hf legic dump available offline: no Read all memory from LEGIC Prime tags and saves to (bin/json) dump file It autodetects card type (MIM22, MIM256, MIM1024)", + "notes": [ + "hf legic dump -> use UID as filename", + "hf legic dump -f myfile", + "hf legic dump --de -> use UID as filename and deobfuscate data" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-f, --file Dump filename", + "--de deobfuscate dump data (xor with MCC)" + ], + "usage": "hf legic dump [-h] [-f ] [--de]" + }, "hf legic info": { "command": "hf legic info", "description": "Gets information from a LEGIC Prime tag like systemarea, user areas, etc", @@ -3857,34 +3921,13 @@ ], "usage": "hf legic wrbl [-h] -o -d [--danger]" }, - "hf list": { - "command": "hf list", - "description": "Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", - "notes": [ - "hf list --frame -> show frame delay times", - "hf list -1 -> use trace buffer" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-1, --buffer use data from trace buffer", - "--frame show frame delay times", - "-c mark CRC bytes", - "-r show relative times (gap and duration)", - "-u display times in microseconds instead of clock cycles", - "-x show hexdump to convert to pcap(ng)", - "or to import into Wireshark using encapsulation type \"ISO 14443\"", - "-f, --file filename of dictionary" - ], - "usage": "hf list [-h1crux] [--frame] [-f ]" - }, - "hf lto dump": { - "command": "hf lto dump", - "description": "Dump data from LTO tag", + "hf lto help": { + "command": "hf lto help", + "description": "help This help list List LTO-CM history --------------------------------------------------------------------------------------- hf lto dump available offline: no Dump data from LTO tag", "notes": [ "hf lto dump -f myfile" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "-f, --file specify a filename for dumpfile" @@ -4707,6 +4750,27 @@ ], "usage": "hf mf hardnested [-habrstw] [-k ] [--blk ] [--tblk ] [--ta] [--tb] [--tk ] [-u ] [-f ] [--in] [--im] [--is] [--ia] [--i2] [--i5]" }, + "hf mf help": { + "command": "hf mf help", + "description": "help This help list List MIFARE history hardnested Nested attack for hardened MIFARE Classic cards decrypt Decrypt Crypto1 data from sniff or trace acl Decode and print MIFARE Classic access rights bytes mad Checks and prints MAD value Value blocks view Display content from tag dump file --------------------------------------------------------------------------------------- hf mf list available offline: yes Alias of `trace list -t mf -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "notes": [ + "hf mf list --frame -> show frame delay times", + "hf mf list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-1, --buffer use data from trace buffer", + "--frame show frame delay times", + "-c mark CRC bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into Wireshark using encapsulation type \"ISO 14443\"", + "-f, --file filename of dictionary" + ], + "usage": "hf mf list [-h1crux] [--frame] [-f ]" + }, "hf mf info": { "command": "hf mf info", "description": "Information and check vulnerabilities in a MIFARE Classic card Some cards in order to extract information you need to specify key and/or specific keys in the command line", @@ -4726,27 +4790,6 @@ ], "usage": "hf mf info [-habnv] [--blk ] [-k ]" }, - "hf mf list": { - "command": "hf mf list", - "description": "Alias of `trace list -t mf -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", - "notes": [ - "hf mf list --frame -> show frame delay times", - "hf mf list -1 -> use trace buffer" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-1, --buffer use data from trace buffer", - "--frame show frame delay times", - "-c mark CRC bytes", - "-r show relative times (gap and duration)", - "-u display times in microseconds instead of clock cycles", - "-x show hexdump to convert to pcap(ng)", - "or to import into Wireshark using encapsulation type \"ISO 14443\"", - "-f, --file filename of dictionary" - ], - "usage": "hf mf list [-h1crux] [--frame] [-f ]" - }, "hf mf mad": { "command": "hf mf mad", "description": "Checks and prints MIFARE Application Directory (MAD)", @@ -5926,13 +5969,13 @@ ], "usage": "hf mfdes getuid [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ]" }, - "hf mfdes info": { - "command": "hf mfdes info", - "description": "Get info from MIFARE DESfire tags", + "hf mfdes help": { + "command": "hf mfdes help", + "description": "help This help list List DESFire (ISO 14443A) history test Regression crypto tests --------------------------------------------------------------------------------------- hf mfdes info available offline: no Get info from MIFARE DESfire tags", "notes": [ "hf mfdes info" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help" ], @@ -6370,6 +6413,27 @@ ], "usage": "hf mfp dump [-hv] [-f ] [-k ] [--ns]" }, + "hf mfp help": { + "command": "hf mfp help", + "description": "help This help list List MIFARE Plus history --------------------------------------------------------------------------------------- hf mfp list available offline: yes Alias of `trace list -t mfp -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "notes": [ + "hf mfp list --frame -> show frame delay times", + "hf mfp list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-1, --buffer use data from trace buffer", + "--frame show frame delay times", + "-c mark CRC bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into Wireshark using encapsulation type \"ISO 14443\"", + "-f, --file filename of dictionary" + ], + "usage": "hf mfp list [-h1crux] [--frame] [-f ]" + }, "hf mfp info": { "command": "hf mfp info", "description": "Get info from MIFARE Plus tags", @@ -6397,27 +6461,6 @@ ], "usage": "hf mfp initp [-hv] [-k ]" }, - "hf mfp list": { - "command": "hf mfp list", - "description": "Alias of `trace list -t mfp -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", - "notes": [ - "hf mfp list --frame -> show frame delay times", - "hf mfp list -1 -> use trace buffer" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-1, --buffer use data from trace buffer", - "--frame show frame delay times", - "-c mark CRC bytes", - "-r show relative times (gap and duration)", - "-u display times in microseconds instead of clock cycles", - "-x show hexdump to convert to pcap(ng)", - "or to import into Wireshark using encapsulation type \"ISO 14443\"", - "-f, --file filename of dictionary" - ], - "usage": "hf mfp list [-h1crux] [--frame] [-f ]" - }, "hf mfp mad": { "command": "hf mfp mad", "description": "Checks and prints MIFARE Application Directory (MAD)", @@ -6660,6 +6703,27 @@ ], "usage": "hf mfu eview [-h] [-e ]" }, + "hf mfu help": { + "command": "hf mfu help", + "description": "help This help list List MIFARE Ultralight / NTAG history keygen Generate 3DES MIFARE diversified keys pwdgen Generate pwd from known algos view Display content from tag dump file --------------------------------------------------------------------------------------- hf mfu list available offline: yes Alias of `trace list -t 14a -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "notes": [ + "hf 14a list --frame -> show frame delay times", + "hf 14a list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-1, --buffer use data from trace buffer", + "--frame show frame delay times", + "-c mark CRC bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into Wireshark using encapsulation type \"ISO 14443\"", + "-f, --file filename of dictionary" + ], + "usage": "hf 14a list [-h1crux] [--frame] [-f ]" + }, "hf mfu info": { "command": "hf mfu info", "description": "Get info about MIFARE Ultralight Family styled tag. Sometimes the tags are locked down, and you may need a key to be able to read the information", @@ -6691,27 +6755,6 @@ ], "usage": "hf mfu keygen [-hr] [-u ]" }, - "hf mfu list": { - "command": "hf mfu list", - "description": "Alias of `trace list -t 14a -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", - "notes": [ - "hf 14a list --frame -> show frame delay times", - "hf 14a list -1 -> use trace buffer" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-1, --buffer use data from trace buffer", - "--frame show frame delay times", - "-c mark CRC bytes", - "-r show relative times (gap and duration)", - "-u display times in microseconds instead of clock cycles", - "-x show hexdump to convert to pcap(ng)", - "or to import into Wireshark using encapsulation type \"ISO 14443\"", - "-f, --file filename of dictionary" - ], - "usage": "hf 14a list [-h1crux] [--frame] [-f ]" - }, "hf mfu ndefread": { "command": "hf mfu ndefread", "description": "Prints NFC Data Exchange Format (NDEF)", @@ -6976,13 +7019,13 @@ ], "usage": "hf ntag424 getfs [-h] --fileno " }, - "hf ntag424 info": { - "command": "hf ntag424 info", - "description": "Get info about NXP NTAG424 DNA Family styled tag.", + "hf ntag424 help": { + "command": "hf ntag424 help", + "description": "help This help view Display content from tag dump file --------------------------------------------------------------------------------------- hf ntag424 info available offline: no Get info about NXP NTAG424 DNA Family styled tag.", "notes": [ "hf ntag424 info" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help" ], @@ -7067,13 +7110,13 @@ ], "usage": "hf search [-hv]" }, - "hf seos info": { - "command": "hf seos info", - "description": "Get info from SEOS tags", + "hf seos help": { + "command": "hf seos help", + "description": "help This help list List SEOS history --------------------------------------------------------------------------------------- hf seos info available offline: no Get info from SEOS tags", "notes": [ "hf seos info" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help" ], @@ -7081,7 +7124,7 @@ }, "hf seos list": { "command": "hf seos list", - "description": "Alias of `trace list -t 7816` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "description": "Alias of `trace list -t seos -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf seos list --frame -> show frame delay times", "hf seos list -1 -> use trace buffer" @@ -7117,13 +7160,13 @@ ], "usage": "hf sniff [-h] [--sp ] [--st ] [--smode [none|drop|min|max|avg]] [--sratio ]" }, - "hf st25ta info": { - "command": "hf st25ta info", - "description": "Get info about ST25TA tag", + "hf st25ta help": { + "command": "hf st25ta help", + "description": "help This help list List ISO 14443A/7816 history ndefread read NDEF file on tag --------------------------------------------------------------------------------------- hf st25ta info available offline: no Get info about ST25TA tag", "notes": [ "hf st25ta info" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help" ], @@ -7214,13 +7257,13 @@ ], "usage": "hf st25ta sim [-h] -u " }, - "hf tesla info": { - "command": "hf tesla info", - "description": "Get info about TESLA Key tag", + "hf tesla help": { + "command": "hf tesla help", + "description": "help This help list List ISO 14443A/7816 history --------------------------------------------------------------------------------------- hf tesla info available offline: no Get info about TESLA Key tag", "notes": [ "hf tesla info" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help" ], @@ -7247,14 +7290,14 @@ ], "usage": "hf tesla list [-h1crux] [--frame] [-f ]" }, - "hf texkom reader": { - "command": "hf texkom reader", - "description": "Read a texkom tag", + "hf texkom help": { + "command": "hf texkom help", + "description": "help This help --------------------------------------------------------------------------------------- hf texkom reader available offline: no Read a texkom tag", "notes": [ "hf texkom reader", "hf texkom reader -@ -> continuous reader mode" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "-1 Use data from Graphbuffer (offline mode)", @@ -7284,13 +7327,13 @@ ], "usage": "hf texkom sim [-hvt] [--raw ] [--id ] [--timeout ]" }, - "hf thinfilm info": { - "command": "hf thinfilm info", - "description": "Get info from Thinfilm tags", + "hf thinfilm help": { + "command": "hf thinfilm help", + "description": "help This help list List NFC Barcode / Thinfilm history - not correct --------------------------------------------------------------------------------------- hf thinfilm info available offline: no Get info from Thinfilm tags", "notes": [ "hf thinfilm info" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help" ], @@ -7345,24 +7388,9 @@ ], "usage": "hf topaz dump [-h] [-f ] [--ns]" }, - "hf topaz info": { - "command": "hf topaz info", - "description": "Get info from Topaz tags", - "notes": [ - "hf topaz info", - "hf topaz info -f myfilename -> save raw NDEF to file" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-f, --file save raw NDEF to file", - "-v, --verbose verbose output" - ], - "usage": "hf topaz info [-hv] [-f ]" - }, - "hf topaz list": { - "command": "hf topaz list", - "description": "Alias of `trace list -t topaz -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "hf topaz help": { + "command": "hf topaz help", + "description": "help This help list List Topaz history view Display content from tag dump file --------------------------------------------------------------------------------------- hf topaz list available offline: yes Alias of `trace list -t topaz -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf topaz list --frame -> show frame delay times", "hf topaz list -1 -> use trace buffer" @@ -7381,6 +7409,21 @@ ], "usage": "hf topaz list [-h1crux] [--frame] [-f ]" }, + "hf topaz info": { + "command": "hf topaz info", + "description": "Get info from Topaz tags", + "notes": [ + "hf topaz info", + "hf topaz info -f myfilename -> save raw NDEF to file" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-f, --file save raw NDEF to file", + "-v, --verbose verbose output" + ], + "usage": "hf topaz info [-hv] [-f ]" + }, "hf topaz raw": { "command": "hf topaz raw", "description": "Send raw hex data to Topaz tags", @@ -7504,14 +7547,14 @@ ], "usage": "hf vas decrypt [-h] [--pid ] [-f ] [-d ]" }, - "hf vas reader": { - "command": "hf vas reader", - "description": "Read and decrypt Value Added Services (VAS) message", + "hf vas help": { + "command": "hf vas help", + "description": "-------- ----------- Value Added Service ----------- help This help -------- ----------------- General ----------------- decrypt Decrypt a previously captured VAS cryptogram --------------------------------------------------------------------------------------- hf vas reader available offline: no Read and decrypt Value Added Services (VAS) message", "notes": [ "hf vas reader --url https://example.com -> URL Only mode", "hf vas reader --pid pass.com.passkit.pksamples.nfcdemo -f vas_privkey.der -@" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "--pid PID, pass type id", @@ -7522,31 +7565,31 @@ ], "usage": "hf vas reader [-h@v] [--pid ] [-f ] [--url ]" }, - "hf waveshare loadbmp": { - "command": "hf waveshare loadbmp", - "description": "Load BMP file to Waveshare NFC ePaper.", + "hf waveshare help": { + "command": "hf waveshare help", + "description": "help This help load Load image file to Waveshare NFC ePaper --------------------------------------------------------------------------------------- hf waveshare load available offline: yes Load image file to Waveshare NFC ePaper", "notes": [ - "hf waveshare loadbmp -f myfile -m 0 -> 2.13 inch e-paper ( 122, 250 )", - "hf waveshare loadbmp -f myfile -m 1 -> 2.9 inch e-paper ( 296, 128 )", - "hf waveshare loadbmp -f myfile -m 2 -> 4.2 inch e-paper ( 400, 300 )", - "hf waveshare loadbmp -f myfile -m 3 -> 7.5 inch e-paper ( 800, 480 )", - "hf waveshare loadbmp -f myfile -m 4 -> 2.7 inch e-paper ( 176, 276 )", - "hf waveshare loadbmp -f myfile -m 5 -> 2.13 inch e-paper B (with red) ( 104, 212 )", - "hf waveshare loadbmp -f myfile -m 6 -> 1.54 inch e-paper B (with red) ( 200, 200 )", - "hf waveshare loadbmp -f myfile -m 7 -> 7.5 inch e-paper HD ( 880, 528 )" + "hf waveshare load -f myfile -m 0 -> 2.13 inch e-paper ( 122, 250 )", + "hf waveshare load -f myfile -m 1 -> 2.9 inch e-paper ( 296, 128 )", + "hf waveshare load -f myfile -m 2 -> 4.2 inch e-paper ( 400, 300 )", + "hf waveshare load -f myfile -m 3 -> 7.5 inch e-paper ( 800, 480 )", + "hf waveshare load -f myfile -m 4 -> 2.7 inch e-paper ( 176, 276 )", + "hf waveshare load -f myfile -m 5 -> 2.13 inch e-paper B (with red) ( 104, 212 )", + "hf waveshare load -f myfile -m 6 -> 1.54 inch e-paper B (with red) ( 200, 200 )", + "hf waveshare load -f myfile -m 7 -> 7.5 inch e-paper HD ( 880, 528 )" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "-m model number [0 - 7] of your tag", - "-s, --save save dithered version in filename-[n].bmp, only for RGB BMP", - "-f, --file specify filename[.bmp] to upload to tag" + "-f, --file specify image to upload to tag", + "-s, --save save paletized version in file" ], - "usage": "hf waveshare loadbmp [-hs] -m -f " + "usage": "hf waveshare load [-h] -m -f [-s ]" }, "hf xerox dump": { "command": "hf xerox dump", - "description": "Dump all memory from a Fuji/Xerox tag", + "description": "Dump all memory from a Fuji/Xerox tag ISO/IEC 14443 type B based communications", "notes": [ "hf xerox dump" ], @@ -7554,13 +7597,36 @@ "options": [ "-h, --help This help", "-f, --file filename to save dump to", - "-d, --decrypt decrypt secret blocks" + "-d, --decrypt decrypt secret blocks", + "--ns no save to file", + "-v, --verbose verbose output" ], - "usage": "hf xerox dump [-hd] [-f ]" + "usage": "hf xerox dump [-hdv] [-f ] [--ns]" + }, + "hf xerox help": { + "command": "hf xerox help", + "description": "help This help list List ISO-14443B history -------- ----------------------- general ----------------------- view Display content from tag dump file --------------------------------------------------------------------------------------- hf xerox list available offline: yes Alias of `trace list -t 14b -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "notes": [ + "hf 14b list --frame -> show frame delay times", + "hf 14b list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-1, --buffer use data from trace buffer", + "--frame show frame delay times", + "-c mark CRC bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into Wireshark using encapsulation type \"ISO 14443\"", + "-f, --file filename of dictionary" + ], + "usage": "hf 14b list [-h1crux] [--frame] [-f ]" }, "hf xerox info": { "command": "hf xerox info", - "description": "Tag information for ISO/IEC 14443 type B / XEROX based tags", + "description": "Tag information for Fuji Xerox based tags ISO/IEC 14443 type B based communications", "notes": [ "hf xerox info" ], @@ -7573,7 +7639,7 @@ }, "hf xerox reader": { "command": "hf xerox reader", - "description": "Act as a 14443B reader to identify a tag", + "description": "Act as a 14443B reader to identify a Fuji Xerox based tag ISO/IEC 14443 type B based communications", "notes": [ "hf xerox reader", "hf xerox reader -@" @@ -7586,6 +7652,20 @@ ], "usage": "hf xerox reader [-hv@]" }, + "hf xerox view": { + "command": "hf xerox view", + "description": "Print a Fuji/Xerox dump file (bin/eml/json) note: - command expects the filename to contain a UID which is needed to determine card memory type", + "notes": [ + "hf xerox view -f hf-xerox-0102030405060708-dump.bin" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-f, --file Specify a filename for dump file", + "-v, --verbose verbose output" + ], + "usage": "hf xerox view [-hv] -f " + }, "hints": { "command": "hints", "description": "Turn on/off hints", @@ -7613,18 +7693,6 @@ ], "usage": "hw bootloader [-h]" }, - "hw break": { - "command": "hw break", - "description": "send break loop package", - "notes": [ - "hw break" - ], - "offline": false, - "options": [ - "-h, --help This help" - ], - "usage": "hw break [-h]" - }, "hw connect": { "command": "hw connect", "description": "Connects to a Proxmark3 device via specified serial port. Baudrate here is only for physical UART or UART-BT, NOT for USB-CDC or blue shark add-on", @@ -7684,6 +7752,18 @@ ], "usage": "hw fpgaoff [-h]" }, + "hw help": { + "command": "hw help", + "description": "------------- ----------------------- Hardware ----------------------- help This help connect Connect Proxmark3 to serial port timeout Set the communication timeout on the client side version Show version information about the client and the connected Proxmark3, if any --------------------------------------------------------------------------------------- hw break available offline: no send break loop package", + "notes": [ + "hw break" + ], + "offline": true, + "options": [ + "-h, --help This help" + ], + "usage": "hw break [-h]" + }, "hw lcd": { "command": "hw lcd", "description": "Send command/data to LCD", @@ -7914,9 +7994,9 @@ ], "usage": "lf awid clone [-h] --fmt --fc --cn [--q5] [--em]" }, - "lf awid demod": { - "command": "lf awid demod", - "description": "Try to find AWID Prox preamble, if found decode / descramble data", + "lf awid help": { + "command": "lf awid help", + "description": "help this help demod demodulate an AWID FSK tag from the GraphBuffer --------------------------------------------------------------------------------------- lf awid demod available offline: yes Try to find AWID Prox preamble, if found decode / descramble data", "notes": [ "lf awid demod" ], @@ -7992,35 +8072,9 @@ ], "usage": "lf cmdread [-hvk@] [-d ] [-c <0|1|...>] [-e ]... [-o ] [-z ] [-s ] [--crc-ht]" }, - "lf config": { - "command": "lf config", - "description": "Get/Set config for LF sampling, bit/sample, decimation, frequency These changes are temporary, will be reset after a power cycle. - use `lf read` performs a read (active field) - use `lf sniff` performs a sniff (no active field)", - "notes": [ - "lf config -> shows current config", - "lf config -b 8 --125 -> samples at 125 kHz, 8 bps", - "lf config -b 4 --134 --dec 3 -> samples at 134 kHz, averages three samples into one, stored with a resolution of 4 bits per sample", - "lf config --trig 20 -s 10000 -> trigger sampling when above 20, skip 10 000 first samples after triggered", - "lf config --reset -> reset back to default values" - ], - "offline": false, - "options": [ - "-h, --help This help", - "--125 125 kHz frequency", - "--134 134 kHz frequency", - "-a, --avg <0|1> averaging - if set, will average the stored sample value when decimating (default 1)", - "-b, --bps <1-8> sets resolution of bits per sample (default 8)", - "--dec <1-8> sets decimation. A value of N saves only 1 in N samples (default 1)", - "--divisor <19-255> Manually set freq divisor. 88 -> 134 kHz, 95 -> 125 kHz", - "-f, --freq <47-600> manually set frequency in kHz", - "-r, --reset reset values to defaults", - "-s, --skip sets a number of samples to skip before capture (default 0)", - "-t, --trig <0-128> sets trigger threshold. 0 means no threshold" - ], - "usage": "lf config [-hr] [--125] [--134] [-a <0|1>] [-b <1-8>] [--dec <1-8>] [--divisor <19-255>] [-f <47-600>] [-s ] [-t <0-128>]" - }, - "lf cotag demod": { - "command": "lf cotag demod", - "description": "Try to find COTAG preamble, if found decode / descramble data", + "lf cotag help": { + "command": "lf cotag help", + "description": "help This help demod demodulate an COTAG tag --------------------------------------------------------------------------------------- lf cotag demod available offline: yes Try to find COTAG preamble, if found decode / descramble data", "notes": [ "lf cotag demod" ], @@ -8063,9 +8117,9 @@ ], "usage": "lf destron clone [-h] -u [--q5] [--em]" }, - "lf destron demod": { - "command": "lf destron demod", - "description": "Try to find Destron preamble, if found decode / descramble data", + "lf destron help": { + "command": "lf destron help", + "description": "help This help demod demodulate an Destron tag from the GraphBuffer --------------------------------------------------------------------------------------- lf destron demod available offline: yes Try to find Destron preamble, if found decode / descramble data", "notes": [ "lf destron demod" ], @@ -8137,27 +8191,6 @@ ], "usage": "lf em 410x clone [-h] [--clk ] --id [--q5] [--em]" }, - "lf em 410x demod": { - "command": "lf em 410x demod", - "description": "Try to find EM 410x preamble, if found decode / descramble data", - "notes": [ - "lf em 410x demod -> demod an EM410x Tag ID from GraphBuffer", - "lf em 410x demod --clk 32 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32", - "lf em 410x demod --clk 32 -i -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data", - "lf em 410x demod -i -> demod an EM410x Tag ID from GraphBuffer while inverting data", - "lf em 410x demod --clk 64 -i --err 0 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors" - ], - "offline": true, - "options": [ - "-h, --help This help", - "--clk clock (default autodetect)", - "--err maximum allowed errors (default 100)", - "--len maximum length", - "-i, --invert invert output", - "-a, --amp amplify signal" - ], - "usage": "lf em 410x demod [-hia] [--clk ] [--err ] [--len ]" - }, "lf em 410x reader": { "command": "lf em 410x reader", "description": "read EM 410x tag", @@ -8224,22 +8257,6 @@ ], "usage": "lf em 410x watch [-h]" }, - "lf em 4x05 brute": { - "command": "lf em 4x05 brute", - "description": "This command tries to bruteforce the password of a EM4205/4305/4469/4569 The loop is running on device side, press Proxmark3 button to abort", - "notes": [ - "Note: if you get many false positives, change position on the antennalf em 4x05 brute", - "lf em 4x05 brute -n 1 -> stop after first candidate found", - "lf em 4x05 brute -s 000022AA -> start at 000022AA" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-s, --start Start bruteforce enumeration from this password value", - "-n Stop after having found n candidates. Default: 0 (infinite)" - ], - "usage": "lf em 4x05 brute [-h] [-s ] [-n ]" - }, "lf em 4x05 chk": { "command": "lf em 4x05 chk", "description": "This command uses a dictionary attack against EM4205/4305/4469/4569", @@ -8285,6 +8302,22 @@ ], "usage": "lf em 4x05 dump [-h] [-p ] [-f ] [--ns]" }, + "lf em 4x05 help": { + "command": "lf em 4x05 help", + "description": "help This help demod Demodulate a EM4x05/EM4x69 tag from the GraphBuffer sniff Attempt to recover em4x05 commands from sample buffer --------------------------------------------------------------------------------------- lf em 4x05 brute available offline: no This command tries to bruteforce the password of a EM4205/4305/4469/4569 The loop is running on device side, press Proxmark3 button to abort", + "notes": [ + "Note: if you get many false positives, change position on the antennalf em 4x05 brute", + "lf em 4x05 brute -n 1 -> stop after first candidate found", + "lf em 4x05 brute -s 000022AA -> start at 000022AA" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-s, --start Start bruteforce enumeration from this password value", + "-n Stop after having found n candidates. Default: 0 (infinite)" + ], + "usage": "lf em 4x05 brute [-h] [-s ] [-n ]" + }, "lf em 4x05 info": { "command": "lf em 4x05 info", "description": "Tag information EM4205/4305/4469//4569 tags. Tag must be on antenna.", @@ -8386,24 +8419,6 @@ ], "usage": "lf em 4x05 write [-h] [-a ] -d [-p ] [--po]" }, - "lf em 4x50 brute": { - "command": "lf em 4x50 brute", - "description": "Tries to bruteforce the password of a EM4x50 card. Function can be stopped by pressing pm3 button.", - "notes": [ - "lf em 4x50 brute --mode range --begin 12330000 --end 12340000 -> tries pwds from 0x12330000 to 0x12340000", - "lf em 4x50 brute --mode charset --digits --uppercase -> tries all combinations of ASCII codes for digits and uppercase letters" - ], - "offline": false, - "options": [ - "-h, --help This help", - "--mode Bruteforce mode (range|charset)", - "--begin Range mode - start of the key range", - "--end Range mode - end of the key range", - "--digits Charset mode - include ASCII codes for digits", - "--uppercase Charset mode - include ASCII codes for uppercase letters" - ], - "usage": "lf em 4x50 brute [-h] --mode [--begin ] [--end ] [--digits] [--uppercase]" - }, "lf em 4x50 chk": { "command": "lf em 4x50 chk", "description": "Run dictionary key recovery against EM4x50 card.", @@ -8474,6 +8489,24 @@ ], "usage": "lf em 4x50 eview [-h]" }, + "lf em 4x50 help": { + "command": "lf em 4x50 help", + "description": "help This help ----------- --------------------- operations --------------------- ----------- --------------------- simulation --------------------- --------------------------------------------------------------------------------------- lf em 4x50 brute available offline: no Tries to bruteforce the password of a EM4x50 card. Function can be stopped by pressing pm3 button.", + "notes": [ + "lf em 4x50 brute --mode range --begin 12330000 --end 12340000 -> tries pwds from 0x12330000 to 0x12340000", + "lf em 4x50 brute --mode charset --digits --uppercase -> tries all combinations of ASCII codes for digits and uppercase letters" + ], + "offline": true, + "options": [ + "-h, --help This help", + "--mode Bruteforce mode (range|charset)", + "--begin Range mode - start of the key range", + "--end Range mode - end of the key range", + "--digits Charset mode - include ASCII codes for digits", + "--uppercase Charset mode - include ASCII codes for uppercase letters" + ], + "usage": "lf em 4x50 brute [-h] --mode [--begin ] [--end ] [--digits] [--uppercase]" + }, "lf em 4x50 info": { "command": "lf em 4x50 info", "description": "Tag information EM4x50.", @@ -8622,13 +8655,13 @@ ], "usage": "lf em 4x70 auth [-h] [--par] --rnd --frn " }, - "lf em 4x70 brute": { - "command": "lf em 4x70 brute", - "description": "Optimized partial key-update attack of 16-bit key block 7, 8 or 9 of an EM4x70 This attack does NOT write anything to the tag. Before starting this attack, 0000 must be written to the 16-bit key block: 'lf em 4x70 write -b 9 -d 0000'. After success, the 16-bit key block have to be restored with the key found: 'lf em 4x70 write -b 9 -d c0de'", + "lf em 4x70 help": { + "command": "lf em 4x70 help", + "description": "help This help --------------------------------------------------------------------------------------- lf em 4x70 brute available offline: no Optimized partial key-update attack of 16-bit key block 7, 8 or 9 of an EM4x70 This attack does NOT write anything to the tag. Before starting this attack, 0000 must be written to the 16-bit key block: 'lf em 4x70 write -b 9 -d 0000'. After success, the 16-bit key block have to be restored with the key found: 'lf em 4x70 write -b 9 -d c0de'", "notes": [ "lf em 4x70 brute -b 9 --rnd 45F54ADA252AAC --frn 4866BB70 -> bruteforcing key bits k95...k80" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "--par Add parity bit when sending commands", @@ -8713,6 +8746,27 @@ ], "usage": "lf em 4x70 writepin [-h] [--par] -p " }, + "lf em help": { + "command": "lf em help", + "description": "help This help 410x { EM 4102 commands... } 4x05 { EM 4205 / 4305 / 4369 / 4469 commands... } 4x50 { EM 4350 / 4450 commands... } 4x70 { EM 4070 / 4170 commands... } ======================================================================================= lf em 410x { EM 4102 commands... } --------------------------------------------------------------------------------------- lf em 410x help available offline: yes help This help demod demodulate a EM410x tag from the GraphBuffer --------------------------------------------------------------------------------------- lf em 410x demod available offline: yes Try to find EM 410x preamble, if found decode / descramble data", + "notes": [ + "lf em 410x demod -> demod an EM410x Tag ID from GraphBuffer", + "lf em 410x demod --clk 32 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32", + "lf em 410x demod --clk 32 -i -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data", + "lf em 410x demod -i -> demod an EM410x Tag ID from GraphBuffer while inverting data", + "lf em 410x demod --clk 64 -i --err 0 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors" + ], + "offline": true, + "options": [ + "-h, --help This help", + "--clk clock (default autodetect)", + "--err maximum allowed errors (default 100)", + "--len maximum length", + "-i, --invert invert output", + "-a, --amp amplify signal" + ], + "usage": "lf em 410x demod [-hia] [--clk ] [--err ] [--len ]" + }, "lf fdxb clone": { "command": "lf fdxb clone", "description": "clone a FDX-B tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", @@ -8734,9 +8788,9 @@ ], "usage": "lf fdxb clone [-ha] -c -n [--extended ] [--q5] [--em]" }, - "lf fdxb demod": { - "command": "lf fdxb demod", - "description": "Try to find FDX-B preamble, if found decode / descramble data", + "lf fdxb help": { + "command": "lf fdxb help", + "description": "help this help demod demodulate a FDX-B ISO11784/85 tag from the GraphBuffer --------------------------------------------------------------------------------------- lf fdxb demod available offline: yes Try to find FDX-B preamble, if found decode / descramble data", "notes": [ "lf fdxb demod" ], @@ -8798,9 +8852,9 @@ ], "usage": "lf gallagher clone [-h] [-r ] [--q5] [--em] [--rc ] [--fc ] [--cn ] [--il ]" }, - "lf gallagher demod": { - "command": "lf gallagher demod", - "description": "Try to find GALLAGHER preamble, if found decode / descramble data", + "lf gallagher help": { + "command": "lf gallagher help", + "description": "help This help demod demodulate an GALLAGHER tag from the GraphBuffer --------------------------------------------------------------------------------------- lf gallagher demod available offline: yes Try to find GALLAGHER preamble, if found decode / descramble data", "notes": [ "lf gallagher demod" ], @@ -8861,9 +8915,9 @@ ], "usage": "lf gproxii clone [-h] --xor --fmt --fc --cn [--q5] [--em]" }, - "lf gproxii demod": { - "command": "lf gproxii demod", - "description": "Try to find Guardall Prox-II preamble, if found decode / descramble data", + "lf gproxii help": { + "command": "lf gproxii help", + "description": "help this help demod demodulate a G Prox II tag from the GraphBuffer --------------------------------------------------------------------------------------- lf gproxii demod available offline: yes Try to find Guardall Prox-II preamble, if found decode / descramble data", "notes": [ "lf gproxii demod -> use graphbuffer to decode", "lf gproxii demod --raw fb8ee718ee3b8cc785c11b92 ->" @@ -8904,6 +8958,32 @@ ], "usage": "lf gproxii sim [-h] --xor --fmt --fc --cn " }, + "lf help": { + "command": "lf help", + "description": "help This help ----------- -------------- Low Frequency -------------- awid { AWID RFIDs... } cotag { COTAG CHIPs... } destron { FDX-A Destron RFIDs... } em { EM CHIPs & RFIDs... } fdxb { FDX-B RFIDs... } gallagher { GALLAGHER RFIDs... } gproxii { Guardall Prox II RFIDs... } hid { HID Prox RFIDs... } hitag { Hitag CHIPs... } idteck { Idteck RFIDs... } indala { Indala RFIDs... } io { ioProx RFIDs... } jablotron { Jablotron RFIDs... } keri { KERI RFIDs... } motorola { Motorola Flexpass RFIDs... } nedap { Nedap RFIDs... } nexwatch { NexWatch RFIDs... } noralsy { Noralsy RFIDs... } pac { PAC/Stanley RFIDs... } paradox { Paradox RFIDs... } pcf7931 { PCF7931 CHIPs... } presco { Presco RFIDs... } pyramid { Farpointe/Pyramid RFIDs... } securakey { Securakey RFIDs... } ti { TI CHIPs... } t55xx { T55xx CHIPs... } viking { Viking RFIDs... } visa2000 { Visa2000 RFIDs... } ----------- --------------------- General --------------------- search Read and Search for valid known tag --------------------------------------------------------------------------------------- lf config available offline: no Get/Set config for LF sampling, bit/sample, decimation, frequency These changes are temporary, will be reset after a power cycle. - use `lf read` performs a read (active field) - use `lf sniff` performs a sniff (no active field)", + "notes": [ + "lf config -> shows current config", + "lf config -b 8 --125 -> samples at 125 kHz, 8 bps", + "lf config -b 4 --134 --dec 3 -> samples at 134 kHz, averages three samples into one, stored with a resolution of 4 bits per sample", + "lf config --trig 20 -s 10000 -> trigger sampling when above 20, skip 10 000 first samples after triggered", + "lf config --reset -> reset back to default values" + ], + "offline": true, + "options": [ + "-h, --help This help", + "--125 125 kHz frequency", + "--134 134 kHz frequency", + "-a, --avg <0|1> averaging - if set, will average the stored sample value when decimating (default 1)", + "-b, --bps <1-8> sets resolution of bits per sample (default 8)", + "--dec <1-8> sets decimation. A value of N saves only 1 in N samples (default 1)", + "--divisor <19-255> Manually set freq divisor. 88 -> 134 kHz, 95 -> 125 kHz", + "-f, --freq <47-600> manually set frequency in kHz", + "-r, --reset reset values to defaults", + "-s, --skip sets a number of samples to skip before capture (default 0)", + "-t, --trig <0-128> sets trigger threshold. 0 means no threshold" + ], + "usage": "lf config [-hr] [--125] [--134] [-a <0|1>] [-b <1-8>] [--dec <1-8>] [--divisor <19-255>] [-f <47-600>] [-s ] [-t <0-128>]" + }, "lf hid brute": { "command": "lf hid brute", "description": "Enables bruteforce of HID readers with specified facility code or card number. This is an attack against the reader. If the field being bruteforced is provided, it starts with it and goes up / down one step while maintaining other supplied values. If the field being bruteforced is not provided, it will iterate through the full range while maintaining other supplied values.", @@ -8956,9 +9036,9 @@ ], "usage": "lf hid clone [-h] [-w ] [--fc ] [--cn ] [-i ] [-o ] [-r ] [--q5] [--em] [--bin ]" }, - "lf hid demod": { - "command": "lf hid demod", - "description": "Try to find HID Prox preamble, if found decode / descramble data", + "lf hid help": { + "command": "lf hid help", + "description": "help this help demod demodulate HID Prox tag from the GraphBuffer --------------------------------------------------------------------------------------- lf hid demod available offline: yes Try to find HID Prox preamble, if found decode / descramble data", "notes": [ "lf hid demod" ], @@ -9071,21 +9151,9 @@ ], "usage": "lf hitag eload [-h12sm] -f " }, - "lf hitag info": { - "command": "lf hitag info", - "description": "Hitag2 tag information", - "notes": [ - "lf hitag info" - ], - "offline": false, - "options": [ - "-h, --help This help" - ], - "usage": "lf hitag info [-h]" - }, - "lf hitag list": { - "command": "lf hitag list", - "description": "Alias of `trace list -t hitag2` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "lf hitag help": { + "command": "lf hitag help", + "description": "help This help list List Hitag trace history --------------------------------------------------------------------------------------- lf hitag list available offline: yes Alias of `trace list -t hitag2` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "lf hitag list --frame -> show frame delay times", "lf hitag list -1 -> use trace buffer" @@ -9104,6 +9172,18 @@ ], "usage": "lf hitag list [-h1crux] [--frame] [-f ]" }, + "lf hitag info": { + "command": "lf hitag info", + "description": "Hitag2 tag information", + "notes": [ + "lf hitag info" + ], + "offline": false, + "options": [ + "-h, --help This help" + ], + "usage": "lf hitag info [-h]" + }, "lf hitag read": { "command": "lf hitag read", "description": "Read Hitag memory Crypto mode key format: ISK high + ISK low", @@ -9220,9 +9300,9 @@ ], "usage": "lf idteck clone [-h] -r [--q5] [--em]" }, - "lf idteck demod": { - "command": "lf idteck demod", - "description": "Try to find Idteck preamble, if found decode / descramble data", + "lf idteck help": { + "command": "lf idteck help", + "description": "help This help demod demodulate an Idteck tag from the GraphBuffer --------------------------------------------------------------------------------------- lf idteck demod available offline: yes Try to find Idteck preamble, if found decode / descramble data", "notes": [ "lf idteck demod" ], @@ -9272,28 +9352,6 @@ ], "usage": "lf indala altdemod [-hl]" }, - "lf indala brute": { - "command": "lf indala brute", - "description": "Enables bruteforce of INDALA readers with specified facility code. This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step if cardnumber is not given, it starts with 1 and goes up to 65535", - "notes": [ - "lf indala brute --fc 224", - "lf indala brute --fc 21 -d 2000", - "lf indala brute -v --fc 21 --cn 200 -d 2000", - "lf indala brute -v --fc 21 --cn 200 -d 2000 --up" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-v, --verbose verbose output", - "--fc facility code", - "--cn card number to start with", - "-d, --delay delay betweens attempts in ms. Default 1000ms", - "--up direction to increment card number. (default is both directions)", - "--down direction to decrement card number. (default is both directions)", - "--4041x specify Indala 4041X format" - ], - "usage": "lf indala brute [-hv] [--fc ] [--cn ] [-d ] [--up] [--down] [--4041x]" - }, "lf indala clone": { "command": "lf indala clone", "description": "clone Indala UID to T55x7 or Q5/T5555 tag using different known formats Warning, encoding with FC/CN doesn't always work", @@ -9335,6 +9393,28 @@ ], "usage": "lf indala demod [-hi] [--clock ] [--maxerr ]" }, + "lf indala help": { + "command": "lf indala help", + "description": "help This help demod Demodulate an Indala tag (PSK1) from the GraphBuffer altdemod Alternative method to demodulate samples for Indala 64 bit UID (option '224' for 224 bit) --------------------------------------------------------------------------------------- lf indala brute available offline: no Enables bruteforce of INDALA readers with specified facility code. This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step if cardnumber is not given, it starts with 1 and goes up to 65535", + "notes": [ + "lf indala brute --fc 224", + "lf indala brute --fc 21 -d 2000", + "lf indala brute -v --fc 21 --cn 200 -d 2000", + "lf indala brute -v --fc 21 --cn 200 -d 2000 --up" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-v, --verbose verbose output", + "--fc facility code", + "--cn card number to start with", + "-d, --delay delay betweens attempts in ms. Default 1000ms", + "--up direction to increment card number. (default is both directions)", + "--down direction to decrement card number. (default is both directions)", + "--4041x specify Indala 4041X format" + ], + "usage": "lf indala brute [-hv] [--fc ] [--cn ] [-d ] [--up] [--down] [--4041x]" + }, "lf indala reader": { "command": "lf indala reader", "description": "read a Indala tag", @@ -9389,9 +9469,9 @@ ], "usage": "lf io clone [-h] --vn --fc --cn [--q5] [--em]" }, - "lf io demod": { - "command": "lf io demod", - "description": "Try to find ioProx preamble, if found decode / descramble data", + "lf io help": { + "command": "lf io help", + "description": "help this help demod demodulate an ioProx tag from the GraphBuffer --------------------------------------------------------------------------------------- lf io demod available offline: yes Try to find ioProx preamble, if found decode / descramble data", "notes": [ "lf io demod" ], @@ -9458,9 +9538,9 @@ ], "usage": "lf jablotron clone [-h] --cn [--q5] [--em]" }, - "lf jablotron demod": { - "command": "lf jablotron demod", - "description": "Try to find Jablotron preamble, if found decode / descramble data", + "lf jablotron help": { + "command": "lf jablotron help", + "description": "help This help demod demodulate an Jablotron tag from the GraphBuffer --------------------------------------------------------------------------------------- lf jablotron demod available offline: yes Try to find Jablotron preamble, if found decode / descramble data", "notes": [ "lf jablotron demod" ], @@ -9514,9 +9594,9 @@ ], "usage": "lf keri clone [-h] [-t ] [--fc ] --cn [--q5] [--em]" }, - "lf keri demod": { - "command": "lf keri demod", - "description": "Try to find KERI preamble, if found decode / descramble data", + "lf keri help": { + "command": "lf keri help", + "description": "help This help demod demodulate an KERI tag from the GraphBuffer --------------------------------------------------------------------------------------- lf keri demod available offline: yes Try to find KERI preamble, if found decode / descramble data", "notes": [ "lf keri demod" ], @@ -9569,9 +9649,9 @@ ], "usage": "lf motorola clone [-h] -r [--q5] [--em]" }, - "lf motorola demod": { - "command": "lf motorola demod", - "description": "Try to find Motorola Flexpass preamble, if found decode / descramble data", + "lf motorola help": { + "command": "lf motorola help", + "description": "help This help demod demodulate an MOTOROLA tag from the GraphBuffer --------------------------------------------------------------------------------------- lf motorola demod available offline: yes Try to find Motorola Flexpass preamble, if found decode / descramble data", "notes": [ "lf motorola demod" ], @@ -9624,9 +9704,9 @@ ], "usage": "lf nedap clone [-hl] [--st ] --cc --id [--q5] [--em]" }, - "lf nedap demod": { - "command": "lf nedap demod", - "description": "Try to find Nedap preamble, if found decode / descramble data", + "lf nedap help": { + "command": "lf nedap help", + "description": "help This help demod demodulate Nedap tag from the GraphBuffer --------------------------------------------------------------------------------------- lf nedap demod available offline: yes Try to find Nedap preamble, if found decode / descramble data", "notes": [ "lf nedap demod" ], @@ -9690,9 +9770,9 @@ ], "usage": "lf nexwatch clone [-h] [-r ] [--cn ] [-m ] [--nc] [--qc] [--hc] [--q5] [--em] [--magic ] [--psk2]" }, - "lf nexwatch demod": { - "command": "lf nexwatch demod", - "description": "Try to find Nexwatch preamble, if found decode / descramble data", + "lf nexwatch help": { + "command": "lf nexwatch help", + "description": "help This help demod demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer --------------------------------------------------------------------------------------- lf nexwatch demod available offline: yes Try to find Nexwatch preamble, if found decode / descramble data", "notes": [ "lf nexwatch demod" ], @@ -9756,9 +9836,9 @@ ], "usage": "lf noralsy clone [-h] --cn [-y ] [--q5] [--em]" }, - "lf noralsy demod": { - "command": "lf noralsy demod", - "description": "Try to find Noralsy preamble, if found decode / descramble data", + "lf noralsy help": { + "command": "lf noralsy help", + "description": "help This help demod demodulate an Noralsy tag from the GraphBuffer --------------------------------------------------------------------------------------- lf noralsy demod available offline: yes Try to find Noralsy preamble, if found decode / descramble data", "notes": [ "lf noralsy demod" ], @@ -9815,9 +9895,9 @@ ], "usage": "lf pac clone [-h] [--cn ] [-r ] [--q5] [--em]" }, - "lf pac demod": { - "command": "lf pac demod", - "description": "Try to find PAC/Stanley preamble, if found decode / descramble data", + "lf pac help": { + "command": "lf pac help", + "description": "help This help demod demodulate a PAC tag from the GraphBuffer --------------------------------------------------------------------------------------- lf pac demod available offline: yes Try to find PAC/Stanley preamble, if found decode / descramble data", "notes": [ "lf pac demod" ], @@ -9875,9 +9955,9 @@ ], "usage": "lf paradox clone [-h] [-r ] [--fc ] [--cn ] [--q5] [--em]" }, - "lf paradox demod": { - "command": "lf paradox demod", - "description": "Try to find Paradox preamble, if found decode / descramble data", + "lf paradox help": { + "command": "lf paradox help", + "description": "help This help demod demodulate a Paradox FSK tag from the GraphBuffer --------------------------------------------------------------------------------------- lf paradox demod available offline: yes Try to find Paradox preamble, if found decode / descramble data", "notes": [ "lf paradox demod --old -> Display previous checksum version" ], @@ -9938,13 +10018,13 @@ ], "usage": "lf pcf7931 config [-hr] [-p ] [-d ] [--lw ] [--lp ]" }, - "lf pcf7931 reader": { - "command": "lf pcf7931 reader", - "description": "read a PCF7931 tag", + "lf pcf7931 help": { + "command": "lf pcf7931 help", + "description": "help This help config Configure the password, the tags initialization delay and time offsets (optional) --------------------------------------------------------------------------------------- lf pcf7931 reader available offline: no read a PCF7931 tag", "notes": [ "lf pcf7931 reader -@ -> continuous reader mode" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "-@ optional - continuous reader mode" @@ -9984,9 +10064,9 @@ ], "usage": "lf presco clone [-h] [-c ] [-d ] [--q5] [--em]" }, - "lf presco demod": { - "command": "lf presco demod", - "description": "Try to find presco preamble, if found decode / descramble data", + "lf presco help": { + "command": "lf presco help", + "description": "help This help demod demodulate Presco tag from the GraphBuffer --------------------------------------------------------------------------------------- lf presco demod available offline: yes Try to find presco preamble, if found decode / descramble data", "notes": [ "lf presco demod" ], @@ -10043,9 +10123,9 @@ ], "usage": "lf pyramid clone [-h] [--fc ] [--cn ] [--q5] [--em] [-r ]" }, - "lf pyramid demod": { - "command": "lf pyramid demod", - "description": "Try to find Farpoint/Pyramid preamble, if found decode / descramble data", + "lf pyramid help": { + "command": "lf pyramid help", + "description": "help this help demod demodulate a Pyramid FSK tag from the GraphBuffer --------------------------------------------------------------------------------------- lf pyramid demod available offline: yes Try to find Farpoint/Pyramid preamble, if found decode / descramble data", "notes": [ "lf pyramid demod" ], @@ -10135,9 +10215,9 @@ ], "usage": "lf securakey clone [-h] -r [--q5] [--em]" }, - "lf securakey demod": { - "command": "lf securakey demod", - "description": "Try to find Securakey preamble, if found decode / descramble data", + "lf securakey help": { + "command": "lf securakey help", + "description": "help This help demod demodulate an Securakey tag from the GraphBuffer --------------------------------------------------------------------------------------- lf securakey demod available offline: yes Try to find Securakey preamble, if found decode / descramble data", "notes": [ "lf securakey demod" ], @@ -10326,18 +10406,6 @@ ], "usage": "lf t55xx chk [-hm] [-f ] [--em ] [--r0] [--r1] [--r2] [--r3] [--all]" }, - "lf t55xx clonehelp": { - "command": "lf t55xx clonehelp", - "description": "Display a list of available commands for cloning specific techs on T5xx tags", - "notes": [ - "lf t55xx clonehelp" - ], - "offline": false, - "options": [ - "-h, --help This help" - ], - "usage": "lf t55xx clonehelp [-h]" - }, "lf t55xx config": { "command": "lf t55xx config", "description": "Set/Get T55XX configuration of the pm3 client. Like modulation, inverted, offset, rate etc. Offset is start position to decode data.", @@ -10457,6 +10525,18 @@ ], "usage": "lf t55xx dump [-ho] [-f ] [-p ] [--ns] [--r0] [--r1] [--r2] [--r3]" }, + "lf t55xx help": { + "command": "lf t55xx help", + "description": "----------- ---------------------------- notice ----------------------------- Remember to run `lf t55xx detect` first whenever a new card is placed on the Proxmark3 or the config block changed. help This help ----------- --------------------- operations --------------------- config Set/Get T55XX configuration (modulation, inverted, offset, rate) detect Try detecting the tag modulation from reading the configuration block info Show T55x7 configuration data (page 0/ blk 0) trace Show T55x7 traceability data (page 1/ blk 0-1) ----------- --------------------- recovery --------------------- sniff Attempt to recover T55xx commands from sample buffer --------------------------------------------------------------------------------------- lf t55xx clonehelp available offline: no Display a list of available commands for cloning specific techs on T5xx tags", + "notes": [ + "lf t55xx clonehelp" + ], + "offline": true, + "options": [ + "-h, --help This help" + ], + "usage": "lf t55xx clonehelp [-h]" + }, "lf t55xx info": { "command": "lf t55xx info", "description": "Show T55x7 configuration data (page 0/ blk 0) from reading the configuration block from tag. Use `-c` to specify a config block data to be used instead of reading tag.", @@ -10705,9 +10785,9 @@ ], "usage": "lf t55xx write [-ht] -b <0-7> [-d ] [-p ] [--pg1] [--verify] [--r0] [--r1] [--r2] [--r3]" }, - "lf ti demod": { - "command": "lf ti demod", - "description": "Try to find TI preamble, if found decode / descramble data", + "lf ti help": { + "command": "lf ti help", + "description": "help This help demod Demodulate raw bits for TI LF tag from the GraphBuffer --------------------------------------------------------------------------------------- lf ti demod available offline: yes Try to find TI preamble, if found decode / descramble data", "notes": [ "lf ti demod" ], @@ -10781,9 +10861,9 @@ ], "usage": "lf viking clone [-h] --cn [--q5] [--em]" }, - "lf viking demod": { - "command": "lf viking demod", - "description": "Try to find Viking AM preamble, if found decode / descramble data", + "lf viking help": { + "command": "lf viking help", + "description": "help This help demod demodulate a Viking tag from the GraphBuffer --------------------------------------------------------------------------------------- lf viking demod available offline: yes Try to find Viking AM preamble, if found decode / descramble data", "notes": [ "lf viking demod" ], @@ -10836,9 +10916,9 @@ ], "usage": "lf visa2000 clone [-h] --cn [--q5] [--em]" }, - "lf visa2000 demod": { - "command": "lf visa2000 demod", - "description": "Try to find visa2000 preamble, if found decode / descramble data", + "lf visa2000 help": { + "command": "lf visa2000 help", + "description": "help This help demod demodulate an VISA2000 tag from the GraphBuffer --------------------------------------------------------------------------------------- lf visa2000 demod available offline: yes Try to find visa2000 preamble, if found decode / descramble data", "notes": [ "lf visa2000 demod" ], @@ -10874,19 +10954,6 @@ ], "usage": "lf visa2000 sim [-h] --cn " }, - "mem baudrate": { - "command": "mem baudrate", - "description": "Set the baudrate for the SPI flash memory communications. Reading Flash ID will virtually always fail under 48MHz setting. Unless you know what you are doing, please stay at 24MHz. If >= 24MHz, FASTREADS instead of READS instruction will be used.", - "notes": [ - "mem baudrate --mhz 48" - ], - "offline": false, - "options": [ - "-h, --help This help", - "--mhz <24|48> SPI baudrate in MHz" - ], - "usage": "mem baudrate [-h] --mhz <24|48>" - }, "mem dump": { "command": "mem dump", "description": "Dumps flash memory on device into a file or view in console", @@ -10906,6 +10973,19 @@ ], "usage": "mem dump [-hv] [-o ] [-l ] [-f ] [-c ]" }, + "mem help": { + "command": "mem help", + "description": "help This help --------------------------------------------------------------------------------------- mem baudrate available offline: no Set the baudrate for the SPI flash memory communications. Reading Flash ID will virtually always fail under 48MHz setting. Unless you know what you are doing, please stay at 24MHz. If >= 24MHz, FASTREADS instead of READS instruction will be used.", + "notes": [ + "mem baudrate --mhz 48" + ], + "offline": true, + "options": [ + "-h, --help This help", + "--mhz <24|48> SPI baudrate in MHz" + ], + "usage": "mem baudrate [-h] --mhz <24|48>" + }, "mem info": { "command": "mem info", "description": "Collect signature and verify it from flash memory", @@ -10955,20 +11035,6 @@ ], "usage": "mem spiffs check [-h]" }, - "mem spiffs copy": { - "command": "mem spiffs copy", - "description": "Copy a file to another (destructively) in SPIFFS file system", - "notes": [ - "mem spiffs copy -s aaa.bin -d aaa_cpy.bin" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-s, --src source file name", - "-d, --dest destination file name" - ], - "usage": "mem spiffs copy [-h] -s -d " - }, "mem spiffs dump": { "command": "mem spiffs dump", "description": "Dumps device SPIFFS file to a local file Size is handled by first sending a STAT command against file to verify existence", @@ -10986,6 +11052,20 @@ ], "usage": "mem spiffs dump [-ht] -s [-d ]" }, + "mem spiffs help": { + "command": "mem spiffs help", + "description": "help This help --------------------------------------------------------------------------------------- mem spiffs copy available offline: no Copy a file to another (destructively) in SPIFFS file system", + "notes": [ + "mem spiffs copy -s aaa.bin -d aaa_cpy.bin" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-s, --src source file name", + "-d, --dest destination file name" + ], + "usage": "mem spiffs copy [-h] -s -d " + }, "mem spiffs info": { "command": "mem spiffs info", "description": "Print file system info and usage statistics", @@ -11139,17 +11219,24 @@ ], "usage": "msleep [-h] [-t ]" }, - "nfc barcode read": { - "command": "nfc barcode read", - "description": "Get info from Thinfilm tags", + "nfc barcode help": { + "command": "nfc barcode help", + "description": "-------- ------------------ NFC Barcode -------------------- -------- --------------------- General --------------------- help This help ======================================================================================= piv { PIV commands... } --------------------------------------------------------------------------------------- piv help available offline: yes help This help list List ISO7816 history --------------------------------------------------------------------------------------- piv select available offline: no Executes select applet command", "notes": [ - "hf thinfilm info" + "piv select -s -> select card, select applet", + "piv select -st --aid a00000030800001000 -> select card, select applet a00000030800001000, show result in TLV" ], - "offline": false, + "offline": true, "options": [ - "-h, --help This help" + "-h, --help This help", + "-s, -S, --select Activate field and select applet", + "-k, -K, --keep Keep field for next command", + "-a, -A, --apdu Show APDU requests and responses", + "-t, -T, --tlv TLV decode results", + "-w, -W, --wired Send data via contact (iso7816) interface. (def: Contactless interface)", + "--aid Applet ID to select. By default A0000003080000100 will be used" ], - "usage": "hf thinfilm info [-h]" + "usage": "piv select [-hskatw] [--aid ]" }, "nfc barcode sim": { "command": "nfc barcode sim", @@ -11165,9 +11252,9 @@ ], "usage": "hf thinfilm sim [-h] -d [--raw]" }, - "nfc decode": { - "command": "nfc decode", - "description": "Decode and print NFC Data Exchange Format (NDEF) You must provide either data in hex or a filename, but not both", + "nfc help": { + "command": "nfc help", + "description": "-------- --------------------- NFC Tags -------------------- type1 { NFC Forum Tag Type 1... } type2 { NFC Forum Tag Type 2... } type4a { NFC Forum Tag Type 4 ISO14443A... } type4b { NFC Forum Tag Type 4 ISO14443B... } mf { NFC Type MIFARE Classic/Plus Tag... } barcode { NFC Barcode Tag... } -------- --------------------- General --------------------- help This help decode Decode NDEF records --------------------------------------------------------------------------------------- nfc decode available offline: yes Decode and print NFC Data Exchange Format (NDEF) You must provide either data in hex or a filename, but not both", "notes": [ "nfc decode -d 9101085402656e48656c6c6f5101085402656e576f726c64", "nfc decode -d 0103d020240203e02c040300fe", @@ -11182,25 +11269,6 @@ ], "usage": "nfc decode [-hv] [-d ] [-f ]" }, - "nfc mf cformat": { - "command": "nfc mf cformat", - "description": "format MIFARE Classic Tag as a NFC tag with Data Exchange Format (NDEF) If no given, UID will be used as filename. It will try default keys and MAD keys to detect if tag is already formatted in order to write. If not, it will try finding a key file based on your UID. ie, if you ran autopwn before", - "notes": [ - "hf mf ndefformat", - "hf mf ndefformat --1k -> MIFARE Classic 1k", - "hf mf ndefformat --keys hf-mf-01020304-key.bin -> MIFARE 1k with keys from specified file" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-k, --keys filename of keys", - "--mini MIFARE Classic Mini / S20", - "--1k MIFARE Classic 1k / S50 (def)", - "--2k MIFARE Classic/Plus 2k", - "--4k MIFARE Classic 4k / S70" - ], - "usage": "hf mf ndefformat [-h] [-k ] [--mini] [--1k] [--2k] [--4k]" - }, "nfc mf cread": { "command": "nfc mf cread", "description": "Prints NFC Data Exchange Format (NDEF)", @@ -11243,6 +11311,18 @@ ], "usage": "hf mf ndefwrite [-hpv] [-d ] [-f ] [--mini] [--1k] [--2k] [--4k]" }, + "nfc mf help": { + "command": "nfc mf help", + "description": "-------- --------- NFC Type MIFARE Classic/Plus Tag -------- -------- --------------------- General --------------------- help This help ======================================================================================= nfc barcode { NFC Barcode Tag... } --------------------------------------------------------------------------------------- nfc barcode read available offline: no Get info from Thinfilm tags", + "notes": [ + "hf thinfilm info" + ], + "offline": true, + "options": [ + "-h, --help This help" + ], + "usage": "hf thinfilm info [-h]" + }, "nfc mf pread": { "command": "nfc mf pread", "description": "Prints NFC Data Exchange Format (NDEF)", @@ -11263,6 +11343,23 @@ ], "usage": "hf mfp ndefread [-hvb] [--aid ] [-k ] [-f ]" }, + "nfc type1 help": { + "command": "nfc type1 help", + "description": "-------- -------------- NFC Forum Tag Type 1 --------------- -------- --------------------- General --------------------- help This help ======================================================================================= nfc type2 { NFC Forum Tag Type 2... } --------------------------------------------------------------------------------------- nfc type2 read available offline: no Prints NFC Data Exchange Format (NDEF)", + "notes": [ + "hf mfu ndefread -> shows NDEF data", + "hf mfu ndefread -k ffffffff -> shows NDEF data with key", + "hf mfu ndefread -f myfilename -> save raw NDEF to file" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-l Swap entered key's endianness", + "-f, --file Save raw NDEF to file", + "-v, --verbose show technical data" + ], + "usage": "hf mfu ndefread [-hlv] [-k Replace default key for NDEF] [-f ]" + }, "nfc type1 read": { "command": "nfc type1 read", "description": "Get info from Topaz tags", @@ -11278,36 +11375,34 @@ ], "usage": "hf topaz info [-hv] [-f ]" }, - "nfc type2 read": { - "command": "nfc type2 read", - "description": "Prints NFC Data Exchange Format (NDEF)", - "notes": [ - "hf mfu ndefread -> shows NDEF data", - "hf mfu ndefread -k ffffffff -> shows NDEF data with key", - "hf mfu ndefread -f myfilename -> save raw NDEF to file" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-l Swap entered key's endianness", - "-f, --file Save raw NDEF to file", - "-v, --verbose show technical data" - ], - "usage": "hf mfu ndefread [-hlv] [-k Replace default key for NDEF] [-f ]" - }, - "nfc type4a format": { - "command": "nfc type4a format", - "description": "Format ISO14443-a Tag as a NFC tag with Data Exchange Format (NDEF)", + "nfc type2 help": { + "command": "nfc type2 help", + "description": "-------- -------------- NFC Forum Tag Type 2 --------------- -------- --------------------- General --------------------- help This help ======================================================================================= nfc type4a { NFC Forum Tag Type 4 ISO14443A... } --------------------------------------------------------------------------------------- nfc type4a format available offline: no Format ISO14443-a Tag as a NFC tag with Data Exchange Format (NDEF)", "notes": [ "hf 14a ndefformat" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", "-v, --verbose show technical data" ], "usage": "hf 14a ndefformat [-hv]" }, + "nfc type4a help": { + "command": "nfc type4a help", + "description": "-------- --------- NFC Forum Tag Type 4 ISO14443A ---------- -------- --------------------- General --------------------- help This help ======================================================================================= nfc type4b { NFC Forum Tag Type 4 ISO14443B... } --------------------------------------------------------------------------------------- nfc type4b read available offline: no Print NFC Data Exchange Format (NDEF)", + "notes": [ + "hf 14b ndefread", + "hf 14b ndefread -f myfilename -> save raw NDEF to file" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-f, --file save raw NDEF to file", + "-v, --verbose show technical data" + ], + "usage": "hf 14b ndefread [-hv] [-f ]" + }, "nfc type4a read": { "command": "nfc type4a read", "description": "Read NFC Data Exchange Format (NDEF) file on Type 4 NDEF tag", @@ -11357,20 +11452,24 @@ ], "usage": "hf 14a ndefwrite [-hpv] [-d ] [-f ]" }, - "nfc type4b read": { - "command": "nfc type4b read", - "description": "Print NFC Data Exchange Format (NDEF)", + "nfc type4b help": { + "command": "nfc type4b help", + "description": "-------- --------- NFC Forum Tag Type 4 ISO14443B ------------- -------- --------------------- General --------------------- help This help ======================================================================================= nfc mf { NFC Type MIFARE Classic/Plus Tag... } --------------------------------------------------------------------------------------- nfc mf cformat available offline: no format MIFARE Classic Tag as a NFC tag with Data Exchange Format (NDEF) If no given, UID will be used as filename. It will try default keys and MAD keys to detect if tag is already formatted in order to write. If not, it will try finding a key file based on your UID. ie, if you ran autopwn before", "notes": [ - "hf 14b ndefread", - "hf 14b ndefread -f myfilename -> save raw NDEF to file" + "hf mf ndefformat", + "hf mf ndefformat --1k -> MIFARE Classic 1k", + "hf mf ndefformat --keys hf-mf-01020304-key.bin -> MIFARE 1k with keys from specified file" ], - "offline": false, + "offline": true, "options": [ "-h, --help This help", - "-f, --file save raw NDEF to file", - "-v, --verbose show technical data" + "-k, --keys filename of keys", + "--mini MIFARE Classic Mini / S20", + "--1k MIFARE Classic 1k / S50 (def)", + "--2k MIFARE Classic/Plus 2k", + "--4k MIFARE Classic 4k / S70" ], - "usage": "hf 14b ndefread [-hv] [-f ]" + "usage": "hf mf ndefformat [-h] [-k ] [--mini] [--1k] [--2k] [--4k]" }, "piv authsign": { "command": "piv authsign", @@ -11453,25 +11552,6 @@ ], "usage": "piv scan [-hskatw] [--aid ]" }, - "piv select": { - "command": "piv select", - "description": "Executes select applet command", - "notes": [ - "piv select -s -> select card, select applet", - "piv select -st --aid a00000030800001000 -> select card, select applet a00000030800001000, show result in TLV" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-s, -S, --select Activate field and select applet", - "-k, -K, --keep Keep field for next command", - "-a, -A, --apdu Show APDU requests and responses", - "-t, -T, --tlv TLV decode results", - "-w, -W, --wired Send data via contact (iso7816) interface. (def: Contactless interface)", - "--aid Applet ID to select. By default A0000003080000100 will be used" - ], - "usage": "piv select [-hskatw] [--aid ]" - }, "prefs get barmode": { "command": "prefs get barmode", "description": "Get preference of HF/LF tune command styled output in the client", @@ -11592,20 +11672,17 @@ ], "usage": "prefs get savepaths [-h]" }, - "prefs set barmode": { - "command": "prefs set barmode", - "description": "Set persistent preference of HF/LF tune command styled output in the client", + "prefs help": { + "command": "prefs help", + "description": "help This help get { Get a preference } set { Set a preference } show Show all preferences --------------------------------------------------------------------------------------- prefs show available offline: yes Show all persistent preferences", "notes": [ - "prefs set barmode --mix" + "prefs show" ], "offline": true, "options": [ - "-h, --help This help", - "--bar measured values as bar only", - "--mix measured values as numbers and bar", - "--val measured values only" + "-h, --help This help" ], - "usage": "prefs set barmode [-h] [--bar] [--mix] [--val]" + "usage": "prefs show [-h]" }, "prefs set client.debug": { "command": "prefs set client.debug", @@ -11681,6 +11758,21 @@ ], "usage": "prefs set emoji [-h] [--alias] [--emoji] [--alttext] [--none]" }, + "prefs set help": { + "command": "prefs set help", + "description": "help This help barmode Set bar mode client.debug Set client debug level client.delay Set client execution delay client.timeout Set client communication timeout color Set color support emoji Set emoji display hints Set hint display savepaths ... to be adjusted next ... output Set dump output style plotsliders Set plot slider display --------------------------------------------------------------------------------------- prefs set barmode available offline: yes Set persistent preference of HF/LF tune command styled output in the client", + "notes": [ + "prefs set barmode --mix" + ], + "offline": true, + "options": [ + "-h, --help This help", + "--bar measured values as bar only", + "--mix measured values as numbers and bar", + "--val measured values only" + ], + "usage": "prefs set barmode [-h] [--bar] [--mix] [--val]" + }, "prefs set hints": { "command": "prefs set hints", "description": "Set persistent preference of showing hint messages in the client", @@ -11741,18 +11833,6 @@ ], "usage": "prefs set savepaths [-hc] [--def ] [--dump ] [--trace ]" }, - "prefs show": { - "command": "prefs show", - "description": "Show all persistent preferences", - "notes": [ - "prefs show" - ], - "offline": true, - "options": [ - "-h, --help This help" - ], - "usage": "prefs show [-h]" - }, "quit": { "command": "quit", "description": "Quit the Proxmark3 client terminal", @@ -11817,22 +11897,9 @@ ], "usage": "smart brute [-ht]" }, - "smart info": { - "command": "smart info", - "description": "Extract more detailed information from smart card.", - "notes": [ - "smart info -v" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-v, --verbose verbose output" - ], - "usage": "smart info [-hv]" - }, - "smart list": { - "command": "smart list", - "description": "Alias of `trace list -t 7816` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "smart help": { + "command": "smart help", + "description": "help This help list List ISO 7816 history upgrade Upgrade sim module firmware --------------------------------------------------------------------------------------- smart list available offline: yes Alias of `trace list -t 7816` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "smart list --frame -> show frame delay times", "smart list -1 -> use trace buffer" @@ -11851,6 +11918,19 @@ ], "usage": "smart list [-h1crux] [--frame] [-f ]" }, + "smart info": { + "command": "smart info", + "description": "Extract more detailed information from smart card.", + "notes": [ + "smart info -v" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-v, --verbose verbose output" + ], + "usage": "smart info [-hv]" + }, "smart raw": { "command": "smart raw", "description": "Sends raw bytes to card", @@ -11917,9 +11997,9 @@ ], "usage": "smart setclock [-h] [--16mhz] [--8mhz] [--4mhz]" }, - "trace extract": { - "command": "trace extract", - "description": "Extracts protocol authentication challenges from trace buffer", + "trace help": { + "command": "trace help", + "description": "help This help extract Extract authentication challenges found in trace list List protocol data in trace buffer load Load trace from file save Save trace buffer to file --------------------------------------------------------------------------------------- trace extract available offline: yes Extracts protocol authentication challenges from trace buffer", "notes": [ "trace extract", "trace extract -1" @@ -12014,19 +12094,6 @@ ], "usage": "usart btfactory [-h]" }, - "usart btpin": { - "command": "usart btpin", - "description": "Change BT add-on PIN. WARNING: this requires 1) BTpower to be turned ON 2) BT add-on to NOT be connected => the add-on blue LED must blink", - "notes": [ - "usart btpin -p 1234" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-p, --pin Desired PIN number (4 digits)" - ], - "usage": "usart btpin [-h] -p " - }, "usart config": { "command": "usart config", "description": "Configure USART. WARNING: it will have side-effects if used in USART HOST mode! The changes are not permanent, restart Proxmark3 to get default settings back.", @@ -12045,6 +12112,19 @@ ], "usage": "usart config [-hNEO] [-b ]" }, + "usart help": { + "command": "usart help", + "description": "help This help --------------------------------------------------------------------------------------- usart btpin available offline: no Change BT add-on PIN. WARNING: this requires 1) BTpower to be turned ON 2) BT add-on to NOT be connected => the add-on blue LED must blink", + "notes": [ + "usart btpin -p 1234" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-p, --pin Desired PIN number (4 digits)" + ], + "usage": "usart btpin [-h] -p " + }, "usart rx": { "command": "usart rx", "description": "Receive string over USART. WARNING: it will have side-effects if used in USART HOST mode!", @@ -12146,9 +12226,9 @@ ], "usage": "wiegand encode [-h] [--fc ] --cn [--issue ] [--oem ] [-w ] [--pre]" }, - "wiegand list": { - "command": "wiegand list", - "description": "List available wiegand formats", + "wiegand help": { + "command": "wiegand help", + "description": "help This help list List available wiegand formats encode Encode to wiegand raw hex (currently for HID Prox) decode Convert raw hex to decoded wiegand format (currently for HID Prox) --------------------------------------------------------------------------------------- wiegand list available offline: yes List available wiegand formats", "notes": [ "wiegand list" ], @@ -12160,8 +12240,8 @@ } }, "metadata": { - "commands_extracted": 703, + "commands_extracted": 707, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2024-01-04T12:13:24" + "extracted_on": "2024-01-16T12:52:56" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index 1820a55f1..a4fc98c18 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -208,18 +208,19 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf 14b help `|Y |`This help` +|`hf 14b list `|Y |`List ISO-14443-B history` |`hf 14b apdu `|N |`Send ISO 14443-4 APDU to tag` |`hf 14b dump `|N |`Read all memory pages of an ISO-14443-B tag, save to file` |`hf 14b info `|N |`Tag information` -|`hf 14b list `|Y |`List ISO-14443-B history` |`hf 14b ndefread `|N |`Read NDEF file on tag` |`hf 14b raw `|N |`Send raw hex data to tag` +|`hf 14b rdbl `|N |`Read SRI512/SRIX4 block` |`hf 14b reader `|N |`Act as a ISO-14443-B reader to identify a tag` |`hf 14b sim `|N |`Fake ISO ISO-14443-B tag` |`hf 14b sniff `|N |`Eavesdrop ISO-14443-B` -|`hf 14b rdbl `|N |`Read SRI512/SRIX4x block` -|`hf 14b sriwrite `|N |`Write data to a SRI512 or SRIX4K tag` +|`hf 14b wrbl `|N |`Write data to a SRI512/SRIX4 tag` |`hf 14b view `|Y |`Display content from tag dump file` +|`hf 14b valid `|Y |`SRIX4 checksum test` ### hf 15 @@ -241,6 +242,7 @@ Check column "offline" for their availability. |`hf 15 restore `|N |`Restore from file to all memory pages of an ISO-15693 tag` |`hf 15 samples `|N |`Acquire samples as reader (enables carrier, sends inquiry)` |`hf 15 view `|Y |`Display content from tag dump file` +|`hf 15 wipe `|N |`Wipe card to zeros` |`hf 15 wrbl `|N |`Write a block` |`hf 15 sim `|N |`Fake an ISO-15693 tag` |`hf 15 eload `|N |`Load image file into emulator to be used by 'sim' command` @@ -314,11 +316,11 @@ Check column "offline" for their availability. |------- |------- |----------- |`hf felica help `|Y |`This help` |`hf felica list `|Y |`List ISO 18092/FeliCa history` -|`hf felica reader `|N |`Act like an ISO18092/FeliCa reader` |`hf felica info `|N |`Tag information` -|`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic` |`hf felica raw `|N |`Send raw hex data to tag` |`hf felica rdbl `|N |`read block data from authentication-not-required Service.` +|`hf felica reader `|N |`Act like an ISO18092/FeliCa reader` +|`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic` |`hf felica wrbl `|N |`write block data to an authentication-not-required Service.` |`hf felica rqservice `|N |`verify the existence of Area and Service, and to acquire Key Version.` |`hf felica rqresponse `|N |`verify the existence of a card and its Mode.` @@ -755,6 +757,16 @@ Check column "offline" for their availability. |`hf vas decrypt `|Y |`Decrypt a previously captured VAS cryptogram` +### hf waveshare + + { Waveshare NFC ePaper... } + +|command |offline |description +|------- |------- |----------- +|`hf waveshare help `|Y |`This help` +|`hf waveshare load `|Y |`Load image file to Waveshare NFC ePaper` + + ### hf xerox { Fuji/Xerox cartridge RFIDs... } @@ -762,9 +774,11 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf xerox help `|Y |`This help` +|`hf xerox list `|Y |`List ISO-14443B history` |`hf xerox info `|N |`Short info on Fuji/Xerox tag` -|`hf xerox reader `|N |`Act like a Fuji/Xerox reader` |`hf xerox dump `|N |`Read all memory pages of an Fuji/Xerox tag, save to file` +|`hf xerox reader `|N |`Act like a Fuji/Xerox reader` +|`hf xerox view `|Y |`Display content from tag dump file` ### hw diff --git a/include/iso14b.h b/include/iso14b.h index 9089cd3d3..de2692e58 100644 --- a/include/iso14b.h +++ b/include/iso14b.h @@ -48,6 +48,7 @@ typedef enum ISO14B_COMMAND { ISO14B_SELECT_CTS = (1 << 10), ISO14B_CLEARTRACE = (1 << 11), ISO14B_SELECT_XRX = (1 << 12), + ISO14B_SELECT_PICOPASS = (1 << 13), } iso14b_command_t; typedef enum ISO14B_TYPE { diff --git a/include/iso15.h b/include/iso15.h index d66a93d2b..7d2b0e12f 100644 --- a/include/iso15.h +++ b/include/iso15.h @@ -34,8 +34,14 @@ typedef enum ISO15_COMMAND { ISO15_RAW = (1 << 2), ISO15_APPEND_CRC = (1 << 3), ISO15_HIGH_SPEED = (1 << 4), - ISO15_READ_RESPONSE = (1 << 5) + ISO15_READ_RESPONSE = (1 << 5), + ISO15_LONG_WAIT = (1 << 6), } iso15_command_t; +typedef struct { + uint8_t flags; // PM3 Flags - see iso15_command_t + uint16_t rawlen; + uint8_t raw[]; // First byte in raw, raw[0] is ISO15693 protocol flag byte +} PACKED iso15_raw_cmd_t; #endif // _ISO15_H_ diff --git a/include/protocols.h b/include/protocols.h index 091c86374..61bc3850f 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -926,5 +926,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. // 0x0A = ACK // 0x05 = NACK +// XEROX Commands +#define XEROX_READ_MEM 0x20 + #endif // PROTOCOLS_H