news 2026/10/16 6:23:36

不运行 APK 就看懂它内部:rea 基于 JADX headless 的 Android 静态分析完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
不运行 APK 就看懂它内部:rea 基于 JADX headless 的 Android 静态分析完整指南

不运行 APK 就看懂它内部:rea 基于 JADX headless 的 Android 静态分析完整指南

【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea

手里拿到一个.apk,想知道它到底做了什么,却不想、也不能在自己机器上真正把它跑起来?这正是 rea 的 Android APK 静态分析要解决的问题:它把一个现成的 jadx-headless-mcp 0.7.1 引擎(所谓 headless,就是没有图形界面的反编译程序)包在一层严格校验后面,让"打开 APK、读清单、找类、拆方法"变成五条可复现、留证据的命令。读完这篇,你能自己配好 JDK 与引擎 JAR 环境、跑通 CLI 和 MCP 两套入口,并正确解读输出里每一个字段的含义与边界。

先看能力边界:不执行 APK 的静态分析能走到哪

先说结论:rea 对 APK 的态度是"只看不碰"——它不执行 APK,也不启动目标代码,所以这套能力天生适合沙箱外的初步排查。

它明确不做的事,同样值得在动手前背下来:

  • 不处理 split APK / AAB(.aab后缀本质是 ZIP 归档,不会当成独立 APK 对待);
  • 不做签名校验,包检查里signature_verification恒为not_performed;
  • 不提供完整资源表语义,不分析 native 库,也没有 Android 运行时捕获。

它能做的,是五个静态问题:包里有什么声明、某个类在不在、这个类有哪些成员、某个方法体写了什么、谁引用了这个类或方法。

如果还想看归档层面,可以用既有的产物清点/提取工具拿到归档证据,再喂给免执行投影命令rea project-android-application-graph(MCP 方法project_android_application_graph,参数inventory_evidence)。投影会报告精确的组件路径与哈希、运行时族提示和基于路径的桥接假设,但它不解码 DEX,也不声称观测到了运行时调用。

动手之前:跑静态 APK 分析要自备什么

结论:rea 本身不安装 Java、Android SDK、JADX、设备服务或模拟器——所有工具都由你供给,它只负责"管好"你给的东西。

你需要备齐两样:

  1. 完整的 JDK 17 或更新版本,必须包含jdk.compiler编译器模块,因为 rea 随包分发的元数据桥 bridge/android/ReaJadxBridge.java 要用 JDK 的 source-file 模式对未修改的引擎 JAR 现场编译——一个只能运行的 JRE 不够用;
  2. jadx-headless-mcp 0.7.1 的引擎 JAR,并且建议先核对它的 SHA-256 是否与 src/android/JadxRelease.ts 中固化的发布元数据一致(6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75,上游提交5844800a486d2248fa949b74c9896285f5b54de2)。

然后在 shell 或 MCP 服务器环境里指给 rea:

export REA_JADX_MCP_JAR=/absolute/path/jadx-headless-mcp-0.7.1-all.jar # 可选:指定一个已存在的 JDK,而不是用 PATH 上的 java export JAVA_HOME=/absolute/path/existing-jdk

解析规则(见 src/android/JadxConfiguration.ts)可以概括成一张表:

配置项要求不满足时
REA_JADX_MCP_JAR绝对路径、常规可读文件,最终以realpath归一抛AnalysisCapabilityUnavailableError,错误里自带补救指引
JAVA_HOME可选;一旦设置就必须是绝对路径,且$JAVA_HOME/bin/java得是常规可执行文件相对路径直接拒绝
两者都缺省回落到PATH上的java—

注意两点。其一,这套配置只在 Android 操作被选中时才解析,跑别的命令不会被它卡住。其二,平台边界在解析第一步就强制:只支持linux与darwin,Windows 不支持该 provider 的自持进程边界;Linux 上 JADX 会启动一个 REA 自持的进程,需要PATH里有 procps 兼容的ps。仓库完成的真实验证环境是 macOS arm64 + OpenJDK 21 + 公开的 Appium ApiDemos fixture,Linux/JDK 25 尚未走完真实验证。另外提醒一句:该功能族存在于仓库 main 分支与 npm 4.1.0,选用前先核对已发布包的边界与目标服务器的工具列表。

你可以向 APK 提的五个问题:一个操作对应一条命令

结论:五个 CLI 命令对应五个同名的 snake_case MCP 方法,每个请求都带path,参数契约收得很紧——类/方法操作要求精确的全限定类名与声明方法名。

  • inspect-android-package:包里有什么?保留解码后的 manifest XML、摘要声明、权限和类/资源计数;摘要字段由上游引擎抽取,存疑时对照保留的 XML 核查。
  • search-android-classes:有没有叫这个名字的类?query是大小写敏感的子串,空串等于全量清点类名;搜索会消费所有分页,计数对不上就失败。
  • inspect-android-class:这个类有哪些成员?读解析后的元数据而不生成源码,返回完整展示类型、字段与内部类名;代码生成隐藏的 synthetic 成员可能出现,overload index 绑定到当前产物与引擎,不是跨构建的稳定身份。
  • inspect-android-method:这个方法体写了什么?报告 Java 或 smali 表示、回退标记与完整/部分文本;同名重载用--overload-index指认。
  • trace-android-references:谁在引用它?--method-name可选,省略时追的是类级引用;目标方法存在多个重载时会报 unsupported,因为引擎的引用操作没法替你选重载。
rea inspect-android-package /path/Example.apk rea search-android-classes /path/Example.apk MainActivity rea inspect-android-class /path/Example.apk example.MainActivity rea inspect-android-method /path/Example.apk example.MainActivity onCreate rea inspect-android-method /path/Example.apk example.MainActivity select --overload-index 1
rea trace-android-references /path/Example.apk example.MainActivity rea trace-android-references /path/Example.apk example.MainActivity --method-name onCreate

MCP 侧长这样(类/方法操作按需给class_name、method_name与可选overload_index):

{ "name": "inspect_android_method", "arguments": { "path": "/path/Example.apk", "class_name": "example.MainActivity", "method_name": "select", "overload_index": 1 } }

解读输出:四个最容易读错的地方

结论:rea 的输出哲学是"不确定就不说",所以读输出时,没给你的一定不是没有,而是没把握。

重载消歧:宁拒勿猜。重载(overload)指同一个类里名字相同、参数不同的多个方法。rea 先让引擎给出成员清单,按引擎返回顺序为同名方法分配从 0 起的overload_index。如果你没带 index 而候选不止一个,请求会被直接拒绝,错误消息里列出全部候选签名——它绝不静默帮你选第一个。引擎在 Java 反编译失败时会退回 smali 表示(smali 是 Android 字节码的汇编级文本),而这条回退会把所有同名重载的函数体拼接在一起;rea 对重载方法直接拒绝该回退,避免把一锅函数体全算到某一个被选中的重载头上。没有函数体的 native/abstract 方法则返回body_status: "not_available",不猜测是哪个实现标志导致的。

partial意味着被截断。解码后的 manifest 与方法文本有 1 MiB 的上游字节预算,超限时截断会被显式报告、状态标为partial。反编译源码是派生表示——拿回了完整文本,不等于拿到了完整语义,更不等于字节级一致的重建。

引用不等于运行时调用。trace-android-references给出的是 provider 节点之间的入向静态关系,source_line与dex_offset显式为null(保持未知)。看到"谁调了谁",别脑补成"运行时确实发生了这次调用"。

Evidence 替你留了底。这里的 Evidence 是与产物绑定的结构化记录:原始请求、APK SHA-256、实际用到的引擎 JAR SHA-256、producer 的原始响应(含 server 版本、桥 SHA-256、加载状态和每次工具调用的原始响应)都留在里面(见 src/android/JadxSession.ts)。source_revision只在 JAR 字节与审计过的发布 JAR 匹配时才填充,否则为null——以后引用结论时,这条证据链就是出处。

幕后机制:rea 是怎么把引擎管住的

结论一句话:引擎不是 rea 的,但对引擎的控制权全是 rea 的。手段分三层:身份核验、会话管理、硬预算。

🔒 引擎"户口本":双重锁定。上游既有提交号也有 JAR 字节 SHA-256,两个锚点钉死在 src/android/JadxRelease.ts。每次分析前,rea 还会调用引擎的rea_jvm_status工具核对它自报的版本是不是 0.7.1,不一致直接抛AnalysisCapabilityUnavailableError;元数据桥自身的身份(rea-jadx-bridge,版本 1)也在连接时重新校验。

会话复用与确定性清理。每个实例保留一个序列化会话,工作区是私有的不可变副本(rea-android-前缀),里面放着 APK、引擎 JAR 和元数据桥的拷贝;桥拷入后被设为0o400只读并重新哈希比对,防止准入期间被动手脚。能不能复用旧会话由"复用键"决定——一个把 APK 路径 + APK SHA-256 + JAR 路径 + JAR 哈希 + 桥哈希 + Java 可执行文件 + JVM 参数 + 相关 Java 环境变量拼成的 JSON;键一变,先退役旧会话再起新的。准入前还会重哈希 APK 与target.sha256比对,事后发现文件变过就报 "APK bytes changed after admission"。会话在 60 秒空闲、目标/配置变化、失败、超时、取消、MCP 断开或服务器关闭时清理;一次性 CLI 命令返回前总是 join 清理。最坏情况:进程清理无法确认时,rea 保留工作区并报告其位置,该实例抛出携带runId与工作区路径的ProviderCleanupError,并阻塞后续引擎启动,直到你处理完报告的资源。无论哪条路径,rea 从不写回原始 APK,也不启动目标代码。这套逻辑的主干在 src/android/JadxProvider.ts。

⏱ 时间与字节都有硬顶。这不是"大概能扛多少"的经验值,而是一条条写死的内存安全边界:

边界上限触顶时的行为
单操作执行期限(到达队首后)120 秒(OPERATION_TIMEOUT_MS)按超时失败
上游反编译上限90 秒引擎侧边界
manifest / 方法文本上游预算1 MiB截断并标记partial
类名分页每片 4,096 个名称切片翻页,不改变搜索契约
单条协议帧8 MiB(src/android/JadxMcpTransport.ts)以诊断失败收场
单操作 stdout/stderr 合计32 MiB拒绝把不完整清单当完整结果返回

JVM:单 worker,配置是你自己的事。单个 JADX 分析 worker 独立于 JVM 处理器与 GC 设置(load_apk固定threads: 1, resources: "full")。rea 不替你做默认堆或可见 CPU 的覆盖,Java 按自己的默认 ergonomics 运行并继承调用方的 JVM 设置;可选的 provider 变量会被映射成显式参数:REA_JADX_HEAP_MIB→-Xmx<N>m,REA_JADX_ACTIVE_PROCESSOR_COUNT→-XX:ActiveProcessorCount=<N>。两者都必须是正的 safe integer,处理器计数还必须落在 JVM 有符号 32 位范围内(超过 2,147,483,647 直接拒绝)。rea 保留JAVA_TOOL_OPTIONS、JDK_JAVA_OPTIONS、_JAVA_OPTIONS而不替换它们,Java 的标准优先级照旧生效。Evidence 里的heap_limit_mib是 worker 观测到的Runtime.maxMemory()向下取整的 MiB,可能与配置的-Xmx不同(Serial GC 下尤其明显);堆也不是总 RSS 上限,JVM 还会用 native 内存。

自己跑一遍:不装任何东西验证真实引擎

结论:仓库自带一条"真实引擎验证车道",全程不装任何工具,几分钟跑完。

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

下载脚本 scripts/fixtures/android/fetch.mjs 会校验固定 SHA-256,复用匹配文件,拒绝覆盖不同的已有文件;APK 与 JAR 落在被忽略的_reference/下,不会混进包内容。验证脚本 scripts/verify/android/analysis.mjs 先断言 APK 与 JAR 的哈希和 fixture/审计值一致,再对五个操作逐一跑真实的 CLI 与 MCP 请求——它和合成的协议回归测试相互独立。整条车道不需要 Gradle 构建、模拟器、Android SDK 或 Ghidra。

小结:反编译是引擎的事,"可引用"是 rea 的事

如果把反编译引擎比作相机,rea 就是那个给每张照片都盖章时间戳、校验和与设备登记号的拍摄助理。遇到歧义(同名重载)它拒绝猜,遇到不确定(字节预算、分页计数)它显式打标,遇到答不了的(运行时行为、签名、native)它把边界原样写进输出。对需要把分析结论拿出来给别人看的工程师来说,这种"每个字段都能溯源、每条拒绝都有理由"的确定性,比多一行反编译代码更值钱。

【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 6:22:28

校园小鸟访客智能计数器全解析:基于源师兄核心板与星闪技术的双端鸟类自动计数系统

嵌入式物联网智能硬件示例工程 【免费下载链接】作品 本仓库用于系统化存储和管理源师兄在学习、竞赛及创作过程中产生的各类作品和项目资源。 项目地址&#xff1a; https://gitcode.com/yuanshixiong/creation 点击查看 免费下载 导读 本文以“校园小鸟‘访客’智能计数器”…

作者头像 李华
网站建设 2026/10/16 6:21:54

Vue+ECharts雷达图实战:组件封装、配置详解与踩坑实录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 6:21:30

KBEngine 内嵌 CPython 3.7.3 的 Code Objects(代码对象)C API 深度解析

游戏开发后端 【免费下载链接】kbengine A MMOG engine of server. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/kb/kbengine 点击查看 免费下载 本指南以 CPython 官方 C API 文档的 Code Objects 章节为主体&#xff0c;结合 KBEngine 仓库 kbe/src/lib/python 中…

作者头像 李华