我一直觉得反编译是这世上最不适合甩给AI干的活——它比考据一部残破古书还难每一步都可能错偏偏大模型又最擅长一本正经地给出错误答案。直到我接到一个非做不可的项目某款老式第一人称射击游戏FPS官方早已停止维护但玩家社区还想把它移植到现代引擎上继续对战。没有源码没有文档只剩一个十几年前的二进制。我先把这活儿交给老办法结果纯人工逆向干了三个月才恢复完地图加载模块和一半武器逻辑换自动化脚本也只能处理模式足够固定的代码一碰到引擎层虚表和状态机就全线翻车。最后我被逼着搭了一套AI智能体流水线持续往里喂了整整500B tokens居然真的把这款FPS项目核心骨架反了出来。这篇文章想讲的不是“AI多神奇”而是这500B tokens到底怎么烧掉的、智能体怎么分工协作、哪些地方惊艳、哪些地方让我差点砸键盘。如果你正准备用大模型做二进制分析、代码自动重构或者大型遗留项目的可读化改造这里面的思路和踩坑记录应该能直接抄作业。1. 为什么我从“纯人工逆向”改投AI智能体阵营1.1 项目起点一个没人维护的老FPS先说清楚这个项目有明确的现实需求。官方停更后社区版的服务器代码缺失地图文件也无法在新引擎上直接用。我们要做的是用反编译手段恢复出关键逻辑给社区版引擎的兼容层打基础。整个过程的边界很明确只做兼容性恢复和学习用途不碰任何需要绕过的防护措施所有代码分析都围绕社区玩家自己拥有的合法副本展开。一开始我完全低估了这款FPS的复杂度。它的代码量放到PC端不算大但特点在于几乎每个子系统都在跑热路径——渲染、武器、敌方AI、网络同步。一个玩家开一枪背后是一串多态调用武器基类虚函数分派到具体枪械类再触发弹道计算、动画状态机、命中检测、网络事件广播。这在静态反编译产物里就是一堆call [regoffset]没有任何符号提示人工看到这种代码只能顺着数据流一点点推。1.2 传统反编译手段为什么在这里失效传统路线有三条我全试过也全卡住了。第一条是直接读反编译器的伪代码。反编译器擅长把汇编转成可读性尚可的C风格伪代码但它丢掉的东西太多了结构体字段名、类继承关系、函数调用意图、状态机的整体结构。你拿到的是一张没有图例的地图街道都在但不知道哪条路通向哪里。第二个问题是反编译产物里充斥着编译器生成的临时变量一长串v1、v2、v3靠人脑去逐个恢复语义对百来个函数还行对几千个函数就是灾难。第二条是纯人工逆向。不是不会是太慢。团队里有经验的逆向工程师一天最多恢复三五个中等复杂度的函数还要反复调试验证。按这个速度要把武器引擎的几百个函数恢复清楚得大半年。而且人有一个致命弱点连续工作几周后会产生“我已经猜对了”的错觉很多结构体偏移错误就是这么漏进去的。第三条是自动化脚本。脚本擅长处理模式固定的代码识别字符串表、提取导入函数、统计调用关系这些都很在行。但游戏引擎的代码不是模式固定的模板同一个功能在不同模块里实现方式差异极大脚本一旦遇到复杂的多态调用和回调链就直接歇菜。1.3 为什么是“AI智能体”而不是“单次调用大模型”有人会问直接拿大模型当翻译器把汇编丢给它让它输出伪代码不行吗我试过。单次调用确实能把一个短函数的汇编“翻译”得相当漂亮比反编译器的默认输出更接近人能读的C代码。但问题是它没有记忆。你给它看第二个函数时它完全不记得第一个函数的结论。如果一段逻辑横跨十个函数你就得把前面九个函数的全部分析结果重复喂进去上下文早就被撑爆了。智能体的差别在于它是奔着一个目标去的拆解任务、带着记忆执行、调用工具、检查结果、根据反馈修正。我要做的就是把一个大型逆向工程拆成几千个子任务分配给不同角色的智能体由它们在记忆库和验证环境的支撑下滚动推进。我的角色从“逐行读代码的人”变成了“维护流水线和真值验证环境的人”。2. 500B tokens的账本大头都花在哪了2.1 先算一笔token开销模型500B tokens是个一听就让人腿软的数字。但真相是这个数字不是你拍脑袋定的而是由任务规模自然推导出来的。先用一个粗粒度的公式理解它总token消耗 ≈ 输入token × 重复系数 输出token × 迭代次数假设最终要恢复的可读伪代码规模在80万行左右。输出侧如果只写一遍几十B tokens确实够了。但问题出在输入侧和迭代次数上。每分析一个函数智能体不仅要看这一段的汇编还要带上周边函数的调用关系、调用方的约束、该函数在这轮之前的所有历史结论。平均每个函数相关的上下文会被重复读取5到10次。输入侧一放大整体消耗很快就冲到几百B了。再算上试错验证500B完全在正常范围。后面我实测下来单项任务的token消耗大概是这样的消耗方向量级约占比说明静态代码分析约180B36%汇编块、反编译伪代码、上下文反复输入试错与假设迭代约100B20%智能体提出错误假设被驳回后重做验证与交叉审查约220B44%编译测试、调试器比对、双模型对读知识沉淀与归档约数B不足1%档案库写入与检索这个账本不是说每个项目都会按这个比例分配但它反映了一个规律真正的花费大头不在“生成”而在“验证”。你让AI多写一段猜测很容易让AI证明这段猜测在真实运行环境下是对的才烧钱。2.2 为什么FPS项目比普通应用更费tokenFPS项目的token消耗比同规模的普通业务应用高出三五倍核心原因是隐式耦合。普通应用代码的逻辑边界比较清晰函数之间通过显式参数传递信息。游戏引擎不是这样大量状态藏在对象成员变量里通过回调、事件、全局状态管理器来流转。举一个实际例子。我在分析一个武器渲染函数时这个函数只有300行伪代码但为了确认其中一个字段到底代表“当前弹匣余量”还是“备用弹药量”智能体把调用它的三个函数全拉了出来又从其中一个回调函数的调用链回溯到了玩家输入系统前后花了大约4M tokens最后才锁定结论。300行代码4M tokens这个放大倍数在FPS项目里非常普遍因为游戏永远是状态机套状态机。2.3 三个“省token”的土办法500B烧到最后我总结出三个能显著省token的方法都是在不牺牲质量的前提下硬抠出来的。一是模块级增量复用。已经验证过的函数结论全部沉淀为档案条目。新会话不再重新分析而是直接读取档案。哪怕需要重新看也只读该函数本身不连带重读整个模块。二是双层模型策略。让便宜的小模型先做粗筛识别模式、命名变量、标记可疑位置。只有小模型标记为“高置信”或“疑难”的样本才进入大模型精读。实测小模型初筛的准确率大概七成剩下三成送给大模型后整体token省了三成左右。三是限制自我反思轮数。我给每个智能体设了硬约束最多推翻自己两次第三轮结论如果还没有验证通过必须标记为“存疑”并提交给人。没有这个限制智能体很容易在几个假设之间无限打转一轮消耗几十万token产出还是零。3. 智能体协作架构侦察、解码、顾问、审查四角色3.1 整体架构设计这套流水线我一开始就设计成四个角色每个角色的输入输出和工具都不同目的就是各管一段、互相制衡。各角色定位如下角色核心输入输出关键工具侦察兵二进制元信息、字符串、导入表模块划分与函数边界图反编译套件、字符串扫描解码者汇编块、模块上下文带临时标签的类型化伪代码反编译器API、调试器领域顾问伪代码块语义标注与结构建议引擎知识库审查官伪代码、原始汇编、数据流验收或驳回报告编译环境、差分脚本流水线的基本流程是侦察兵先切模块解码者逐模块产出伪代码顾问做语义补全审查官做反向验证。验证不通过的打回解码者重做验证通过的写入档案库。这样每个函数至少经过两次独立视角的处理单点错误被放大的概率低了很多。3.2 侦察兵从二进制汪洋里切出第一刀侦察兵的核心任务不是读代码而是画出地图。切入顺序是先读二进制头再整理导入表扫描所有字符串常量最后按调用图聚类把几万个函数划分成渲染、武器、AI、物理、网络等模块。这一步最管用的路标是字符串表。看到PlayerHealth、RespawnTimer、KillStreak这些字符串基本可以断定附近的代码在管玩家状态和计分逻辑看到图形API的调用名马上标记为渲染模块。侦查智能体做的事比我早年人工做的聪明之处在于它会用调用图把这些标记扩散邻近函数大概率属于同一个模块因为它被同一个模块调用了几十次。这一个阶段的产出是整个项目的地基后面所有角色的工作都依赖这张模块图。3.3 解码者把汇编“翻译”成有类型注释的伪代码解码者是整个流水线里最核心的角色。它的工作不是逐指令翻译而是识别高层模式从jmp回退看出循环从跳转表看出switch分支从[reg0x14]这类偏移访问看出结构体字段。我给它设计的输出格式是带临时标签的伪代码字段名先用偏移量占位后续由顾问统一绑定。举个例子一段武器伤害计算的汇编经解码者恢复后大概长这样// 原始汇编片段经解码者恢复后的形式 int weapon_apply_damage(Player* target, int baseDamage) { int damage baseDamage; // 0x14 偏移处的护甲值判定 if (target-armor 0) { damage (damage * 2) / 3; target-armor--; } return damage; }注意armor这个名字不是解码者从汇编里读出来的而是顾问在后续阶段结合玩家属性系统推断的。解码者的核心贡献是把控制流还原正确把数据访问关系写清楚语义命名交给更懂业务的人去补。这种分工可以避免解码者过度“发挥”导致幻觉泛滥。3.4 顾问与审查官领域知识和幻觉过滤器领域顾问的任务是回答“这段代码在游戏里是干什么的”。它的知识库里存了引擎架构的常见模式描述实体组件系统怎么组织、渲染队列怎么流转、AI状态机一般有哪些状态。当解码者产出一段“看起来像状态切换”的伪代码时顾问会补上一句“这可能是从‘瞄准’状态到‘射击’状态的转换”并把相邻函数中所有引用同一个状态变量的位置一起标出来。审查官则负责反向验证。它的做法是拿到解码者的伪代码后先尝试把它转成一份简化汇编骨架再和原始汇编做结构比对。不是逐字匹配而是比对关键要素控制流图是否同构、vtable槽位引用是否一致、循环边界是否吻合。不一致的地方审查官会输出差异报告打回解码者重做。我后来统计了一下经过审查官这一道关卡幻觉率从初始的20%以上降到了5%以下。这个角色的价值不是锦上添花是保命。4. 反编译一款FPS时AI必须翻过的那几座山4.1 虚函数表与多态调用链的恢复FPS的游戏逻辑几乎全部构筑在多态之上。武器有基类不同枪械是派生类敌人AI有基类不同怪物是派生类连UI里的按钮都是继承关系。汇编层面的多态调用特征非常明显一个对象指针的头几个字节存着虚函数表指针vptr调用时通过call [regslot]间接跳转。问题是静态反编译后你只看到一堆call [reg0x4]根本不知道这个slot对应的是哪个类、哪个方法。我让智能体专门扮演“vtable猎人”扫描所有构造函数——通常是在分配内存后立即写入vptr的序列——然后把每个slot上的方法地址收集起来再根据这些地址回溯函数名或字符串引用最终还原出一张类层次关系表。这个任务AI干得比我预期好得多原因是构造函数里vptr的赋值模式在汇编中重复度极高属于典型的模式识别问题。我大概只人工介入了20%的疑难类关系其余都是智能体自己整理出来的。4.2 玩家状态机与主循环识别FPS的灵魂是状态机玩家在空闲、移动、瞄准、射击、受伤、换弹、死亡这些状态之间切换敌人AI也有巡逻、警戒、追击、攻击等状态。静态反编译之后状态机是最难还原的一类逻辑因为编译器的优化会把case分支拆得七零八落一个状态的入口可能在函数A处理逻辑却在函数B出口又跳回函数C。我的做法是让解码者先输出所有可疑的状态枚举值再生成一张状态转换表。每个switch分支都标注“从哪个状态进入、经过什么条件、跳往哪个状态”。这些信息汇总后再反查函数之间的跳转图把零散的分支重新拼起来。这个过程原本特别消耗人工但让AI按“先列状态→再连边→最后补条件”的顺序做效率提升非常明显。最后我拿到了一张完整的玩家状态转换图分支还原率达到85%左右。4.3 渲染数学库的“宝藏识别”FPS项目里有大量矩阵乘法、四元数插值、点积运算、视锥体裁剪、坐标变换。这类代码在汇编里有强烈的模式指纹对AI来说简直是送分题。一堆连续的乘法和加法指令前面带着特殊的内存排列后面跟着一个投影函数的调用AI很快就能识别出“这是4x4矩阵乘法”。这部分是整个项目里token消耗最低、准确率最高的区域。原因很简单数学代码没有隐藏状态输入输出都是数值不依赖全局变量的神秘变化。凡是这类模式清晰的代码智能体几乎一遍过不需要反复试错。我也因此得出一个经验做这种大型逆向工程第一个阶段应该优先让AI啃数学库和工具函数先积累一批高置信度的“锚点函数”后面的状态机恢复才有抓手。5. 上下文窗口装不下500B记忆分层与分段复卷5.1 问题的本质不是一次对话而是一套档案体系很多想做类似项目的人会问500B tokens怎么塞进上下文窗口这个问题的前提就错了。500B是整个项目从开始到结束的token总流量不是某一次对话的长度。真正要解决的问题是几万次会话之间怎么让智能体始终记得曾经得出的结论不至于每次都从零开始。如果每次会话都从零开始那么消耗的不只是token还有一致性——昨天刚验证过的结构体定义今天换个智能体可能又猜出另一个版本项目越推进越混乱。所以我在项目第一个人工作包跑完之后就停了一天专门重建记忆架构。5.2 三层记忆架构全局记忆、会话记忆与档案库记忆系统最后设计成三层每层的生命周期和写入时机都不一样记忆层内容写入时机示例全局记忆层模块边界、函数清单、已验证事实侦察兵完成模块划分后“武器系统包含37个函数vtable索引4被基类占用”会话记忆层当前工作包内的临时推断解码者处理某个函数的过程中“疑似0x1C偏移是后坐力待审查确认”档案库工作包完成后的结论沉淀函数族分析结束后“伤害函数族全部恢复14个中12个正确2个待修复”全局记忆层不会频繁改动它是整个流水线的“宪法”。会话记忆层只存在于单个工作包执行期间工作包一结束就把其中有价值的内容提炼进档案库其他临时推断直接丢弃。档案库是跨会话共享的任何角色开工前都要先读相关档案。5.3 分段复卷让智能体像读编年史一样读代码代码不是孤立的集合它有强烈的时序关系。同一个功能族的函数往往在运行期形成一条调用链分析A函数时需要知道B函数会怎么调用它。我把项目按函数族切分成工作包比如“武器射击族”包括触发、弹道、命中、换弹、特效五类函数每次只分析一个工作包。分析每个工作包时我要求智能体先读档案库里所有与这个函数族相关的旧结论再开始新的分析结束后把新结论追加回档案库。这就像读编年史先读前面已经写好的章节再续写新的一章。如果只追结果不复卷新结论很可能和旧结论在细节上打架。复卷操作本身也会消耗token但它可以把后期的返工成本降到最低这笔投资非常划算。5.4 向量检索给了惊喜也给了教训我们还给档案库加了一套向量检索让智能体能按语义搜索“可能相关的历史代码”。结果第一次上线就给了我一个教训检索出来的内容是碎片化的智能体知道“有某个函数提到了伤害衰减”但不知道它在哪个模块、是什么状态、和当前分析有没有上下游关系。它拿着这个碎片反而比不看更迷茫。后来我加了两层索引第一层是模块摘要索引每个函数族有一段总结性描述第二层才是代码段索引。检索结果必须带上模块路径、函数名、验证状态、修改时间这些元数据智能体才能判断这段历史的可信度和关联度。加了这套改造之后相关代码的召回率明显提升。我的经验是做知识检索别急着上花哨的框架先把档案的元数据写规范了效果自然就出来了。6. 真值锚点与纠错AI胡说八道时怎么把它拽回来6.1 可执行的真值锚点编译、调试、数据流对照智能体再聪明写出的伪代码也可能是错的。怎么证明它对我的答案只有一句把输出交给机器执行让机器当裁判。这个项目里我铺了三类真值锚点。第一类是可编译锚点。AI输出的伪代码经过人工或辅助脚本转成C后要能成功编译成测试目标。能过编译不意味着逻辑正确但至少说明类型、依赖关系和语法骨架是一致的这是第一道大筛。第二类是调试器锚点。对关键函数设置断点单步执行核对寄存器值、内存内容、调用顺序是不是符合AI注释里描述的语义。比如AI说某个函数“把准星从窗口坐标转为世界坐标”但实际运行时输入只有鼠标增量没有窗口坐标那这个描述就是错的立即打回。第三类是数据流一致性检查。把每个变量的定义点、使用点、传递路径全部拉出来检查是否有断链。这一步可以抓到大量“看似合理但实则无中生有”的字段访问。6.2 双智能体交叉审查让两个模型互相挑刺除了机器验证我还做了另一个设计解码者产出的伪代码不让同一个模型自我检查——自我检查在同一套“逻辑偏好”里容易自己骗自己。审查官是另一套独立配置任务是从伪代码反推出简化的汇编执行骨架再和原始汇编做控制流图同构比对、vtable槽位比对、循环边界比对。这套方法抓错能力很强。因为解码者是从汇编到伪代码审查官是从伪代码到汇编两条路径只要有一个环节理解错了最终比对一定会露出不一致的尾巴。我统计过审查官平均能从一份伪代码里找出1.8处需要返工的问题其中六成是寄存器依赖错误三成是分支条件错误剩下的是标注不准确。它已经成为整个流水线里不可替代的质检员。6.3 实测中遇到的三类高发幻觉AI生成的伪代码再漂亮拿到机器上跑不通一切白搭。这里我把项目里遇到最频繁的三类幻觉列出来也写下对策幻觉类型典型症状根因对策寄存器复用读错把旧值当成新值没追踪寄存器生命周期改用SSA式数据流表达结构体字段错位函数能编译但运行结果不对根据可疑偏移随意猜测交叉引用并用调试器实测内联函数误判把重复代码当成独立函数未识别内联展开模板对重复代码做相似度聚类寄存器复用读错是最隐蔽的。在x86汇编里同一个寄存器在不同阶段保存不同值AI如果没有追踪每个寄存器的写入点很容易把前一条指令的参数当成当前指令的返回值。改用SSA形式的数据流表达后这个问题的发生率大幅下降。结构体字段错位是最难防的。AI猜了一个偏移量单独看好像讲得通但程序一跑就错。对付这个我没有任何捷径只能靠调试器实测和交叉引用比对宁可慢一点也不能放过。6.4 验证环节烧掉了一半token但这笔钱省不得账本里验证约占220B tokens接近总消耗的一半。单看很心疼但这是整个项目里最不该省的钱。原因很简单这在工程上是一个连锁反应问题。符号表就像地基地基歪了后面每个智能体都会依赖错误结论二次纠错的成本往往是初次验证的三四倍。到项目后期我干脆定了规矩没有经过机器验证的结论一律不进档案库其他智能体无权引用。这条规矩一度让流程变慢但也让最终产物的可信度保持在了一个相当高的水平。7. 成果复盘500B tokens烧得值不值7.1 最终拿到了什么整个项目结束后我拿到了这样一组数据子系统恢复函数数正确率可重建率玩家状态与计分约12085%高武器系统约46078%高渲染与视锥约21063%中AI行为状态机约18070%中网络同步约9045%低整体来看恢复出的可读伪代码有1700多个函数判定了1300多个结构体建立了2100多个符号名。这个产出足以支撑社区版引擎的兼容层开发。移植版最终能跑起单机和局域网对战画面表现和弹道手感已经比较接近原版了。对一个没有源码的十几年前老游戏来说这个结果远远超出了我最初的预期。正确率是动态验证的口径不是猜的每个标注为“正确”的函数都至少跑通了一次调试器单步验证。渲染和网络同步的准确率偏低和项目里最难的部分基本重合。7.2 AI擅长什么人必须看住什么复盘之后我把AI和人工的能力边界划得很清楚了。AI真正擅长的是高频重复模式识别数学库、构造函数、渲染状态设置、成组的赋值逻辑。这些代码有几万个相似片段AI一遍就能学会而且不会厌倦。项目里这部分代码的恢复速度快到令人怀疑人生。AI最露馅的地方是长程数据流和隐藏状态。典型例子是“存活玩家列表”的更新链路它跨越十几个模块通过异步回调和全局事件传递中间还经过几个被其他子系统复用的公共函数。AI每次分析一段都会觉得眼前逻辑完整但它看不到全局最终需要我从档案库里跨模块追踪人工把整个链路补出来。网络同步恢复率只有45%这个项目让我深刻认识到协议逆向前置条件的重要性。机制代码的逻辑藏在代码结构里而协议逻辑藏在二进制格式和时序约束里后者恰好是纯静态分析最不占优势的领域。7.3 如果重新来一次我会改这三个地方500B tokens不是最优解它只是第一次跑通这条路时的成本。如果让我重做一遍至少有三个改动可以把成本压到250B到300B。第一步先建风格样本库再开干。开工第一周不分析任何业务函数只让智能体学习这套旧引擎的编码风格函数命名习惯、结构体组织方式、异常处理模式。样本库建好后后续所有智能体都会沿用同一套风格先验猜对概率大幅上升。第二步粗恢复和精调分离。先用便宜小模型跑完整个二进制的粗恢复只拿回函数边界、调用关系、基本控制流搭起一个粗糙骨架再让大模型集中精力攻坚骨架里标记为“高复杂度”和“待确认”的函数。大模型的token就只花在刀刃上。第三步验证前移。不要等一个模块全部恢复完才去验证。每拆完一个工作包就立刻建立最小测试环境跑通一个包再进下一个。前期的验证投入会增加一点但后期返工能省一大笔。说实话500B这个数字第一次出现在预算表上的时候我自己都怀疑是不是疯了。但真把它跑完之后我对AI做逆向这件事的看法彻底变了它不是万能的但它是第一个能把这种规模项目的初稿速度提升几十倍的工具。我现在更愿意把它当成一个手快、眼亮但需要盯着的实习生——给它工具给它真值检查机制它会还你一份可以继续打磨的初稿。而你要做的就是替它守住那根不能错的底线。这是我从这个项目里踩完500B的坑之后最想分享的一句话。
阅读完成 · 觉得有帮助?