mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-05 14:22:33 +00:00
docs(legacy): ImHex patterns for v2 trezor.bin, v1+v2 combined trezor.bin and bootloader binary images
[no changelog]
This commit is contained in:
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.
|
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.
|
||||||
|
|
||||||
|
37
legacy/imhex/README.md
Normal file
37
legacy/imhex/README.md
Normal file
@ -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
|
||||||
|
|
||||||
|

|
BIN
legacy/imhex/imhex_screenshot.png
Normal file
BIN
legacy/imhex/imhex_screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 KiB |
9
legacy/imhex/t1_bootloader_bin.hexpat
Normal file
9
legacy/imhex/t1_bootloader_bin.hexpat
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma base_address 0x8000000
|
||||||
|
|
||||||
|
#include "t1_firmware.pat"
|
||||||
|
|
||||||
|
u32 VTOR = base();
|
||||||
|
|
||||||
|
VectorTable vector_table @ VTOR;
|
||||||
|
|
||||||
|
|
91
legacy/imhex/t1_firmware.pat
Normal file
91
legacy/imhex/t1_firmware.pat
Normal file
@ -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")]];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
15
legacy/imhex/t1_firmware_trezor_bin_v2.hexpat
Normal file
15
legacy/imhex/t1_firmware_trezor_bin_v2.hexpat
Normal file
@ -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");
|
||||||
|
|
||||||
|
|
30
legacy/imhex/t1_firmware_v1+v2.hexpat
Normal file
30
legacy/imhex/t1_firmware_v1+v2.hexpat
Normal file
@ -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…
Reference in New Issue
Block a user