A community-driven registry for Claude, Cursor, Windsurf, Cline & more. Not affiliated with Anthropic.
Are you the author? Sign in to claim
Recover and statically analyze manually-mapped DLLs whose PE headers are wiped at runtime. Pure-stdlib Python, no driver
Recover and statically analyze manually-mapped DLLs whose PE headers are
wiped at runtime. Works against any process you can OpenProcess() on. No
driver, no debugger, no symbols required. Pure-stdlib Python 3.
Common targets: malware loaders, in-process implants, packers, anti-cheat modules, and any other code mapped by a custom user-mode loader rather than the Windows loader.
Authorized use only. Only point this at processes you own or are explicitly authorized to analyze (your own code, malware in a lab, samples from a sandbox). Don't use it against software you don't have rights to.
Manually-mapped DLLs commonly:
MZ / PE\0\0 headers post-DllMain so a casual memory scan
doesn't see themA normal dumper (scylla, pe-sieve) finds them inconsistently or not at
all when the headers are gone. PEReconstruct finds the regions by their
runtime characteristics (executable + private) and forges a synthetic PE
header so IDA can analyze the dump as a normal DLL.
┌─────────────────────────────────┐
│ Target process (running) │
│ PID = whatever │
└────────────┬────────────────────┘
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────────┐ ┌────────────────────┐
│ scan_exec_ │ │ scan_pe_deep.py │ │ dump_manualmap.py │
│ private.py │ │ │ │ │
│ │ │ Aggressive PE-sig │ │ Looks for MZ at │
│ Lists every RX │ │ sweep — finds wiped │ │ region start (the │
│ MEM_PRIVATE │ │ DLLs by their PE\0\0 │ │ "well-behaved" │
│ region. The big │ │ at +e_lfanew. │ │ case where headers │
│ one (~1-10 MB, │ │ Catches anti-dumping │ │ survive). │
│ entropy ~7) is │ │ tricks where MZ is │ │ │
│ usually it. │ │ zeroed but PE isn't. │ │ │
└────────┬─────────┘ └──────────┬───────────┘ └─────────┬──────────┘
│ │ │
└───────────────────────┼────────────────────────┘
│ (you pick the right region from the surveys)
▼
┌────────────────────────────────┐
│ raw .bin file on disk │
│ "execpriv_<HEX_BASE>_ │
│ 0x<SIZE>.bin" │
│ filename encodes runtime VA │
│ you'll feed to step 3. │
└────────────┬───────────────────┘
│
▼
┌────────────────────────────────┐
│ rebuild_headerless.py │
│ │
│ Forges a synthetic PE header │
│ in the first 0x1000 bytes: │
│ - DOS stub │
│ - PE32+ NT headers │
│ - Single .text section RX │
│ covering the whole image. │
└────────────┬───────────────────┘
│
▼
┌────────────────────────────────┐
│ <name>_reconstructed.dll │
│ (loadable PE — open in IDA) │
└────────────┬───────────────────┘
│
▼
┌────────────────────────────────┐
│ analyze_hooks.py │
│ resolve_exports.py │
│ │
│ Reconstruct the IAT from │
│ absolute addresses found in │
│ the dump; name every API │
│ call by module+offset. │
└────────────────────────────────┘
# 1. Find your target process
tasklist | findstr /i "<your_target>"
# Note the PID
# 2. Survey executable private regions (the headerless catcher)
py 01_acquire/scan_exec_private.py --pid <PID> --dump
# 2b. Optionally also try the deep PE-sig sweep
py 01_acquire/scan_pe_deep.py --pid <PID>
# 2c. If the target HAS valid MZ headers (rare for hidden modules), this is fastest
py 01_acquire/dump_manualmap.py --pid <PID>
# Output: a folder of .bin files at C:\path\to\execprivate_<PID>\
# Identify the candidate by size (1-10 MB) and entropy (~6-7).
# Filename pattern: execpriv_<runtime_base_hex>_0x<size_hex>.bin
# 3. Reconstruct the PE — pass the runtime base from the filename
py 02_reconstruct/rebuild_headerless.py \
execprivate_<PID>/execpriv_<BASE_HEX>_<SIZE_HEX>.bin \
0x<BASE_HEX> \
target_reconstructed.dll
# 4. Open target_reconstructed.dll in IDA. Auto-analyze. Done.
# 5. Optional: enrich with imports + named API calls
py 03_enrich/analyze_hooks.py --pid <PID> \
--target target_reconstructed.dll \
--target-base 0x<BASE_HEX> \
--out target_imports.md
| Folder | Script | Purpose |
|---|---|---|
01_acquire/ | scan_exec_private.py | Primary tool. Lists every RX MEM_PRIVATE region. Use this first — works on headerless dumps. |
01_acquire/ | scan_pe_deep.py | Aggressive PE-signature sweep across all committed memory. Catches dumps where MZ was zeroed but PE\0\0 wasn't. |
01_acquire/ | dump_manualmap.py | Strict MZ-at-region-start detector. Use only if the target preserves headers. |
01_acquire/ | dump_contiguous_image.py | Stitch a contiguous VA range from a target into a single dump, zero-filling unmapped gaps. |
02_reconstruct/ | rebuild_headerless.py | Core tool. Forges DOS+NT+section-table over the first 0x1000 bytes of a raw dump. |
03_enrich/ | analyze_hooks.py | Walks trampoline pages, identifies hooked functions by absolute-address pattern. Produces a markdown report. |
03_enrich/ | resolve_exports.py | Resolves module.dll:0xOFFSET → kernel32!CreateFileA+0x12 style names. |
No section recovery. rebuild_headerless.py declares ONE .text
section covering the whole image RX. The original may have had separate
.rdata / .data / .pdata sections — those become indistinguishable
from code. Side effects:
.idata import table is GONE — you can't follow API calls by name
unless you reconstruct imports (use analyze_hooks.py)No relocation table. The reconstructed DLL hardcodes the original
runtime ImageBase. If you try to actually LOAD it via LoadLibrary,
ASLR will rebase it and absolute pointers internal to the dump will be
broken. Only use the output for static analysis in IDA, not for
re-injection.
Wiped padding. If the loader zeroed regions inside the dump (PE header padding, freed allocations), those bytes are lost. Reconstruction won't recover them — the IDB will have zero-filled gaps where things used to be.
Hardened processes.
OpenProcess(PROCESS_VM_READ) is blocked when the target installs a
kernel callback (e.g. ObRegisterCallbacks). You'll get
ERROR_ACCESS_DENIED (5) or a stripped-rights handle. To proceed:
kdmapper,
or any \Device\PhysicalMemory-style helper. The dump scripts here
all assume user-mode RPM and will silently fail otherwise.Stdlib only. Tested with CPython 3.12 on Windows. No pip installs needed.
PEReconstruct is built to be driven from a coding agent — every script
is argparse-based, prints structured output, and writes deterministic
filenames. A typical Claude Code session looks like:
You: Dump the manually-mapped DLL inside PID 24468 and reconstruct it as a loadable PE for IDA.
Claude Code: (runs
scan_exec_private.py --pid 24468 --dump, reads the entropy + size table, picks the highest-entropy region in the 1-10 MB range, runsrebuild_headerless.pyagainst the dumped.binwith the base parsed from the filename, outputs the path to the reconstructed.dll)
Helpful prompts:
<N> for hidden modules and tell me which regions look
like manual-mapped DLLs."<path-to-bin> at base 0x<BASE> and open it in IDA
via the IDA-Pro MCP server."analyze_hooks.py against the reconstructed DLL and summarize
which Win32 modules it imports from."Tip: this pairs well with ida-pro-mcp. After reconstruction, point Claude at the IDA MCP server to drive disassembly, decompilation, and symbol-naming over MCP.
The skills/pe-reconstruct/ directory in this repo is a ready-to-use
Claude Code skill.
Once installed, Claude Code automatically invokes it when you ask about
dumping, recovering, or analyzing manually-mapped/headerless DLLs.
# Install for the current user (all projects)
mkdir -p ~/.claude/skills
cp -r skills/pe-reconstruct ~/.claude/skills/
# Or install for one project only
mkdir -p .claude/skills
cp -r skills/pe-reconstruct .claude/skills/
The skill's SKILL.md tells Claude exactly which script to run for which
task and how to chain them.
MIT — see LICENSE.
Design enforcement with memory — keeps your UI consistent across a project
Claude Code skill for YouTube creators — channel audits, video SEO, retention scripts, thumbnails, content strategy, Sho
AI image generation skill for Claude Code -- Creative Director powered by Gemini
A Claude Code skill by Hao (駱君昊) that learns your Facebook voice and auto-posts to FB / IG / Threads / X with a 14-day c