re(frida): import-map applied to /v2 — 248 Win32 APIs named; validated

Labeled the module-resident IAT at RVA 0x16f000 (imp_<dll>_<func> x248,
0 clobbers). Validated in decomp: FUN_0044f390 -> imp_kernel32_CreateFileA
/ SetFilePointer; sleep_timer_arm -> imp_winmm_timeGetTime (pins
DAT_0056f3d4). d3d9/heap-resolved DLLs unlabeled by design.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-09 09:26:19 -04:00
parent fa7b48c4da
commit e166cab2d5
2 changed files with 18 additions and 7 deletions

View File

@@ -48,13 +48,23 @@ Related: `docs/scjump-progression.md` (the SCJUMP decoder that hit this wall), `
`GetProcAddress`-resolved into private pointer tables, invisible to a static IAT scan. Report/dump left
at `build/pe-sieve/process_<pid>/` (disposable).
**→ The right approach (queued, Frida-based; the real "Task B"):** name the dynamically-resolved APIs at
their call sites via the LIVE process. (1) Frida-read the loaded modules' export tables → `{runtime_addr
→ dll!Func}`; (2) read the engine module's resolved import-pointer storage from the SAME live process,
resolve each stored pointer → name, and record **`RVA → name`** (RVAs in the fixed `0x400000` main module
are ASLR-stable; only the DLL targets relocate, and we resolve those live); (3) apply the `RVA → name`
labels to the `/v2` Ghidra image. All plain-JS Frida reads (no spawn, no patching — anti-tamper-safe).
This replaces the pe-sieve step; spec/plan when picked up.
**→ The Frida import-map approach — ✅ DONE 2026-07-09 (replaced pe-sieve).** Named the
dynamically-resolved APIs at their call sites via the LIVE process. `tools/frida/map_imports.py`
(read-only, plain-JS): (1) Frida-reads all loaded modules' export tables → `{runtime_addr → dll!Func}`
(23,342 exports); (2) scans the `0x400000` module for aligned DWORDs holding those addresses → `RVA →
name` (ASLR-stable: RVAs into the fixed main module transfer to the dump even though the DLL targets
relocate); (3) a `run_script_inline` pass labels the `/v2` image `imp_<dll>_<func>`. **Result: the packer's
rebuilt core IAT lives at RVA `0x16f000` (VA `0x56f000`) — 248 imports labeled** (kernel32 129, user32 57,
winmm 20, gdi32 17, advapi32/ole/oleaut/version/ntdll), 0 clobbers. **Validated:** `FUN_0044f390` now reads
`(*imp_kernel32_CreateFileA)` / `(*imp_kernel32_SetFilePointer)` at its resolver I/O; `sleep_timer_arm` reads
`(*imp_winmm_timeGetTime)()` — pinning the long-standing `DAT_0056f3d4` = **timeGetTime**. Tool:
`tools/frida/map_imports.py [--recon]` → `build/import-map.json`; plan
`docs/superpowers/plans/2026-07-09-frida-import-map.md`.
**Known limit (by design):** only the module-resident IAT is labelable. `d3d9`/`shell32`/`dsound`/CRT are
`GetProcAddress`-resolved into HEAP (not in the `0x400000` dump), so they aren't labeled — and D3D9 is used
via COM vtables (`Present` = device vtable slot 17, see `probe_present.py`), not an import thunk, so this
costs us nothing on the render path. 29 isolated singleton matches were set aside (`build/import-map-singletons.json`),
not auto-applied.
---