首页
社区
课程
招聘
[旧帖] [翻译]规避网络游戏的外挂检测机制,求邀请码 0.00雪花
发表于: 2012-10-10 12:59 1904

[旧帖] [翻译]规避网络游戏的外挂检测机制,求邀请码 0.00雪花

2012-10-10 12:59
1904
I-介绍
你们有些人可能已经知道,很多游戏公司(译注:就是指暴雪)最近对“黑客”采取了严厉措施。他们全方位地实现了基于用户态(userland)的检测机制,手段从非常简单到极其复杂的都有。我在过去几周里花了大量的时间,试图找到一种通用的规避检测的方法。从某种意义上来说,我们面临的处境和游戏公司很像:你只需找到他们的游戏系统的一个缺点就可以加以利用,而他们必须把系统设计得毫无漏洞;同样,在我们隐藏自身躲开他们的检测代码时,他们只要发现一处失误就可以抓住我们,而我们要把系统设计、实现得完美无缺。下面的文章是我在这方面的尝试。它肯定不是完整或者完美的,但我想这是朝着这个目标迈进的第一步。
II-已加载模块的检测
这里假设我们要往目标(译注:指游戏进程)加载一个模块(大部分外挂或者bot的做法)。我们必须对两种不同的情况加以区分,它们都可能导致恶意模块被检测出来。这两种情况是:注入时和其他时间(译注,指外挂加载时和外挂工作时)。
基本上每种DLL注入法都会在某处调用LoadLibrary。因此如果你想捕捉模块,一种简单的检测办法是截获LoadLibrary(或者LdrLoadDll,或更底层的Native API)。这个问题有两种解决方法。第一种也是最简单的一种方法是把模块名称随机化。由于很多合法软件往系统里所有进程注入DLL(Trillian, AIM, 热键软件,等等),合理的检测系统不会使用“白名单”设计(这种检测方法确认只有那些验证过的模块可以加载,而把那些没在白名单上列出来的统统看成恶意模块),因此他们只能用黑名单,这就使得随机化模块名称是对付这类检测的完美、可行的解决方案。我实现的另外一种方法是换一种做法来注入DLL,我称之为“手工映射”(manual mapping)。第一眼看上去,去模拟windows的PE loader是一件令人沮丧的事-你很难把每件事情都做正确。但其实它也没那么难,我的ManualMap(附录)代码就是干这个用的。我知道对ManualMap还可以做很多很多改进-事实上我自己有一个改进很大的版本-这个只是一个概念验证(proof of concept)的东西。
模块被注入到正在运行的进程后,有两种办法可以检测到它。第一种是扫描模块链表或者对那些你认为是外挂的模块调用GetModuleHandle(译注,看GetModuleHandle是否返回NULL)。对付这种检测的办法是利用CloakDll(附录)之类的工具把你的模块从链表中去掉。或者用ManualMap,这样你的模块从一开始就不会被加到链表中。我认为第二种做法好一些,但他们差不多是一样的。  
第二种检测已加载模块的方法就聪明多了。它的做法是枚举系统中的所有内存页面(内存页面是1024字节对齐的,所以这其实很容易做),然后检查不良代码的特征码。应对措施是做一个改进的dll loader,把内存页面的边界到实际数据的起始偏移随机化(译注,也就是说不把DLL加载在页面边界处,而是离边界有一个随机的偏移)。然而,我觉得更好的方法是创建两个新的空白页面来包住你的模块,然后用VirtualProtect给这两页设上PAGE_GUARD标志。标有PAGE_GUARD位的内存在访问时会产生一个异常,你可以用未处理异常过滤器(unhandled exception filter)、向量化异常处理(vectored exception handling)或者KiUserExceptionDispatcher hook(我推荐后者)捕捉这些异常,这样碰到扫描时你就有机会做一些处理来避免检测代码抓到你。III-Hooks,Patches和CRC检查值得让人一用的外挂基本上都会以某种方式修改游戏代码。但是修改代码是非常容易被检测到的,到现在也没有人能对这个问题提出一个可行、通用的解决方案。我恐怕也不敢号称我已经完全解决了这个问题,但我发现了一个让它变得驯服点儿的办法。我提出过一种不用修改任何目标进程代码就能hook函数的方法,唯一的缺点是你只能同时hook4个函数。我的做法是利用调试寄存器(即硬件断点),你可以在附录的CHook类中看到我的实现。由于调试寄存器检测起来相当容易,任何人只要用CONTEXT_DEBUG_REGISTERS来调GetThreadContext就可以发现它,随便一个异常处理例程都会拿到一个包含调试寄存器的上下文结构(context structure),等等。解决办法是hook住NtGetContextThread、NtSetContextThread和KiUserExceptionDispatcher。当然啦,你得用一些patch来hook这些API。由于颇有一些防病毒/防广告/防火墙软件也hook这类函数来“增强系统的整体安全”,所以检测系统如果仅仅因为你改了这些系统dll就认为你作弊也是不大可能的。这意味着你可以安全的hook这4个函数,用不着担心被检测。 即使他们也许不会仅仅因为在系统模块中发现了这些hooks就抓你,但它们还是给检测留下了一点线索-他们可以通过定位你在系统模块中的hooks,分析patch的跳转指令看它跳到了哪里,然后对hook处理过程做一下CRC就足以把你认出来。
这又有两种解决办法。一种是利用int 3断点指令来做hook,然后捕捉异常(如果看的够仔细的话你会发现这在我的CHook类里也实现了)并把异常重定向到合适的hook处理过程-你需要用标准的jmp patch来hook KiUserExceptionDispatcher(这有点和我们的目标矛盾),或者用两种标准的SEH(结构化异常处理)形式之一。
还有一种办法,我觉得要好的多,虽然实现起来有点儿困难。其实也没什么花头,就是写一个hook处理过程的变形引擎,在真正有用的指令之间填充NOP等效指令(NOP等效指令是指mov eax, eax之类的指令。译注:push eax, pop eax这样的也是)。这样,对你的函数做CRC检查就行不通了。我现在还没有这么做,不过以后我可能会写些PoC代码(译注:PoC即Proof of Concept)。
最容易的一种做法是从shellcode那里来的。我敢肯定你们都知道,为了避开IDS签名(译注,IDS=Intrusion-detection system),shellcode通常是加密的,带一个动态解密的loader。用汇编给运行时解密代码写一个简单的变形引擎是很容易的,通过在不同的指令之间放置NOP指令,并且让****在每次加、解密时随机变化,你可以把创建签名的任何企图变得非常困难-即使不是不可能的话,而且不会牺牲多少性能。
调试寄存器在其他很多方面也是相当有用的,你可以用它hook内存读写和指令读取,这意味着你可以为内存修改做一个回调函数(用在内存数据监测上很理想,这意味着你再也用不着轮询了)。对调试寄存器的完整描述可以在附录中找到。
另外一点要考虑的是,他们可能都不检测你的API hooks,简单的用原始数据patch回去就能让你的hooks无效。这种方法实现起来不难,而且有足够的可移植性-因为不同的Windows版本中大多数API的开始几个字节是不会经常改变的-游戏公司是有可能这么干的。要对付这个问题,我们得意识到一点,就是在对进程映象的代码段进行写操作之前,必须调用VirtualProtect临时改变它的页面属性。因此,截获NtProtectVirtualMemory就可以防止他们轻易的覆盖掉你的辛勤劳动成果。
IV-总结 总而言之,注入一个模块并设置4个不可检测(在ring3级别上)的hooks是可能的。也许在某些地方会有漏洞,但我所说的基本原理应该是能到达这个效果的。以上是我对在用户态创建反检测系统的所有尝试。我知道你们肯定有能力在我描述的基础上加上你们自己的见解,我也真诚的希望你们会这么做。这个解决方案不像很多正在搞game hacking的人想的那样是一个秘密的安全体系,也和那些闭源软件开发商的做法不一样。游戏黑客比别人懂得更多,应该知道这一点,因为你们全都是玩逆向工程的。你们活着就是为了击败那些通过晦涩的手段来实现的系统安全。。。自己不要掉进同样的陷阱。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
观摩一下译文。。

个人觉得利用游戏利用用户状态检测来反外挂,增加了巨大的工作量。而且状态机的变化,不一定能考虑周全。
2012-10-10 13:39
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这个需要看一下。毕竟,暴雪的反外挂很难搞定。
2012-10-11 06:59
0
雪    币: 102
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
这文章...
1、不是LZ原创的吧?
2、时间是N年前的吧?google了下,结果里第一个时间都是2006-12-01。

BTW:文中涉及的附件在那帖子中也有,似乎需要翻Q才能下
2012-10-11 10:12
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
他写了是翻译!
2012-10-11 10:23
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我就是看看,不说话的。
2012-10-11 13:45
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
不是说kx会随着在线时间增加的吗?怎么一直不变啊???
2012-10-11 13:46
0
雪    币: 4560
活跃值: (1002)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
需要一直刷新论坛
2012-10-11 14:42
0
雪    币: 31
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
wow!好牛的样子
2012-10-11 17:03
0
雪    币: 34
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
时间限制能不能破解啊~~~
2012-10-13 17:05
0
游客
登录 | 注册 方可回帖
返回
//