From 70db77af464826a862d6bb2b1c12640cfc8d1112 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 6 Jul 2026 23:43:54 -0400 Subject: [PATCH] =?UTF-8?q?fix(frida):=20dump=5Fengine=20=E2=80=94=20use?= =?UTF-8?q?=20ptr.readByteArray=20(frida=2017),=20skip=20system=20DLLs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dump validated: AGE.EXE is unpacked in-place at 0x400000 in memory (AGF-decoder landmark @0x474f1f reads real code with the 'BM' 0x4D42 check). Kelebek handler VAs map directly (VA-0x400000 = file offset). Handler ABI: thiscall (esi=engine context), operands fetched via call 0x41b940, per-object command-type table at [esi+idx*120+0x53d88]. 0x215 is part of a native gfx command-buffer manager. Co-Authored-By: Claude Opus 4.8 (1M context) --- tools/frida/dump_engine.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/frida/dump_engine.py b/tools/frida/dump_engine.py index a683754..9ea5c95 100644 --- a/tools/frida/dump_engine.py +++ b/tools/frida/dump_engine.py @@ -39,8 +39,9 @@ function dump(baseStr, size, tag){ for (let off = 0; off < size; off += CHUNK){ const n = Math.min(CHUNK, size - off); let buf; - try { buf = Memory.readByteArray(base.add(off), n); } + try { buf = base.add(off).readByteArray(n); } // frida 17: method on the pointer catch(e){ send({kind:'gap', base:baseStr, off:off, n:n, err:''+e}); continue; } + if (buf === null){ send({kind:'gap', base:baseStr, off:off, n:n, err:'null'}); continue; } send({kind:'chunk', base:baseStr, off:off, n:n, tag:tag}, buf); } send({kind:'done', base:baseStr, size:size, tag:tag}); @@ -52,16 +53,18 @@ const rw = ranges('rw-'); // landmark check: the AGF decoder is documented at AGE.EXE+0x74f1f (stable, unpacked in-place) let landmark = null; -try { landmark = Memory.readByteArray(mod.base.add(0x74f1f), 16); } catch(e){} +try { landmark = mod.base.add(0x74f1f).readByteArray(16); } catch(e){} send({kind:'manifest', age_base: mod.base.toString(), age_size: mod.size, rx: rx, rw: rw}, landmark); -// dump targets: the AGE.EXE module image, plus every r-x range >= 1 MB (the unpacked heap code) +// dump targets: the AGE.EXE module image, plus every ANONYMOUS r-x range >= 1 MB (the unpacked heap +// code). Skip file-backed r-x ranges — those are Windows system DLLs, not the engine. dump(mod.base.toString(), mod.size, 'age-module'); for (const r of rx){ if (r.base === mod.base.toString()) continue; // module already covered + if (r.file) continue; // skip system DLLs if (r.size >= 1*1024*1024) dump(r.base, r.size, 'rx-heap'); } send({kind:'alldone'});