docs(legacy): ImHex patterns for v2 trezor.bin, v1+v2 combined trezor.bin and bootloader binary images

[no changelog]
pull/2597/head
Ondrej Mikle 2 years ago committed by matejcik
parent e4bc37f10b
commit 09ebe29369

@ -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.

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

@ -0,0 +1,9 @@
#pragma base_address 0x8000000
#include "t1_firmware.pat"
u32 VTOR = base();
VectorTable vector_table @ VTOR;

@ -0,0 +1,91 @@
#pragma once
#pragma endian little
// You must download standard libraries via menu
// Help->Content Store->Libraries
#include <std/io.pat>
#include <std/mem.pat>
#include <std/sys.pat>
#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")]];
};

@ -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");

@ -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");
Loading…
Cancel
Save