资讯动态

用AI Agent重塑逆向工程:从动态分析到二进制还原的自动化实践

发布时间:2026/10/13 11:25:22 来源:尧图企业网站定制
1. 逆向工程还没被 Agent 替代它真正擅长的是整合与调度1.1 传统手工逆向的时间花在哪我不知道别人怎么开始的反正我第一次听说把 AI Agent 用到逆向工程上时脑子里第一反应是这不就是拿 LLM 把老逆向师傅的活儿再干一遍吗可等我真正拆开看才发现传统逆向分析里最耗时间的部分根本不在“看懂代码”这一步而在“反复切换工具和上下文”这一步。一个稍微有点规模的 App 做下来你至少要经历这么一圈先把应用跑起来用动态插桩工具看它调了什么函数再开抓包工具看网络请求和返回然后解包静态资源读配置清单接着反编译代码从几千个方法里找到关键路径最后再回到动态环境验证你猜的逻辑对不对。每一步之间都要手动搬运数据抓到的类名要去反编译结果里搜反编译看不懂的函数要到调用栈里对照调用栈里的符号名又要在资源文件里找线索。这中间只要换一次工具脑内缓存基本就断了。我试过用脚本把这些步骤写成固定的批处理问题是逆向分析不是流水线不同目标的入口、逻辑、保护方式都不一样固定脚本一遇到例外就废了。这时候你需要的不是一个“自动执行预设命令”的脚本而是一个能根据上一步结果决定下一步动作的智能调度系统。REA 就是奔着这个缺口去的。1.2 Agent 切入的准确位置指挥工具而不是发明工具REA 的全称是 Reverse Engineering Agent核心思路只有一个把逆向工程里重复、机械、吃上下文的那部分工作交给 LLM Agent 去干人只负责判断方向和审核结果。它不负责把一个二进制文件变成奇迹它负责拿 LLM 的推理能力去指挥一堆已经存在的工具比如运行时插桩、反汇编器、字符串搜索、调用链提取让这些工具按顺序执行并根据上一步的结果决定下一步做什么。你可以把它看成一位现场协调员动态插桩工具是它的听诊器反编译器是它的显微镜解包工具是它的开箱刀而它自己负责看检查结果决定下一步拆哪里。我跑过的 Agent 循环基本长这样def run_rea_analysis(target): plan llm.plan(对目标 App 做行为与二进制分析目标找到核心输入处理函数) context [] for step in plan: result tool_executor(step, target) context.append(result) if result.status error: fix llm.suggest_fix(step, result) context.append(tool_executor(fix, target)) return llm.write_report(context)这段伪代码说明了一个关键区别REA 不是一个“自动破解器”而是一个持续调度的 Agent。它和人做分析时的思路一样也是先猜、再验证、猜错了就换方向只是它不需要休息可以在几分钟内完成几十轮工具调用。我实际用下来效率提升最大的一段并不是“读伪代码”这个环节而是“发现下一步该查什么”这个环节。过去这一步完全依赖个人经验现在可以交给 Agent 的推理能力。虽然它偶尔会跑偏但只要你设定好检查点它跑偏的代价远低于手工遗漏。1.3 合规边界先讲清楚这套流程只用在授权目标上在我把具体方法摆出来之前必须先说一句非常重要的话REA 这套流程只能用在你有权分析的对象上。什么叫有权要么是你自己开发的 App要么是公司或客户明确委托你做的安全测试要么是开源项目、CTF 题目这类本身允许被研究的代码。标题里的“破解”我理解为把黑盒还原成白盒的过程不是绕过授权机制去白嫖功能。逆向工程本身是安全研究、漏洞分析、知识学习的正常手段但拿它去分析任何你无权接触的 App结论就是越界。后面所有操作我都会默认你已经站在合法授权的前提下。简单说技术本身是中性的用在哪、为谁用这个判断比一百个 Hook 脚本都重要。把合规意识刻进流程里REA 才是一款对自己负责的工具。2. 动态行为分析让 Agent 先用日志画出 App 的执行地图2.1 动态分析为什么比“翻开代码”更适合第一步做逆向最怕的事情是闭着眼睛进到一个完全陌生的代码仓库里然后试图用跳蚤跳高的方式去理解整个系统。行为分析的意义在于它能在你打开反编译工具之前先建立起一层“预期”。你不需要知道一个按钮背后的函数具体长什么样你只需要知道用户点击按钮之后应用会发起一个网络请求、把加密过的内容写到本地文件、然后刷新界面。有了这层动态预期你再去静态代码里找“那个加密函数”时搜索范围就小了很多。REA 的第一层能力就是做自动化的行为采集。它会在目标 App 启动时注入观察代码记录被调用的类和方法名、关键函数的入参和返回值、操作后产生的外部特征比如新建了文件、发起了网络请求。这和很多测试工程师跑自动化测试的思路很像但区别是 REA 不会按预设用例跑它会根据你给的“分析目标”自己决定要触发哪些行为。比如目标是“找到登录逻辑”它就会优先去观察所有和认证相关的函数目标是“找到某个字符串的生成算法”它就会优先 hook 所有接收字符串参数的方法。行为层收集到的信息质量直接决定后面静态分析的准确率所以这一步值得花时间做扎实。2.2 让 Agent 自动写 Hook 脚本而不是手动猜方法名动态行为采集最常用的手段是运行时插桩核心能力是给正在运行的代码“打补丁”让函数调用时额外打印参数和返回值。常见方案对比可以整理成一张表方式适用对象上手难度关键优势进程运行时注入原生/混合应用中不需要重启进程适合长期观察启动时注入需要 hook 初始化逻辑时中不会错过早期函数调用轻量日志 hook快速验证低改造成本小只记录关键点REA 在这个环节做的事就是把“我想观察方法 X 的参数和返回值”翻译成一段可执行的 hook 脚本。以 JavaScript 插桩为例Agent 生成出来的脚本风格是这样的Java.perform(function () { var target Java.use(com.example.securenote.core.CipherBox); target.encryptText.implementation function (input) { console.log([hook] encryptText called, input input); var result this.encryptText(input); console.log([hook] encryptText result result); return result; }; });看起来简单但这里有一个 Agent 和人一样必须面对的问题你怎么知道有encryptText这个方法所以 Agent 不会凭空写脚本它会先用反射接口把目标类里的所有方法列出来看名字、参数列表再挑和任务相关的对象去下钩子。这其实是个很好的思路让 Agent 先做“侦察”再决定“打哪”而不是一上来就乱猜函数名。2.3 日志和对象状态要横向对照才能还原因果链单看函数调用日志往往只能得到“发生了什么”的表面叙事。比如你看到encryptText被调用输入是明文输出是一串看起来像密文的内容但这还不能证明它就是加密函数因为也许它只是做了 Base64 编码。要判断真实逻辑REA 会把行为日志和对象状态变化放到一起分析调用前后内存里某个字符串有没有变、调用后有没有新建文件、文件内容是不是和返回值一致。这些关联信息是纯日志抓不到的。我常用的做法是让 Agent 在行为采集的同时定期 dump 关键对象的属性值或者监控应用沙盒目录里的文件变化。等行为跑完Agent 会生成一张“操作-结果对照表”。比如一次典型会话可能产出这样的结论CipherBox.encryptText()接收明文 A返回密文 B同时把 B 写入了securenote.db的字段cipher。这个信息链非常关键因为到了静态分析阶段你只需要搜索“对同一个数据库字段赋值”的代码就能反向定位到调用点效率提高很多。我一直觉得动态分析做得好不好不取决于你收集了多少条日志而取决于你能不能把日志还原成一个有因果关系的“故事”。REA 的价值就是它会把零散日志整理成故事再把这个故事作为静态分析的地图。3. 静态资源与结构盘点动手还原前先摸清目标的骨架3.1 拆包和资源提取先把零件摆上桌动态分析有了初步结论接下来要去静态侧找证据。这一步做的第一件事是拆包。无论目标 App 是什么平台整个安装包其实就是一个压缩文件里面装着可执行代码、资源配置、清单和元数据。拆包的意义不是直接读二进制而是先弄清楚“这个 App 有哪些组成部分、入口在哪里、权限边界是什么”。对常见的移动应用包我一般分成两个层级处理第一层是直接用解压工具把所有文件倒出来第二层是解析清单/配置元数据用专门工具对代码进行反汇编和资源解码。REA 会把整个拆包过程当作一次“资料盘点任务”它会自动解压资源用工具还原可读配置再把解析结果按模块分类。例如清单文件里通常会声明这个应用包含哪些组件、启用了哪些系统权限、对外暴露哪些服务。即使没有细节代码这些信息已经能帮你建立行为假设一个需要定位权限的地图类 App和一个需要读取通讯录的社交类 App分析的侧重点完全不同。Agent 在这一阶段还会做一件事就是提取所有硬编码字符串和资源引用。这些字符串往往藏着 API 地址、加密算法名、错误提示等线索。目标里面只要出现过 “AES” 这个词后面分析基本上就有一个明确方向了。3.2 入口清单决定从哪个类开始读拿移动 App 举例无论平台怎么抽象每次都必然有一个“启动入口”和一个“界面加载逻辑”。 静态阶段要做的不是在几万个类里大海捞针而是先在配置清单里找到启动入口组件然后把它当作分析的第一站。启动入口通常对应一个界面控制器它的生命周期方法里会做界面初始化、读取参数甚至调用核心业务逻辑。把这些生命周期方法打开等于打开了一扇门入口接什么数据、跳转到哪个界面、初始化时创建了哪些服务这些信息会形成一条主链路。REA 的做法是让 Agent 在解析完清单之后顺着入口类往下走先看它的初始化方法收集它 new 了哪些对象再看这些对象各自的类定义找出它们都暴露了哪些方法最后比较这些方法名和行为日志里的函数调用记录找出重合的部分。重合的这部分就是你接下来真正要盯住的“核心逻辑区”。很多新手会卡在“我要看所有代码”这个误区里而 Agent 的优势恰恰是没有耐心它只会按“跟任务相关的链路”走。你给它的目标越明确它推荐的入口就越准如果目标含糊它就会退化成一台只会罗列类名的“名词解释器”。3.3 调用关系树动静交叉把地图画干净静态分析最难熬的时候不是看单个函数而是看函数之间怎么调用。你可以用反编译工具打开某个方法但一个方法里可能调了二三十个其他方法而这些方法分布在完全不同的类里。人工跟踪这种调用链非常容易迷路你需要来回搜索方法名记录谁是调用方谁是外部依赖还要随时注意循环引用。REA 在处理这件事时会让 Agent 把反编译工具导出的调用图接口自动跑一遍把目标方法的所有引用位置抓出来生成一张调用关系树再结合动态日志里记录过的调用顺序给这棵树标注“哪些路径是实际发生的哪些只是理论可达”。这里的价值特别明显理论调用图可以很大但实际执行路径往往只有两三条。Agent 把两套数据叠在一起等于把一张杂乱的地铁图简化成了一条你真正要坐的线路。我遇到过不少情况静态上看到一个方法有三十多处引用看起来特别复杂但动态日志一对照只有两个调用点真的出现过。这时候就知道该把注意力集中在哪了。这种“动静交叉验证”的思路贯穿 REA 的整个流程也是让它和单纯的反编译工具拉开差距的原因。4. 二进制级还原从行为特征反推核心函数破解不是绕过4.1 反汇编和反编译是两个层级别混为一谈静态分析走到后段你会遇到一个分水岭有些目标 App 的代码逻辑并没有被完整还原成高级语言而是以汇编指令或者中间表示的形式躺在二进制里。这种情况常见于用非托管语言编写的核心模块、商业加固模块或者跨平台编译产物。这时候需要的工具链就变成反汇编器和反编译器。反汇编器负责把机器码转成汇编指令告诉你 CPU 执行了什么反编译器负责再进一步把汇编还原成接近高级语言的伪代码告诉你“人的意图大概是什么”。REA 在这里的角色有点像“代码讲解员”它拿到反汇编结果后会先让 Agent 做一轮符号扫描把常见库函数、常量字符串、导入表都标记出来再把这些标注喂给 LLM让它输出一段带注释的伪代码。我常用的交叉验证方式是先在反汇编层面看数据引用比如某个函数访问了一个特殊的内存字面量那么大概率这个函数和某个关键常量相关然后到高级伪代码层面把这段逻辑和动态行为日志里的输入输出做对比。两道证据对上了这个函数的功能基本上就可以定案了。4.2 把长函数拆小块让 Agent 当反编译代码讲解员反编译工具生成伪代码的能力已经很强了但伪代码依然是反编译器的规则输出变量名可能是一堆形如local_78的占位符类型信息可能是粗略推断控制流里还可能有反编译器自己的伪宏。人肉看这些代码很容易被拗口的表述带偏。Agent 使用的策略是“分块讲解”不把一个巨大的函数整体扔给 LLM而是把函数拆成 5 到 10 行的小块每块让 Agent 回答四个问题这段在做什么、输入来自哪里、输出流向哪里、有没有和已知加密库/字符串相关的特征。等所有小块都分析完再让 Agent 合并成整体逻辑。这个技巧看着笨拙但在上下文受限的现实环境里非常有效。大部分模型一次能处理的信息量有限小步快跑反而比一口气吞下整个函数更稳定。另外一个值得记录的细节是Agent 在讲解代码时往往会产生“幻觉性命名”明明只是做了个字节交换却因为里面出现了一个看起来像 key 的变量就猜测这是加密算法。所以我在流程里专门设计了一步“反讲解校验”要求 Agent 的输出必须能对应到实际指令中的具体参数和操作。宁可让输出啰嗦一点也不要因为它猜得顺滑就盲信。4.3 行为特征反查关键函数比从头读代码更快二进制逆向最实用的经验之一就是“从结果倒推源头”。如果你在动态阶段已经观察到某个核心函数的输入输出特征比如收到固定长度字符串、返回一串特定密文那你到二进制里找它的方法不是从头开始读代码而是直接搜索这个输入输出特征在代码中留下的痕迹。这些痕迹包括字符串常量、特定的位运算模式、内存写入顺序、导入表中被调用的标准函数。Agent 可以自动把这些特征组合成一个搜索式在反编译结果里做全量匹配然后把匹配到的所有位置汇总。这种方法对加密逻辑特别有效很多开发者在应用里自己实现了加解密流程哪怕他们最终调用了标准库函数在数据变换前后也一定会出现典型的特征操作比如异或循环、查表、位移。Agent 会把这些操作和动态日志里的函数调用点做关联覆盖掉“从入口一层层追”的低效路径。这里想再强调一次二进制级“破解”的核心关键词是“还原”整个过程的目标是理解目标软件的行为与逻辑而不是破坏、绕过或滥用。分析过程中生成的任何伪代码、调用链和报告都只应服务于授权范围内的安全研究、教学或开发调试。5. REA 实操一条龙五步从零还原一个模拟目标的完整过程5.1 先造一个合规的模拟目标为了演示不越界我准备了一个我自己写的模拟目标一个叫com.example.securenote的简单笔记应用把用户输入的标题做一轮字符串变换后写入本地文件同时在界面显示变换后的结果。这个 Demo 没有真实的云端接口也没有第三方 SDK做它的目的就是让整套流程在自己可控的范围内跑通。你得知道实操练习最忌讳一上来就拿真实生产环境试手。我建议每个人都先搭这样一个“靶场式”目标把 Agent 的每个步骤跑出信心后再到有授权的商业项目里使用。搭建目标的过程很简单一个空工程、一个按钮、一个输入框、一个文本显示区域以及一个名为CipherBox.encryptText()的核心方法。这个模拟项目的代码量很小但它已经覆盖了 REA 的完整流程有界面入口、有核心处理函数、有文件写入。实战中你会遇到的功能类型它基本都包含了唯一的区别只是规模。5.2 Agent 的五步执行链路每一步都在验证上一步我把整个 REA 的实跑过程拆成五个大步骤Agent 会沿着这个循环执行。第一步是动态采集让目标 App 启动Agent 自动注入监听代码记录点击按钮到文本变化的完整路径。第二步是特征提取从日志里找关键类名、方法名、输入输出和文件操作记录。第三步是静态检索基于动态特征去反编译结果里搜索对应的方法和调用链。第四步是二进制验证在反编译代码层面确认核心方法的运算细节并把关键参数和分支标记出来。第五步是回归校验修改输入重新跑一遍动态采集用新的日志验证静态还原的逻辑是否一致。这五步不需要人为穿插Agent 会自己决定从一个阶段进入下一个阶段的时机。比如它在第三步没有找到匹配方法就会回到第一步重新补充行为数据而不是硬着头皮继续。执行的关键在于“中途不手工接盘”你只需要启动 Agent、给定目标、指定产物格式然后观察每一步生成的分析中间结果。如果哪一步的结果和常识冲突比如日志显示调用了一个静态分析里完全不存在的方法Agent 会把它标记为异常并尝试重新取证。我实际跑完这一套流程后产出通常是两份东西一份是行为分析报告另一份是核心逻辑还原说明。前者用于回答“这个 App 做了什么”后者用于回答“它是怎么做出来的”。5.3 四段式报告怎么生成才不用返工机器自动生成的报告最常见的问题就是“看起来全面但站不住脚”。为了避免这种空壳报告我在 REA 里给 Agent 指定了四段式结构第一段写清楚分析目标、授权范围、分析环境第二段放行为层面的证据包括关键调用时间线、输入输出样例第三段放静态和二进制层面的证据包括方法签名、调用链和伪代码关键片段第四段给出结论结论里每一项都必须对应到前面某一项证据。如果一段结论找不到证据Agent 必须明确标注“推测”而不是让它混进事实陈述里。这个结构看起来简单但能让报告真正经得起同事和客户的追问。我还习惯让 Agent 在报告的末尾加一栏“待验证项”把所有没走完验证流程的猜测单独列出来。这样即使 Agent 有幻觉也不会污染已经验证过的结论。6. 避坑实录与验证方法让 Agent 的分析结论可回查、不跑偏6.1 Hook 白写大多是时机问题不是脚本问题我最早用 REA 跑动态采集时遇到最多的问题就是脚本明明注入成功日志却一条都没有。后来排查了一圈发现绝大多数情况是 Hook 时机太晚目标 App 在我注入之前已经把要观察的方法执行完了。解决的办法是让进程启动后、在入口代码执行前完成注入或者给目标方法增加一个延迟等待条件。在实际操作中我会让 Agent 在刚开始抓行为时优先看一眼目标方法的声明位置和调用时机再决定用立即注入还是延迟注入。还有一类问题是线程界面操作和后台任务运行在不同线程Hook 打印语句虽然存在但中途发生了异步回调日志顺序混乱。对这种情况我建议在 Agent 生成的脚本里强制添加线程标识和时间戳后续分析才能把不同线程的事件理清楚。这两条经验都属于“工具不复杂错在预期不对”的典型坑。6.2 上下文窗口不够时用三层压缩法解决LLM Agent 不是无限内存处理超大函数时很容易把前面的细节忘掉。我现在的做法是三层压缩首先用静态分析工具做一次函数精简去掉外部库调用部分只保留任务相关路径其次让 Agent 对每段伪代码生成更精炼的“逻辑摘要”存成一个可检索的中间文件最后在最核心的环节再把摘要拉回上下文做深度的逻辑推理。这种分层记忆机制很像人的思维方式先看大概再看重点最后看细节。如果你发现 Agent 在一轮分析里反复重复同一段结论大概率不是模型变笨了而是它的记忆里塞了太多不重要的东西。这时候的解法不是买更大的上下文而是把输入变得更干净。6.3 遇到混淆和加壳别急着脱壳我想先说结论不要一上来就脱壳。先做行为分析再做资源盘点再到反汇编里搜特征字符串。如果目标 App 的保护强度并不影响你回答“它做了什么”这个问题那很多情况下你根本不需要碰更底层的东西。但如果静态代码确实被混淆成无意义符号名而你又必须还原核心逻辑那才需要考虑在授权范围内做脱壳或内存 dump。这类操作在技术上并不难难的是它要求你对进程的内存布局和 App 的加载机制足够熟悉而且容易制造大体积内存镜像导致分析环境卡死。我的建议是先把脱壳当成最后手段而不是默认选项。另外凡是涉及加壳目标的报告一定要把脱壳前后的代码差异写清楚避免让读者以为你“凭空变出”了源代码。6.4 三验法验证结论防止 Agent 编出“合理幻觉”REA 最大的风险不是它能力不够而是它太自信。模型在解释一段绕口的反编译代码时很容易生成听起来非常合理、但实际上不存在的内容。为了防幻觉我总结出一个“三验法”第一验单步运算验证拿一个已知输入手动跑一遍还原出来的伪代码看输出是否和动态日志一致第二验输入变异验证改变参数重新运行看行为特征是否随还原的逻辑预期变化第三验交叉验证用两种不同工具分别生成伪代码比对关键段落的一致性。这三步做完我才会把一个结论写进报告的事实部分。很多同事觉得这套流程麻烦但逆向工程本来就是个试错学科任何不经过验证的“聪明结论”最后都可能在线上环境里变成事故。宁可慢一点也要保证每一个结论都能追到证据。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑