REA 逆向 iOS 应用完整实操:从 IPA 清单到 Mach-O 动态库追踪
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
REA 是一款面向 AI Agent 的逆向工程工具,这篇文章讲清 REA 逆向 iOS 应用这条链路:对 IPA 做静态认证清单、投影 bundle 结构、追踪 Mach-O 动态库加载,全程零执行,不越狱、不运行应用。
它到底是什么:不跑应用,先把包变成证据
REA(Reverse engineer anything with agents)把逆向流程拆成一条条可审计的 CLI 命令,由 Agent 或你自己按图索骥地执行。和传统解包工具不同,它不直接给你一棵文件树,而是先建立"认证过的库存证据"(authenticated inventory evidence):包内每个文件都带 sha256 指纹、格式、大小和可执行标记,后续所有结构结论都能回溯到这份清单。
对 iOS 开发者,它回答的是三个静态解包答不了的问题:
- 完整性:这个包改过没有?——靠逐文件哈希校验
- 归属:哪个文件属于哪个
.app?哪些是嵌套 Framework、XPC 服务、登录项? - 加载逻辑:主二进制声明的每条 dylib 依赖,实际会命中包内哪个文件?
核心工作流:从输入到输出
装好之后按 安装文档 完成 Provider 配置即可开工。整条链路的数据形态变化如下。
输入侧:你交给它的是什么
一个.ipa文件,或者解出来的Payload/<Name>.app目录、ZIP、DMG 镜像。命令本身不关心文件怎么来的,只要求字节稳定——清单是内容寻址的,源文件动过,后面所有证据都会失效。
rea inspect-artifact ./MyApp.ipa --json | jq . > inventory.json输出是一份inventory_artifactEvidence,你只需要记住它的 Evidence ID,下一步要用。
中间态:认证清单长什么样
这份清单是"证据"而非猜测,关键字段:
| 字段 | 说明 |
|---|---|
root_sha256 | 根文件哈希指纹,后续回溯的锚点 |
nodes | 每个组件的格式、架构、可执行位 |
occurrences | 逻辑路径、声明大小与verified校验状态 |
limitations | 无法核实的内容如实标注,不静默跳过 |
关注occurrences里有没有verified之外的状态——那代表哈希和声明大小对不上,包可能被动过。
输出侧:应用结构图谱与动态库解析图
把清单投进投影命令,得到 bundle 解剖结果:
rea project-apple-application-graph '{"inventory_evidence":["<Evidence ID>"]}'打开之后你会看到应用根、bundles列表(含info_plist_path、executable_candidates、signing_paths),以及基于路径的 JavaScript ↔ 原生桥接假设。投影不解析 plist 和签名语义,CFBundleExecutable、URL Scheme 用inspect_plist,签名声明用inspect_signature单独核查。
应用根的识别规则很直白:
| 库存根 | 识别为应用根 |
|---|---|
| IPA | 每个Payload/<Name>.app |
.app目录 | 目录本身 |
| 含应用的 ZIP / DMG | 每个最外层带Contents/的<Name>.app |
bundle 布局分三类:macos-deep(含Contents/)、versioned-framework(含Versions/,按真实版本目录分析)、shallow(典型 iOS 形态,凭Info.plist判定为ios平台)。*.appex、*.xpc、*.framework、登录项(Contents/Library/LoginItems/)、特权助手(Contents/Library/LaunchServices/)按路径惯例自动归类——这是找隐藏启动项和提权点的高效线索,实现见 Apple 应用投影服务。
下钻一层,看每条 dylib 加载到底命中哪个文件:
rea trace-dylib-resolution MyApp.app --json输出里每条依赖边都列出所有尝试过的候选路径及结果(resolved/absent/architecture-missing/escapes-target),并给出resolved、conditional、unresolved、undetermined四级判定。关注unresolved的边——那是包内缺文件、运行时必然出问题的点。
Mach-O 和 FAT 头的解析是纯 TypeScript 实现(工具契约),不需要 otool、lipo,Linux 上也能跑。想验证清单预测的加载顺序,可以接 Hopper 等反汇编引擎看实际汇编:
跑一个最小例子
以MyApp.ipa为例,完整终端交互:
$ rea inspect-artifact ./MyApp.ipa --json | jq . > inventory.json $ jq -r '.. | select(.evidence_id?) // empty' inventory.json | head -1 evid_9f3c... $ rea project-apple-application-graph '{"inventory_evidence":["evid_9f3c..."]}' | jq . # 输出 application roots、bundles、bridge 假设 $ rea trace-dylib-resolution Payload/MyApp.app --json | jq '.findings'投影输出里先看coverage是否为complete-within-inventory,再看platforms是否为ios;dylib 输出里只看findings,required-load-unresolved这类发现优先处理。想对某条unresolved边追到底,就顺着它的候选路径回到清单里核对occurrences的校验状态。
容易踩的坑
- plist 和签名不在投影里:
project-apple-application-graph只报路径与哈希,看CFBundleExecutable或 URL Scheme 要用inspect_plist,签名声明用inspect_signature。 - DMG 子卷依赖 macOS 挂载:在非 macOS 环境,DMG 往往只有根身份,投影会如实标记
partial并说明"缺失未知",不要当成"包里没有这个 bundle"。 - 桥接假设会截断:候选对最多序列化 2 MiB,超出时
bridge_candidate_coverage报告省略数量,coverage 降级为partial——这是透明降级,不是丢数据。 - AppleDouble 侧车文件:
._*和__MACOSX/会被识别为清单事实,但自动排除在 bundle 角色和解剖组件之外,别把它们当成真实启动项。 conditional不等于resolved:包内能解析,但/usr/lib/swift这类根外候选在运行系统上存在时会抢先加载,结论要留有余地。
速查
| 场景 | 命令 | 产出物 |
|---|---|---|
| 生成认证清单 | rea inspect-artifact ./MyApp.ipa --json | inventory_artifactEvidence |
| 投影应用结构 | rea project-apple-application-graph '<evidence>' | bundle 解剖、应用根、桥接假设 |
| 追踪动态库加载 | rea trace-dylib-resolution MyApp.app --json | dyld 解析图与 findings |
| 核查 plist 字段 | rea inspect-plist <info_plist_path> | plist 字段值 |
| 反汇编验证 | rea decompile <binary> --provider hopper | 反汇编 / 伪代码 |
完整字段语义与状态表见 Apple 应用分析文档;首次使用先读 安装与 Provider 配置。
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考