diff --git a/docs/legacy/index.md b/docs/legacy/index.md index 374f9682d..49f9c59fc 100644 --- a/docs/legacy/index.md +++ b/docs/legacy/index.md @@ -125,3 +125,10 @@ This table shows the result for bootloader 1.8.0+ and 1.9.1+: The other three possibilities with signed firmware and `PRODUCTION!=0` for bootloader/firmware don't exist. +## Parsing existing T1 binary images with ImHex + +There is multi-platform hex editor [ImHex](https://github.com/WerWolv/ImHex) ([another link](https://imhex.werwolv.net/)) +that allows for parsing firmware images we distribute such as those from https://github.com/trezor/data/tree/master/firmware + +See `legacy/imhex/` directory in repo and `README.md` there how to use it to parse headers from existing images. + diff --git a/legacy/imhex/README.md b/legacy/imhex/README.md new file mode 100644 index 000000000..97d6a6132 --- /dev/null +++ b/legacy/imhex/README.md @@ -0,0 +1,37 @@ +# ImHex patterns for T1 firmware images + +ImHex is multiplatform hex editor, with ability to parse binary files +based on patterns. + +Here are patterns for decoding binary images, there are 3 types: + +1. firmware with both headers (TRZR and TRZF) which we distribute - `t1_firmware_v1+v2.hexpat` +2. firmware built from git (TRZF header) - `t1_firmware_trezor_bin_v2.hexpat` +3. bootloader - `t1_bootloader_bin.hexpat` + +## Using ImHex with these patterns + +Download ImHex from https://github.com/WerWolv/ImHex or https://imhex.werwolv.net/ + +### First download base library + +You must download standard libraries via menu +`Help->Content Store->Libraries` + +### Opening T1 firmware images + +In this directory, run `imhex /path/to/some_firmware.bin` (so that patterns can be +found in current directory with includes). + +Open pattern via `File->Load Pattern->Browse...` or add the patterns to existing +pattern directories so that you can load without using browse. Pattern dirs are +XDG-BASED, so your dir depending on installation will be something like + +* `/usr/share/imhex/patterns` +* `.local/share/imhex/patterns` + +or see [where the directories are for other OSes](https://hackersonlineclub.com/imhex-hex-editor-for-reverse-engineers-and-programmers/). + +## Sample screenshot + +![ImHex screenshot](imhex_screenshot.png) diff --git a/legacy/imhex/imhex_screenshot.png b/legacy/imhex/imhex_screenshot.png new file mode 100644 index 000000000..5a8494430 Binary files /dev/null and b/legacy/imhex/imhex_screenshot.png differ diff --git a/legacy/imhex/t1_bootloader_bin.hexpat b/legacy/imhex/t1_bootloader_bin.hexpat new file mode 100644 index 000000000..8a94b0b79 --- /dev/null +++ b/legacy/imhex/t1_bootloader_bin.hexpat @@ -0,0 +1,9 @@ +#pragma base_address 0x8000000 + +#include "t1_firmware.pat" + +u32 VTOR = base(); + +VectorTable vector_table @ VTOR; + + diff --git a/legacy/imhex/t1_firmware.pat b/legacy/imhex/t1_firmware.pat new file mode 100644 index 000000000..9d34dc00f --- /dev/null +++ b/legacy/imhex/t1_firmware.pat @@ -0,0 +1,91 @@ +#pragma once +#pragma endian little + +// You must download standard libraries via menu +// Help->Content Store->Libraries + +#include +#include +#include + +#define FW_MAGIC_OLD "TRZR" +#define FW_MAGIC_NEW "TRZF" + +struct ImageHeader_v1 { + char magic_old[4]; + u32 code_length; + u8 key_indexes[3]; + u8 flags; + u8 __reserved1[52]; + u8 sig1[64]; + u8 sig2[64]; + u8 sig3[64]; +}; + +struct ImageHeader_v2 { + char magic_new[4]; + u32 hdrlen_or_reset_handler_thumb; + u32 expiry; + u32 codelen; + u32 version; + u32 fix_version; + u8 __reserved1[8]; + u8 hashes[512]; + u8 sig1[64]; + u8 sig2[64]; + u8 sig3[64]; + u8 sigindex1; + u8 sigindex2; + u8 sigindex3; + u8 __reserved2[220]; + u8 __sigmask; + u8 __sig[64]; +}; + +fn base() { + return std::mem::base_address(); +}; + +//#define VTOR (base()+0x500) + //0x8010400 + +bitfield ARMAddress { + ThumbMode : 1; + Address : 31 [[transform("address_transform")]]; +} [[right_to_left]]; + +fn address_transform(u32 value) { + return value << 1; +}; + +fn address_mask(u32 value) { + return value & 0xFFFFFFFE; +}; + +using Address = u32; + +struct Exceptions { + Address reset [[name("Reset Handler"), transform("address_mask")]]; + // size is just estimate so that it highlights some bytes + u8 reset_function[256] @ reset; + Address nmi [[name("Non-maskable Interrupt Handler")]]; + Address hard_fault [[name("HardFault Handler")]]; + Address mem_manage [[name("Memory Protection Error Handler")]]; + Address bus_fault [[name("Bus Fault Handler")]]; + Address usage_fault [[name("UsageFault (Instruction Execution fault) Handler")]]; + Address reserved_1[4] [[hidden]]; + Address sv_call [[name("Synchronous Supervisor Call (SVC Instruction) Handler")]]; + Address debug_monitor [[name("Synchronous Debug Event Handler")]]; + Address reserved_2[1] [[hidden]]; + Address pend_sv [[name("Asynchronous Supervisor Call Handler")]]; + Address sys_tick [[name("System Timer Tick Handler")]]; +}; + +struct VectorTable { + Address initial_sp [[name("Initial Stack Pointer Value")]]; + Exceptions exceptions [[inline, name("Exceptions")]]; +}; + + + + diff --git a/legacy/imhex/t1_firmware_trezor_bin_v2.hexpat b/legacy/imhex/t1_firmware_trezor_bin_v2.hexpat new file mode 100644 index 000000000..5adce9a55 --- /dev/null +++ b/legacy/imhex/t1_firmware_trezor_bin_v2.hexpat @@ -0,0 +1,15 @@ +#pragma base_address 0x8010000 + +#include "t1_firmware.pat" + +u32 V2_HEADER_BASE = base(); +u32 VTOR = V2_HEADER_BASE + 0x400; + +#define FW_MAGIC_NEW "TRZF" + +ImageHeader_v2 header_v2 @ V2_HEADER_BASE; +VectorTable vector_table @ VTOR; + +std::assert(header_v2.magic_new == FW_MAGIC_NEW, "Wrong NEW magic, expected TRFZ at start"); + + diff --git a/legacy/imhex/t1_firmware_v1+v2.hexpat b/legacy/imhex/t1_firmware_v1+v2.hexpat new file mode 100644 index 000000000..1bf715cdc --- /dev/null +++ b/legacy/imhex/t1_firmware_v1+v2.hexpat @@ -0,0 +1,30 @@ +#pragma base_address 0x800FF00 + +#include "t1_firmware.pat" + +u32 V1_HEADER_BASE = base(); +u32 V2_HEADER_BASE = base() + 0x100; +u32 VTOR = V2_HEADER_BASE + 0x400; + +#define FW_MAGIC_OLD "TRZR" +#define FW_MAGIC_NEW "TRZF" + +ImageHeader_v1 header_v1 @ V1_HEADER_BASE; +ImageHeader_v2 header_v2 @ V2_HEADER_BASE; +VectorTable vector_table @ VTOR; + +// this could be out of bounds, just warn if VTOR and old pre-1.8.0 bootloader +// reset handlers are not the same +u32 reset_start_v1 = (header_v2.hdrlen_or_reset_handler_thumb & 0xFFFFFFFE); +if (reset_start_v1 != (vector_table.exceptions.reset)) { + std::print("v1 reset handler differs from VTOR"); +}; + +// another possible declaration of exception handler with masking +// u8 reset_start_vtor[256] @ (vector_table.exceptions.reset & 0xFFFFFFFE); +// declaration via ptr, needs mask out Thumb bit +// u8 *reset_start_v1_ptr : u32 @ (V2_HEADER_BASE + 0x4); + +std::assert(header_v1.magic_old == FW_MAGIC_OLD, "Wrong OLD magic"); +std::assert(header_v2.magic_new == FW_MAGIC_NEW, "Wrong NEW magic"); +