From e35385fde1add453ac729462371eed807cf2f090 Mon Sep 17 00:00:00 2001 From: Martijn Plak Date: Mon, 22 Jan 2024 16:38:09 +0100 Subject: [PATCH 1/3] Adding processor flash memory reading, viewing and writing to file. Works when the device is running either osimage or bootloader. - New memory reading command in osimage and bootloader. - Extended 'hw readmem' command with length parameter, file writing and hex viewer. - Introduced '--dumpmem' option to proxmark3 executable to support dumping from bootloader. Simple interactive examples: hw readmem -f flashdump hw readmem -l 1024 CLI example: ./pm3 --dumpmem flashdump.bin Reading from arbitrary memory ranges can be unlocked using the 'raw' option. --- armsrc/appmain.c | 46 ++++++++++++ armsrc/util.c | 31 ++++++++ armsrc/util.h | 3 + bootrom/bootrom.c | 82 ++++++++++++++++++++- client/src/cmdhw.c | 59 ++++++++++++--- client/src/comms.c | 6 ++ client/src/comms.h | 2 + client/src/proxmark3.c | 158 ++++++++++++++++++++++++++++++++++++++++- doc/commands.md | 2 +- include/pm3_cmd.h | 9 ++- 10 files changed, 386 insertions(+), 12 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 1e4a1ca15..7032983f7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -2364,6 +2364,52 @@ static void PacketReceived(PacketCommandNG *packet) { ReadMem(packet->data.asDwords[0]); break; } + case CMD_READ_MEM_DOWNLOAD: { + LED_B_ON(); + + size_t offset = packet->oldarg[0]; + size_t count = packet->oldarg[1]; + uint32_t flags = packet->oldarg[2]; + + bool isok = true; + uint8_t *base = NULL; + + bool raw_address_mode = (flags & CMD_READ_MEM_DOWNLOAD_RAW) != 0; + if (!raw_address_mode) { + + base = (uint8_t *) _flash_start; + + size_t flash_size = get_flash_size(); + + // Boundary check the offset. + if (offset > flash_size) { + isok = false; + Dbprintf("reading mcu flash failed :: | out of bounds, offset %u count %u", offset, count); + } + + // Clip the length if it goes past the end of the flash memory. + count = MIN(count, flash_size - offset); + + } else { + // Allow reading from any memory address and length in special 'raw' mode. + base = NULL; + } + + if (isok) { + for (size_t pos = 0; pos < count; pos += PM3_CMD_DATA_SIZE) { + size_t len = MIN((count - pos), PM3_CMD_DATA_SIZE); + isok = 0 == reply_old(CMD_READ_MEM_DOWNLOADED, pos, len, 0, &base[offset + pos], len); + if (!isok) { + Dbprintf("transfer to client failed :: | pos %u len %u", pos, len); + break; + } + } + } + + reply_old(CMD_ACK, 1, 0, 0, 0, 0); + LED_B_OFF(); + break; + } #ifdef WITH_FLASH case CMD_SPIFFS_TEST: { test_spiffs(); diff --git a/armsrc/util.c b/armsrc/util.c index 0834e619d..f23046eee 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -321,3 +321,34 @@ bool data_available_fast(void) { return usb_available_length(); #endif } + +uint32_t flash_size_from_cidr(uint32_t cidr) { + uint8_t nvpsiz = (cidr & 0xF00) >> 8; + switch (nvpsiz) { + case 0: + return 0; + case 1: + return 8*1024; + case 2: + return 16*1024; + case 3: + return 32*1024; + case 5: + return 64*1024; + case 7: + return 128*1024; + case 9: + return 256*1024; + case 10: + return 512*1024; + case 12: + return 1024*1024; + case 14: + default: // for 'reserved' values, guess 2MB + return 2048*1024; + } +} + +uint32_t get_flash_size(void) { + return flash_size_from_cidr(*AT91C_DBGU_CIDR); +} diff --git a/armsrc/util.h b/armsrc/util.h index da45219a7..5421889cd 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -103,4 +103,7 @@ int BUTTON_HELD(int ms); bool data_available(void); bool data_available_fast(void); +uint32_t flash_size_from_cidr(uint32_t cidr); +uint32_t get_flash_size(void); + #endif diff --git a/bootrom/bootrom.c b/bootrom/bootrom.c index e92b86e35..632fe88d1 100644 --- a/bootrom/bootrom.c +++ b/bootrom/bootrom.c @@ -89,6 +89,37 @@ static void Fatal(void) { for (;;) {}; } +static uint32_t flash_size_from_cidr(uint32_t cidr) { + uint8_t nvpsiz = (cidr & 0xF00) >> 8; + switch (nvpsiz) { + case 0: + return 0; + case 1: + return 8*1024; + case 2: + return 16*1024; + case 3: + return 32*1024; + case 5: + return 64*1024; + case 7: + return 128*1024; + case 9: + return 256*1024; + case 10: + return 512*1024; + case 12: + return 1024*1024; + case 14: + default: // for 'reserved' values, guess 2MB + return 2048*1024; + } +} + +static uint32_t get_flash_size(void) { + return flash_size_from_cidr(*AT91C_DBGU_CIDR); +} + static void UsbPacketReceived(uint8_t *packet) { bool ack = true; PacketCommandOLD *c = (PacketCommandOLD *)packet; @@ -104,7 +135,8 @@ static void UsbPacketReceived(uint8_t *packet) { DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM | DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH | DEVICE_INFO_FLAG_UNDERSTANDS_CHIP_INFO | - DEVICE_INFO_FLAG_UNDERSTANDS_VERSION; + DEVICE_INFO_FLAG_UNDERSTANDS_VERSION | + DEVICE_INFO_FLAG_UNDERSTANDS_READ_MEM; if (g_common_area.flags.osimage_present) arg0 |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT; @@ -126,6 +158,54 @@ static void UsbPacketReceived(uint8_t *packet) { } break; + case CMD_READ_MEM_DOWNLOAD: { + ack = false; + LED_B_ON(); + + size_t offset = (size_t) c->arg[0]; + size_t count = (size_t) c->arg[1]; + uint32_t flags = (uint32_t) c->arg[2]; + + bool isok = true; + uint8_t *base = NULL; + + bool raw_address_mode = (flags & CMD_READ_MEM_DOWNLOAD_RAW) != 0; + if (!raw_address_mode) { + + base = (uint8_t *) _flash_start; + + size_t flash_size = get_flash_size(); + + // Boundary check the offset. + if (offset > flash_size) + isok = false; + + // Clip the length if it goes past the end of the flash memory. + count = MIN(count, flash_size - offset); + + } else { + // Allow reading from any memory address and length in special 'raw' mode. + base = NULL; + } + + if (isok) { + for (size_t pos = 0; pos < count; pos += PM3_CMD_DATA_SIZE) { + size_t len = MIN((count - pos), PM3_CMD_DATA_SIZE); + isok = 0 == reply_old(CMD_READ_MEM_DOWNLOADED, pos, len, 0, &base[offset + pos], len); + if (!isok) + break; + } + } + + if (isok) + reply_old(CMD_ACK, 1, 0, 0, 0, 0); + else + reply_old(CMD_NACK, 0, 0, 0, 0, 0); + + LED_B_OFF(); + break; + } + case CMD_FINISH_WRITE: { #if defined ICOPYX if (c->arg[1] == 0xff && c->arg[2] == 0x1fd) { diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 8c2757249..572516639 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -633,20 +633,63 @@ static int CmdLCDReset(const char *Cmd) { static int CmdReadmem(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hw readmem", - "Read memory at decimal address from ARM chip flash.", - "hw readmem -a 10000" + "Reads processor flash memory into a file or views on console", + "hw readmem -f myfile -> save 512KB processor flash memory to file\n" + "hw readmem -a 8192 -l 512 -> display 512 bytes from offset 8192\n" ); void *argtable[] = { arg_param_begin, - arg_u64_1("a", "adr", "", "address to read"), + arg_int0("a", "adr", "", "flash address to start reading from"), + arg_int0("l", "len", "", "length (default 32 or 512KB)"), + arg_str0("f", "file", "", "save to file"), + arg_int0("c", "cols", "", "column breaks"), + arg_lit0("r", "raw", "use raw address mode: read from anywhere, not just flash"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - uint32_t address = arg_get_u32(ctx, 1); + CLIExecWithReturn(ctx, Cmd, argtable, false); + + // check for -file option first to determine the output mode + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + bool save_to_file = fnlen > 0; + + // default len to 512KB when saving to file, to 32 bytes when viewing on the console. + uint32_t default_len = save_to_file ? 512*1024 : 32; + + uint32_t address = arg_get_u32_def(ctx, 1, 0); + uint32_t len = arg_get_u32_def(ctx, 2, default_len); + int breaks = arg_get_int_def(ctx, 4, 32); + bool raw = arg_get_lit(ctx, 5); CLIParserFree(ctx); - clearCommandBuffer(); - SendCommandNG(CMD_READ_MEM, (uint8_t *)&address, sizeof(address)); + + uint8_t *buffer = calloc(len, sizeof(uint8_t)); + if (!buffer) { + PrintAndLogEx(ERR, "error, cannot allocate memory "); + return PM3_EMALLOC; + } + + const char *flash_str = raw ? "" : " flash"; + PrintAndLogEx(INFO, "reading "_YELLOW_("%u")" bytes from processor%s memory", + len, flash_str); + + DeviceMemType_t type = raw ? MCU_MEM : MCU_FLASH; + if (!GetFromDevice(type, buffer, len, address, NULL, 0, NULL, -1, true)) { + PrintAndLogEx(FAILED, "ERROR; reading from MCU flash memory"); + free(buffer); + return PM3_EFLASH; + } + + if (save_to_file) { + PrintAndLogEx(INFO, "saving to "_YELLOW_("%s"), filename); + saveFile(filename, ".bin", buffer, len); + } else { + PrintAndLogEx(INFO, "---- " _CYAN_("processor%s memory") " ----", flash_str); + print_hex_break(buffer, len, breaks); + } + + free(buffer); return PM3_SUCCESS; } @@ -1150,7 +1193,7 @@ static command_t CommandTable[] = { {"lcd", CmdLCD, IfPm3Lcd, "Send command/data to LCD"}, {"lcdreset", CmdLCDReset, IfPm3Lcd, "Hardware reset LCD"}, {"ping", CmdPing, IfPm3Present, "Test if the Proxmark3 is responsive"}, - {"readmem", CmdReadmem, IfPm3Present, "Read memory at decimal address from flash"}, + {"readmem", CmdReadmem, IfPm3Present, "Read from processor flash"}, {"reset", CmdReset, IfPm3Present, "Reset the Proxmark3"}, {"setlfdivisor", CmdSetDivisor, IfPm3Present, "Drive LF antenna at 12MHz / (divisor + 1)"}, {"setmux", CmdSetMux, IfPm3Present, "Set the ADC mux to a specific value"}, diff --git a/client/src/comms.c b/client/src/comms.c index efd395917..c47c24cb7 100644 --- a/client/src/comms.c +++ b/client/src/comms.c @@ -1134,6 +1134,12 @@ bool GetFromDevice(DeviceMemType_t memtype, uint8_t *dest, uint32_t bytes, uint3 SendCommandNG(CMD_FPGAMEM_DOWNLOAD, NULL, 0); return dl_it(dest, bytes, response, ms_timeout, show_warning, CMD_FPGAMEM_DOWNLOADED); } + case MCU_FLASH: + case MCU_MEM: { + uint32_t flags = memtype == MCU_MEM ? CMD_READ_MEM_DOWNLOAD_RAW : 0; + SendCommandBL(CMD_READ_MEM_DOWNLOAD, start_index, bytes, flags, NULL, 0); + return dl_it(dest, bytes, response, ms_timeout, show_warning, CMD_READ_MEM_DOWNLOADED); + } } return false; } diff --git a/client/src/comms.h b/client/src/comms.h index 63b1af989..4e61da429 100644 --- a/client/src/comms.h +++ b/client/src/comms.h @@ -54,6 +54,8 @@ typedef enum { SIM_MEM, SPIFFS, FPGA_MEM, + MCU_FLASH, + MCU_MEM, } DeviceMemType_t; typedef enum { diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index 476b900a0..fcd530902 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -636,6 +636,11 @@ static void show_help(bool showFullHelp, char *exec_name) { PrintAndLogEx(NORMAL, " --unlock-bootloader Enable flashing of bootloader area *DANGEROUS* (need --flash)"); PrintAndLogEx(NORMAL, " --force Enable flashing even if firmware seems to not match client version"); PrintAndLogEx(NORMAL, " --image image to flash. Can be specified several times."); + PrintAndLogEx(NORMAL, "\nOptions in memory dump mode:"); + PrintAndLogEx(NORMAL, " --dumpmem dumps Proxmark3 flash memory to file"); + PrintAndLogEx(NORMAL, " --dumpaddr
starting address for dump, default 0"); + PrintAndLogEx(NORMAL, " --dumplen number of bytes to dump, default 512KB"); + PrintAndLogEx(NORMAL, " --dumpraw raw address mode: dump from anywhere, not just flash"); PrintAndLogEx(NORMAL, "\nExamples:"); PrintAndLogEx(NORMAL, "\n to run Proxmark3 client:\n"); PrintAndLogEx(NORMAL, " %s "SERIAL_PORT_EXAMPLE_H" -- runs the pm3 client", exec_name); @@ -660,6 +665,109 @@ static void show_help(bool showFullHelp, char *exec_name) { } } +static int dumpmem_to_file(const char *filename, uint32_t addr, uint32_t len, bool raw, bool in_bootloader) { + int res = PM3_EUNDEF; + + uint8_t *buffer = calloc(len, sizeof(uint8_t)); + if (!buffer) { + PrintAndLogEx(ERR, "error, cannot allocate memory "); + res = PM3_EMALLOC; + goto fail; + } + + size_t read = 0; + DeviceMemType_t type = raw ? MCU_MEM : MCU_FLASH; + if (GetFromDevice(type, buffer, len, addr, NULL, 0, NULL, 1000, true)) { + res = PM3_SUCCESS; + read = len; // GetFromDevice does not report the actual number of bytes received. + } + + if (res == PM3_SUCCESS) { + FILE *fd = fopen(filename, "wb"); + if (!fd) { + PrintAndLogEx(ERR, _RED_("Could not open file") " %s >>> ", filename); + res = PM3_EFILE; + goto fail2; + } + fwrite(buffer, 1, read, fd); + fclose(fd); + } + +fail2: + free(buffer); +fail: + return res; +} + +static int dumpmem_pm3(char *serial_port_name, const char *filename, uint32_t addr, uint32_t len, bool raw) { + int ret = PM3_EUNDEF; + bool in_bootloader = false; + + if (serial_port_name == NULL) { + PrintAndLogEx(ERR, "You must specify a port.\n"); + return PM3_EINVARG; + } + + if (OpenProxmark(&g_session.current_device, serial_port_name, true, 60, true, FLASHMODE_SPEED)) { + PrintAndLogEx(NORMAL, _GREEN_(" found")); + msleep(200); + } else { + PrintAndLogEx(ERR, "Could not find Proxmark3 on " _RED_("%s") ".\n", serial_port_name); + ret = PM3_ETIMEOUT; + goto finish; + } + + // Determine if we're talking to a bootloader or main firmware. + SendCommandBL(CMD_DEVICE_INFO, 0, 0, 0, NULL, 0); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_UNKNOWN, &resp, 1000) == false) { + PrintAndLogEx(ERR, "Could not get device info."); + goto finish2; + } + uint32_t dev_info = resp.oldarg[0]; + in_bootloader = (dev_info & DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM) != 0; + if (in_bootloader) { + if ((dev_info & DEVICE_INFO_FLAG_UNDERSTANDS_READ_MEM) != 0) { + PrintAndLogEx(INFO, "Device is running the bootloader."); + } + else { + PrintAndLogEx(ERR, "Device is running the bootloader, but the bootloader" + " doesn't understand the READ MEM command."); + goto finish2; + } + } + + PrintAndLogEx(SUCCESS,"Dump requested from address "_YELLOW_("%u")", length "_YELLOW_("%u")"%s.", + addr, len, raw ? ", in raw address mode" : ""); + + PrintAndLogEx(SUCCESS, _CYAN_("Memory dumping to file...")); + ret = dumpmem_to_file(filename, addr, len, raw, in_bootloader); + if (ret != PM3_SUCCESS) { + goto finish2; + } + PrintAndLogEx(NORMAL, ""); + +finish2: + clearCommandBuffer(); + if (in_bootloader) { + g_session.current_device->g_conn->run = false; + SendCommandOLD(CMD_PING, 0, 0, 0, NULL, 0); + } else { + SendCommandNG(CMD_QUIT_SESSION, NULL, 0); + msleep(100); + } + CloseProxmark(g_session.current_device); + +finish: + if (ret == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, _CYAN_("All done")); + else if (ret == PM3_EOPABORTED) + PrintAndLogEx(FAILED, "Aborted by user"); + else + PrintAndLogEx(ERR, "Aborted on error %u", ret); + return ret; +} + static int flash_pm3(char *serial_port_name, uint8_t num_files, const char *filenames[FLASH_MAX_FILES], bool can_write_bl, bool force) { int ret = PM3_EUNDEF; @@ -812,6 +920,11 @@ int main(int argc, char *argv[]) { bool debug_mode_forced = false; int flash_num_files = 0; const char *flash_filenames[FLASH_MAX_FILES]; + bool dumpmem_mode = false; + const char *dumpmem_filename = NULL; + uint32_t dumpmem_addr = 0; + uint32_t dumpmem_len = 512*1024; + bool dumpmem_raw = false; // color management: // 1. default = no color @@ -1013,6 +1126,44 @@ int main(int argc, char *argv[]) { continue; } + // go to dump mode + if (strcmp(argv[i], "--dumpmem") == 0) { + dumpmem_mode = true; + if (i + 1 == argc) { + PrintAndLogEx(ERR, _RED_("ERROR:") " missing file specification after --dumpmem\n"); + show_help(false, exec_name); + return 1; + } + dumpmem_filename = argv[++i]; + continue; + } + if (strcmp(argv[i], "--dumpaddr") == 0) { + if (i + 1 == argc) { + PrintAndLogEx(ERR, _RED_("ERROR:") " missing address specification after -dumpaddr\n"); + show_help(false, exec_name); + return 1; + } + uint32_t tmpaddr = strtol(argv[i + 1], NULL, 10); + dumpmem_addr = tmpaddr; + i++; + continue; + } + if (strcmp(argv[i], "--dumplen") == 0) { + if (i + 1 == argc) { + PrintAndLogEx(ERR, _RED_("ERROR:") " missing address specification after -dumplen\n"); + show_help(false, exec_name); + return 1; + } + uint32_t tmplen = strtol(argv[i + 1], NULL, 10); + dumpmem_len = tmplen; + i++; + continue; + } + if (strcmp(argv[i], "--dumpraw") == 0) { + dumpmem_raw = true; + continue; + } + // go to flash mode if (strcmp(argv[i], "--flash") == 0) { flash_mode = true; @@ -1094,6 +1245,11 @@ int main(int argc, char *argv[]) { if (speed == 0) speed = USART_BAUD_RATE; + if (dumpmem_mode) { + dumpmem_pm3(port, dumpmem_filename, dumpmem_addr, dumpmem_len, dumpmem_raw); + exit(EXIT_SUCCESS); + } + if (flash_mode) { flash_pm3(port, flash_num_files, flash_filenames, flash_can_write_bl, flash_force); exit(EXIT_SUCCESS); @@ -1148,7 +1304,7 @@ int main(int argc, char *argv[]) { } // ascii art only in interactive client - if (!script_cmds_file && !script_cmd && g_session.stdinOnTTY && g_session.stdoutOnTTY && !flash_mode && !reboot_bootloader_mode) { + if (!script_cmds_file && !script_cmd && g_session.stdinOnTTY && g_session.stdoutOnTTY && !dumpmem_mode && !flash_mode && !reboot_bootloader_mode) { showBanner(); } diff --git a/doc/commands.md b/doc/commands.md index 94241bfbe..87643a2c3 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -798,7 +798,7 @@ Check column "offline" for their availability. |`hw lcd `|N |`Send command/data to LCD` |`hw lcdreset `|N |`Hardware reset LCD` |`hw ping `|N |`Test if the Proxmark3 is responsive` -|`hw readmem `|N |`Read memory at decimal address from flash` +|`hw readmem `|N |`Read from processor flash` |`hw reset `|N |`Reset the Proxmark3` |`hw setlfdivisor `|N |`Drive LF antenna at 12MHz / (divisor + 1)` |`hw setmux `|N |`Set the ADC mux to a specific value` diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 06dbe057a..45da25e6d 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -379,7 +379,9 @@ typedef struct { #define CMD_LCD_RESET 0x0103 #define CMD_LCD 0x0104 #define CMD_BUFF_CLEAR 0x0105 -#define CMD_READ_MEM 0x0106 +#define CMD_READ_MEM 0x0106 // legacy +#define CMD_READ_MEM_DOWNLOAD 0x010A +#define CMD_READ_MEM_DOWNLOADED 0x010B #define CMD_VERSION 0x0107 #define CMD_STATUS 0x0108 #define CMD_PING 0x0109 @@ -880,6 +882,9 @@ typedef struct { /* Set if this device understands the version command */ #define DEVICE_INFO_FLAG_UNDERSTANDS_VERSION (1<<6) +/* Set if this device understands the read memory command */ +#define DEVICE_INFO_FLAG_UNDERSTANDS_READ_MEM (1<<7) + #define BL_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) #define BL_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define BL_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) @@ -891,6 +896,8 @@ typedef struct { // Different versions here. Each version should increase the numbers #define BL_VERSION_1_0_0 BL_MAKE_VERSION(1, 0, 0) +/* CMD_READ_MEM_DOWNLOAD flags */ +#define CMD_READ_MEM_DOWNLOAD_RAW (1<<0) /* CMD_START_FLASH may have three arguments: start of area to flash, end of area to flash, optional magic. From 974713a4d8d757d84bded404c7e24284c2c01bd1 Mon Sep 17 00:00:00 2001 From: Martijn Plak Date: Mon, 22 Jan 2024 17:17:56 +0100 Subject: [PATCH 2/3] CMD_READ_MEM_DOWNLOAD, hw readmem and --dumpmem --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e14bbd15..4fdc394bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ 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 `--dumpmem` to proxmark3 client for memory dumping to file (@martian01010) + - Changed `hw readmem` to allow larger reads, write to file and better hex viewer (@martian01010) + - Added `CMD_READ_MEM_DOWNLOAD` and `CMD_READ_MEM_DOWNLOADED` to osimage and bootloader (@martian01010) - Changed `hf 14b dump/view` - now supports `z` flag for dense output (@iceman1001) - Changed `hf xerox dump/view` - now supports `z` flag for dense output (@iceman1001) - Changed `hf mfu dump/view/eview` - now supports `-z` flag for dense output (@iceman1001) From de91e850b459f3cd27e0c6a569aec19c347fc260 Mon Sep 17 00:00:00 2001 From: Martijn Plak Date: Mon, 22 Jan 2024 18:16:27 +0100 Subject: [PATCH 3/3] use fileutils to write memory dump --- client/src/proxmark3.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index fcd530902..a6cfe1dd7 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -683,17 +683,13 @@ static int dumpmem_to_file(const char *filename, uint32_t addr, uint32_t len, bo } if (res == PM3_SUCCESS) { - FILE *fd = fopen(filename, "wb"); - if (!fd) { - PrintAndLogEx(ERR, _RED_("Could not open file") " %s >>> ", filename); + PrintAndLogEx(INFO, "saving to "_YELLOW_("%s"), filename); + if (saveFile(filename, ".bin", buffer, read) != 0) { + PrintAndLogEx(ERR, "error writing to file "_YELLOW_("%s"), filename); res = PM3_EFILE; - goto fail2; } - fwrite(buffer, 1, read, fd); - fclose(fd); } -fail2: free(buffer); fail: return res;