#!/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(" {os.path.basename(fn)}") open(f"{out}/info.txt", "w").write("\n".join(info) + "\n"); print("\n".join(info))