docs(legacy): ImHex patterns for v2 trezor.bin, v1+v2 combined trezor.bin and bootloader binary images
[no changelog]pull/2597/head
parent
e4bc37f10b
commit
09ebe29369
@ -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)
|
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…
Reference in new issue