diff --git a/client/src/flash.c b/client/src/flash.c index 7da19840f..6bd525ce0 100644 --- a/client/src/flash.c +++ b/client/src/flash.c @@ -85,7 +85,8 @@ 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, uint32_t flash_end) { +static int build_segs_from_phdrs(flash_file_t *ctx, uint32_t flash_size) { + uint32_t flash_end = FLASH_START + flash_size; Elf32_Phdr_t *phdr = ctx->phdrs; flash_seg_t *seg; uint32_t last_end = 0; @@ -149,11 +150,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, uint32_t flash_end PrintAndLogEx(ERR, "Error: Out of memory"); return PM3_EMALLOC; } - if (fseek(fd, offset, SEEK_SET) < 0 || fread(data, 1, filesz, fd) != filesz) { - PrintAndLogEx(ERR, "Error while reading PHDR payload"); - free(data); - return PM3_EFILE; - } + memcpy(data, ctx->elf + offset, filesz); uint32_t block_offset = paddr & (BLOCK_SIZE - 1); if (block_offset) { @@ -209,7 +206,8 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, uint32_t flash_end } // Sanity check segments and check for bootloader writes -static int check_segs(flash_file_t *ctx, int can_write_bl, uint32_t flash_end) { +static int check_segs(flash_file_t *ctx, int can_write_bl, uint32_t flash_size) { + uint32_t flash_end = FLASH_START + flash_size; for (int i = 0; i < ctx->num_segs; i++) { flash_seg_t *seg = &ctx->segments[i]; @@ -237,170 +235,13 @@ static int check_segs(flash_file_t *ctx, int can_write_bl, uint32_t flash_end) { return PM3_SUCCESS; } -// Read an ELF file and do some checks -int flash_check(flash_file_t *ctx, const char *name) { +// Load an ELF file for flashing +int flash_load(flash_file_t *ctx) { FILE *fd; - Elf32_Ehdr_t ehdr; - Elf32_Phdr_t *phdrs = NULL; + Elf32_Ehdr_t *ehdr; Elf32_Shdr_t *shdrs = NULL; - uint16_t num_phdrs; - uint16_t num_shdrs; uint8_t *shstr = NULL; - struct version_information_t *vi = NULL; - int res = PM3_EUNDEF; - - fd = fopen(name, "rb"); - if (!fd) { - PrintAndLogEx(ERR, _RED_("Could not open file") " %s >>> ", name); - res = PM3_EFILE; - goto fail; - } - - PrintAndLogEx(SUCCESS, _CYAN_("Loading ELF file") _YELLOW_(" %s"), name); - - if (fread(&ehdr, sizeof(ehdr), 1, fd) != 1) { - PrintAndLogEx(ERR, "Error while reading ELF file header"); - res = PM3_EFILE; - goto fail; - } - if (memcmp(ehdr.e_ident, elf_ident, sizeof(elf_ident)) - || le32(ehdr.e_version) != 1) { - PrintAndLogEx(ERR, "Not an ELF file or wrong ELF type"); - res = PM3_EFILE; - goto fail; - } - if (le16(ehdr.e_type) != ET_EXEC) { - PrintAndLogEx(ERR, "ELF is not executable"); - res = PM3_EFILE; - goto fail; - } - if (le16(ehdr.e_machine) != EM_ARM) { - PrintAndLogEx(ERR, "Wrong ELF architecture"); - res = PM3_EFILE; - goto fail; - } - if (!ehdr.e_phnum || !ehdr.e_phoff) { - PrintAndLogEx(ERR, "ELF has no PHDRs"); - res = PM3_EFILE; - goto fail; - } - if (le16(ehdr.e_phentsize) != sizeof(Elf32_Phdr_t)) { - // could be a structure padding issue... - PrintAndLogEx(ERR, "Either the ELF file or this code is made of fail"); - res = PM3_EFILE; - goto fail; - } - num_phdrs = le16(ehdr.e_phnum); - - phdrs = calloc(le16(ehdr.e_phnum) * sizeof(Elf32_Phdr_t), sizeof(uint8_t)); - if (!phdrs) { - PrintAndLogEx(ERR, "Out of memory"); - res = PM3_EMALLOC; - goto fail; - } - if (fseek(fd, le32(ehdr.e_phoff), SEEK_SET) < 0) { - PrintAndLogEx(ERR, "Error while reading ELF PHDRs"); - res = PM3_EFILE; - goto fail; - } - if (fread(phdrs, sizeof(Elf32_Phdr_t), num_phdrs, fd) != num_phdrs) { - res = PM3_EFILE; - PrintAndLogEx(ERR, "Error while reading ELF PHDRs"); - goto fail; - } - - 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; i < ehdr.e_shnum; i++) { - if (strcmp(((char *)shstr) + shdrs[i].sh_name, ".version_information") == 0) { - vi = calloc(shdrs[i].sh_size, sizeof(uint8_t)); - if (!vi) { - PrintAndLogEx(ERR, "Out of memory"); - res = PM3_EMALLOC; - goto fail; - } - if (fseek(fd, le32(shdrs[i].sh_offset), SEEK_SET) < 0) { - PrintAndLogEx(ERR, "Error while reading ELF version_information section"); - res = PM3_EFILE; - goto fail; - } - if (fread(vi, shdrs[i].sh_size, 1, fd) != 1) { - res = PM3_EFILE; - PrintAndLogEx(ERR, "Error while reading ELF version_information section"); - goto fail; - } - if (strlen(g_version_information.armsrc) == 9) { - if (strncmp(vi->armsrc, 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; + struct version_information_t *vi = NULL; int res = PM3_EUNDEF; fd = fopen(ctx->filename, "rb"); @@ -410,19 +251,104 @@ int flash_load(flash_file_t *ctx, int can_write_bl, int flash_size) { 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; + PrintAndLogEx(SUCCESS, _CYAN_("Loading ELF file") _YELLOW_(" %s"), ctx->filename); + // get filesize in order to malloc memory + fseek(fd, 0, SEEK_END); + long fsize = ftell(fd); + fseek(fd, 0, SEEK_SET); + + if (fsize <= 0) { + PrintAndLogEx(ERR, "Error, when getting filesize"); + res = PM3_EFILE; + fclose(fd); + goto fail; + } + + ctx->elf = calloc(fsize, sizeof(uint8_t)); + if (!ctx->elf) { + PrintAndLogEx(ERR, "Error, cannot allocate memory"); + res = PM3_EMALLOC; + fclose(fd); + goto fail; + } + + size_t bytes_read = fread(ctx->elf, 1, fsize, fd); fclose(fd); + + if (bytes_read != fsize) { + PrintAndLogEx(ERR, "Error, bytes read mismatch file size"); + res = PM3_EFILE; + goto fail; + } + + ehdr = (Elf32_Ehdr_t *)ctx->elf; + if (memcmp(ehdr->e_ident, elf_ident, sizeof(elf_ident)) + || le32(ehdr->e_version) != 1) { + PrintAndLogEx(ERR, "Not an ELF file or wrong ELF type"); + res = PM3_EFILE; + goto fail; + } + if (le16(ehdr->e_type) != ET_EXEC) { + PrintAndLogEx(ERR, "ELF is not executable"); + res = PM3_EFILE; + goto fail; + } + if (le16(ehdr->e_machine) != EM_ARM) { + PrintAndLogEx(ERR, "Wrong ELF architecture"); + res = PM3_EFILE; + goto fail; + } + if (!ehdr->e_phnum || !ehdr->e_phoff) { + PrintAndLogEx(ERR, "ELF has no PHDRs"); + res = PM3_EFILE; + goto fail; + } + if (le16(ehdr->e_phentsize) != sizeof(Elf32_Phdr_t)) { + // could be a structure padding issue... + PrintAndLogEx(ERR, "Either the ELF file or this code is made of fail"); + res = PM3_EFILE; + goto fail; + } + ctx->num_phdrs = le16(ehdr->e_phnum); + ctx->phdrs = (Elf32_Phdr_t *)(ctx->elf + le32(ehdr->e_phoff)); + shdrs = (Elf32_Shdr_t *)(ctx->elf + le32(ehdr->e_shoff)); + shdrs = (Elf32_Shdr_t *)(ctx->elf + le32(ehdr->e_shoff)); + shstr = ctx->elf + le32(shdrs[ehdr->e_shstrndx].sh_offset); + + for (uint16_t i = 0; i < le16(ehdr->e_shnum); i++) { + if (strcmp(((char *)shstr) + shdrs[i].sh_name, ".version_information") == 0) { + vi = (struct version_information_t *)(ctx->elf + le32(shdrs[i].sh_offset)); + if (strlen(g_version_information.armsrc) == 9) { + if (strncmp(vi->armsrc, 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 + } + } + } + } + return PM3_SUCCESS; + +fail: + flash_free(ctx); + return res; +} + +// Prepare an ELF file for flashing +int flash_prepare(flash_file_t *ctx, int can_write_bl, int flash_size) { + int res = PM3_EUNDEF; + + res = build_segs_from_phdrs(ctx, flash_size); + if (res != PM3_SUCCESS) + goto fail; + res = check_segs(ctx, can_write_bl, flash_size); + if (res != PM3_SUCCESS) + goto fail; + return PM3_SUCCESS; fail: - if (fd) - fclose(fd); flash_free(ctx); return res; } @@ -719,6 +645,16 @@ int flash_write(flash_file_t *ctx) { void flash_free(flash_file_t *ctx) { if (!ctx) return; + if (ctx->filename != NULL) { + free(ctx->filename); + ctx->filename = NULL; + } + if (ctx->elf) { + free(ctx->elf); + ctx->elf = NULL; + ctx->phdrs = NULL; + ctx->num_phdrs = 0; + } if (ctx->segments) { for (int i = 0; i < ctx->num_segs; i++) free(ctx->segments[i].data); @@ -726,11 +662,6 @@ 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 beb994c6a..b4cac2e2a 100644 --- a/client/src/flash.h +++ b/client/src/flash.h @@ -32,7 +32,8 @@ typedef struct { } flash_seg_t; typedef struct { - const char *filename; + char *filename; + uint8_t *elf; Elf32_Phdr_t *phdrs; uint16_t num_phdrs; int can_write_bl; @@ -40,8 +41,8 @@ typedef struct { flash_seg_t *segments; } flash_file_t; -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_load(flash_file_t *ctx); +int flash_prepare(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 2b0f0ac6d..1fce51cd8 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -607,7 +607,6 @@ static int flash_pm3(char *serial_port_name, uint8_t num_files, char *filenames[ int ret = PM3_EUNDEF; flash_file_t files[FLASH_MAX_FILES]; memset(files, 0, sizeof(files)); - char *filepaths[FLASH_MAX_FILES] = {0}; if (serial_port_name == NULL) { PrintAndLogEx(ERR, "You must specify a port.\n"); @@ -627,16 +626,16 @@ static int flash_pm3(char *serial_port_name, uint8_t num_files, char *filenames[ if (ret != PM3_SUCCESS) { goto finish2; } - filepaths[i] = path; + files[i].filename = path; } PrintAndLogEx(SUCCESS, "About to use the following file%s:", num_files > 1 ? "s" : ""); for (int i = 0 ; i < num_files; ++i) { - PrintAndLogEx(SUCCESS, " "_YELLOW_("%s"), filepaths[i]); + PrintAndLogEx(SUCCESS, " "_YELLOW_("%s"), files[i].filename); } for (int i = 0 ; i < num_files; ++i) { - ret = flash_check(&files[i], filepaths[i]); + ret = flash_load(&files[i]); if (ret != PM3_SUCCESS) { goto finish; } @@ -661,7 +660,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], can_write_bl, max_allowed * ONE_KB); + ret = flash_prepare(&files[i], can_write_bl, max_allowed * ONE_KB); if (ret != PM3_SUCCESS) { goto finish; } @@ -686,8 +685,6 @@ finish: finish2: for (int i = 0 ; i < num_files; ++i) { flash_free(&files[i]); - if (filepaths[i] != NULL) - free(filepaths[i]); } if (ret == PM3_SUCCESS) PrintAndLogEx(SUCCESS, _CYAN_("All done"));