REA APK 静态分析快速指南:headless JADX 五步跑通方法级反编译与引用追踪
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
快速导读
本文带你用 REA(Reverse Engineer Anything)在 5 条 CLI 命令内完成 headless JADX 的 APK 静态分析全链路:从 manifest 权限、类名搜索,到方法级反编译与引用追踪。全程无需模拟器、无需 Android SDK,每次结果都附带可审计的 Evidence。
能力全景:能做什么,底层怎么跑
先说它能干什么:给定一个本地 APK 文件,你可以查它的声明与权限列表、搜索和盘点全部类名、读取单个类的字段与内部类、反编译任意一个方法体、追踪指向某个类或方法的静态引用。整个过程不执行 APK、不写入原始文件,属于纯静态、纯本地分析。
再说它怎么工作。REA 没有魔改 JADX:它把一个未修改、按 commit 锁定的 jadx-headless-mcp(v0.7.1)引擎当作黑盒,通过自研的 Provider 适配器来驱动。引擎源码以 Git 子模块形式存放在 third_party/jadx-headless-mcp,保留上游 Apache-2.0 许可;REA 侧的协议、会话、传输逻辑集中在 src/android/(如 JadxProvider.ts),应用层服务在 src/application/android/AndroidAnalysisService.ts。
这套"原样引擎 + 自研适配层"的分工带来两个直接好处:
- 反编译结果完全来自上游引擎,边界清晰,方便你核对来源;
- 分析时REA 不会自动下载任何引擎,JAR 由你提供,并用 SHA-256 校验审计版本。CLI 与 MCP 走同一套工作流,所以你在终端验证过的命令,在 Agent 里同样成立。
开工前 30 秒自检:红线清单
在敲第一条命令之前,先把下面的硬约束过一遍,能帮你避开绝大多数环境坑:
平台红线
- headless JADX 提供方在Linux 和 macOS上走 POSIX 适配器(macOS arm64 + OpenJDK 21 已验证);
- Windows x64 需要带配套 Windows 原生控制(含 owned 协议 stdin 支持)的 REA 包,旧版发布包可能直接拒绝该主机;Windows arm64 不在当前原生边界内。
依赖红线
- 必须是一个完整的 JDK 17+(含编译器模块
jdk.compiler);只有可运行 JRE 不够,因为 REA 要在源码文件模式下编译它的 Java 元数据桥;- 必须自行提供jadx-headless-mcp 0.7.1 的 fat JAR,REA 永不替你下载引擎;
- 输入必须是独立 APK 的本地路径;
.aab后缀是 ZIP 归档,不被当作 APK 处理。行为红线
- REA 不安装 Java、Android SDK、设备服务或模拟器;
- 分析全程不执行目标代码,也永不写入原始 APK。
完整契约见官方文档:docs/android-analysis.md。
环境三步配置:JDK、引擎 JAR、可选调优
第一步:确认 JDK 可用。用java --list-modules确认输出里有jdk.compiler。如果你机器上有多套 Java,用JAVA_HOME显式指定。
第二步:指向引擎 JAR。
export REA_JADX_MCP_JAR=/absolute/path/jadx-headless-mcp-0.7.1-all.jar export JAVA_HOME=/absolute/path/existing-jdk # 可选,指向已存在的 JDK第三步(可选):JVM 调优。大 APK 建议加大堆内存:
export REA_JADX_HEAP_MIB=8192 # 堆内存上限(MiB) export REA_JADX_ACTIVE_PROCESSOR_COUNT=4 # 可见处理器数,与单个 JADX worker 相互独立两个 REA 配置都必须是正安全整数;REA 会保留而非覆盖你已有的JAVA_TOOL_OPTIONS、JDK_JAVA_OPTIONS、_JAVA_OPTIONS。
提醒一下:就绪检查只会检查所选 JAR 的 ZIP 目录里是否含元数据桥要用的类、以及 Java 的编译器和版本模块,不会加载 APK 或执行引擎代码——类路径清点通过不等于每个类都能加载成功。
跑通完整分析链路:五步递进
五个命令都注册在 src/cli/androidCommands.ts,按"由浅入深"排成一条链路:
| 步骤 | 命令 | 你会拿到什么 |
|---|---|---|
| 第 1 步:检查包结构 | rea inspect-android-package /path/Example.apk | 解码后的 manifest XML、声明摘要、权限列表、类/资源数量 |
| 第 2 步:搜索类名 | rea search-android-classes /path/Example.apk MainActivity | 大小写敏感的子串匹配结果;传空查询则盘点全部类名 |
| 第 3 步:查看类成员 | rea inspect-android-class /path/Example.apk example.MainActivity | 解析后的类型、字段、内部类名(不生成源码) |
| 第 4 步:方法反编译 | rea inspect-android-method /path/Example.apk example.MainActivity onCreate | 该方法的 Java 或 smali 源码 |
| 第 5 步:引用追踪 | rea trace-android-references /path/Example.apk example.MainActivity | 指向该类的静态引用;加--method-name onCreate可追踪唯一方法 |
几个执行细节值得注意:
第 2 步会消费所有分页并校验计数,空查询返回的是完整的类名清单;
第 3 步读的是解析后的元数据,代码生成隐藏的合成成员可能出现,但它在会话内与方法反编译保持一致;重载序号绑定的是"这个工件 + 这个引擎",不是跨构建的稳定标识;
第 4 步遇到同名重载时必须显式指定序号(从 0 开始):
rea inspect-android-method /path/Example.apk example.MainActivity select --overload-index 1这是刻意的拒绝式设计:遇到模糊请求,REA 会直接报错而不是悄悄选第一个匹配项,避免把错误的函数体归因给错误的重载。引擎的方法引用操作无法选择重载,所以存在多个同名方法时,REA 会把该边界报告为不支持;smali 回退同样会被拒绝,而不是把所有方法体都挂到一个重载上。
从 CLI 到 Agent:MCP 接入与工具映射
如果你在用 Agent(npx rea-agents setup完成注册后),MCP 工具与上面的 CLI 一一对应,参数命名规则一致:所有请求都带path,类/方法操作另用class_name、method_name和可选的overload_index。
| MCP 工具 | 对应 CLI 命令 | 作用 |
|---|---|---|
inspect_android_package | inspect-android-package | 检查 APK 声明与解码 manifest |
search_android_classes | search-android-classes | 搜索/盘点类名 |
inspect_android_class | inspect-android-class | 查看类成员清单 |
inspect_android_method | inspect-android-method | 方法级反编译(支持overload_index) |
trace_android_references | trace-android-references | 追踪类/方法引用 |
让 Agent 反编译一个重载方法的调用示例:
{ "name": "inspect_android_method", "arguments": { "path": "/path/Example.apk", "class_name": "example.MainActivity", "method_name": "select", "overload_index": 1 } }完整工具契约与输出模式见 docs/mcp-contracts.md。
读懂结果:Evidence 的三条阅读注意
每次请求都会把原始请求、APK SHA-256、引擎 JAR SHA-256 和原始响应保留在 Evidence 里(source revision仅在字节与审计发布 JAR 匹配时才填充)。拿到结果后,记住三条:
- 反编译源码是派生表示。文本完整 ≠ 语义完整,更不等于可字节级重构;方法检查还会标注 Java/smali 来源、回退标记和文本是否被截断。
- 引用结果是静态关系,不是运行时事实。它给出的是提供方节点间的入向关系,源行号和 DEX 指令偏移未知,不能当作"观测到的调用"。
- 没有函数体就不猜。native/abstract 方法会报告
body_status: "not_available",REA 不会推断是哪个实现标志导致的。
另外:包检查里的签名验证字段明确是not_performed;这些操作不处理 split APK/AAB、签名校验、完整资源表语义、native 库分析和运行时捕获。如果你需要存档层面的证据,可以先用工件清点工具,再执行rea project-android-application-graph做无执行的图谱投影。
边界与开销:必须知道的限制
| 项目 | 数值 | 含义 |
|---|---|---|
| 会话闲置清理 | 60 秒 | 超时/失败/断连/取消均触发清理 |
| 操作执行时限 | 120 秒 | 到达队列头部后开始计时 |
| 上游反编译时限 | 90 秒 | JADX 引擎侧限制 |
| manifest/方法文本 | 1 MiB | 超预算会明确报告截断 |
| 类名分页 | 每页至多 4,096 个 | 索引切片,不改变大小写敏感的完整搜索契约 |
| 协议帧上限 | 8 MiB | 超限直接失败,而非返回残缺数据 |
| 每操作 stdout/stderr | 32 MiB | 合并超限同样失败 |
这些都是内存安全边界,不是 undocumented 的结果上限。会话复用也值得理解:REA 只保留一个序列化会话(含私有、不可变的 APK/引擎 JAR/元数据桥副本),请求复用时先校验 APK 与引擎 JAR 摘要及 JVM 配置,匹配才复用;输入一变,旧会话即被淘汰。一次性 CLI 命令返回前总会等待清理完成——所以放心,它不会动你的原始 APK,更不会启动目标代码。
验证链路可用:端到端自检
项目自带一条真实引擎的端到端验证 lane,用公开的 Appium ApiDemos(v6.0.18)作样本:
npm run fixtures:android export REA_JADX_MCP_JAR="$PWD/_reference/apk-integration/jadx-headless-mcp-0.7.1-all.jar" export REA_ANDROID_TEST_APK="$PWD/_reference/apk-integration/ApiDemos-debug.apk" npm run verify:android几点说明:
- 下载脚本校验固定的 SHA-256 值,复用匹配文件,且拒绝覆盖已有的不同文件;
- 该 lane 还会用所选 JDK 的
jlink造一个不含编译器模块的临时 JRE,专门检查真实 Java 启动失败、选择器缺失、失败后恢复和 CLI 取消清理; - 全程不需要 Gradle 构建、模拟器、Android SDK 或 Ghidra,原始 APK 与主机 Java 配置保持不变。
常见问题
Q:分析过程需要联网吗?不需要。引擎 JAR 由你自己提供,分析完全在本地进行,文件不上传、引擎不自动下载。
Q:只有 JRE 能跑吗?不能。必须是含jdk.compiler模块的完整 JDK 17+——元数据桥需要在源码文件模式下编译,可运行的 JRE 无法完成这一步。
Q:同名重载方法会选错吗?不会。REA 对模糊请求直接拒绝,要求你先用inspect_android_class看清成员、再用--overload-index显式指定;引擎侧无法选择重载的场景会明确报告为不支持,而不是默默合并方法体。
收尾
把这句话带走就能上手:先配好"完整 JDK + 自供的 0.7.1 引擎 JAR",然后按包检查 → 类搜索 → 类成员 → 方法反编译 → 引用追踪五步递进;每个结论的出处都在 Evidence 里,重载歧义会被拒绝而不是猜。上游溯源记录见 third_party/README.md,契约细节见 docs/android-analysis.md。
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考