首页
社区
课程
招聘
[原创]反模拟类游戏外挂
发表于: 2013-9-17 16:44 31565

[原创]反模拟类游戏外挂

2013-9-17 16:44
31565
一.        游戏外挂有模拟类、内部Call功能调用、脱机类外挂。模拟类外挂通过模拟键盘鼠标的按键信息达到挂机的目的。内部Call功能挂往游戏进程注入dll并调用游戏功能函数,此类外挂需分析清楚主要功能函数。脱机类外挂需要还原游戏客户端协议明文,见http://bbs.pediy.com/showthread.php?t=178255,通过发送协议封包操纵游戏。
      按键精灵、按键游侠、许多游戏辅助都属于模拟类外挂。下图是按键精灵的模拟技术的选择:


二.以下分别介绍上面四种模拟技术的检测方法:
1. 普通模式、增强模式:
普通模式调用SendMessage、PostMessage,增强模式调用keybd_event,mouse_event、 SendInput发送键盘鼠标消息。keybd_event,mouse_event是调用SendInput。只要HOOK 内核层的NtUserPostThreadMessage、NtUserPostMessage、NtUserMessageCall、NtUserSendInput这几个API,并在其中判断发送的目的地址是否为我们要保护的进程就行了。附件中代码使用Hook KiFastCallEntry的方式Hook NtUserPostThreadMessage、NtUserPostMessage、NtUserMessageCall、NtUserSendInput这几个内核API。

2. 软件模式:
比较常用的方式,很多游戏辅助用的就是这种方式。因为是操作类驱动中的函数,所以能同时兼容PS/2和USB的键盘鼠标模拟,被按键精灵、游戏辅助广泛使用。它直接调用KeyboardClassServiceCallback、MouseClassServiceCallback。这两个函数是Windows键盘鼠标端口驱动(Kbdhid.sys、i8042prt.sys、mouclass.sys、mouhid.sys)在获得键盘鼠标硬件输入后往上传递给类驱动(Kbdclass.sys、mouclass.sys)的两个回调函数。
如何模拟参考:看雪文章:http://bbs.pediy.com/showthread.php?t=101653
检测方法为:HOOK键盘鼠标类驱动中KeyboardClassServiceCallback和MouseClassServiceCallback回调,进入到自己的函数中时栈回溯(ebp+4)判断调用地址是否在系统的键盘鼠标端口驱动中,若不在说明是直接调用的,也就是按键精灵模拟操作的。
若是键盘鼠标类驱动和端口驱动中有层过滤驱动(eaps2kbd),则需回溯多个栈帧(ebp+n)查找系统的键盘鼠标端口驱动。附件中代码使用Call Hook替换键盘鼠标回调。kbdclass.sys驱动中KeyboardClassServiceCallback函数的反汇编代码如下:
:00011192 ; int __stdcall KeyboardClassServiceCallback(size_t, void *, int, int)
.text:00011192 _KeyboardClassServiceCallback@16 proc near
.text:00011192 var_8           = dword ptr -8
.text:00011192 var_4           = dword ptr -4
.text:00011192 arg_0           = dword ptr  8
.text:00011192 arg_4           = dword ptr  0Ch
.text:00011192 arg_8           = dword ptr  10h
.text:00011192 arg_C           = dword ptr  14h
.text:00011192
.text:00011192                 mov     edi, edi
.text:00011194                 push    ebp
.text:00011195                 mov     ebp, esp
.text:00011197                 push    ecx
.text:00011198                 push    ecx
.text:00011199                 mov     eax, [ebp+arg_0]  //DeviceObject
.text:0001119C                 and     [ebp+arg_0], 0
.text:000111A0                 push    ebx
.text:000111A1                 mov     ebx, [ebp+arg_8]  //InputDataEnd
.text:000111A4                 sub     ebx, [ebp+arg_4]   //ebx为键盘输入的数量
.text:000111A7                 push    esi
.text:000111A8                 mov     esi, [eax+28h]
.text:000111AB                 mov     eax, [ebp+arg_C]
.text:000111AE                 and     dword ptr [eax], 0
.text:000111B1                 push    edi
.text:000111B2                 push    4               ; Flags
.text:000111B4          call    PoSetSystemState(x)  //此函数将被Call Hook替换


替换后的键盘回调函数代码如下:
__declspec(naked)void MyKeyboardClassServiceCallback()
{
	_asm 
	{
		pop   g_OrigRetAddr //调用被Call Hook替换的函数前,平衡堆载
		call  g_ulkbdNeedCallAddr //xp是PoSetSystemState函数
		push  eax          
		mov   eax,[ebp+4h] //判断调用Callback的函数的地址是否在端口驱动中

		cmp   eax,g_ulKbdPs2PortStart
		jae	  ps2StartOk			   //先判断是否为ps2端口驱动调用,
		jmp   short isUsbKbd		   //再判断是否为usb端口驱动调用
ps2StartOk:
		cmp   eax,g_ulKbdPs2PortEnd
		jbe   over

isUsbKbd:
		cmp   eax,g_ulKbdUsbPortStart
		jae	  usbStartOk
		jmp   short isFilter
usbStartOk:
		cmp   eax,g_ulKbdUsbPortEnd
		jbe   over

isFilter:              //检查是否在过滤驱动中,允许过滤驱动调用kbdCallBack(比如eaps2kbd)
		push  ebx      
		push  ecx
		push  edx
		mov   ecx,20   //从ebp+18h(跳过4个传入的参数)往下检测20个堆载帧
		mov   al,0
		mov   ebx,14h
conCheck:
		add   ebx,4
		mov   edx,[ebp+ebx]
		cmp   edx, MmSystemRangeStart  //低于内核地址(一般是0x80000000)
		jb    fOver
		cmp   edx,g_ulKbdPs2PortStart //有过滤驱动
		jae	  _ps2StartOk
		jmp   short _isUsbKbd
_ps2StartOk:
		cmp   edx,g_ulKbdPs2PortEnd
		setbe al        //满足则置al为1
		jbe   fOver

_isUsbKbd:
		cmp   edx,g_ulKbdUsbPortStart
		jae	  _usbStartOk
		jmp   short fLoop
_usbStartOk:
		cmp   edx,g_ulKbdUsbPortEnd
		setbe al        //满足则置al为1
		jbe   fOver

fLoop:
		Loop  conCheck

fOver:		
		pop   edx
		pop   ecx
		pop   ebx
		test  al,1
		jnz   over

		mov   eax,[ebp+10h]  //fake
		sub   eax,[ebp+0Ch]
		cmp   eax,ebx		//真实Callback函数调用第一个函数前会把输入的数量赋值给ebx
		jne   cmpEcx		//(其它也要判断下,以防微软代码小变动,winxp使用ebx,win7使用eax)
		mov   ebx,0			//把需要伪造的数量置为0
		jmp   short doLast
cmpEcx:
		cmp   eax,ecx
		jne   cmpEdx
		mov   ecx,0
		jmp   short doLast
cmpEdx:
		cmp   eax,edx
		jne   cmpEsi
		mov   edx,0
		jmp   short doLast
cmpEsi:
		cmp   eax,esi
		jne   cmpEdi
		mov   esi,0
		jmp   short doLast
cmpEdi:
		cmp   eax,edi
		jne   cmpArg1
		mov   edi,0
		jmp   short doLast
cmpArg1:                     //编译器有时会用传入的参数保存临时变量
		cmp   eax,[ebp+8h]   //参数2和3为InputDataStart和InputDataEnd,
		jne   cmpArg4		 
		mov   [ebp+8],0
		jmp   short doLast
cmpArg4:
		cmp   eax,[ebp+14h]
		jne   doLast
		mov   [ebp+14h],0
		jmp   short doLast
doLast:
		mov   [ebp+8],0		  //DeviceObject置为NULL
		mov   eax,[ebp+0Ch]  //设置InputDataEnd=InputDataStart 键盘输入数量置为0
		mov   [ebp+10h],eax	
		mov   m_bFake,1
over:
		pop   eax
		push  g_OrigRetAddr  //返回到真实kbdCallBack Call后的地址
		ret
	}
}


3. 硬件模式:模拟挂使用WRITE_PORT_UCHAR、往0x60、0x64端口直接发送键盘数据。使用READ_PORT_UCHAR读取0x64端口状态(实际上是调用in、out输入输出汇编指令)。检测方法为hook int 0x93中断,在中断中获取按键,并要求i8048(键盘控制器)重发上次的按键,若两次不相等则说明是模拟挂在操作键盘。因为直接使用WRITE_PORT_UCHAR发送的按键是不会在i8048中保存上次按键的。有关i8048详细资料参考:http://hi.baidu.com/_erex/item/63120114b5b0aee55e53b11d。
以下是检测硬件模拟中操作i8048的代码:
BOOL __stdcall AntiKeyboardMock()
{
UCHAR sch=0, ch= 0,vch= 0,temp= 0,comand = 0;
    KIRQL oldIrql, currentIrql;
currentIrql = KeGetCurrentIrql();
if (currentIrql < DISPATCH_LEVEL) //防止多核CPU同时执行
	KeAcquireSpinLock(&KbdLock,&oldIrql);
	
	_asm
	{
		push eax
		push ebx
cmp  bKbdWriteBacked,1  //鼠标和键盘情况不一样,鼠标发送4个包可能就一次中断,
		mov  bKbdWriteBacked,0  //所以写回不会引起中断,而键盘会
		jz   short retB

		in   al,64h
		test al,00001000b      //若是命令直接返回给原中断
		jnz  retB
		mov al,0x60        // 禁止鼠标键盘接口
		call RealSend8042Cmd
		mov al,0x77
		call Write8042Data
		mov  bl,0              
		call Read8042Data
		cmp  bl,1              //判断是否读到数据
		jb   short overDo        //没有数据
		mov  sch,al
		mov  dl,al			   //保存到寄存器,加快处理
		call Flush8042
		mov al,0xFE			   //通过i8042间接要求i8048重发扫描码
		call Write8042Data     //发送给i8048(键盘控制器)不用发送0xD4,直接发给i8048
		mov bl,2	           //表示请求重传,需要等待的时间稍微长些
		call Read8042Data	   //获得重发的扫描码
		mov vch,al             //无需判断是否要求重传命令i8048没接收正确,因为不好判断,
							   //i8048有可能上次发送的是要求重传命令
		cmp dl,al
		jz  writeback
		add al,80h			   //重发的扫描码若等于之前获得扫描码+80h(键按下),认为不是伪造的
		cmp dl,al  
		jz  writeback
		mov m_bFake,1
writeback:
		mov al,0xD2
		call RealSend8042Cmd
		mov al,dl
		call Write8042Data //写回数据。写回数据时会再次引起中断,中断后判断原因
		mov  bKbdWriteBacked,1 //,若是写回则返回,若是新数据则处理
overDo:
		mov al,0x60        // 打开鼠标键盘接口
		call RealSend8042Cmd
		mov al,0x47
		call Write8042Data
retB:
		pop ebx
		pop eax
	}
	if (currentIrql < DISPATCH_LEVEL)
		KeReleaseSpinLock(&KbdLock,oldIrql);
	return TRUE;
}


附件中TestProtect为被保护的测试程序,它会调用dll bProtect,由bProtect加载驱动,键盘鼠标回调函数由inpout32.dll传入。

                                       

                                       

                                       


AntiRabot.rar
反模拟类游戏外挂.doc

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
免费 6
支持
分享
最新回复 (37)
雪    币: 185
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
游戏为啥要反模拟类的?
2013-9-17 16:49
0
雪    币: 6394
活跃值: (2207)
能力值: ( LV12,RANK:320 )
在线值:
发帖
回帖
粉丝
3
游戏外挂有模拟类、内部Call功能调用、脱机类外挂。模拟类外挂就是模拟人的行为,自动操作鼠标键盘。
2013-9-17 16:57
0
雪    币: 611
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
摸拟类挂执行效率是最差的,拿来商用的很少,一般都是个人使用,基于这样来说,使用者仍是在用自己的努力玩游戏,努力封这种挂不如去努力封调用CALL的,和脱机挂,这些才是严重影响游戏平衡的根源。
2013-9-17 17:19
0
雪    币: 281
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
摸拟类挂不会被警察叔叔请饮茶吧
2013-9-17 17:21
0
雪    币: 43
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
这个总有方法过的吧
2013-9-17 17:56
0
雪    币: 204
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
模拟挂相对其他几种挂来说应该比较难检测
2013-9-17 18:48
0
雪    币: 90
活跃值: (80)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
实用性略低,毕竟按键精灵不用加载驱动,x64按键精灵一样用你就没用了
2013-9-17 18:59
0
雪    币: 6394
活跃值: (2207)
能力值: ( LV12,RANK:320 )
在线值:
发帖
回帖
粉丝
9
键盘鼠标回调、WRITE_PORT_UCHAR、READ_PORT_UCHAR需要在内核中调用的。
2013-9-17 19:47
0
雪    币: 9560
活跃值: (2391)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
讲的很详细!不过这样怕人家玩了游戏,居然连模拟键盘都不放过,那还不如不玩那游戏~
2013-9-17 20:41
0
雪    币: 371
活跃值: (72)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
11
牛x,
据说TP就是这样干的 囧~
2013-9-17 20:53
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
12
收藏了,反键盘鼠标模拟 游戏外挂
2013-9-17 21:06
0
雪    币: 198
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
下载来看看
2013-9-17 21:33
0
雪    币: 99
活跃值: (96)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
一篇牛文胜过百篇空谈,让人收获很大,我一直接触的就是模拟外挂,毕竟键盘按来按去,手累,键盘也磨损,而且很单调,总是按几个键,自己写模拟挂不应该封的
2013-9-17 23:33
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
15
其实对付模拟外挂,收益很小,搞掉内存挂这种严重影响游戏平衡的才真正有意义。

想按键精力这种,顶多做个自瞄自动开枪自动找图打怪这类,危害性还是较小。

堆栈回溯这些检测方法也很弱,想绕也简单。费力不讨好啊。
2013-9-18 00:05
0
雪    币: 228
活跃值: (115)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
16
非常不错的文章!比较科普!
2013-9-18 00:35
0
雪    币: 163
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
谢谢谢谢分享
2013-9-18 04:47
0
雪    币: 1602
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
开卷有益,了解了不少
2013-9-18 06:13
0
雪    币: 813
活跃值: (175)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
19
好文,mark,收藏之
2013-9-18 08:13
0
雪    币: 184
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
好文章,值得学习
2013-9-18 09:05
0
雪    币: 558
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
但是也没Hook吧
2013-9-18 09:22
0
雪    币: 110
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
22
学习了 模拟挂
2013-9-18 09:24
0
雪    币: 8599
活跃值: (5060)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
不错,学习了。
2013-9-18 09:46
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
楼主搞研究怎么赤裸裸的在主机搞

应该虚拟机的干活
2013-9-18 09:46
0
雪    币: 219
活跃值: (738)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
25
你最近打爆发
2013-9-18 11:26
0
游客
登录 | 注册 方可回帖
返回
//