逆向工程这行,这些年是越来越难干了。以前拿到一个 App,静态分析、动态调试两条腿走路,配合一点经验基本能摸清门道。但现在的移动应用普遍做了混淆、加固、反调试、动态加载,有些核心逻辑甚至直接丢到服务端,App 里只剩一层壳,单纯靠人肉逆向,光脱壳、理调用链就能耗掉一整天。最近我一直在折腾一个思路:把大语言模型 Agent 引入逆向流程,形成一套“行为分析在前、二进制拆解在后”的自动化分析管线。这套方案我内部管它叫 REA,核心逻辑是先通过动态行为观察回答“App 到底在做什么”,再结合二进制分析回答“关键逻辑是怎么实现的”。这篇就从头到尾拆一拆 REA 的思路、落地步骤和踩过的坑,给同样在搞移动安全、漏洞分析、合规审计的朋友一个参考。
1. 从逆向困境到 AI Agent:REA 的整体设计思路
先说说我为什么觉得传统逆向流程需要变。早年分析一个 App,常规路径就三步:第一,用反编译工具把源码翻出来,或者用反汇编器看汇编;第二,全盘扫描字符串、硬编码密钥、可疑方法;第三,动态调试,在关键函数上下断点,看输入输出。这套流程对付几年前的 App 还算顺手,因为那时候很多应用代码基本是明文状态,加了 ProGuard 也只是简单混淆标识符,可读性还在。
但现在的情况完全不同。某大型电商 App 的安卓端,代码加固后 DEX 跑到内存里才释放;某社交产品直接在 native 层做了控制流平坦化,反汇编出来的代码不是给人读的。再加上越来越多的关键逻辑走了服务端接口,App 里只剩 UI 壳和业务参数组装层。这种情况下,你花大力气逆向出来的结果可能只是一堆无关紧要的展示代码,真正的敏感点在远端,在加密协议里,在自定义的二进制资源里。
所以 REA 的第一个设计理念是:改变信息获取的顺序。传统逆向习惯“从底层往上打”,恨不得第一眼就落到汇编指令上。REA 反过来,先做行为分析,用动态插桩、UI 自动化、网络流量采集等手段,把 App 的行为当成一个黑盒来观察,搞清楚它在什么时候调用了什么接口、访问了哪个文件、上传了什么数据、Activity 跳转路径是什么。这段工作产出的是一份“行为地图”,而不是一坨汇编代码,信息密度高得多,而且不需要去对抗加固和混淆就能拿到。
有了行为地图,AI Agent 就派上用场了。大语言模型最擅长的就是从杂乱信息里提取结构化规律、总结意图、推断调用关系。把行为日志、API 调用链、堆栈摘要丢给模型,它能帮你快速生成“这个 App 启动后第 2 秒调用了初始化接口,参数看起来包含设备指纹信息”这类中间结论。这个中间结论不是最终答案,但它能大幅收敛后续二进制分析的范围,告诉你该去哪个函数、哪段代码里找真相。
最后才是二进制层面。先通过反汇编工具把 native 库和加固后的关键代码块还原出来,再用符号恢复、控制流分析、字符串解密做针对性处理,最后让 AI Agent 对反汇编片段做语义总结,生成函数级伪代码。这里 AI 的作用不是替代反编译器,而是作为“翻译官”,把人类程序员和机器代码之间的理解鸿沟填平一部分。
用一句话概括 REA 的逻辑:先外后内、先行为后代码、先收敛后深挖。人负责定策略和验证结论,AI 负责读数据、筛线索、写摘要,工具链负责提供原始素材。
这种方案的好处非常直接。第一,分析时间大幅缩短。以前理清一个中型 App 的业务调用链可能需要半天,现在借助行为录制加 Agent 分析,一两个小时能出一个高置信度的候选集。第二,对抗加固能力变强了。因为你前面主要依赖运行时行为,而不是静态代码,加固和混淆对你前期工作的干扰被降到了最低。第三,门槛变低了。团队里不是每个人都是汇编大牛,但借助 Agent 生成的伪代码解释,初级安全工程师也能快速上手参与分析。
当然,REA 也不是万能药。它对行为信息的要求很高,行为录得不全,后头分析就是空中楼阁。而且大语言模型在代码推理上仍然会出错,必须配合验证机制,不能盲目相信 AI 的结论。这套方案的定位是“大幅提升分析效率”,不是“取代人的判断”。
2. 核心细节解析与实操要点:行为采集到二进制还原的关键环节
2.1 行为分析层:数据地基怎么打
行为分析层是整个 REA 管线里最吃功夫的部分,因为后续 Agent 的推理质量完全取决于你喂给它什么数据。数据不够,它就只能靠猜;数据太杂,它又会把噪声当真。我实践下来,行为数据至少要覆盖五个维度:
第一,组件生命周期。App 里 Activity、Service、BroadcastReceiver、ContentProvider 各自的启动时序和跳转关系。这类信息是理解 App “页面结构”和“业务流”的基础,可以通过框架层插桩来抓,安卓端用 ActivityThread 的 hook 或者布局转储都能拿到,iOS 端则可以从 ViewController 生命周期入手。
第二,API 调用记录。特别是涉及敏感能力的 API,比如定位、相机、通讯录、剪贴板、Keychain 等权限接口的调用时间、调用栈和参数摘要。这部分能直接回答“App 有没有偷读取你的剪贴板”“定位是在前台获取还是后台获取”这类隐私合规问题。
第三,网络通讯明细。完整的 HTTP/HTTPS 请求记录,包括 URL、头、参数和返回体。HTTPS 需要配置抓包代理来实现,App 里如果做了证书校验,还得先绕过。这部分数据能够回答“App 数据都往哪传、传了哪些字段”这类关键问题。
第四,文件系统变动。App 会在沙箱目录里创建哪些文件、写入哪些配置、加载哪些插件包。这个维度经常被新手忽略,但往往很重要,动态加载的 dex、so 都是从文件读出来的,文件事件基本能暴露 App 的核心模块路径。
第五,反射与动态调用。现在很多 App 用反射来做防静态检测,会在运行时通过类名和方法名的字符串拼接去调用隐藏 API。这些调用普通静态分析很难摸清,但动态插桩一抓一个准。
采集工具的选型上,安卓端我主要用 Frida 来做动态插桩,配合自研的脚本批量 hook。模拟器里跑自动化测试用例,再用面向 UI 的工具录制操作路径,比如登录、搜索、下单等核心流程的点击序列。iOS 端相对麻烦一点,越狱环境下可以用运行时方法替换的脚本工具做方法级 trace,非越狱环境则更多依赖代理和工具提供的受限 API 观测能力,能覆盖多少取决于设备的可用接口。
数据打完之后要落地成结构化格式,不能直接堆给 Agent。我通常是把行为事件组织成 JSON 序列,每个事件至少包含时间戳、线程、类名、方法名、参数摘要、返回值摘要和堆栈前若干帧。然后按业务阶段分组切片,比如“启动阶段”“登录流程”“支付环节”,再交给 Agent 做逐段分析。
有些读者可能想问:这么细的行为数据,涉及很多隐私内容,做分析合法吗?这里必须明确:所有分析行为都必须限定在你拥有测试授权或自行开发的应用范围内。做的是安全研究、漏洞评估、合规审计,不是帮别人偷数据。工具本身没有善恶之分,使用场景决定了性质,这条底线我后面还会再强调。
2.2 Agent 的中间表征设计:把原始行为转成可推理的“案情摘要”
行为数据是一堆“原始事实”,但直接全部塞给大模型,效果其实很差。原因有二:一是 token 消耗太大,一个 App 启动一次可能产生数千条事件,塞满上下文后模型就“消化不良”了,推理质量断崖式下跌;二是原始事件缺乏语义归纳,模型分析时容易只见树木不见森林。
所以我做了个中间环节:行为压缩与意图推理。简单说,就是用另一段提示词模板,让 Agent 把原始行为事件转换成高层次的“案情摘要”,主要包括:
- 业务阶段划分:例如启动初始化、用户认证、首页数据加载、支付确认。
- 每个阶段的关键 API 调用链:谁调了谁,参数里有什么值得注意的数据。
- 网络请求与代码行为的对应关系:某个接口的某个参数可能来自哪个类的哪个字段。
- 可疑行为标记:后台定位、剪贴板读取、越权接口访问等。
这一步相当于让 Agent 当了一个“技术文员”,干的是抽象和归纳的活。转换出来的摘要既保留了核心证据线索,又大幅压低了信息量,适合作为下一步分析的输入。
这里有一个很关键的技巧:要让 Agent 在输出摘要时保留证据的定位信息。比如“剪贴板读取发生在 MainActivity.onCreate → ClipboardManager.getPrimaryClip,证据来自事件 0032”。不能让它只输出“读取了剪贴板”这种笼统结论。因为你后续还需要根据这些证据去二进制里做交叉验证,如果证据链断掉,AI 给你的结论就无法落地。
大模型的上下文里,JSON 压缩格式有一个隐藏的小坑。结构化格式会引入大量花括号和引号,非常占 token。我试过压缩成 CS 风格的简写记录,比如t=1.02 th=main act=startMethod cls=MainActivity method=onCreate,整体 token 占用可以减少约三成,而且对 Agent 的语义理解没有损失。前提是你在提示词里把字段定义说清楚,否则 Agent 可能看不懂简写。
另外还要注意一个问题:同一段行为日志,不同的人想从里面挖的信息是不同的。做隐私合规的人关心敏感权限调用,做漏洞挖掘的人关心可疑的序列化、反序列化入口,做恶意软件分析的人关心 C2 通信特征。所以 REA 的 Agent 提示词里应该定义“分析视角”,否则它输出的内容会比较泛泛。我的做法是在中间表征阶段同时生成三个视角的摘要:功能视角、安全视角、隐私视角,后面根据需要再做侧重。
2.3 二进制分析链路:从反汇编到函数级语义还原
行为分析给出了“该看哪里”,二进制分析负责回答“这里具体在干什么”。这一步没法完全自动化,但 AI Agent 可以大幅加速。
核心流程分四段来做。
第一段是架构与加载方式识别。安卓端要先搞清楚目标 App 是纯 Java 层、混合 ART 层还是加了 native 层容器,DEX 是整体加固还是拆分加载,so 文件是哪些架构、有没有做 elf 加壳。常用的工具是反编译工具加十六进制编辑器,跑一遍头部信息扫描,把待分析的“材料清单”建好。
第二段是二进制材料拆解与预处理。DEX/JAR 用反编译工具转成可读的 Java 伪代码,so 库用反汇编器加载。这一阶段不要指望工具输出完美的结果,加固过的代码大概率是看不太懂的状态。必要的时候先做内存转储,从运行中的进程里把已经解密加载的 DEX 或 so dump 出来,这个是应对加固最有效的手段。配合 Frida 脚本在模拟器里定点释放,能将大量“看起来乱码”的代码还原成接近原始的状态。
第三段是关键函数标注。这一步我会让 Agent 配合工具做“函数级语义猜想”。给模型一段反汇编或伪代码,让它输出:函数可能的用途、主要调用了哪些外部 API、处理了什么数据结构、有什么硬编码常量值得注意。为了验证猜想,还需要回查交叉引用,看哪些函数调用了这个函数、它又被谁引用。这个过程相当于给每个函数贴上语义标签,最后形成一份“函数地图”。
第四段是做核心加密与协议还原。当 Agent 发现某个函数明显在做 Base64 解码、字节运算或密钥扩展,就要动手还原具体算法。这里模型的价值在于“见过很多代码模式”,它能很快告诉你这像是 AES 的 S 盒变换,或者像某种自定义异或混淆。然后你再拿着算法特征去做工具层面的验证和参数还原。
二进制分析这条链路,工作量最大的是第三段和第四段,但它恰恰是 Agent 最能发挥作用的地方。因为大语言模型在阅读大段汇编风格代码时的模式识别能力,比大多数初级工程师强得多,它能把看似无意义的寄存器操作归纳成“这像是一个计数器循环”“这部分像是在做 memset”。这种粗粒度的语义猜测,恰好人脑不擅长、传统工具又做不到。
3. 实操过程与核心环节实现:一次完整的 REA 逆向工作流
前面把关键模块的原理讲了,这里拿一个虚构的案例串一遍完整流程。假设我手上有一个某金融类 App 的测试版本(已获得授权,用于安全评估),目标是查明它的设备指纹采集逻辑、是否存在隐私合规风险、核心加密算法的大致结构。
3.1 环境准备与目标选择
实操第一步不是下载工具,而是先想清楚合规边界和测试目标。我给自己定的规矩是:没有书面授权的目标不做主动逆向。这次案例是内部开发的测试包,所以没有这个问题。
环境上,我用了一套组合:
- 安卓模拟器 + 已 root 的测试镜像,用来跑目标 App。
- Frida 作为动态插桩框架,服务端运行在模拟器里。
- 网络代理工具抓 HTTPS 流量,配合自定义证书安装绕过 SSL 校验。
- 逆向工程套件,既看反编译也看反汇编。
- 自研的数据抽取脚本,负责把 Frida 行为日志落盘成 JSON。
选定目标 App 之后,我还做了一个额外动作:关闭系统自动更新、禁用模拟器里其他无关应用通讯,尽量减少噪声数据和外部变量。这一步对分析质量影响很大,行为日志里混入系统调用和第三方应用事件,Agent 很容易被带偏。
3.2 阶段一:黑盒行为观察,录制完整业务流程
先不碰任何代码分析,直接跑 App,按真实用户路径操作:启动、注册、登录、浏览首页、搜索商品、模拟支付。操作的同时,Frida 脚本开始全量记录 Java 层方法调用、native 层函数调用、文件读写事件和网络流量。
整个录制大概持续了 40 分钟,产出行为日志约 15 万条。单看原始数据,人眼的有效信息几乎为零。但经过时间轴归并,可以摸到几条清晰的主线:
- 启动阶段有一个私有 SDK 初始化流程,调用了大量反射接口,多半是设备指纹采集。
- 登录接口请求体里包含一串 hex 字符串,看格式像是加密后的时间戳加设备 ID。
- 支付阶段有一次跨进程调用,疑似读取了外部存储里的某个配置文件。
- 界面上几乎所有埋点事件都会附带一个全局唯一标识,来源不明确。
这些观察结果,记录成“行为地图”,供第二阶段使用。这里有个实操细节要提:录制过程中建议给每个业务阶段打时间戳标记。我当时是在 UI 自动化脚本里插入日志动作,比如“点击登录按钮”“等待首页加载完”,后面分析时才能精确切片。
3.3 阶段二:Agent 行为推理,生成可疑逻辑候选集
拿到行为日志之后,我从里面切片出“启动阶段”和“登录阶段”的 JSON,配上预设的提示词模板,交给 REA 的 Agent 模块做分析。提示词模板的内容会围绕几个问题展开:识别参数来源、标注可疑调用、给出调用链路径、建议需要进一步检查的类或方法。
Agent 跑完第一轮,输出了一份很有意思的摘要:
- 私有 SDK 的主入口疑似叫 DeviceProfileManager,通过反射加载了至少 5 个隐藏类。
- 登录请求里的 hex 参数字段名是
fp_sign,它由两个部分拼接而成:硬件标识的哈希结果和一个随机因子加密后的值。 - 跨进程调用的目标组件疑似是某个热更新服务,它从外部存储读文件后,在校验完毕写入内部沙箱。
Agent 给出的东西不是百分百正确,但非常关键。它把 15 万条日志收敛成了 3 个候选方向,效率提升是肉眼可见的。不过这里也有个坑:Agent 偶尔会对日志中没有的信息进行补全,也就是所谓的幻觉。比如它可能硬编造一个不存在的类名,或者把两个不相干的方法拼成一条调用链。所以第二轮,我会要求它对每个结论附上日志证据的 event_id 和原始行内容,凡是没有依据的推测,单独归类为“待验证假设”。
有了候选集,我挑了两个方向做二进制验证:一个是DeviceProfileManager的反射调用链,另一个是fp_sign的生成逻辑。
3.4 阶段三:二进制还原与代码级理解,交叉验证
先把第二步发现的类在内存转储中找到。加固壳在这种情况下基本无效,因为在运行态它的私有方法已经完整存在内存里。dump 出来的 DEX 直接用反编译工具打开,果然看到了DeviceProfileManager,里面的反射调用列表和 Agent 推测的基本吻合。
再往下查fp_sign。字符串搜索发现一个 native 方法signData,定义在libsecure.so。我直接把 so 文件丢进反汇编器,找到了signData的导出函数。函数开头是一段很长的常量表,看着像查表逻辑,Agent 扫描完这段汇编后给了个判断:这不是标准加密算法,更像自定义的字节混淆,输入先做哈希,再拿一个固定的 16 字节 key 做逐位异或,最后拼接设备时间。
为了验证这个猜测,我在 Frida 里调用了同一个函数,传入构造的测试数据,对比输出与 Agent 模拟代码的输出是否一致。比对了十几个用例后,结果完全匹配,说明还原基本正确。整个过程从录制到确认,大约花了一个下午。如果走纯传统逆向路线,光是在这个没有注释的 native 混淆函数里找到“异或加密”这个模式,可能就够折腾两三天。
3.5 阶段四:输出报告,建立长期可追溯档案
最后一步是输出结构化报告。REA 的做法是让 Agent 自动生成一份漏洞与风险档案:包括行为时序图描述、关键方法标注、调用链路径、发现的风险点(如无加密传输设备标识、本地存储权限过宽)以及待修复建议。
报告我通常不直接拿给开发看,要再人工校对一遍。因为 AI 生成的“建议修复方案”偶尔会过于理想化,比如建议用某种加密算法替换自定义算法,但实际上服务端不一定支持。所以报告里区分了“客观事实”和“AI 建议”,由人最终判断并补充注释,再交付给相关团队。
4. 常见问题与排查技巧实录
这套管线跑过多个目标,也踩了不少坑,挑几个最容易让新手翻车的点详细讲讲。
4.1 行为采集不完整:漏掉的隐式调用和后台任务
第一次用这套方案分析一个周期性后台任务的时候,行为日志里完全看不到它的活动。UI 自动化只管前台界面的点击,后台 Service 是靠闹钟定时器触发的,压根没走到页面层。所以后来我们改了策略:录制脚本里除了 UI 操作,还加入了静置观察阶段,就是让 App 停在某个页面,等 10 到 20 分钟,同时把系统闹钟、任务调度器的 hook 也补上。另外,一些系统广播事件,比如网络切换、屏幕亮灭,也会触发 App 的隐式调用,这些都得靠 broadcast 层面的 hook 才能采到。
还有一个容易被忽略的点是ContentProvider的初始化。很多 SDK 会把初始化逻辑放在 ContentProvider.onCreate 里,App 一启动它就执行,比 Application 的 onCreate 还要早。如果你只 hook 了应用主进程,那要看清楚 provider 是在哪个进程启动的,多进程 App 往往有独立的push进程或remote进程,数据要分别采集。
4.2 Agent 幻觉:模型对二进制结论过度自信,怎么办
大语言模型在分析汇编代码时,经常会对寄存器操作进行“过度解读”。它看到一个异或指令,就推测这是解密逻辑;看到一个常量加载,就说这像魔数。十次里可能错个三四次,但更危险的是它表达得极其笃定,新手很容易被带沟里。
我现在的处理方法是强制所有 Agent 结论必须带三重标注:证据来源、置信度、替代假设。证据来源是日志事件或反汇编地址;置信度必须是低、中、高三档;替代假设则是“如果这个结论不成立,还有哪种可能是成立的”。并要求系统在最终报告里把所有“中低置信度”的结论单独列出,默认不能直接作为漏洞报告定论。
另外一个技巧是引入“对抗式提问”。让 Agent 扮演一个怀疑论者,专门挑自己上一个回答的毛病。比如同一段反汇编,先让正向 Agent 推断功能,再让反向 Agent 提出反驳意见。两种视角一叠加,很多幻觉结论就自动被过滤了。这个办法一次都没有让人失望过,唯一的要求是你要多消耗一些 token。
4.3 反混淆的泥潭:字符串加密和控制流平坦化
很多加固方案里的字符串是加密的,直接在二进制里搜关键词是一无所获。但运行时解密的逻辑,终究绕不开内存,所以最管用的方法还是动态转储。先 hook 字符串解密函数,在它执行完后把结果读出来,然后再回去定位调用点,人工补上语义关联。这套思路对 android 和 ios 都适用。
控制流平坦化是更恶心的一层,它把原来的 if-else 逻辑全部打平成一个大循环加分发器,分析器直接阅读会看得极其费劲。我的做法是先让 Agent 看分发器的状态转移特征,把每个状态块与它指向的原始代码块做映射,再让模型尝试重构控制流结构。这个工作没法一次完成,要迭代好几轮,但好消息是每次迭代模型都会更接近源代码逻辑,比人肉梳理还是要快得多。
4.4 流量抓不完整:证书固定与双向校验
分析 HTTPS 流量时遇到证书固定机制,是家常便饭。Frida 里 hook 证书校验方法能够解决一部分,但某些金融类 App 做了双向 TLS,光改客户端还不够,服务器端也会校验客户端证书,就得提前拿到测试环境的客户端证书配置,或者做系统层面的信任注入。
对这种场景,更合理的方式其实不是硬刚,而是调整思路:抓不到流量的时候,先看代码。Agent 可以从二进制里找出证书固定的实现位置,看它的固定逻辑是怎么写的、证书指纹是内置还是外部可读。如果是内置指纹,那基本没法简单解,如果是外部配置,往往可以配合环境更改加载自己的证书。这种“代码分析辅助流量分析”的思路,其实是 REA 的强项,因为行为分析与二进制分析本来就是联动的。
4.5 多进程与双开环境下的数据隔离
某些 App 会故意把敏感逻辑放到独立进程里,和行为采集脚本不在一个进程,导致 hook 不生效。我遇到过一个用多进程做反调试的双开场景,主进程里跑 UI,子进程里做加密计算,两边内存不互通。解决方案是先拿到完整进程列表,把每个进程的 hook 脚本分别加载,然后在统一的日志输出通道里打上进程标签。分析阶段要时刻关注事件属于哪个进程,否则特别容易把 A 进程的行为安在 B 进程头上。
5. REA 还可以怎么扩展:自动化审计、样本批量分析和团队协作
REA 这套思路除了单个 App 逆向,其实还能外延到几个比较实用的方向。
第一个是自动化隐私合规预审。现在上架审核对隐私合规要求越来越严,但靠人工翻每条权限调用路径极其费时。REA 把行为录制和 Agent 推理接上之后,可以直接输出一份“权限使用清单”,标出每个敏感权限的调用场景和对应代码位置。哪怕结论还需要人工复核,但前期 80% 的梳理工作已经省掉了。
第二个是恶意样本批量分析。威胁情报团队经常会拿到一堆恶意 App 样本,目标是快速回答“这个家族有哪些共同特征”“有没有 C2 域名复用”。REA 可以并行部署多台模拟器,同时跑 20 个样本,Agent 对每个样本做自动化行为摘要,然后统一归并聚类。这种场景下,人的精力只花在看聚类结果和深度确认上,效率比逐个分析高一个数量级。
第三个是团队协作模式的变化。以前逆向分析总是一个牛人搭环境、抓数据、看汇编,全程单打独斗。REA 让金字塔下层的初级工程师也能参与进来:初级人员跑行为记录和初步报告整理,高级人员只处理 Agent 标记的高置信度重点和疑难杂症,工作分配更加合理。
就我个人这段折腾的体会来说,REA 带来的最大价值不是“替代逆向工程师”,而是把人的脑力从大量重复劳动中解放出来。过去我花在一个样本上的前四小时基本都是机械操作:起环境、导日志、搜特征、试错。现在这些工作大部分可以交给工具链和 Agent 去跑,我可以直接跳到需要人类判断力的部分,比如确认漏洞影响面、评估攻击可行性和设计修复方案。大语言模型的幻觉问题短期内不可能完全消失,但它能帮助分析师跑得更快、看得更全这一点,已经实实在在体现在每一次分析里了。
如果你也想试着把 AI Agent 引入自己的逆向分析流程,我的建议是别急着搞一套大而全的框架。先挑一个你平时最耗时的环节,比如“行为日志归纳”或者“函数语义标注”,做一个最小闭环验证一下效果,跑通之后再逐步把其他环节接进来。投入产出比最高的,永远是先解决你手头最痛的那一环。