Files

48 lines
1.6 KiB
Python

"""Scan a binary blob for MZ markers, validate as PE, dump each as separate file."""
import struct, sys, pathlib
blob_path = pathlib.Path(sys.argv[1])
out_dir = pathlib.Path(sys.argv[2])
out_dir.mkdir(parents=True, exist_ok=True)
data = blob_path.read_bytes()
def pe_total_size(buf, off):
"""Compute size of PE image at offset using section table."""
# MZ at off; PE header offset at off+0x3C
if off + 0x40 > len(buf):
return None
pe_off = struct.unpack_from("<I", buf, off + 0x3C)[0]
pe_start = off + pe_off
if pe_start + 24 > len(buf) or buf[pe_start:pe_start+4] != b"PE\x00\x00":
return None
num_sections = struct.unpack_from("<H", buf, pe_start + 6)[0]
optional_header_size = struct.unpack_from("<H", buf, pe_start + 20)[0]
sections_start = pe_start + 24 + optional_header_size
last_end = sections_start + num_sections * 40
for i in range(num_sections):
s = sections_start + i * 40
raw_size = struct.unpack_from("<I", buf, s + 16)[0]
raw_off = struct.unpack_from("<I", buf, s + 20)[0]
end = off + raw_off + raw_size
last_end = max(last_end, end)
return last_end - off
i = 0
n = 0
while True:
j = data.find(b"MZ", i)
if j == -1:
break
sz = pe_total_size(data, j)
if sz and 4096 < sz < 5_000_000:
out = out_dir / f"plain_{j:08x}.dll"
out.write_bytes(data[j:j+sz])
print(f"[ok] offset=0x{j:08x} size={sz} -> {out.name}")
n += 1
i = j + sz
else:
i = j + 2
print(f"\nExtracted {n} plain PE files into {out_dir}")