AI 不会帮你做游戏,但它读得懂二十年前的二进制

抓包代理:自动识别链路,对每一帧给出成帧判定

前段时间我在复刻的时候,卡在一个特别小的动作上:「捡东西」。

就是角色走过去,把地上的东西捡起来,就这么简单。我用客户端的二进制试了很久,就是测试不过。

最后我才发现,答案根本不在客户端,而在服务端里,而且跟我猜的方向完全相反!

这个系列的第 1 篇讲过:把一款 2003 年上线、早就停运的韩国网游客户端复刻一遍,标准只有一条——跟原版一模一样。

上一篇的 fallback 事件收尾时留了个问题:AI 会编,而且编得像真的——那它说的话,到底信还是不信?

这一篇讲整个系列的地基:为什么逆向这件事特别适合交给 AI,以及更重要的,拿什么判断它读得对不对?

逆向本质上是个「读」的问题

先看规模:原版客户端的可执行文件大约 6 MB,里面有 17,000+ 个函数,没有符号、没有注释、没有源码。

而且服务端那边还有 7 个独立的服务器进程。

一个人从头读,根本读不完。这完全不是勤奋不勤奋能解决的问题。

所以我们需要 AI 的「读」,把 2003 年开发者做过的决定,从编译产物里一个一个反推出来。

而读,恰好是大模型远超人类速度的地方。它读反编译不会喊累、也不会走神,凌晨三点跟下午三点一个状态。

听起来很美好,感觉 AI 在这个项目里特别有价值,是不是?

是也不是,AI 是「读得快」,但不是「读得对」,而且还「错得快」。🤦‍♂️

读得快,错得也快

这是整篇最重要的一句:正因为它读得快,它错得也快,而且错得很像真的。

大模型给结论的时候,语气永远是确定的:「这个字段是血量」、「这个分支在校验距离」。

说得跟真的一样。有的对,有的错,从外观上根本无法区分。

人读累了还会标注一句「这里不确定」,模型不会,它对和错的置信度写在脸上是一模一样的(人至少还会心虚)。

更麻烦的是,错误的读数往往比正确的更「圆」。它会把周围的代码也解释得自洽,一套结论环环相扣,你顺着读下去只觉得通顺,挑不出刺。等实机一跑,一整个垮掉。

所以整套方法的重心根本不在「让它读」,而在于「拿什么判断它读得对不对」。这也是这篇不写成工具教程的原因,工具谁都会装,判断标准才是缺的那个。

这里就得给那些想靠一句话就让 AI 完成分析、破解、重构的小伙伴泼个冷水了:自己不会判断,只有 AI 和工具,是没有用的——基本功还是得练!

三层工具,各管一段

实际干活的分工是三层:

角色 干什么
反编译器(主力) 日常全部分析 结构体、函数原型、枚举、重命名、注释回写
第二个反编译器 二次意见 交叉验证不放心的读数;恢复 C++ 类名这类主力常常认不出的东西
动态插桩 / 中间人抓包 裁决者 实机跑起来,看它到底发生了什么

前两层就是 Ghidra、IDA 这类公开工具,动态那层是 Frida 这一挂的。名字其实不重要,重要的是第三层为什么必须存在。

日常干活九成时间在主力那层,读数不放心了才去第二层拿个二次意见,前两层的说法互相打架、或者跟行为对不上了,才请第三层出来裁决。

层数越往后,成本越高,但权威也越高。

因为这个客户端登录之后的流量是加密的。挂在发送函数上,看到的全是密文。想拿到字节级的真相就只有一个办法:让原版客户端和原版服务端对着跑,从中间把明文完整录下来。

而这份抓取下来的原始数据才是标准答案。

实机 > 反汇编 > 文档

于是有了项目规范里明写的一条权威顺序:

实机捕获 > 反汇编 > 文档

三者打架的时候,按这个顺序判。注意文档排最后:包括我自己之前写的文档。自己写的也不能豁免,因为文档从落笔那一刻起就在腐烂,区别只是烂得快慢。

反汇编为什么排中间?因为反汇编本身也是一次「读」——反编译器在猜,我在猜,模型也在猜,猜的都是「代码看起来会怎么做」。

而实机给的是「它实际是这么做的」。一个是推测,一个是事实。两者冲突,永远信后者。

下面五个案例,每一个都是交过的学费。

案例一:捡东西的答案在服务端

回到开头那个问题:捡东西这个动作,到底什么条件下服务端才认?

只读客户端,我和 AI 反复猜了很久。最顺的猜测是「肯定有距离限制」——合情合理,哪个游戏让你隔着半张地图捡东西?然而实机测试一直不通过。

最后是去读服务端的二进制才拿到答案:判定条件在移动包里的一个状态字节上,而且服务端根本没有做距离校验。之前所有基于「肯定有距离限制」的猜测,方向就是错的。

教训:客户端只能告诉你它发了什么,规则在服务端。问「客户端该发什么」的时候,先去读服务端的处理函数,不要从客户端反推。

案例二:一个错了很久的结论

项目文档里长期写着一条:登出时脚下那道光柱,是没有声音的。这个判断被当成事实用了很久。

2026-07-31 做了一次实机 A/B:把原版跑起来,挂上钩子,把整场——登录、吃药、打怪、传送、登出——所有音效逐条比对。

结果登出光柱是有声音的。证明 AI 之前的判断是错的。

同时还发现,登录音效原版会同时响两遍:一遍是代码直接放的,一遍是数据表触发的。这个「重复」的 bug,最后确认是原版行为,就照实保留了。

这条案例最让人后怕的地方在于,错的那条结论不碍任何事。

光柱没声音,游戏照样玩,文档照样被引用,没有任何报警会响。它只是安静地错在那里,等一次实机对照来收尸。

案例三:文档写错了格式

背景音乐这一块,旧文档写的是某种微软的音乐格式。一次多路并行的实机分析把它纠正过来:其实就是 MP3。

这条的教训最短,也最让人不舒服:文档会烂。今天核对过的结论,三个月后可能已经不成立,而它看起来跟正确的结论一模一样。

案例四:上周刚翻的车

前三个案例都是几个月前的,你可能会说:那是早期不熟的时候踩的坑嘛。那我们说个上周的。

2026-08-09 做了一次实机抓包,把原版两台服务器之间真实跑的主干协议流量记录下来,原本几个消息编号都是从反汇编里读出来的,本以为确定无误,结果全是错的,最后按抓包的真实数据修正。

结果发现,在早期的 AI 反汇编分析过程中有五个消息名字被改错了,能发现是因为它们跟协议的实际行为自相矛盾。

顺便写了个校验工具:抓包代理可以自动识别哪一条链路,并且对每一帧给出成帧判定。

这钱花得非常值得,裁判得自己先可靠,不然你拿一把不准的尺子去裁数据,裁出来的全是冤案。

这条为什么值得单独写?因为它发生在项目已经很成熟、协议文档写得很详细之后,AI 照样读错。

前三个案例还可以安慰自己「那是早期」,这一个不行。再次说明「实机 > 反汇编 > 文档」不是新手保护措施,是常设纪律。

项目越往后走,文档越厚、反汇编标注越全,人越容易偷懒信它们,这条顺序就越要紧。

案例五:证据也分楼层,别查错那一层

就在写这篇的这一周,又交了两次学费。

之前一直在分析的客户端是一个 ASPack 脱壳过的版本,这周正式换成了 2003 年官方原版。

两份反汇编数据库并存,原版的在 IDA 里,脱壳版的在 Ghidra 里,长得都像那么回事。

结果换完目标后,AI 想都没想,顺手就打开了 Ghidra,来「分析」原版可执行文件。

它拿着之前那份数据库里的旧偏移,直接往新版本上套,然后给出各种奇怪的建议,每个结论都错得理直气壮,令人发指!

还有就是,版本库里的文档记了一大堆从二进制里读出来的旧地址,AI 依然视旧文档为圣经——而那些旧文档一个字都没改,安静地躺在那里,等着后续的工作爆雷。

所以,我给它立了条新规矩:地址要重新从二进制里推,永远不许从文档里抄。 文档不只是会写错,它还会过期,这比没有文档更可怕。

长期记忆

规范里还有一条硬规矩:

反编译工具的数据库只是一个工作台。任何事实,都不允许只存在于工具里。

工具数据库是二进制的,不进 Git,没法 review,换台机器就没了。

所以所有结论都要导出成能用 Git 管理的纯文本,工具里的状态随时可以重建。

纯文本还有一个附带好处:每条结论的改动都有 diff,谁改的、什么时候改的、为什么改,一翻历史就一清二楚。

这一条对于 AI 干活尤其重要。模型在一次会话里得出的结论,如果不落到文件里,下一次会话它就再也不知道了。

并且还会很自信地重新猜一个。你猜猜它会不会猜出同一个答案?🐶

说白了,文件系统是模型的长期记忆,版本库是这套记忆的防伪机制。少了这两样,每一次会话都是从零开始的重新猜测。

几条能直接用的

  • 把 AI 当成给假设的机器,别当成给答案的机器。 它的价值是读得快,不是读得对。每次它说「这个字段是 X」,心里自动翻译成「这个字段可能是 X」,然后去找证据。
  • 备一个跟模型完全无关的判断手段,权威高于任何模型输出。 这个项目里是实机抓包;你的项目里可以是集成测试、线上日志、对着真实数据跑一遍。没有这一层,你就是在拿模型的自信当证据。
  • 结论当天落进 Git。 不落盘的结论等于不存在,而模型对「不存在的结论」从来不会说不知道——它会重新猜一个,还猜得理直气壮。
  • 怀疑「客户端该发什么」的时候,先去读服务端。 客户端只能告诉你它发了什么,规则在另一边。从单侧反推协议,推出来的东西通常合情、合理、而且是错的。
  • 这个系列第 1 篇《五个月,一个人,把一款 2003 年的韩国网游客户端重写了一遍》里说,重活是读、而读是大模型最强的地方。这篇是它的另一半:读得最快的地方,恰恰最需要一个人工裁判。