1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#!/usr/bin/env python3
"""Wrap a raw ARM/Thumb firmware image in a minimal ELF32 so IDA auto-detects
processor (EM_ARM), load address, and Thumb entry — no CLI / no -parm needed.
usage: mkelf.py <raw.bin> <base_hex> <out.elf> [--arm]
"""
import struct, sys, os
def mkelf(raw: bytes, base: int, thumb: bool = True) -> bytes:
EHSIZE, PHENTSIZE = 52, 32
DATA_OFF = 0x1000
entry = base | (1 if thumb else 0) # bit0 set => Thumb entry
eh = b'\x7fELF' # magic
eh += bytes([1, 1, 1, 0, 0]) # 32-bit, LSB, ELFv1, SysV ABI
eh += b'\x00' * 7
eh += struct.pack('<HHI', 2, 40, 1) # ET_EXEC, EM_ARM, version
eh += struct.pack('<III', entry, EHSIZE, 0) # entry, phoff, shoff
eh += struct.pack('<I', 0x05000000) # EF_ARM_EABI_VER5
eh += struct.pack('<HHHHHH', EHSIZE, PHENTSIZE, 1, 0, 0, 0)
ph = struct.pack('<IIIIIIII', 1, DATA_OFF, base, base,
len(raw), len(raw), 7, 0x1000) # PT_LOAD, RWX
out = bytearray(eh + ph)
out += b'\x00' * (DATA_OFF - len(out))
out += raw
return bytes(out)
if __name__ == '__main__':
raw_p, base_s, out_p = sys.argv[1], sys.argv[2], sys.argv[3]
thumb = '--arm' not in sys.argv
data = open(raw_p, 'rb').read()
open(out_p, 'wb').write(mkelf(data, int(base_s, 16), thumb))
print(f"{os.path.basename(raw_p)} -> {os.path.basename(out_p)} "
f"base={base_s} thumb={thumb} size={len(data):,}")
|