diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-31 02:55:10 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-31 02:55:10 +0200 |
| commit | 1963a0a6d7398a426d0701f90a5bc796e32899ae (patch) | |
| tree | 8294a30acd2c8bb0d0ff98ebaee14f9667cbcc6d /fix_pe_simple.py | |
| download | rsboot-1963a0a6d7398a426d0701f90a5bc796e32899ae.tar.gz rsboot-1963a0a6d7398a426d0701f90a5bc796e32899ae.zip | |
feat(rsboot): initial commit — UEFI bootloader extracted from RNG
Diffstat (limited to 'fix_pe_simple.py')
| -rw-r--r-- | fix_pe_simple.py | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/fix_pe_simple.py b/fix_pe_simple.py new file mode 100644 index 0000000..77b1366 --- /dev/null +++ b/fix_pe_simple.py | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | """fix_pe_simple.py — PE header fixup for PIE-built UEFI bootloader | ||
| 3 | |||
| 4 | The -fPIE-built bootloader uses only PC-relative addressing, so it needs | ||
| 5 | zero absolute fixups. This script just sets proper PE flags: | ||
| 6 | |||
| 7 | - ImageBase (env IMAGE_BASE, default 0x10000000) | ||
| 8 | - Characteristics = 0x022e (RELOCS_STRIPPED) | ||
| 9 | - DllChar = 0x0160 (NX | DYNAMIC_BASE | HIGH_ENTROPY_VA) | ||
| 10 | - Clears .reloc DD (no relocations needed) | ||
| 11 | - Clears checksum (not signed) | ||
| 12 | """ | ||
| 13 | |||
| 14 | import struct, os, sys | ||
| 15 | |||
| 16 | def fix_pe(path): | ||
| 17 | try: | ||
| 18 | with open(path, 'rb') as f: | ||
| 19 | d = bytearray(f.read()) | ||
| 20 | except IOError as e: | ||
| 21 | print(f" ERROR: cannot read {path}: {e}") | ||
| 22 | return False | ||
| 23 | |||
| 24 | po = struct.unpack('<I', d[0x3C:0x40])[0] | ||
| 25 | if d[po:po+4] != b'PE\x00\x00': | ||
| 26 | print(f" Not a PE file") | ||
| 27 | return False | ||
| 28 | |||
| 29 | coff = po + 4 | ||
| 30 | opt = po + 24 | ||
| 31 | |||
| 32 | magic = struct.unpack('<H', d[opt:opt+2])[0] | ||
| 33 | if magic != 0x20b: | ||
| 34 | print(f" Not PE32+") | ||
| 35 | return False | ||
| 36 | |||
| 37 | ib_env = os.environ.get('IMAGE_BASE', '0x10000000') | ||
| 38 | img_base = int(ib_env, 16) if ib_env.startswith('0x') else 0x10000000 | ||
| 39 | struct.pack_into('<Q', d, opt+24, img_base) | ||
| 40 | struct.pack_into('<H', d, coff+18, 0x022e) | ||
| 41 | struct.pack_into('<H', d, opt+70, 0x0160) | ||
| 42 | struct.pack_into('<I', d, coff+8, 0) | ||
| 43 | struct.pack_into('<I', d, coff+12, 0) | ||
| 44 | struct.pack_into('<I', d, opt+64, 0) | ||
| 45 | |||
| 46 | dd = opt + 112 | ||
| 47 | struct.pack_into('<II', d, dd + 5*8, 0, 0) | ||
| 48 | |||
| 49 | try: | ||
| 50 | with open(path, 'wb') as f: | ||
| 51 | f.write(d) | ||
| 52 | except IOError as e: | ||
| 53 | print(f" ERROR: cannot write {path}: {e}") | ||
| 54 | return False | ||
| 55 | |||
| 56 | print(f" Fixed: ImageBase={img_base:#010x} char=0x022e dll=0x0160 reloc=cleared") | ||
| 57 | return True | ||
| 58 | |||
| 59 | if __name__ == '__main__': | ||
| 60 | if len(sys.argv) < 2: | ||
| 61 | print(f"Usage: IMAGE_BASE=0x... {sys.argv[0]} <pe-path>") | ||
| 62 | sys.exit(1) | ||
| 63 | if not fix_pe(sys.argv[1]): | ||
| 64 | sys.exit(1) | ||
