diff --git a/README.md b/README.md index 998abe2..28ed1a7 100644 --- a/README.md +++ b/README.md @@ -505,9 +505,16 @@ set APKREV_TOOLS=; # Windows, e.g. an SDK or proje export APKREV_TOOLS=: # POSIX ``` -The scripts themselves are plain `python3` and are intended to work identically on Windows, macOS and +The scripts themselves are plain `python3` and are designed to work identically on Windows, macOS and Linux; where a snippet is POSIX-only it is labelled. Nothing here assumes a Unix shell. +**Measured on Windows only.** Every gate run, every test result and every figure in the evidence +record comes from one host (Windows 10.0.26100, PowerShell 7, CPython 3.14). Cross-platform behaviour +is a design intention, not an observation: treat another platform as `unverified` until the suite has +been run there, and expect the usual suspects to be the difference — path separators, `os.pathsep` in +`APKREV_TOOLS`, console encodings, and shell quoting in the ADB helpers. If you run the gates on +macOS or Linux and they pass, that is a `observed` result worth recording next to this paragraph. + | Tool | Used for | |---|---| | Python 3.9+ | all scripts | diff --git a/README.zh-CN.md b/README.zh-CN.md index 0e3893e..e0ed8ad 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -417,6 +417,8 @@ export APKREV_TOOLS=: # POSIX 脚本本身是纯 `python3`,并且意图在 Windows、macOS 和 Linux 上行为一致;凡有片段仅限 POSIX,都会标注出来。这里没有任何东西假定你用的是 Unix shell。 +**实测只在 Windows 上做过。** 每一次门禁运行、每一个测试结果、以及证据记录里的每一个数字,都来自同一台主机(Windows 10.0.26100、PowerShell 7、CPython 3.14)。跨平台行为是设计意图,不是观测结果:在别处跑通之前,把另一个平台当作 `unverified`,并预期差异出在几个老地方 —— 路径分隔符、`APKREV_TOOLS` 里的 `os.pathsep`、控制台编码,以及 ADB 辅助脚本里的 shell 引号转义。如果你在 macOS 或 Linux 上跑门禁并通过了,那是一个值得记在这段旁边的 `observed` 结果。 + | 工具 | 用途 | |---|---| | Python 3.9+ | 所有脚本 | diff --git a/skills/apk-reverse/references/toolchain.md b/skills/apk-reverse/references/toolchain.md index 1c6e92c..0d3d0e3 100644 --- a/skills/apk-reverse/references/toolchain.md +++ b/skills/apk-reverse/references/toolchain.md @@ -270,6 +270,29 @@ line numbers and even which branch is which can differ from the bytecode. When a it, verify in smali or at runtime. `jadx` writing `(unknown)`/empty method bodies means it failed, not that the method is empty. +### A tool that ran out of room did not tell you the target is empty + +Every JVM-based reader in this list, and several of the native ones, can die on a large or deeply +nested input without saying anything about the artifact: `OutOfMemoryError`, a `Killed` from the OOM +killer, a container limit, or a timeout. The output looks like a tool that read the file and found +nothing — an empty result plus a line most people skim past. + +**What a failed analysis supports is a claim about the analysis, not the artifact**: "this route could +not complete on this input" is `present but unreadable` (`SKILL.md` §Coverage), and it is exactly +where a wrong "that class is not in there" gets written into a record. Three things to do before a +negative from a heavy tool becomes a finding: + +- read the **exit code and stderr**, not just stdout — a heap death often exits non-zero with a + partial result already printed; +- give the tool the room the input warrants (a larger heap for the JVM readers) and re-run before + concluding anything; +- prefer a route that does not have to materialise everything: an indexed query against the APK + (`rasc`/`droidasc`/`dexsql`) answers most location questions without decompiling a single class, and + it is also the route that survives a target too large for a full export. + +The same reading applies to a **time budget** you set yourself: a command you killed at your own +deadline reported nothing about the target, only about your deadline. + **`smali` assembling can abort silently** — the tree produces no dex while the process still exits 0. Never treat exit code as proof of a build. Assert the artifact exists, is fresh, and is non-empty (`patch-audit.md`).