ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

REA 逆向 iOS 应用完整实操:从 IPA 清单到 Mach-O 动态库追踪

REA 逆向 iOS 应用完整实操:从 IPA 清单到 Mach-O 动态库追踪

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 --jsoninventory_artifactEvidence
投影应用结构rea project-apple-application-graph '<evidence>'bundle 解剖、应用根、桥接假设
追踪动态库加载rea trace-dylib-resolution MyApp.app --jsondyld 解析图与 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),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进