diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e846aa05..2023e24bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ 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 15 eview` and `hf 15 esave` - Retrieve emulator image for ISO15693 simulation (@markus-oehme-pg40) + - Changed `hf 15 sim` - now supports reader writes (@markus-oehme-pg40) + - Added `hf 15 eload` - specify memory image for ISO15693 simulation (@markus-oehme-pg40) + - Added `hf 15 sim --blocksize` - configure block size for simulation (@markus-oehme-pg40) - Fixed buffer overflow in mfu ndef decode (@mwalker) - Changed spiffs write/append to send in 8192 chunks to ensure its eraised (@mwalker) - Fixed spiffs dump to ensure to fails correctly if no big_buff was allocated (@mwalker) @@ -90,8 +94,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added new standalone mode `lf_em4100rsww` (@zabszk) - Fixed `hf 15 slixdisable` wrong pass id (@r1ddl3rz) - Added `script run hf_mf_hid_sim.lua` (@micsen) - - Added `hf 15 sim --blocksize` - configure block size for simulation (@markus-oehme-pg40) - - Added `hf 15 eload` - specify memory image for ISO15693 simulation (@markus-oehme-pg40) ## [Frostbit.4.14831][2022-01-11] diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 7e4c5c4f3..388aaddce 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -2111,6 +2111,11 @@ void EmlSetMemIso15693(uint8_t count, uint8_t *data, uint32_t offset) { memcpy(emCARD + offset, data, count); } +void EmlGetMemIso15693(uint8_t count, uint8_t *output, uint32_t offset) { + uint8_t *emCARD = BigBuf_get_EM_addr(); + memcpy(output, emCARD + offset, count); +} + // Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands // all demodulation performed in arm rather than host. - greg void SimTagIso15693(uint8_t *uid, uint8_t block_size) { @@ -2235,29 +2240,19 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { // READ_BLOCK and READ_MULTI_BLOCK if ((cmd[1] == ISO15693_READBLOCK) || (cmd[1] == ISO15693_READ_MULTI_BLOCK)) { bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); + bool addressed = cmd[0] & ISO15_REQ_ADDRESS; bool option = cmd[0] & ISO15_REQ_OPTION; uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - uint8_t block_idx = 0; + uint8_t address_offset = 0; + if (addressed) { + address_offset = 8; + } + + uint8_t block_idx = cmd[2 + address_offset]; uint8_t block_count = 1; - if (cmd[1] == ISO15693_READBLOCK) { - if (cmd_len == 13) { - // addressed mode - block_idx= cmd[10]; - } else if (cmd_len == 5) { - // non-addressed mode - block_idx = cmd[2]; - } - } else if (cmd[1] == ISO15693_READ_MULTI_BLOCK) { - if (cmd_len == 14) { - // addressed mode - block_idx= cmd[10]; - block_count= cmd[11] + 1; - } else if (cmd_len == 6) { - // non-addressed mode - block_idx = cmd[2]; - block_count = cmd[3] + 1; - } + if (cmd[1] == ISO15693_READ_MULTI_BLOCK) { + block_count = cmd[3 + address_offset] + 1; } // Build READ_(MULTI_)BLOCK response @@ -2268,11 +2263,8 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { security_offset = 1; } uint8_t resp_readblock[response_length]; - for (int i = 0; i < response_length; i++) { - resp_readblock[i] = 0; - } + memset(resp_readblock, 0, response_length); - uint8_t *emCARD = BigBuf_get_EM_addr(); resp_readblock[0] = 0; // Response flags for (int j = 0; j < block_count; j++) { // where to put the data of the current block @@ -2280,13 +2272,12 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { if (option) { resp_readblock[work_offset] = 0; // Security status } - for (int i = 0; i < block_size; i++) { - // Block data - if (block_size * (block_idx + j + 1) <= CARD_MEMORY_SIZE) { - resp_readblock[work_offset + security_offset + i] = emCARD[block_size * (block_idx + j) + i]; - } else { - resp_readblock[work_offset + security_offset + i] = 0; - } + // Block data + if (block_size * (block_idx + j + 1) <= CARD_MEMORY_SIZE) { + EmlGetMemIso15693(block_size, resp_readblock + (work_offset + security_offset), + block_size * (block_idx + j)); + } else { + memset(resp_readblock + work_offset + security_offset, 0, block_size); } } @@ -2299,6 +2290,45 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); LogTrace_ISO15693(resp_readblock, response_length, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); } + + // WRITE_BLOCK and WRITE_MULTI_BLOCK + if ((cmd[1] == ISO15693_WRITEBLOCK) || (cmd[1] == ISO15693_WRITE_MULTI_BLOCK)) { + bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); + bool addressed = cmd[0] & ISO15_REQ_ADDRESS; + uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; + + uint8_t address_offset = 0; + if (addressed) { + address_offset = 8; + } + + uint8_t block_idx = cmd[2 + address_offset]; + uint8_t block_count = 1; + uint8_t multi_offset = 0; + if (cmd[1] == ISO15693_WRITE_MULTI_BLOCK) { + block_count = cmd[3 + address_offset] + 1; + multi_offset = 1; + } + uint8_t *data = cmd + 3 + address_offset + multi_offset; + + // write data + EmlSetMemIso15693(block_count * block_size, data, block_idx * block_size); + + // Build WRITE_(MULTI_)BLOCK response + int response_length = 3; + uint8_t resp_writeblock[response_length]; + memset(resp_writeblock, 0, response_length); + resp_writeblock[0] = 0; // Response flags + + // CRC + AddCrc15(resp_writeblock, response_length - 2); + CodeIso15693AsTag(resp_writeblock, response_length); + + tosend_t *ts = get_tosend(); + + TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); + LogTrace_ISO15693(resp_writeblock, response_length, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); + } } switch_off(); diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 6bd3882bc..f9ba6e9da 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -48,6 +48,7 @@ void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader void EmlClearIso15693(void); void EmlSetMemIso15693(uint8_t count, uint8_t *data, uint32_t offset); +void EmlGetMemIso15693(uint8_t count, uint8_t *output, uint32_t offset); 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 diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index f08d7f764..285769f68 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -1043,7 +1043,7 @@ static int CmdHF15ELoad(const char *Cmd) { uint8_t *data = NULL; size_t bytes_read = 0; - int res = loadFile_safe(filename, ".bin", (void **)&data, &bytes_read); + int res = pm3_load_dump(filename, (void **)&data, &bytes_read, CARD_MEMORY_SIZE); if (res != PM3_SUCCESS) { return res; } @@ -1098,6 +1098,121 @@ static int CmdHF15ELoad(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHF15ESave(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 esave", + "Save emulator memory into three files (BIN/EML/JSON) ", + "hf 15 esave -f hf-15-01020304" + "hf 15 esave -b 8 -c 42 -f hf-15-01020304" + ); + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "filename of dump"), + arg_int0("b", "blocksize", "", "block size, defaults to 4"), + arg_int0("c", "count", "", "number of blocks to export, defaults to all"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int fnlen = 0; + char filename[FILE_PATH_SIZE]; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + int blocksize = arg_get_int_def(ctx, 2, 4); + int count = arg_get_int_def(ctx, 3, -1); + CLIParserFree(ctx); + + int bytes = CARD_MEMORY_SIZE; + if (count > 0 && count * blocksize <= bytes) { + bytes = count * blocksize; + } + + // reserve memory + uint8_t *dump = calloc(bytes, sizeof(uint8_t)); + if (dump == NULL) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + + PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes); + if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(dump); + return PM3_ETIMEOUT; + } + + pm3_save_dump(filename, dump, bytes, jsf15, blocksize); + free(dump); + return PM3_SUCCESS; +} + +static void print_hrule(int blocksize) { + char dashes[] = "------------------------------------------------------------"; + PrintAndLogEx(INFO, "-----+%.*s-+-%.*s-", 3*blocksize, dashes, blocksize, dashes); +} + +static void print_blocks_15693(uint8_t *data, uint16_t bytes, int blocksize) { + int blocks = bytes / blocksize; + 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, ""); +} + +static int CmdHF15EView(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 eview", + "It displays emulator memory", + "hf 15 eview\n" + "hf 15 eview -b 8 -c 60\n" + ); + 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_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + int blocksize = arg_get_int_def(ctx, 1, 4); + int count = arg_get_int_def(ctx, 2, -1); + CLIParserFree(ctx); + + int bytes = CARD_MEMORY_SIZE; + if (count > 0 && count * blocksize <= bytes) { + bytes = count * blocksize; + } + + uint8_t *dump = calloc(bytes, sizeof(uint8_t)); + if (dump == NULL) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + + PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes); + if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(dump); + return PM3_ETIMEOUT; + } + + print_blocks_15693(dump, bytes, blocksize); + free(dump); + return PM3_SUCCESS; +} + // Simulation is still not working very good // helptext static int CmdHF15Sim(const char *Cmd) { @@ -2289,7 +2404,9 @@ static command_t CommandTable[] = { {"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO-15693 reader"}, {"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)"}, - {"eload", CmdHF15ELoad, IfPm3Iso15693, "Load image file to be used by 'sim' command"}, + {"eload", CmdHF15ELoad, IfPm3Iso15693, "Load image file into emulator to be used by 'sim' command"}, + {"esave", CmdHF15ESave, IfPm3Iso15693, "Save emulator memory into image file"}, + {"eview", CmdHF15EView, IfPm3Iso15693, "View emulator memory"}, {"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO-15693 tag"}, {"slixdisable", CmdHF15SlixDisable, IfPm3Iso15693, "Disable privacy mode on SLIX ISO-15693 tag"}, {"wrbl", CmdHF15Write, IfPm3Iso15693, "Write a block"},