diff --git a/CHANGELOG.md b/CHANGELOG.md index 7279766f6..2fda95253 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ 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 detection of a possible mismatch between client and Proxmark3 image (@doegox) - Changed `hf 14a info` - added a ATR historical compact TLV decoder (@iceman1001) - Added `hf mf value` - decode a value block (@iceman1001) - Changed `hf mf nested` - removed option `--single` redundant with usage of `--tblk` (@doegox) @@ -22,7 +23,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hf_mf_uidbruteforce` - added support for S70, enhance UID length management (@cactuschibre) - Fixed build issues that may happen from building `mfd_aes_brute` (@linuxgemini) - Added silicon data parsing logic for NXP chips in `hf mfu info` (@linuxgemini) - - Addes luascript `hf_mf_em_util.lua` - Script for emulator configuration (@nisgola) + - Added luascript `hf_mf_em_util.lua` - Script for emulator configuration (@nisgola) - Fixes `hf mf restore` - now takes bin/eml/json as dump files (@iceman1001) - Fixes `script run some_python_script` segfault on armhf architecture (@doegox) - Added `trace extract` - extract authentication parts from trace (@iceman1001) @@ -37,7 +38,7 @@ 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) -## [Frostbit.4.14831] [2022-01-11] +## [Frostbit.4.14831][2022-01-11] - Changed Wiegand format lookup - now case-insensitive (@iceman1001) - Added new standalone mode `hf_15SNIFF` - Same as `hf_14ASNIFF` standalone mode for RDV4 - flashmem (@startrk1995) - Added `hf gallagher` commands for read/writing DESFire cards (@DarkMatterMatt) diff --git a/armsrc/Makefile b/armsrc/Makefile index 968dc445d..86ac7b39f 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -184,7 +184,7 @@ showinfo: # version_pm3.c should be remade on every time fullimage.stage1.elf should be remade version_pm3.c: default_version_pm3.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) $(info [-] GEN $@) - $(Q)$(SH) ../tools/mkversion.sh > $@ || $(PERL) ../tools/mkversion.pl > $@ || $(CP) $< $@ + $(Q)$(SH) ../tools/mkversion.sh > $@ || $(CP) $< $@ fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR) $(info [-] GEN $@) @@ -210,14 +210,6 @@ $(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $ $(info [=] LD $@) $(Q)$(CROSS_LD) $(CROSS_LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) -$(OBJDIR)/fullimage.nodata.bin: $(OBJDIR)/fullimage.stage1.elf - $(info [-] GEN $@) - $(Q)$(CROSS_OBJCOPY) -O binary -I elf32-littlearm --remove-section .data $^ $@ - -$(OBJDIR)/fullimage.nodata.o: $(OBJDIR)/fullimage.nodata.bin - $(info [-] GEN $@) - $(Q)$(CROSS_OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=stage1_image $^ $@ - $(OBJDIR)/fullimage.data.bin: $(OBJDIR)/fullimage.stage1.elf $(info [-] GEN $@) $(Q)$(CROSS_OBJCOPY) -O binary -I elf32-littlearm --only-section .data $^ $@ @@ -230,14 +222,10 @@ else $(FPGA_COMPRESSOR) $(filter %.bin,$^) $@ endif -$(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z - $(info [-] GEN $@) - $(Q)$(CROSS_OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@ - -$(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o +$(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.stage1.elf $(OBJDIR)/fullimage.data.bin.z ifeq (,$(findstring WITH_NO_COMPRESSION,$(APP_CFLAGS))) $(info [=] LD $@) - $(Q)$(CROSS_LD) $(CROSS_LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ + $(Q)$(CROSS_OBJCOPY) -O elf32-littlearm -I elf32-littlearm --strip-all --update-section .data=$(OBJDIR)/fullimage.data.bin.z $(OBJDIR)/fullimage.stage1.elf $@ else $(Q)$(CP) $(OBJDIR)/fullimage.stage1.elf $@ endif diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 5176b7367..53c59469a 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -287,6 +287,7 @@ static void SendVersion(void) { strncat(VersionString, "\n", sizeof(VersionString) - strlen(VersionString) - 1); } + FormatVersionInformation(temp, sizeof(temp), " os: ", &g_version_information); strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); strncat(VersionString, "\n", sizeof(VersionString) - strlen(VersionString) - 1); diff --git a/armsrc/ldscript b/armsrc/ldscript index 4d48d9948..1dd09e937 100644 --- a/armsrc/ldscript +++ b/armsrc/ldscript @@ -24,7 +24,6 @@ SECTIONS } >osimage :text .text : { - KEEP(*(stage1_image)) *(.text) *(.text.*) *(.eh_frame) @@ -36,12 +35,10 @@ SECTIONS *(.rodata) *(.rodata.*) *(fpga_all_bit.data) - KEEP(*(.version_information)) . = ALIGN(8); } >osimage :text .data : { - KEEP(*(compressed_data)) *(.data) *(.data.*) *(.ramfunc) @@ -52,9 +49,9 @@ SECTIONS __data_start__ = ADDR(.data); __data_end__ = __data_start__ + SIZEOF(.data); __os_size__ = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.rodata); - + .bss : { - __bss_start__ = .; + __bss_start__ = .; *(.bss) *(.bss.*) . = ALIGN(4); diff --git a/armsrc/start.c b/armsrc/start.c index 26a190d68..8e0453467 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -28,6 +28,7 @@ #endif #include "BigBuf.h" #include "string.h" +#include "ticks.h" extern common_area_t g_common_area; extern uint32_t __data_src_start__[], __data_start__[], __data_end__[], __bss_start__[], __bss_end__[]; @@ -40,9 +41,15 @@ static void uncompress_data_section(void) { // uncompress data segment to RAM char *p = (char *)__data_src_start__; int res = LZ4_decompress_safe(p + 4, (char *)__data_start__, avail_in, avail_out); - - if (res < 0) - return; + if (res < 0) { + while (true) { + LED_A_INV(); + LED_B_INV(); + LED_C_INV(); + LED_D_INV(); + SpinDelay(200); + } + } // save the size of the compressed data section g_common_area.arg1 = avail_in; } diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index f6a0c9e9f..4c5e834a1 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -358,7 +358,7 @@ set (TARGET_SOURCES add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/version_pm3.c - COMMAND sh ${PM3_ROOT}/tools/mkversion.sh > ${CMAKE_BINARY_DIR}/version_pm3.c || perl ${PM3_ROOT}/tools/mkversion.pl > ${CMAKE_BINARY_DIR}/version_pm3.c || ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c + COMMAND sh ${PM3_ROOT}/tools/mkversion.sh > ${CMAKE_BINARY_DIR}/version_pm3.c || ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c DEPENDS ${PM3_ROOT}/common/default_version_pm3.c ) diff --git a/client/Makefile b/client/Makefile index 4debb130f..a93ab5409 100644 --- a/client/Makefile +++ b/client/Makefile @@ -881,9 +881,9 @@ src/pm3_pywrap.c: pm3.i .PHONY: all clean install uninstall tarbin .FORCE # version_pm3.c should be remade on every compilation -src/version_pm3.c: default_version_pm3.c +src/version_pm3.c: .FORCE default_version_pm3.c $(info [=] GEN $@) - $(Q)$(SH) ../tools/mkversion.sh > $@ || $(PERL) ../tools/mkversion.pl > $@ || $(CP) $< $@ + $(Q)$(SH) ../tools/mkversion.sh > $@ || $(CP) $< $@ # easy printing of MAKE VARIABLES print-%: ; @echo $* = $($*) diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index 618b5af28..e82f73953 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -359,7 +359,7 @@ set (TARGET_SOURCES add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/version_pm3.c - COMMAND sh ${PM3_ROOT}/tools/mkversion.sh > ${CMAKE_BINARY_DIR}/version_pm3.c || perl ${PM3_ROOT}/tools/mkversion.pl > ${CMAKE_BINARY_DIR}/version_pm3.c || ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c + COMMAND sh ${PM3_ROOT}/tools/mkversion.sh > ${CMAKE_BINARY_DIR}/version_pm3.c || ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c DEPENDS ${PM3_ROOT}/common/default_version_pm3.c ) diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index c6b763c08..6e96b130f 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -1072,12 +1072,27 @@ void pm3_version(bool verbose, bool oneliner) { struct p *payload = (struct p *)&resp.data.asBytes; + bool armsrc_mismatch = false; + char *ptr = strstr(payload->versionstr, " os: "); + if (ptr != NULL) { + ptr = strstr(ptr, "\n"); + if ((ptr != NULL) && (strlen(g_version_information.armsrc) == 9)) { + if (strncmp(ptr - 9, g_version_information.armsrc, 9) != 0) { + armsrc_mismatch = true; + } + } + } PrintAndLogEx(NORMAL, payload->versionstr); if (strstr(payload->versionstr, "2s30vq100") == NULL) { PrintAndLogEx(NORMAL, " FPGA firmware... %s", _RED_("chip mismatch")); } lookupChipID(payload->id, payload->section_size); + if (armsrc_mismatch) { + PrintAndLogEx(NORMAL, ""); + 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"); + } } } PrintAndLogEx(NORMAL, ""); 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 df115b7d0..c43d6fd28 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,13 @@ 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, 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; - 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 +100,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; @@ -148,11 +150,7 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr_t *phdr 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) { @@ -208,7 +206,8 @@ static int build_segs_from_phdrs(flash_file_t *ctx, FILE *fd, Elf32_Phdr_t *phdr } // 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]; @@ -236,92 +235,150 @@ 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) { +static int print_and_validate_version(struct version_information_t *vi) { + if (vi->magic != VERSION_INFORMATION_MAGIC) + return PM3_EFILE; + char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image + FormatVersionInformation(temp, sizeof(temp), "", vi); + PrintAndLogEx(SUCCESS, _CYAN_("ELF file version") _YELLOW_(" %s"), temp); + 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")); + return PM3_EINVARG; + } else { + return PM3_SUCCESS; + } + } + return PM3_EUNDEF; +} + +// Load an ELF file for flashing +int flash_load(flash_file_t *ctx, bool force) { FILE *fd; - Elf32_Ehdr_t ehdr; - Elf32_Phdr_t *phdrs = NULL; - uint16_t num_phdrs; - uint32_t flash_end = FLASH_START + flash_size; + Elf32_Ehdr_t *ehdr; + Elf32_Shdr_t *shdrs = NULL; + uint8_t *shstr = NULL; + struct version_information_t *vi = NULL; int res = PM3_EUNDEF; - fd = fopen(name, "rb"); + fd = fopen(ctx->filename, "rb"); if (!fd) { - PrintAndLogEx(ERR, _RED_("Could not open file") " %s >>> ", name); + PrintAndLogEx(ERR, _RED_("Could not open file") " %s >>> ", ctx->filename); res = PM3_EFILE; goto fail; } - PrintAndLogEx(SUCCESS, _CYAN_("Loading ELF file") _YELLOW_(" %s"), name); + PrintAndLogEx(SUCCESS, _CYAN_("Loading ELF file") _YELLOW_(" %s"), ctx->filename); - if (fread(&ehdr, sizeof(ehdr), 1, fd) != 1) { - PrintAndLogEx(ERR, "Error while reading ELF file header"); + // 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; } - if (memcmp(ehdr.e_ident, elf_ident, sizeof(elf_ident)) - || le32(ehdr.e_version) != 1) { + + 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) { + 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) { + if (le16(ehdr->e_machine) != EM_ARM) { PrintAndLogEx(ERR, "Wrong ELF architecture"); res = PM3_EFILE; goto fail; } - if (!ehdr.e_phnum || !ehdr.e_phoff) { + 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)) { + 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); + 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); - 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; + 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)); + res = print_and_validate_version(vi); + break; + } + if (strcmp(((char *)shstr) + shdrs[i].sh_name, ".bootphase1") == 0) { + uint32_t offset = *(uint32_t*)(ctx->elf + le32(shdrs[i].sh_offset) + le32(shdrs[i].sh_size) - 4); + if (offset >= le32(shdrs[i].sh_addr)) { + offset -= le32(shdrs[i].sh_addr); + if (offset < le32(shdrs[i].sh_size)) { + vi = (struct version_information_t *)(ctx->elf + le32(shdrs[i].sh_offset) + offset); + res = print_and_validate_version(vi); + } + } + break; + } } + if (res == PM3_SUCCESS) + return res; + // We could not find proper version_information + if (res == PM3_EUNDEF) + PrintAndLogEx(WARNING, "Unable to check version_information"); + if (force) + return PM3_SUCCESS; + PrintAndLogEx(INFO, "Make sure to flash a correct and up-to-date version"); + PrintAndLogEx(INFO, "You can force flashing this firmware by using the option '--force'"); +fail: + flash_free(ctx); + return res; +} - res = build_segs_from_phdrs(ctx, fd, phdrs, num_phdrs, flash_end); +// 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_end); + res = check_segs(ctx, can_write_bl, flash_size); 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); return res; } @@ -618,6 +675,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); diff --git a/client/src/flash.h b/client/src/flash.h index 518027b4f..5c2535620 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 @@ -31,13 +32,17 @@ 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; 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_load(flash_file_t *ctx, bool force); +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 f9e101469..26062f9d7 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -576,7 +576,8 @@ static void show_help(bool showFullHelp, char *exec_name) { PrintAndLogEx(NORMAL, " --incognito do not use history, prefs file nor log files"); PrintAndLogEx(NORMAL, "\nOptions in flasher mode:"); PrintAndLogEx(NORMAL, " --flash flash Proxmark3, requires at least one --image"); - PrintAndLogEx(NORMAL, " --unlock-bootloader Enable flashing of bootloader area *DANGEROUS* (need --flash or --flash-info)"); + 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, "\nExamples:"); PrintAndLogEx(NORMAL, "\n to run Proxmark3 client:\n"); @@ -602,12 +603,11 @@ static void show_help(bool showFullHelp, char *exec_name) { } } -static int flash_pm3(char *serial_port_name, uint8_t num_files, char *filenames[FLASH_MAX_FILES], bool can_write_bl) { +static int flash_pm3(char *serial_port_name, uint8_t num_files, char *filenames[FLASH_MAX_FILES], bool can_write_bl, bool force) { 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,12 +627,20 @@ 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_load(&files[i], force); + if (ret != PM3_SUCCESS) { + goto finish2; + } + PrintAndLogEx(NORMAL, ""); } if (OpenProxmark(&g_session.current_device, serial_port_name, true, 60, true, FLASHMODE_SPEED)) { @@ -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_prepare(&files[i], can_write_bl, max_allowed * ONE_KB); if (ret != PM3_SUCCESS) { goto finish; } @@ -667,22 +675,22 @@ 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, ""); } finish: if (ret != PM3_SUCCESS) - PrintAndLogEx(INFO, "The flashing procedure failed, follow the suggested steps!"); + PrintAndLogEx(WARNING, "The flashing procedure failed, follow the suggested steps!"); ret = flash_stop_flashing(); CloseProxmark(g_session.current_device); finish2: for (int i = 0 ; i < num_files; ++i) { - if (filepaths[i] != NULL) - free(filepaths[i]); + flash_free(&files[i]); } 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"); PrintAndLogEx(INFO, "\nHave a nice day!"); @@ -725,6 +733,7 @@ int main(int argc, char *argv[]) { bool flash_mode = false; bool flash_can_write_bl = false; + bool flash_force = false; bool debug_mode_forced = false; int flash_num_files = 0; char *flash_filenames[FLASH_MAX_FILES]; @@ -941,6 +950,12 @@ int main(int argc, char *argv[]) { continue; } + // force flash even if firmware seems to not match client version + if (strcmp(argv[i], "--force") == 0) { + flash_force = true; + continue; + } + // flash file if (strcmp(argv[i], "--image") == 0) { if (flash_num_files == FLASH_MAX_FILES) { @@ -982,7 +997,7 @@ int main(int argc, char *argv[]) { speed = USART_BAUD_RATE; if (flash_mode) { - flash_pm3(port, flash_num_files, flash_filenames, flash_can_write_bl); + flash_pm3(port, flash_num_files, flash_filenames, flash_can_write_bl, flash_force); exit(EXIT_SUCCESS); } diff --git a/common/commonutil.c b/common/commonutil.c index a3e026dd1..310578233 100644 --- a/common/commonutil.c +++ b/common/commonutil.c @@ -49,6 +49,8 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers strncat(dst, " ", len - strlen(dst) - 1); strncat(dst, v->buildtime, len - strlen(dst) - 1); + strncat(dst, " ", len - strlen(dst) - 1); + strncat(dst, v->armsrc, len - strlen(dst) - 1); } /* diff --git a/common/default_version_pm3.c b/common/default_version_pm3.c index d2a1deb83..46eac57c9 100644 --- a/common/default_version_pm3.c +++ b/common/default_version_pm3.c @@ -14,7 +14,7 @@ // See LICENSE.txt for the text of the license. //----------------------------------------------------------------------------- #include "common.h" -/* This is the default version_pm3.c file that Makefile.common falls back to if neither sh nor perl are available */ +/* This is the default version_pm3.c file that Makefile.common falls back to if sh is not available */ #ifndef ON_DEVICE #define SECTVERSINFO #else diff --git a/include/common.h b/include/common.h index 2e245da43..22c7a90e7 100644 --- a/include/common.h +++ b/include/common.h @@ -53,6 +53,7 @@ struct version_information_t { char clean; /* 1: Tree was clean, no local changes. 0: Tree was unclean. 2: Couldn't be determined */ char gitversion[50]; /* String with the git revision */ char buildtime[30]; /* string with the build time */ + char armsrc[10]; /* sha256sum of sha256sum of armsrc files */ } PACKED; // debug diff --git a/pm3 b/pm3 index ab2d9e3b7..e4469cd29 100755 --- a/pm3 +++ b/pm3 @@ -288,6 +288,8 @@ elif [ "$SCRIPT" = "pm3-flash" ]; then while [ "$1" != "" ]; do if [ "$1" == "-b" ]; then ARGS+=("--unlock-bootloader") + elif [ "$1" == "--force" ]; then + ARGS+=("--force") else ARGS+=("--image" "$1") fi @@ -320,7 +322,19 @@ elif [ "$SCRIPT" = "pm3-flash-all" ]; then FINDBTDONGLE=false FINDBTRFCOMM=false FINDBTDIRECT=false - CMD() { $CLIENT "--port" "$1" "--flash" "--unlock-bootloader" "--image" "$BOOTIMAGE" "--image" "$FULLIMAGE"; } + + + CMD() { + ARGS=("--port" "$1" "--flash" "--unlock-bootloader" "--image" "$BOOTIMAGE" "--image" "$FULLIMAGE") + shift; + while [ "$1" != "" ]; do + if [ "$1" == "--force" ]; then + ARGS+=("--force") + fi + shift; + done + $CLIENT "${ARGS[@]}"; + } HELP() { cat << EOF Quick helper script for flashing a Proxmark device via USB @@ -340,7 +354,17 @@ elif [ "$SCRIPT" = "pm3-flash-fullimage" ]; then FINDBTDONGLE=false FINDBTRFCOMM=false FINDBTDIRECT=false - CMD() { $CLIENT "--port" "$1" "--flash" "--image" "$FULLIMAGE"; } + CMD() { + ARGS=("--port" "$1" "--flash" "--image" "$FULLIMAGE") + shift; + while [ "$1" != "" ]; do + if [ "$1" == "--force" ]; then + ARGS+=("--force") + fi + shift; + done + $CLIENT "${ARGS[@]}"; + } HELP() { cat << EOF Quick helper script for flashing a Proxmark device via USB @@ -360,7 +384,17 @@ elif [ "$SCRIPT" = "pm3-flash-bootrom" ]; then FINDBTDONGLE=false FINDBTRFCOMM=false FINDBTDIRECT=false - CMD() { $CLIENT "--port" "$1" "--flash" "--unlock-bootloader" "--image" "$BOOTIMAGE"; } + CMD() { + ARGS=("--port" "$1" "--flash" "--unlock-bootloader" "--image" "$BOOTIMAGE") + shift; + while [ "$1" != "" ]; do + if [ "$1" == "--force" ]; then + ARGS+=("--force") + fi + shift; + done + $CLIENT "${ARGS[@]}"; + } HELP() { cat << EOF Quick helper script for flashing a Proxmark device via USB diff --git a/tools/mkversion.pl b/tools/mkversion.pl deleted file mode 100755 index 9f47a355b..000000000 --- a/tools/mkversion.pl +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/perl -w - -# Output a version_pm3.c file that includes information about the current build -# Normally a couple of lines of bash would be enough (see openpcd project, original firmware by Harald Welte and Milosch Meriac) -# but this will, at least in theory, also work on Windows with our current compile environment. -# -- Henryk Plötz 2009-09-28 -# Modified april 2014 because of the move to github. -# --- Martin Holst Swende -# Modified january 2016 to work with Travis-CI -# --- iceman - -# Clear environment locale so that git will not use localized strings -$ENV{'LC_ALL'} = "C"; -$ENV{'LANG'} = "C"; - -# if you are making your own fork, change this line to reflect your fork-name -my $fullgitinfo = 'RRG/Iceman'; -my $ctime; -# GIT status 0 = dirty, 1 = clean , 2 = undecided -my $clean = 2; -my $undecided = (defined $ARGV[0]) && ($ARGV[0] =~ '--undecided'); -# Do we have access to git command? -####### -# solves some bug on macos i.e: -## -# perl ../tools/mkversion.pl .. > version_pm3.c || cp ../common/default_version_pm3.c version_pm3.c -# /usr/bin/which: /usr/bin/which: cannot execute binary file -# fatal: No names found, cannot describe anything. -## -# anyway forcing any kind of shell is at least useless, at worst fatal. -my $commandGIT = "env which git"; - -if ( defined($commandGIT) ) { - - # this goes on Internet and cause major slowdowns on poor connections or intranets, let's comment it - #my $githistory = `git fetch --all`; - # now avoiding the "fatal: No names found, cannot describe anything." error by fallbacking to abbrev hash in such case - my $gitversion = `git describe --dirty --always`; - my $gitbranch = `git rev-parse --abbrev-ref HEAD`; - if (not $undecided) { - $clean = $gitversion =~ '-dirty' ? 0 : 1; - } - if ( defined($gitbranch) and defined($gitversion) ) { - $fullgitinfo = $fullgitinfo.'/'. $gitbranch . '/' . $gitversion; - - my @compiletime = localtime(); - $compiletime[4] += 1; - $compiletime[5] += 1900; - $ctime = sprintf("%6\$04i-%5\$02i-%4\$02i %3\$02i:%2\$02i:%1\$02i", @compiletime); - } else { - $fullgitinfo = $fullgitinfo.'/master/release (git)'; - } -} else { - $fullgitinfo = $fullgitinfo.'/master/release (no_git)'; - my @dl_time = localtime( (stat('../README.md'))[10] ); - $dl_time[4] += 1; - $dl_time[5] += 1900; - $ctime = sprintf("%6\$04i-%5\$02i-%4\$02i %3\$02i:%2\$02i:%1\$02i", @dl_time); -} - -$fullgitinfo =~ s/(\s)//g; - -# Crop so it fits within 50 characters -#$fullgitinfo =~ s/.{50}\K.*//s; -$fullgitinfo = substr $fullgitinfo, 0, 49; - -print <