From fa7b48c4da5b06c3d5f80e598188ceccef926ca7 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Thu, 9 Jul 2026 09:23:25 -0400 Subject: [PATCH] re(frida): write import-map.json (in-table matches; singletons set aside) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 248 module-resident core imports at the RVA 0x16f000 rebuilt IAT (kernel32/user32/gdi32/winmm/advapi32/ole/oleaut/version/ntdll); 29 singletons set aside. Anchors confirmed: ReadFile/CreateFileA/ SetFilePointer + timeGetTime@0x16f3d4 (=DAT_0056f3d4). d3d9/shell32 etc. are heap-resolved (out of dump) — expected. Co-Authored-By: Claude Opus 4.8 (1M context) --- tools/frida/map_imports_full.py | 43 +++++++++++++++++++++++++++++++++ tools/frida/test_map_imports.py | 10 ++++++++ 2 files changed, 53 insertions(+) create mode 100644 tools/frida/map_imports_full.py diff --git a/tools/frida/map_imports_full.py b/tools/frida/map_imports_full.py new file mode 100644 index 0000000..44613a2 --- /dev/null +++ b/tools/frida/map_imports_full.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +"""Task 2 of the frida import-map slice: write build/import-map.json from the live scan. + +Splits the pointer matches into (a) those inside a contiguous in-module import-table run +(>= min_run) -> auto-apply, written to build/import-map.json; and (b) isolated singletons +(more likely a coincidental DWORD) -> build/import-map-singletons.json for review, NOT +auto-applied. Invoked by `map_imports.py` default mode (no --recon). + +See docs/superpowers/plans/2026-07-09-frida-import-map.md (Task 2) and the design spec. +""" +import json + +from map_imports import BUILD, build_export_index, cluster_runs, collect, scan_pointer_matches + + +def select_table_matches(matches, runs, min_run=3): + """Split [(rva,val,name)] by whether each RVA falls in a contiguous run of >= min_run. + + Returns (table, singles) as {hex_rva: 'dll!func'} dicts. + """ + run_rvas = set() + for start, count in runs: + if count >= min_run: + run_rvas.update(start + i * 4 for i in range(count)) + table = {hex(r): n for r, _, n in matches if r in run_rvas} + singles = {hex(r): n for r, _, n in matches if r not in run_rvas} + return table, singles + + +def build(): + exports, base, mem = collect() + idx = build_export_index(exports) + matches = scan_pointer_matches(mem, base, idx) + runs = cluster_runs([r for r, _, _ in matches]) + table, singles = select_table_matches(matches, runs) + (BUILD / "import-map.json").write_text(json.dumps(table, indent=2) + "\n", encoding="utf-8") + (BUILD / "import-map-singletons.json").write_text(json.dumps(singles, indent=2) + "\n", encoding="utf-8") + print(f"wrote {len(table)} table imports -> build/import-map.json; " + f"{len(singles)} singletons -> build/import-map-singletons.json (review, not applied)") + + +if __name__ == "__main__": + build() diff --git a/tools/frida/test_map_imports.py b/tools/frida/test_map_imports.py index ee533f9..5bb3bd7 100644 --- a/tools/frida/test_map_imports.py +++ b/tools/frida/test_map_imports.py @@ -58,12 +58,22 @@ def test_cluster_runs_groups_contiguous(): "cluster groups contiguous aligned runs, isolates singleton") +def test_select_table_matches_splits_runs_from_singletons(): + from map_imports_full import select_table_matches + matches = [(0x100, 0, "a!f"), (0x104, 0, "b!g"), (0x108, 0, "c!h"), (0x200, 0, "d!i")] + runs = [(0x100, 3), (0x200, 1)] + table, singles = select_table_matches(matches, runs, min_run=3) + check(set(table) == {"0x100", "0x104", "0x108"} and set(singles) == {"0x200"}, + "run members auto-apply; singleton set aside") + + def main(): test_export_index_canonicalizes() test_export_index_first_name_wins_and_skips_zero() test_scan_matches_little_endian_aligned() test_scan_ignores_unaligned() test_cluster_runs_groups_contiguous() + test_select_table_matches_splits_runs_from_singletons() print("FAILURES:", len(FAILS)) return 1 if FAILS else 0