Ran the scripts against a real Flutter AOT / multi-dex / 36-.so APK (Dart 3.6.0,
com.tingfeng.tool) and recorded what each one actually did. Two of them were wrong
in the direction that reads as a target finding, one Coverage claim overstated what
ships, and four documentation statements were false.
Fixed:
dart_pprefs.py decoded only the general-purpose register file, so `ldr dN,[x27,#imm]`
(0xFD400000) was never matched and every double constant read from the object pool
was dropped -- 302 pool offsets and 1802 sites on this sample, one of them with 150
references that would have been reported as zero. The documented advice is to count
references before editing a shared constant, so a one-sided quiet gap here produces
exactly the wrong decision. Now covers both register files; a purpose-written
arbiter agrees with it to 0/0 across .text, against 0/302 before.
Documented but deliberately not fixed, because a fix would not have been run:
elf_plt.py misses the last PLT stub slot (`off < fsz - 16`), which on libloader.so
turned a real, called import (dl_iterate_phdr) into "not a resolved stub".
find_refs.py advertises dex-directory input but iter_files() accepts only .smali,
so it answers "no references" with exit 0 for input it never read.
so_constpatch.py's rebuild drops the zip `extra` field and destroys 4 KB alignment.
Each has its root cause and fix sketch recorded.
Documentation corrections in dart-aot.md:
blutter's asm/ does contain full instruction listings with pool annotations -- the
file said to ignore it, and it is the richest artifact in the chain.
The first build costs ~78 s, not "tens of minutes"; MSVC 19.34 suffices, not VS 2022.
The file-PP offset mapping is not recoverable from the binary (4241 shared strings,
4237 distinct deltas), so a snapshot-decoding front end is a dependency, now stated.
Documented aotopsy as the no-toolchain route, and the trap that its version label is
a structural profile name (it says 3.6.2 for a 3.6.0 snapshot).
Coverage now separates what was measured from what is inferred, names blutter/aotopsy
as a prerequisite instead of implying the pool decodes itself, lists the scripts this
pass did not run, and says plainly that the packer / VMP / integrity-check scenarios
were not exercised at all.
Added hand-off points for JNI, dex-observed hardening, and the existing native boundary
documents, plus docs/verification-jiongnew/ -- the evidence record, including the four
gate outputs verbatim. No second skill: the gap is one front-end dependency, not a
subject area, and relocating Flutter docs would not have supplied it.
The skill lived at the repository root, which the CLI reads as a single-skill repository and which makes a second skill impossible to add. SKILL.md, references/ and scripts/ move under skills/apk-reverse/ with git mv, so history follows and no in-skill reference needs changing (they are relative to SKILL.md).
check_repo.py now discovers every skills/*/SKILL.md, validates frontmatter by parsing it instead of pattern-matching it, and requires the README to name skills through explicit skills/<name>/... paths.
check_refs.py is new: it audits file.md section cross-references against the real headings in the target file. It found six dangling ones, all fixed here.
SKILL.md: the description is now quoted. Unquoted, it contained a colon-space, which is invalid YAML, so the CLI skipped the skill and reported No skills found. Adds a Coverage section stating what is out of scope and what to do when nothing matches. toolchain.md: IDA is not GUI-only (idalib-mcp is a headless MCP server), plus a section on MCP servers as external dependencies and the deobfuscate-before-LLM boundary. README.md: install via npx skills add, the new layout, coverage and maintenance tools.
Verified: check_repo.py and check_refs.py both clean, build_scripts.py audit 0 findings, npx skills add . --list reports apk-reverse, and an install into a scratch directory lands SKILL.md plus 28 references and 38 scripts.