69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Linear-sweep Thumb disassembly of DA14585 firmware.
|
|
|
|
Code region = file[0x40:], mapped base 0x07FC0000.
|
|
- 16KB-aligned linear sweep; on decode failure emit .word and resync (+2).
|
|
- Function prologue detection: PUSH {...,lr} (encoding 0xB5xx).
|
|
Output: analysis/firmware/fw.asm (addr: bytes mnemonic [;;FUNC markers])
|
|
"""
|
|
from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB, CS_MODE_LITTLE_ENDIAN
|
|
|
|
IMG = "app/firmware-PP_da14585_4.2_CH.img"
|
|
OUT = "analysis/firmware/fw.asm"
|
|
BASE = 0x07FC0000
|
|
HDR = 0x40
|
|
|
|
def main():
|
|
data = open(IMG, "rb").read()[HDR:]
|
|
md = Cs(CS_ARCH_ARM, CS_MODE_THUMB | CS_MODE_LITTLE_ENDIAN)
|
|
md.detail = False
|
|
|
|
out = open(OUT, "w")
|
|
out.write(f"; DA14585 firmware linear sweep, base 0x{BASE:08x}, {len(data)} bytes\n")
|
|
off = 0
|
|
n_ins = 0
|
|
n_bad = 0
|
|
funcs = []
|
|
while off < len(data):
|
|
chunk = data[off:off+0x2000]
|
|
addr = BASE + off
|
|
consumed = 0
|
|
for ins in md.disasm(chunk, addr):
|
|
# skip if disassembler resync'd mid-chunk oddly
|
|
if ins.address < addr + consumed:
|
|
continue
|
|
# fill any gap (undecodable bytes) with .word
|
|
gap = ins.address - (addr + consumed)
|
|
while gap > 0:
|
|
g = addr + consumed
|
|
raw = data[off+consumed:off+consumed+2]
|
|
if len(raw) == 2:
|
|
w = raw[0] | raw[1] << 8
|
|
out.write(f"0x{g:08x}: {w:04x} .word 0x{w:04x}\n")
|
|
else:
|
|
out.write(f"0x{g:08x}: {raw.hex():<9s} .byte {raw.hex()}\n")
|
|
consumed += 2
|
|
gap -= 2
|
|
n_bad += 1
|
|
b = ins.bytes
|
|
# prologue: PUSH {...,lr} => 0xB5xx ; also push {lr} alone? (B500)
|
|
mark = ""
|
|
if len(b) == 2 and b[1] == 0xB5:
|
|
mark = " ;;FUNC"
|
|
funcs.append(ins.address)
|
|
out.write(f"0x{ins.address:08x}: {b.hex():<9s} {ins.mnemonic} {ins.op_str}{mark}\n")
|
|
consumed = ins.address + ins.size - addr
|
|
n_ins += 1
|
|
off += consumed if consumed else 2
|
|
if consumed == 0:
|
|
n_bad += 1
|
|
out.write(f"; instructions={n_ins} badwords={n_bad} functions={len(funcs)}\n")
|
|
out.close()
|
|
print(f"instructions={n_ins} badwords={n_bad} prologues={len(funcs)}")
|
|
with open("analysis/firmware/funcs.txt", "w") as f:
|
|
for a in funcs:
|
|
f.write(f"0x{a:08x}\n")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|