From 0ed0735709aeb6cf8e8ad48ff6510aea553943da Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Tue, 15 Feb 2022 03:09:52 +0100 Subject: [PATCH] flasher: parse ELF to check version_information and do ELF checks before looking for a proxmark3 --- client/src/elf.h | 15 ++++- client/src/flash.c | 130 +++++++++++++++++++++++++++++++++++++---- client/src/flash.h | 6 +- client/src/proxmark3.c | 12 +++- 4 files changed, 147 insertions(+), 16 deletions(-) diff --git a/client/src/elf.h b/client/src/elf.h index c05a48018..f79675cfb 100644 --- a/client/src/elf.h +++ b/client/src/elf.h @@ -48,9 +48,22 @@ typedef struct { uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; - uint16_t e_shtrndx; + uint16_t e_shstrndx; } PACKED Elf32_Ehdr_t; +typedef struct { + uint32_t sh_name; // Section name, index in string tbl + uint32_t sh_type; // Type of section + uint32_t sh_flags; // Miscellaneous section attributes + uint32_t sh_addr; // Section virtual addr at execution + uint32_t sh_offset; // Section file offset + uint32_t sh_size; // Size of section in bytes + uint32_t sh_link; // Index of another section + uint32_t sh_info; // Additional section information + uint32_t sh_addralign; // Section alignment + uint32_t sh_entsize; // Entry size if section holds table +} PACKED Elf32_Shdr_t; + #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 diff --git a/client/src/flash.c b/client/src/flash.c index 5bc6fbcab..78365c940 100644 --- a/client/src/flash.c +++ b/client/src/flash.c @@ -29,6 +29,7 @@ #include "at91sam7s512.h" #include "util_posix.h" #include "comms.h" +#include "commonutil.h" #define FLASH_START 0x100000 @@ -84,12 +85,12 @@ static int chipid_to_mem_avail(uint32_t iChipID) { // Turn PHDRs into flasher segments, checking for PHDR sanity and merging adjacent // unaligned segments if needed -static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr_t *phdrs, uint16_t num_phdrs, uint32_t flash_end) { - Elf32_Phdr_t *phdr = phdrs; +static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, uint32_t flash_end) { + Elf32_Phdr_t *phdr = ctx->phdrs; flash_seg_t *seg; uint32_t last_end = 0; - ctx->segments = calloc(sizeof(flash_seg_t) * num_phdrs, sizeof(uint8_t)); + ctx->segments = calloc(sizeof(flash_seg_t) * ctx->num_phdrs, sizeof(uint8_t)); if (!ctx->segments) { PrintAndLogEx(ERR, "Out of memory"); return PM3_EMALLOC; @@ -98,7 +99,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr_t *phdr seg = ctx->segments; PrintAndLogEx(SUCCESS, "Loading usable ELF segments:"); - for (int i = 0; i < num_phdrs; i++) { + for (int i = 0; i < ctx->num_phdrs; i++) { if (le32(phdr->p_type) != PT_LOAD) { phdr++; continue; @@ -236,13 +237,16 @@ static int check_segs(flash_file_t *ctx, int can_write_bl, uint32_t flash_end) { return PM3_SUCCESS; } -// Load an ELF file and prepare it for flashing -int flash_load(flash_file_t *ctx, const char *name, int can_write_bl, int flash_size) { +// Read an ELF file and do some checks +int flash_check(flash_file_t *ctx, const char *name) { FILE *fd; Elf32_Ehdr_t ehdr; Elf32_Phdr_t *phdrs = NULL; + Elf32_Shdr_t *shdrs = NULL; uint16_t num_phdrs; - uint32_t flash_end = FLASH_START + flash_size; + uint16_t num_shdrs; + uint8_t *shstr = NULL; + struct version_information_t *vi = NULL; int res = PM3_EUNDEF; fd = fopen(name, "rb"); @@ -305,21 +309,118 @@ int flash_load(flash_file_t *ctx, const char *name, int can_write_bl, int flash_ goto fail; } - res = build_segs_from_phdrs(ctx, fd, phdrs, num_phdrs, flash_end); + num_shdrs = le16(ehdr.e_shnum); + + shdrs = calloc(le16(ehdr.e_shnum) * sizeof(Elf32_Shdr_t), sizeof(uint8_t)); + if (!shdrs) { + PrintAndLogEx(ERR, "Out of memory"); + res = PM3_EMALLOC; + goto fail; + } + if (fseek(fd, le32(ehdr.e_shoff), SEEK_SET) < 0) { + PrintAndLogEx(ERR, "Error while reading ELF SHDRs"); + res = PM3_EFILE; + goto fail; + } + if (fread(shdrs, sizeof(Elf32_Shdr_t), num_shdrs, fd) != num_shdrs) { + res = PM3_EFILE; + PrintAndLogEx(ERR, "Error while reading ELF SHDRs"); + goto fail; + } + + shstr = calloc(shdrs[ehdr.e_shstrndx].sh_size, sizeof(uint8_t)); + if (!shstr) { + PrintAndLogEx(ERR, "Out of memory"); + res = PM3_EMALLOC; + goto fail; + } + if (fseek(fd, le32(shdrs[ehdr.e_shstrndx].sh_offset), SEEK_SET) < 0) { + PrintAndLogEx(ERR, "Error while reading ELF section string table"); + res = PM3_EFILE; + goto fail; + } + if (fread(shstr, shdrs[ehdr.e_shstrndx].sh_size, 1, fd) != 1) { + res = PM3_EFILE; + PrintAndLogEx(ERR, "Error while reading ELF section string table"); + goto fail; + } + + for(uint16_t i=0; iarmsrc, g_version_information.armsrc, 9) != 0) { + PrintAndLogEx(WARNING, _RED_("ARM firmware does not match the source at the time the client was compiled")); + PrintAndLogEx(WARNING, "Make sure to flash a correct and up-to-date version"); +// TODO: prompt user to continue or abort + } + } + free(vi); + } + } + + free(shdrs); + free(shstr); + fclose(fd); + ctx->filename = name; + ctx->phdrs = phdrs; + ctx->num_phdrs = num_phdrs; + return PM3_SUCCESS; + +fail: + if (phdrs) + free(phdrs); + if (shdrs) + free(shdrs); + if (shstr) + free(shstr); + if (vi) + free(vi); + if (fd) + fclose(fd); + flash_free(ctx); + return res; +} + +// Load an ELF file and prepare it for flashing +int flash_load(flash_file_t *ctx, int can_write_bl, int flash_size) { + FILE *fd; + uint32_t flash_end = FLASH_START + flash_size; + int res = PM3_EUNDEF; + + fd = fopen(ctx->filename, "rb"); + if (!fd) { + PrintAndLogEx(ERR, _RED_("Could not open file") " %s >>> ", ctx->filename); + res = PM3_EFILE; + goto fail; + } + + res = build_segs_from_phdrs(ctx, fd, flash_end); if (res != PM3_SUCCESS) goto fail; res = check_segs(ctx, can_write_bl, flash_end); if (res != PM3_SUCCESS) goto fail; - free(phdrs); fclose(fd); - ctx->filename = name; return PM3_SUCCESS; fail: - if (phdrs) - free(phdrs); if (fd) fclose(fd); flash_free(ctx); @@ -625,6 +726,11 @@ void flash_free(flash_file_t *ctx) { ctx->segments = NULL; ctx->num_segs = 0; } + if (ctx->phdrs) { + free(ctx->phdrs); + ctx->phdrs = NULL; + ctx->num_phdrs = 0; + } } // just reset the unit diff --git a/client/src/flash.h b/client/src/flash.h index 518027b4f..beb994c6a 100644 --- a/client/src/flash.h +++ b/client/src/flash.h @@ -20,6 +20,7 @@ #define __FLASH_H__ #include "common.h" +#include "elf.h" #define FLASH_MAX_FILES 4 #define ONE_KB 1024 @@ -32,12 +33,15 @@ typedef struct { typedef struct { const char *filename; + Elf32_Phdr_t *phdrs; + uint16_t num_phdrs; int can_write_bl; int num_segs; flash_seg_t *segments; } flash_file_t; -int flash_load(flash_file_t *ctx, const char *name, int can_write_bl, int flash_size); +int flash_check(flash_file_t *ctx, const char *name); +int flash_load(flash_file_t *ctx, int can_write_bl, int flash_size); int flash_start_flashing(int enable_bl_writes, char *serial_port_name, uint32_t *max_allowed); int flash_write(flash_file_t *ctx); void flash_free(flash_file_t *ctx); diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index f9e101469..2b0f0ac6d 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -635,6 +635,14 @@ static int flash_pm3(char *serial_port_name, uint8_t num_files, char *filenames[ PrintAndLogEx(SUCCESS, " "_YELLOW_("%s"), filepaths[i]); } + for (int i = 0 ; i < num_files; ++i) { + ret = flash_check(&files[i], filepaths[i]); + if (ret != PM3_SUCCESS) { + goto finish; + } + PrintAndLogEx(NORMAL, ""); + } + if (OpenProxmark(&g_session.current_device, serial_port_name, true, 60, true, FLASHMODE_SPEED)) { PrintAndLogEx(NORMAL, _GREEN_(" found")); } else { @@ -653,7 +661,7 @@ static int flash_pm3(char *serial_port_name, uint8_t num_files, char *filenames[ goto finish; for (int i = 0 ; i < num_files; ++i) { - ret = flash_load(&files[i], filepaths[i], can_write_bl, max_allowed * ONE_KB); + ret = flash_load(&files[i], can_write_bl, max_allowed * ONE_KB); if (ret != PM3_SUCCESS) { goto finish; } @@ -667,7 +675,6 @@ static int flash_pm3(char *serial_port_name, uint8_t num_files, char *filenames[ if (ret != PM3_SUCCESS) { goto finish; } - flash_free(&files[i]); PrintAndLogEx(NORMAL, ""); } @@ -678,6 +685,7 @@ finish: CloseProxmark(g_session.current_device); finish2: for (int i = 0 ; i < num_files; ++i) { + flash_free(&files[i]); if (filepaths[i] != NULL) free(filepaths[i]); }