反作弊

什么是DLL注入与函数挂钩?— 进程渗透与Native层防御

"没有外部程序运行,作弊却在工作"——看不见的入侵者

隔墙锁定敌人的自瞄,或者技能冷却为零的玩家——调查时却找不到任何可疑的外部进程。当高级作弊在没有明显外部程序的情况下运行时,攻击者很可能已经在游戏进程内部建立了阵地。

现代高级作弊工具不只是从外部读取和修改游戏内存。它们将恶意代码直接注入游戏进程,强迫游戏自身执行作弊。

这就是DLL注入函数挂钩的本质。由于代码从游戏内部而非外部运行,简单的后台进程扫描和C#级别的检测逻辑难以捕获。本文将解析注入和挂钩的实际工作原理,以及如何在系统层面有效抑制它们。

DLL注入的工作原理

DLL注入是将包含攻击者编写代码(作弊逻辑)的.dll文件强制加载到运行中的目标进程(游戏)内存空间的技术。注入成功后,恶意代码与游戏本身拥有相同的内存访问权限和执行权限。

攻击者准备DLL ──> 在游戏进程内强制加载并执行
                       └──> 对游戏内存的直接读写访问
                       └──> 调用和挂钩游戏内部函数的能力

实现注入的技术方法多种多样——线程劫持、CreateRemoteThread滥用等——但结果相同:攻击者的代码成为游戏的一部分。从操作系统的角度看,这段代码看起来像是游戏客户端正在合法运行的线程,这就是为什么表面上的进程监控无法检测到它。

注入后——通过函数挂钩操控游戏逻辑

DLL成功注入后,攻击者用来控制游戏流程的最常见技术是函数挂钩。它拦截目标函数的入口点,使得游戏调用该函数时,攻击者的代码代替原始逻辑(或在其之前)执行。

汇编层面的典型内联挂钩如下所示:

[原始函数入口点]              [挂钩后]
push rbp              →    jmp <攻击者作弊代码>   ← 首条指令被替换
mov rbp, rsp               ...
...                         (攻击者代码执行后返回或强制退出)

设想CheckSpeedHack()等安全函数的前几个字节被覆写为跳转到攻击者代码的jmp指令。每次游戏调用此检测函数时,真实的检测被跳过,恶意代码返回"未发现问题"。

Cheat Engine的高级功能以及Frida等动态插桩框架都基于这一原理运作,实现自瞄、技能冷却移除和支付验证绕过。

C#层防御的结构性局限

许多Unity开发者用熟悉的C#脚本编写作弊检测和防御逻辑。但面对DLL注入,这种方法存在根本性漏洞。

注入的恶意DLL可以在比C#虚拟机(Mono或IL2CPP)更深的层次——靠近操作系统的Native层级——运行。它可以在任何C#代码执行之前夺取进程控制权,并通过内联挂钩使C#脚本中编写的"守卫"(检测函数)失明。

换句话说:即使将检测逻辑放在C#脚本中,在更低层次渗透的攻击者也能先找到并禁用该检测逻辑。将防御代码放在攻击者容易分析的地方本身就是一个结构性盲点。

在Native层抑制注入和挂钩

要有效检测和抑制注入和挂钩攻击,检测逻辑本身必须放在攻击者分析工具难以触及的层次。

(1) 已加载模块列表扫描 在运行时定期检查加载到游戏进程内存中的DLL模块列表。将实际加载列表与正版发行构建中应存在的模块白名单进行比较,识别任何未经授权或未知的模块。

(2) 函数前言完整性验证 记录发行时关键游戏逻辑和安全函数入口点(前几个字节)的状态,在运行时重新读取并比较。内联挂钩必须覆写这些入口点字节才能工作——即使几个字节的篡改也能被精确的完整性验证捕获。

(3) 调试器与挂钩工具环境检测 检查Cheat Engine、Frida、x64dbg等知名分析和挂钩工具留下的痕迹——调试器附加状态、特定驱动程序、内存句柄等。将作弊工具本身的存在作为早期检测信号,在游戏逻辑被修改之前响应。

(4) 将验证系统隔离在Native层 最重要的是,所有上述检测功能都必须放在经过混淆的Native C++层,而非C#。将守卫的位置和行为与IL2CPP和C#脚本分离,使攻击者理解和绕过防御所需的时间和成本呈指数级增加。

OZero Security在Native C++层完整执行未授权注入模块检测、函数完整性验证和挂钩工具环境检测。所有检测逻辑安全地存储在经过混淆的二进制文件中,与C#层完全隔离。Plus Add-on的应用专属Native Variant确保安全二进制结构在构建间有所不同,防止针对某款游戏的破解教程被用于攻击其他游戏。

总结

  • DLL注入将攻击者代码直接植入游戏进程内部,使其仅靠外部进程扫描无法检测。
  • 注入的代码拥有与游戏相同的权限,并通过挂钩——覆写函数入口点——禁用检测逻辑并执行自瞄等高级作弊。
  • C#层编写的防御代码在结构上对Native级注入和挂钩脆弱。 守卫本身成为首个被修改的目标。
  • 有效防御需要将未授权模块扫描、函数完整性验证和分析工具环境检测相结合,并将所有安全逻辑安全隔离在Native层。

现代作弊不从外部敲门。当它们已经在进程内部时,需要一个能察觉微妙变化的精密传感器。

通过OZero Security的Native层在进程级入侵发生前进行检测,阻断注入与挂钩。

相关阅读