Birditch的博客 Birditch的博客

拆《生死狙击》的战斗引擎:从 dump DLL 到绕过反作弊

游戏一开,反作弊就跟着起来了。它盯着你,你也可以反过来把它拆开看看——这篇讲怎么从内存里 dump 出战斗引擎,以及反作弊这场拉锯是怎么打的。

上一篇拆的是《生死狙击》的 Flash 大厅,走的是 SWF 解密和 AMF3 协议那条线。但真正的对枪发生在战斗引擎里——那是一个 Unity 客户端,和大厅完全两套东西。这篇就从它入手。

先说明:本文是技术分析记录,讲的是原理和方法,不提供成品工具,也不涉及具体的对抗代码。写下来是因为「客户端信任」这件事本身值得聊——它对做游戏安全的人同样有参考价值。


一、开局:GameGuard 已经在盯着你了

打开游戏那一刻,反作弊 GameGuard 就开始跑了。它一跑起来,就意味着你在游戏里的一部分行为——进程、内存、模块、可疑句柄——都在被监听和检测。

这是所有客户端反作弊的共同前提:它和游戏跑在同一台机器、同一个信任域里,既是裁判也是选手。理解这一点,后面的拉锯才讲得通。


二、把战斗引擎从内存里 dump 出来

战斗引擎是用 C# 写的 Unity 程序。这类程序有个绕不开的特点:无论它的原生 DLL 在磁盘上加没加密,只要运行起来,内存里的状态一定是解密的——不然 CLR 根本没法执行它。

所以思路很直接:等它跑起来,直接从内存里把已经解密的 DLL 抓出来。工具用 ExtremeDumper,它专门干这个——扫描目标进程里加载的 .NET 程序集,原样 dump 到磁盘。

dump 出来的一堆 DLL 里,最核心的是这一个:

Assembly-CSharp.dll

这是 Unity 项目里所有 C# 业务逻辑的编译产物。对一款 FPS 来说,它几乎就等于整个战斗引擎——人物、武器、射击判定、准星、视野、移动,全在里面。

磁盘上它可能是加密的,但你从内存 dump 出来的这份是解密后的明文。拿它扔进反编译器(dnSpy、ILSpy 这类),就能看到游戏运行时的真实代码。


三、反编译之后,直接调它的方法

拿到解密后的 Assembly-CSharp.dll,接下来不只是「读」,而是「用」。

做法是把这个 DLL 直接当依赖引用进来,照着反编译的结果分析它的类和方法,然后在自己的代码里直接调用它——它管理人物、武器、瞄准的那些方法,对你也是敞开的。因为你的代码和它跑在同一个进程里,共享同一份游戏状态。

能做的事情,举几个例子:

  • 瞄准辅助(喵边 / aimbot)——读取敌人坐标,把准星拉过去

  • 自动开火(triggerbot)——枪口一对准人物就自动扣扳机

  • 视野内自动瞄准 + 开火——扫描视野里的敌人(任意 FOV、指定范围或全部),锁定并开火

  • 旋转人物——直接操纵角色的朝向

  • 假头——让命中判定和视觉模型对不上,扰乱对手的爆头

这些本质上都是同一件事:既然战斗逻辑的方法都在你手里,那「谁在哪、朝哪开火、怎么转」就都能被程序化地驱动。


四、把改动送回游戏:注入器

代码写好、编译成 DLL 之后,还差最后一步——让它在游戏进程里跑起来。这靠一个注入器(injector)。

注入器把你编译好的 DLL 塞进正在运行的游戏进程,让它被加载执行。一旦进去了,你的代码就和 Assembly-CSharp.dll 处在同一个地址空间里,能直接拿到那些方法和游戏对象——你写的修改,这一刻才真正作用到战斗引擎上

整条链路串起来就是这样:

内存里运行的游戏
      │
      ▼
ExtremeDumper 抓出解密后的 Assembly-CSharp.dll
      │
      ▼
反编译分析 → 引用它,写自己的逻辑 → 编译成 DLL
      │
      ▼
注入器把 DLL 送进游戏进程
      │
      ▼
改动生效,跑在战斗引擎里

到这里,「读懂它」就变成了「改造它」。


五、反作弊这场拉锯

上面这套之所以能成立,前提是你能绕过 GameGuard。而这正是一场持续的猫鼠游戏——它出一招,对面就琢磨一招,来来回回。

第一回合:掐掉它的网络

最早的办法很朴素:不让反作弊访问互联网。断了它的联网,很多云端校验和上报就失效了,本地这套就能安稳跑。简单,且有效。

第二回合:它必须联网了

但前段时间这个口子被补上了。改动之后,反作弊变成了强制联网——连不上网它就不让你正常进游戏,断网大法直接作废。

第三回合:从内核挡住它

所谓它出什么、你就对应改什么。很快有人换了个更底层的思路:用系统内核驱动,禁止任意程序访问战斗引擎的进程

反作弊之所以能检测,靠的是去读游戏进程的内存和状态;而一个跑在内核层的驱动,权限比它更高,可以直接拦住这类跨进程访问。换句话说,不再是躲着它,而是从更底层把它的眼睛蒙上。这样又绕了过去。

本篇到此为止,后面就不再往下展开了。


写在最后

把这条链路连起来看,会发现它其实一直在敲同一个点:客户端反作弊天生有个死结——代码要在用户的机器上运行,就绕不开「运行时必然解密」这件事。内存里那份一定是明文,dump 得到、引用得了、注入得进去。

而反作弊的每一次升级——强制联网、行为检测——都是在给攻击者抬门槛,却没法从根上堵死;对面则从更底层找突破口,从断网一路走到内核驱动。这场拉锯不会真正结束,只会一层层往下打。看懂这个动态,比记住任何一个具体手法都重要。