Android APK 逆向工程 Agent 技能:dex 修补、解包、重打包、广告与付费墙移除、原生 .so 分析,以及使用 Frida 进行运行时插桩。
English · 简体中文
能力 · 结构 · 安装 · 环境要求 · 失败目录 · 范围 · 维护 · 免责声明
面向 Android APK 逆向工程、去臃肿、去广告、外科式 dex 补丁、重打包,以及运行时/服务端分析的 Agent Skill。
它是一个 skill,不是教程:它是写给 agent(Claude Code、Codex,或任何支持 Agent Skills 格式的 harness)在工作过程中加载的,因此按 progressive disclosure(渐进披露)来组织——一份简短、面向决策的 SKILL.md,只在某一步真正需要时才加载的详细 references,以及可直接运行的参数化脚本。
SKILL.md 刻意写成一份带 gate 的流程,而不是建议,因为观察到的失败模式并不是无知——而是模型把整份文档读完、表示认同,然后照样从第一性原理重新推理一遍。
所以正文里有四样东西是用来执行的,不是用来读的:
另外还有一样在结尾、应当被扣住的东西:**「done」**有定义(六项)。一份干净的日志不在其中。少于六项全部达成,就只是一个检查点,应当作为检查点汇报,并说明还剩什么。
如果你是正在读这段的 agent:成本最低的第一条命令是 python skills/apk-reverse/scripts/doctor.py。它会告诉你这里存在哪些工具、哪些脚本真的能跑,以及环境里是否已经有什么东西在污染你的测量结果。
fault addr 0x4),它看起来和普通的空指针解引用 bug 一模一样;以及「把它失效化,但绝不要让它不返回」这条规则,它决定修法是生效,还是以完全看不出与原因有关的方式冻住整个 app。frida 本身被拒绝时走 root 侧 dump。这次测量能看见什么、看不见什么,写在 skills/apk-reverse/references/advanced-unpacking.md。svc 系统调用、init_array 早期检测)、上下相邻层实际能做什么,以及什么时候继续升级是错误答案。SKILL.md、references/ 与 scripts/ 都在 skill 目录 skills/apk-reverse/ 内。仓库根目录下的一切是跨 skill 共享的维护工具,不属于已安装的 skill。
SKILL.md 带 gate 的流程,不是背景阅读材料:
how-to-use -> 四条覆盖规则(R1-R4)
症状索引(命中一行即为停止信号)
四个 gate(G1-G4,带通过标准的动作)
十三个分类问题
工作流,带每一步的跳过条件和一条两击规则
「done」的含义 -> 停止条件 -> 约束 -> 索引
references/ 按需加载,每个文件一个主题
recon.md 识别壳、SDK、代码位置、篡改检查;脱壳
server-config-and-updates.md
「广告」最常见的那种形态,也是通常被误诊的那种:
服务端提供 UI,客户端负责渲染(启动屏、弹窗、
公告、tab 集合)。证明它的两层抓取、如何按
data class 保留的字段名找到配置 DTO、为什么
你要补的是决策而不是数据、「移除」的范围如何界定,
以及远端重新启用 / 配置缓存持久性
byte-level-patching.md 等长字节编辑:为什么它优于方法重建(实测)、
如何在不刮 listing 的情况下定位一条指令的精确偏移、
会让解码失步的指令宽度陷阱、把分支失效化还是重定向它、
dex 头完整性字段的顺序,以及校验器的 move-result 规则
packers.md 加固目标:拒绝信号、用单变量测试测量校验边界、
选择 native 宿主
code-virtualization-and-custom-linkers.md
「已加壳」与「干净」之间的那一层:整个类被变成
`native` 声明、SONAME 与文件名不匹配的私有加载器、
内嵌的自解密 payload、一个 Java 层「签名杀手」在日志里
报告成功而 native 检查却在杀你。留还是删的死锁、
如何把*检查器*与*实现*分开,以及那条不做任何
失效化就终结它的字符串重定向技术
framework-runtimes.md Flutter / React Native / Unity:UI 归哪一层所有,
以及在没有符号时怎么找逻辑(字符串编码陷阱)
dart-aot.md Dart AOT 深入:版本钉定与构建一个匹配的反编译器、
对象池与引用索引、寄存器/布尔约定、
识别业务逻辑的三种签名、定位、打补丁。
开篇先讲它所依赖的 snapshot 解码前端(aotopsy 或
blutter),因为 pool 列表是输入,不是本 skill 自己产出的东西
native-and-so.md .so 宿主、DT_NEEDED vs JNI_OnLoad、重定位限制、
免重定位的 bootstrap、用 native 替换 Java 方法,
以及*实际加载并执行*的是哪个 ABI/库
native-tamper-and-suicide.md 加固库如何杀掉自己的进程:可见的机制、
如何判断实际触发的是哪一个、如何定位现场、
伪造的 section header、由 PT_GNU_EH_FRAME 推出的
函数边界、扫描器陷阱,以及安全地失效化
detection-and-anti-analysis.md 当 app 反击,或工具在这里跑不起来时:把检测与
环境损坏区分开、按成本而不是按升级来决策、认出
动态分析根本无效的环境,并把「挡住我的分析」这个问题
与「挡住交付物」分开
toolchain.md 该装什么、如何非交互地调用它、哪些工具只有 GUI、
版本对齐陷阱、离线工作、**「不在 PATH 上」不等于「没装」**,
以及该用哪个签名器
long-task-discipline.md 实时记录、结论分级、漂移控制、超时与等待校准、
交付物形态漂移、你从未看过的截图、
长上下文衰减、交接
ad-removal.md 广告分类学、包装层映射、回调陷阱、全局闸门、验证
updates-and-forced-upgrade.md 让打过补丁的构建活下去:定位版本检查、
两层补丁(把例程 no-op、把比较失效化)、不能碰的东西
(manifest 版本、安装器权限、host 阻断)、
自更新与热更新/远程配置通道、验证根本没有发出任何版本请求
account-gates.md 登录墙、强制手机绑定、游客模式:把客户端侧闸门
(可补)与账号维度资源(不可补)区分开、为什么
伪造 session 比保持未登录更糟,以及重装后
无法避免的登录态丢失
signature-derived-keys.md 当 app 自己的签名证书被当作密钥材料时:
检测用 grep、为什么离线提取不可靠、
先硬编码再验证的流程
membership-and-limits.md 服务端 vs 客户端权威;什么可补、什么不可补
server-api.md 探测 app 的 API;证明闸门归谁所有
tls-and-cert.md 功能维度的网络失败:过期证书、双信任链
third-party-builds.md 在信任一个「破解版」/「魔改版」APK 之前审计它
dex-patching.md 补丁层对照表 + dexlib2 技术深入
patch-audit.md 证明一个补丁*落地*了并且*合法*:长度 vs 字节
比较、等长替换的盲区、校验器层面的合法性
(move-result 相邻性)静态检查、文本匹配式
补丁陷阱,以及如何报告一个缺失的补丁
repack-and-sign.md 重打包规则、解包与重打包、签名、安装后隐患
runtime-data.md DataStore / SharedPreferences / SQLite / protobuf;app 何时
会改写你的编辑,以及解码一个看起来像加密的值
dynamic-frida.md Frida 配置、版本钉定、四层探测、hook 策略
environment.md 设备/模拟器配置、root、ADB、离线设备、日志信号、
模拟器 console 控制与恢复、preflight、看一眼屏幕
verification.md 主张阶梯;「done」的含义
desensitization-and-leak-scans.md
发表纪律:什么必须脱敏、什么必须保留、
不得匿名化的清单、泄漏扫描器及其退出状态,以及
入口文件本身就是一处提示词暴露面
precedents/ 正向案例库:含死路的路线、每条断言的分级、
实测到的坑,以及回写清单
routing.md 按需清单:每个 reference 及其加载时机、每个
script 及其用途,以及症状索引的镜像
rasc-and-droidsaw.md ASC 索引器的 Rust 重实现:实测加速比与
完全一致的类集合、它会静默丢掉方法体的 enum 形态,
以及如何构建与验证它
evidence-summary.md 随 skill 一起发布的浓缩版:能力、一行结论、
强度,以及你在已安装副本里实际能打开的证据
../evals/ 也不是 spec 目录,而是 Agent Skills 指南推荐的
位置:`evals.json` 存放本 skill **尚未**运行过的
带 skill / 不带 skill 用例,运行方法写在文件里
../evidence/ 不是 spec 目录:上面 evidence summary reference 的
机器可读配套文件 —— `capability-matrix.json`(同样的行、
更多字段)、`tested-tool-versions.json`(版本及每个版本背后的
探测)、`known-limitations.md`(面向安装者的限制清单)。随 skill
一起发布,使已安装的副本不需要仓库就能回答「这一条验证过吗、
强度如何」
pitfalls.md 失败目录 —— 构建之前先读
advanced-unpacking.md dump 拿到了但方法体是空的:按平凡方法体比例做
抽取壳诊断、FART 式主动调用以及为什么它的经典 hook
在 Android 12-16 上失效、code_item 拼接、当 frida
本身被拒绝时的 root 侧 dump,以及诚实的 VMP 边界
lsposed-and-modules.md 重打包被拒绝,那就交付一个系统级 hook 模块:模块解剖、
无 gradle 的构建链、作用域配置与如何验证注入,
以及 Java 模块够不到的那一层
emulation-and-rpc.md 调用例程而不是读它:Unidbg/Unicorn 模拟及其
环境填充成本,对比把活函数通过 Frida RPC 服务化
native-dbi-and-deobfuscation.md
OLLVM 形态、Frida-Stalker trace、trace 到 CFG 的路线、
Stalker/QBDI/模拟的取舍,以及两条实测边界(一次
不产生任何事件的 follow,和一次因 follow 热 libc 导出而崩溃)
protocol-reverse.md 无 schema 的 protobuf、从反编译代码恢复 schema、gRPC 帧
抓取、QUIC/HTTP3 的限制,以及 native 侧证书固定
kernel-and-environment-hardening.md
用户态 hooking 可证明够不到检查:裸 `svc`、init_array 早期
检测、每种 root 方案隐藏了什么、带版本闸门的
内核路线图,以及什么时候停止升级
on-device-tooling.md 直接在手机上工作:MT Manager 的编辑/重打包/签名及其 APK MCP、
LSPosed Manager、Termux+frida、设备上数据检查
java2c-and-jni-sinking.md Java2C 与 JNI sinking,最容易与抽取壳混淆的两种加固
形态:区分落地壳 / 抽取壳 / VMP / Java2C / JNI sinking
的那张表、为什么代码在 `.so` 里而*永远*不在 dump 出的 dex 里,
以及为什么 `Java_*` 符号搜索会一无所获(动态注册、
`-fvisibility=hidden`)
split-apk.md App Bundle / split APK 集合:集合是什么、如何从设备拉取、
合并成一个 APK 还是把整个集合作为一个单元签名、安装拒绝
及其各自含义,以及如何从拉取的集合做出一个可安装的 fixture
vmp-differential-analysis.md
针对真实 Dex VMP 的已知明文差分:哪些环节可以
自动化、哪些不能(上传是瓶颈)、一个编译出的
fixture 能覆盖到什么程度、如何*证明*一张推导出的私有
opcode 表、smali 生成,以及这条路线何时关闭
coverage-and-limits.md 把主张阶梯用在 skill 自己身上:每个已覆盖条目背后的
证据、本 skill 不随附的依赖,以及从未实际演练过的东西
handoff-boundaries.md 本 skill 在哪里结束、另一门学科在哪里开始:JNI 形态
对照表、壳与加载器的分界,以及「已核实」对四种
交付物形态各自意味着什么
scripts/ 参数化、与路径无关
doctor.py 先跑这个:能力报告 + 每个脚本的可运行性,发现
安装在 PATH 之外或作为可运行 jar 存在的工具,并暴露
会污染实验的环境事实(时钟偏移、残留的
adb forward / proxy、设备侧已在运行的 frida 进程)
dexutil.py 无依赖的 dex 读取器:结构遍历 + 精确指令
解码、dex 头重算/校验(正确的 checksum/signature
顺序)、分支目标与操作数辅助函数。被
dex 脚本共享的库,也可独立运行以带偏移 dump 单个方法
dex_find_insn.py 按解码语义定位一条指令,并打印其精确字节
偏移,附上下文与任一分支的两侧 —— 你靠这个找到
补丁点,而不是猜偏移
dex_patch_bytes.py 按 JSON 规格做等长字节补丁:语义匹配、通过
expect_next 钉定极性、等长强制、校验器检查、dex
头重算、重新解码以证明它已落地(先 --dry-run)
dex_check_verifier.py 三级检查:是否有任何条件分支以 move-result 为目标
(绕过它的生产者)?比较两个构建,并把
既存发现与你补丁引入的回归分开
coldstart.py 冷启动捕获:定时截图连拍 + logcat 信号 +
已安装构建事实 + 启动计时,并在前台
activity 不是你的 app 时发出警告
so_constpatch.py 对一个孤立的字符串常量做等长原地改写,用于
重定向一次库加载,而不是击败一个检查
smtool.py 带可配置 classpath 的 baksmali/smali 包装器
dexpatch/ dexlib2 方法级重写器(用于需要新指令的改动)
patch_smali.py smali 树中的方法体替换
dex_strpatch.py 带 string_ids 顺序守卫的字节级字符串补丁
dex_classdiff.py 证明一次 dex 编辑是外科式的
dex_strings.py 不需要反编译器的 strings/URL/SDK 标记提取
dart_pool_strings.py 从 Dart AOT snapshot 恢复字面量(带帧条目、
单字节 vs UTF-16 的分岔、文件偏移、游程噪声过滤)
dart_pprefs.py 为 Dart snapshot 构建/查询 对象池 -> 代码位置 索引
dart_disasm.py Dart AOT 代码的带注释窗口式反汇编 + B/BL 调用者索引
find_refs.py 在给一个方法打补丁之前统计它的调用者
repack.py 重建 APK、只剥离签名、保留 META-INF/services/、写出
4 字节对齐的归档(resources.arsc STORED+对齐)、签名、校验;
也处理 split APK / App Bundle 集合:清点、用一个
keystore 为每个成员签名,或把 code/native 成员合并成独立 APK
devsh.py 引号安全的 ADB shell 辅助工具
usb_net_proxy.py 通过 USB 给离线设备提供网络
datastore_inject.py 安全地编码/注入 AndroidX DataStore preferences
probe_api.py 带正确请求头探测一个 HTTP API
grab_crash.py 恢复被崩溃上报 SDK 藏起来的栈
install_test.py 安装 + 启动健康检查,带 logcat 信号扫描
frida_probe.js 四层运行时探测(app 网络层 + OkHttp + java.net + 异常)
run_probe.py 注入探测、把它流式写入日志文件、保持常驻
tls_check.py 对一个或多个 host 做严格证书检查
preflight.py 每个实验块之前的环境检查(设备、root、
ABI/翻译层、时钟偏移、残留 proxy/forward、失联的 server)
lib_map.py 一个活进程里*实际映射*了什么:每库路径、
基址、架构,以及它来自 APK 还是
运行时物化出来的
elf_plt.py 从重定位表把 PLT stub 解析到它导入的符号(x86_64 + aarch64);
列出某个符号的调用者;对两个
库做字节级 diff,并指出每个变更 stub 属于哪个符号
apk_diff.py 两个构建的条目级 diff:变更 / 新增 / 移除,按
内容哈希,使等长替换也能被抓住
native_crash.py 从日志或 tombstone 定位一次 native 死亡:signal、故障
地址、寄存器、把帧拆成 app 与 system、故障
指令本身,以及当故障看起来是*被安排好的*时给出标记
blob_decode.py 搜索、而不是猜测一个存储值的分帧
(base64/hex x 旋转 x deflate);把编辑后的 payload 重新编码
snap.py 有界连拍截图 + 带停滞检测的控件树捕获,
并对这棵控件树是否可用给出结论
sig_probe.py 找到确切的 signatures[0].toCharsString() 值 —— 从 APK 得到的
离线候选,或从设备读取的权威值
spawn_patch_detach.py 在 Frida 探测下 spawn、detach,然后启动并捕获:在
spawn 模式下 Activity 栈常常起不来,而内存
写入能在 detach 后存活,hook 不能
hook_patch_only.js spawn_patch_detach.py 的最小探测 —— 按偏移把一个 native
死亡点失效化并报告 PATCHED
dex_dump_validate.py 对一目录的 dump dex 镜像去重、校验并排序:sha256
分组、头完整性、区分真实 dump 与抽取壳骨架的
平凡方法体比例,以及一个最可能原件的排序
(对页对齐的 /proc/<pid>/mem 捕获用 --trim)
dex_mem_scan.py 在内存捕获中搜索内嵌的 dex 镜像,并按每个镜像自己头部
声明的尺寸抽取出来 —— 用于躺在匿名映射里、
没有任何 maps 条目为它命名的解密 dex
lsposed_scaffold.py 生成一个最小 LSPosed/Xposed 模块工程(带
xposed meta-data 的 manifest、assets/xposed_init、hook 类、无 gradle 的构建说明)
frida_rpc_serve.py 把 Frida 脚本的 rpc.exports 桥接到本地调用方,带断线重连
处理,从而可以调用一个活的 native 函数,而不是逆向它
rpc_template.js frida_rpc_serve.py 的可编辑配套脚本
stalker_trace.js 用 Frida Stalker 做指令级追踪:可配置目标、
触发选择、事件流,以及输出体积规则
stalker_report.py 把 stalker_trace.js 的日志归约为基本块直方图与调用序列,
并对实测到的零事件情形给出明确诊断
mt_mcp_probe.py 探测 MT Manager 的设备端 APK MCP(Streamable HTTP,端口 8787):
JSON-RPC 握手加上分组后的工具清单
java2c_probe.py 收集能区分 Java2C 与抽取壳、VMP 及普通 JNI sinking 的
证据:从 dex 得到 native 密度与 stub 比例、
从 `.so` 得到 JNI_OnLoad / 动态注册 / 工具链字符串,
每一项都标注为 强/中/弱
protobuf_decode_raw.py 无 schema 的 protobuf 解码:hex / 文件 / stdin 到 JSON 树,每个
长度定界字段都保留为一个候选集合、并列项予以标注而
不是猜测,另含字节级精确重编码以检查一次往返
vmp_diff_harness.py 构建带标注的 opcode 覆盖 fixture、从原始/加固 dex 对
推导候选私有 opcode 映射、在闭环中验证该比较,
并把还原出的指令流渲染成 smali 骨架
kernelsu_syscall_mask.py 生成 KernelSU/APatch 系统调用遮蔽脚手架:一个可安装的
用户态模块骨架加上 KPM/LKM/eBPF 内核侧模板,每个
都带自己的版本闸门和明确的未核实标注
rasc_build.py 构建并验证 rasc,即 ASC 索引器的 Rust 重实现:
--check 检查已有什么、--build 克隆并 cargo、--verify 用
droidasc 校验一个 APK,并在任何类集合差异上失败
scan_leaks.py 在发布一个仓库之前扫描其中的目标身份:manifest / `pm` / `ps`
上下文里的 bundle id、序列号形态的 token、PAT、内联
appkey 赋值、字面 endpoint、宿主用户路径。对
必须保留的一切给予豁免(工具、库、CVE、加固产品、
公开 crackme、占位符),发现项带上下文,
`--show-exempt` 打印某个命中项为什么被抑制,退出码 0/1/2
svc_scan.py 指出某条内联 `svc` 背后的系统调用以及它所在的段,
这决定 libc 层面的 hook 究竟能否观察到该调用;
`--context` 展示邻近字节,因为字节扫描也会匹配到数据
anti_detect_probe.js 仅观察的 Frida 探测(不打任何补丁):path/loader/thread/kill
hook 附调用者模块 + 偏移、一份环境自述
(`TracerPid`、以 frida 命名的映射),以及实时流式输出,使一个
亚秒级自毁目标仍能产出证据
仓库另外带有一个可执行的测试层,它与证据记录是两回事:tests/ 断言脚本的行为(单元、CLI 契约、无设备集成),tests/benchmark.md 记录某条路线在真实目标上的表现。tests/README.md 说明了这个划分,.github/workflows/ci.yml 运行各闸门加测试套件。
这个仓库是一个 skills 仓库:skill 位于 skills/apk-reverse/,这正是 skills CLI 解析的布局;安装是按名字进行的,而不是复制一个目录:
npx skills add newliver666/apk-reverse # install every skill in the repo
npx skills add newliver666/apk-reverse --list # list what is here, install nothing
npx skills add newliver666/apk-reverse --skill apk-reverse -y
npx skills use newliver666/apk-reverse@apk-reverse # use it once, without installing
CLI 默认把 skill 软链进你的 agent 的 skills 目录(--copy 则生成独立副本),-g 为所有项目安装而不是仅当前项目。仓库里只有一个 skill 时,--skill apk-reverse 今天是多余的;这里把它写出来,是因为等第二个 skill 存在时,正是它用来选中单个 skill。
安装后,agent 在任务匹配其描述时加载 SKILL.md,并且只在需要时拉入 references/*。没有全局状态,没有与机器绑定的路径,也没有构建步骤。
没有什么是强制的;每个脚本都自己检查所需。skills/apk-reverse/scripts/doctor.py 报告这里哪些工具存在、因此哪些脚本能跑,以及——这很有用——哪些工具存在于 PATH 之外。
如果你的工具链不在 PATH 上(项目本地的 tools/ 目录、带版本号的 SDK 目录、可运行的 .jar 而不是一条命令),把 APKREV_TOOLS 设为一个或多个目录,doctor.py 就会找到它们:
set APKREV_TOOLS=<dir>;<dir> # Windows, e.g. an SDK or project-local tools dir
export APKREV_TOOLS=<dir>:<dir> # POSIX
脚本本身是纯 python3,并且意图在 Windows、macOS 和 Linux 上行为一致;凡有片段仅限 POSIX,都会标注出来。这里没有任何东西假定你用的是 Unix shell。
这些都不需要在 PATH 上:每个脚本都为它外壳调用的工具接受显式路径,skills/apk-reverse/references/toolchain.md 覆盖了如何找到一个 PATH 不认识的安装(对 apksigner 和 keytool 来说这是常见情况)。
本项目仅为学习、研究和经授权的安全测试而发布。 它不附带任何 exploit payload、任何目标数据、任何第三方二进制 —— 它是一套方法、一组脚本和一份证据记录。你有责任确保自己对所分析的对象拥有相应权利;见文末免责声明。
skills/apk-reverse/references/pitfalls.md。这是这里最有价值的文件 —— 每一条都是在看起来完全健康的情况下产出了损坏产物的失败。
最痛的四个:
META-INF/ 剥离,会删掉 ServiceLoader 注册,app 在启动时死掉,而报错信息指向一个毫不相干的库。string_ids 顺序,整个 dex 会被拒绝,而 checksum 和签名却完美通过校验。为处理你自己的应用、你被授权分析的样本,以及 CTF/竞赛沙箱而构建。它不含任何内置的第三方二进制,也不含任何目标特定数据。
它覆盖什么、刻意不覆盖什么,写在 SKILL.md 顶部 Coverage 一节。简版:仅 Android(不含 iOS),并且在经过真实打磨的层上深入 —— dex 补丁、重打包、壳与自定义加载器、native 篡改响应,以及 Flutter/Dart AOT。一次扩展迭代加入了第二梯队的已记录路线:重打包受阻时的模块侧交付、抽取壳恢复及其 VMP 边界、用于「调用而不是阅读」的模拟执行与实时 RPC、针对 OLLVM 的指令级追踪、REST 之外的协议逆向、当用户态 hooking 可证明够不到时用的内核路线图,以及设备上工具。随后一次基准迭代把公开目标放到这些路线之下(tests/benchmark.md):它加入了 Java2C 判别(那种会让 agent 去追一个从不存在的解密 DEX 的误诊)、split APK / App Bundle 处理、无 schema 的 protobuf 解码、一个 Dex-VMP 差分测试台,以及带版本闸门的内核模块模板 —— 并纠正了先前两条与自身测量结果不一致的说法。Unity/IL2CPP 逻辑恢复、React Native/Hermes 字节码内部,以及击败服务端权威不在覆盖范围内,skill 的写法就是明说这一点并停下,而不是把最近的一条已记录流程套用到一个它并非为之编写的目标上。
Coverage 一节完整陈述、同时也应当放在这里的四条限定:
pp.txt 一类输出)。产出它需要一个 snapshot 解码反编译器 —— aotopsy(静态二进制,不需要工具链)或 blutter(从源码构建,约 80 秒)—— 而本仓库不含其中之一。它被点名为前置条件,而不是留在那里让人自己推。docs/tool-verification/ 记录了实际测量了什么、在哪个目标上、用哪个独立交叉检查确认;那里未覆盖的内容都是凭经验记录的,按本 skill 自己的主张阶梯,应当读作推断。docs/tool-verification/EXTENSION-*.md,一个主题一个文件,各自带强度说明。那里常见的形态是工具被测量过,路线没有 —— 所以在把任何较新的文档当作已验证路径之前,先读那些文件。tests/benchmark.md 列出每个公开目标、该行演练的脚本、实际发生了什么(包括失败的行和没人跑的行),以及证据有多强。标为 unverified 的行是在陈述本仓库证据的状况,不是在陈述机制本身。根目录下住着四个工具,它们不属于已安装的 skill:
check_repo.py 发现的每个 skill、frontmatter 有效、脚本可运行、
文档中的路径可解析、README 路径显式且存在,
并且 —— 仅在受跟踪的表面上 —— 没有目标身份
(把规则委派给 skills/apk-reverse/scripts/scan_leaks.py,
这样要争论豁免清单时就只有一个地方)
check_refs.py 每一处指向另一文档某节的交叉引用,
都能到达该文档里真实存在的标题
check_routing.py 按需清单仍与入口点一致:症状镜像与 SKILL.md 一致、
每个 reference 文件都在 skills/apk-reverse/references/routing.md 中
被点名,每个脚本也是
check_commands.py 文档让你运行的每条命令都会与脚本自己的 argparse 表
核对 —— 一个不存在却被写进文档的 flag,是锚点检查
看不见的漂移
check_budget.py 阻止常驻加载的部分悄悄膨胀:按行和 token 测量 SKILL.md
的整个主体(含索引行,因为它们也会被加载)、索引行长度、
没有可导航头部的长文件,并把含糊其辞的规则作为趋势报告
build_scripts.py 审计机器特定残留物(绝对路径、凭据)
一致性有一种天然的反向压力 —— 一条断掉的路径会大声失败,然后有人修它。膨胀没有,这正是第三个工具存在的原因:每次迭代都会加一个 reference、一行索引和一条覆盖主张,而没有测量的话,仓库里没有任何东西会注意到。
tests/benchmark.md 保存回归矩阵:维度 -> 公开目标 -> 该行演练的脚本 -> 实测结果 -> 强度标注。它是你在信任 docs/tool-verification/ 下任何主张之前要重跑的检查表。样本会下载进 tools/_work/ 且从不提交,因此每一行都点名它的公开来源并记录它所针对的哈希。
docs/tool-verification/ 也不属于已安装的 skill。它是针对一个真实目标、一次测量迭代的证据记录:每个脚本实际做了什么、哪个独立方法确认了它、发现了哪些缺陷,以及该目标未能演练哪些场景。它存在的意义,是让 SKILL.md 里的 Coverage 主张可以被对照运行来检查,而不是被信任;也让缺口被写在下一个人能找到它们的地方。
Proudly supported by the LINUX DO community.
仅为学习、研究和经授权的安全测试。 本仓库中的每个脚本、reference 和已记录结果,都是为了解释 Android 应用分析如何工作,使从业者能对自己已经拥有的工具进行推理。这里没有任何东西是一项服务、一个产品,也不构成对任何特定用途的背书。
.so、已存储的 app 数据),有些会在已 root 的设备上操作。保留你自己的副本、在副本上作业,并在对你在意的东西跑任何东西之前先读 SKILL.md 的 gate。.gitignore 排除了它们),只存在于本地被忽略的工作区中。你为了跟做而取得的任何东西,都由你自己负责保管,并在用完后删除 —— 遵守你本地的规则以及样本自带的条款。本仓库确实发表的是方法与证据,且已移除全部目标身份。.so。pm install-multiple,或在合法时把 code/native 成员合并成一个独立 APK。| 工具 | 用途 |
|---|
| Python 3.9+ | 所有脚本 |
droidasc(ASC)(可选,但强烈建议——先装这个) | 整 APK 交叉引用索引:findrefs / listclass / getclass / getmanifest。一句 pip install droidasc,无 JVM、无 SDK、无需建索引。把「这几千个类里哪一个提到过这个字符串」变成亚秒级查询,也是找到名字被 R8 混淆过的类的唯一路线。这是 agent 在做任何完整反编译之前应当伸手去拿的工具 —— 见 skills/apk-reverse/references/toolchain.md §droidasc (ASC) —— 一次查询就能问一个 APK「谁引用了这个?」 |
ddc(可选,但强烈建议) | 单文件 dex→Java 反编译器,带查询子命令(info、findrefs、strings --with-locations、按类反编译)。无 JVM。读 ASC 所定位的东西;也能可靠地报告包身份 —— 见 skills/apk-reverse/references/toolchain.md §ddc —— 带查询子命令的 dex 转 Java(值得采用) |
baksmali / smali + dexlib2 jars | 反汇编、汇编、外科式打补丁 |
JDK(javac、java) | 构建/运行 dexlib2 补丁器;同时提供 keytool/jarsigner |
Android SDK build-tools(aapt、zipalign、apksigner) | manifest 信息、对齐、签名。apksigner 才是该用的签名器 —— jarsigner 会重写归档并破坏 Android R+ 所要求的对齐 |
uber-apk-signer(可选) | 一步完成对齐 + 签名 |
| ADB | 设备工作 |
| Frida(宿主包 + 与之匹配的设备端 server) | 动态分析 |
| 一台已 root 的设备或模拟器 | 静态分析之外的任何事 |