Sanitized research log, build/reproducibility docs, DTS, kernel configs, patches, initramfs sources, bootchain migration plans and test logs. B5 direct boot PASS; B6 modem lifecycle in progress. No dumps, NV/EFS, vendor firmware or device identifiers included.
29 lines
2 KiB
Python
29 lines
2 KiB
Python
#!/usr/bin/env python3
|
|
# Android boot.img v0 (+ Qualcomm QCDT in dt_size field) unpacker. Read-only on input.
|
|
import struct, sys, os, hashlib
|
|
src, out = sys.argv[1], sys.argv[2]; os.makedirs(out, exist_ok=True)
|
|
d = open(src, "rb").read()
|
|
assert d[:8] == b"ANDROID!", "not a boot image"
|
|
(ks, ka, rs, ra, ss, sa, ta, ps, dts, _u) = struct.unpack_from("<10I", d, 8)
|
|
name = d[48:64].rstrip(b"\0"); cmd = d[64:576].split(b"\0")[0]; idh = d[576:608]; extra = d[608:1632]
|
|
pg = lambda n: (n + ps - 1) // ps * ps
|
|
o = ps; kern = d[o:o+ks]; o += pg(ks); rd = d[o:o+rs]; o += pg(rs); sec = d[o:o+ss]; o += pg(ss); dt = d[o:o+dts]; o += pg(dts)
|
|
info = [f"kernel_size={ks:#x} kernel_addr={ka:#x}", f"ramdisk_size={rs:#x} ramdisk_addr={ra:#x}",
|
|
f"second_size={ss:#x} tags_addr={ta:#x} page_size={ps}", f"dt_size={dts:#x}", f"name={name!r}",
|
|
f"cmdline={cmd.decode(errors='replace')}", f"id={idh.hex()}",
|
|
f"extra_cmdline_first_bytes={extra[:32].hex()} (nonzero={any(extra)})", f"image_end={o:#x} of {len(d):#x}",
|
|
f"tail_after_image_nonzero={len(d[o:]) - d[o:].count(0)}"]
|
|
for n, b in (("kernel", kern), ("ramdisk", rd), ("second", sec), ("dt.img", dt)):
|
|
if b: open(f"{out}/{n}", "wb").write(b); info.append(f"{n}: {len(b)} bytes sha256 {hashlib.sha256(b).hexdigest()}")
|
|
# appended DTBs in zImage?
|
|
k = kern.find(b"\xd0\x0d\xfe\xed"); info.append(f"first FDT magic in kernel at {k:#x}" if k >= 0 else "no FDT magic in kernel (no appended DTB)")
|
|
if dt[:4] == b"QCDT":
|
|
ver, n = struct.unpack_from("<II", dt, 4); info.append(f"QCDT version={ver} entries={n}")
|
|
esz = {1: 20, 2: 24, 3: 40}[ver]; seen = {}
|
|
for i in range(n):
|
|
f = struct.unpack_from("<" + "I" * (esz // 4), dt, 12 + i * esz)
|
|
off, sz = f[-2], f[-1]; blob = dt[off:off+sz]
|
|
fn = seen.setdefault(off, f"{out}/dtb_{len(seen):02d}.dtb")
|
|
open(fn, "wb").write(blob)
|
|
info.append(f" entry{i}: fields={[hex(x) for x in f[:-2]]} off={off:#x} size={sz:#x} -> {os.path.basename(fn)}")
|
|
open(f"{out}/info.txt", "w").write("\n".join(info) + "\n"); print("\n".join(info))
|