#!/usr/bin/env python3
"""Extrait l'image mémoire complète d'un module depuis un minidump.
Reconstitue [base, base+SizeOfImage) à partir des régions Memory64, trous en zéros."""
import struct, sys, mmap

def main(dmp, want):
    f = open(dmp, "rb")
    m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
    nst, dr = struct.unpack_from("<II", m, 8)
    st = {}
    for i in range(nst):
        t, s, r = struct.unpack_from("<III", m, dr + i * 12)
        st[t] = (s, r)

    _, rva = st[4]
    n = struct.unpack_from("<I", m, rva)[0]
    target = None
    for i in range(n):
        o = rva + 4 + i * 108
        base, size, nr = struct.unpack_from("<QII", m, o)[0], \
                         struct.unpack_from("<I", m, o + 8)[0], \
                         struct.unpack_from("<I", m, o + 20)[0]
        ln = struct.unpack_from("<I", m, nr)[0]
        nm = m[nr + 4:nr + 4 + ln].decode("utf-16-le", "replace").split("\\")[-1]
        if nm.lower() == want.lower():
            target = (base, size, nm)
    if not target:
        print("module introuvable"); return
    base, size, nm = target
    print(f"{nm}  base=0x{base:x}  taille=0x{size:x} ({size/1048576:.1f} Mo)")

    _, rva = st[9]
    nr, br = struct.unpack_from("<QQ", m, rva)
    out = bytearray(size)
    got, off = 0, br
    for i in range(nr):
        s, sz = struct.unpack_from("<QQ", m, rva + 16 + i * 16)
        a, b = max(s, base), min(s + sz, base + size)
        if a < b:
            out[a - base:b - base] = m[off + (a - s): off + (a - s) + (b - a)]
            got += b - a
        off += sz
    open(sys.argv[3], "wb").write(out)
    print(f"couverture : {got/size*100:.1f} %  ({got/1048576:.1f} Mo présents)")
    print(f"écrit → {sys.argv[3]}")

main(sys.argv[1], sys.argv[2])
