mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-09-22 00:06:13 +08:00
Flasher: read the firmware file in one go
This commit is contained in:
parent
2a705d3a44
commit
72f7bc762d
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"));
|
||||
|
|
Loading…
Reference in a new issue