一直以来在想金山游侠在游戏中弹出的方式,在网上找了很久,网上也有很多人在问,找来找去只有个在DX游戏中弹出的VC代码,在MSDN下载还花了我几个积分...,该代码在不能在DirectDraw游戏中弹出。
在写大富翁4游戏的修改器时,该游戏不能切换,键盘钩子也无效,迫使需要一种想金山游侠似的在游戏中弹出才行。即然写外挂不公布弹出技术(我猜测外挂用的是挂钩DirectDraw或D3D函数方式,但这种方式我觉得通用性不强),那我就自已动手分析金山游侠是怎么做的...
经过一段漫长时间,约两个星期吧,其中一个星期是每天8小时分析(还好在成都电力职大学习网络与安全有的是时间,都没听老师讲的什么,真对不住许老师呀),边分析,边做测试代码,顺便说句,国产内核调试器Syser Debug真不稳定,动不动蓝屏。
那么,金山游侠按了快捷键后,到底做了些什么呢?
一切秘密都在KSKnight.dll中....
1、先安装三个全局钩子:CBT、Mouse、Keyboat,只有CBT钩子是有用的,其它的都是空的。
下面全是在CBT钩子中
2、当按下快捷键后,取得DirectDrawCreate地址,创建个DX对象接口。
3、用EnumSurface或GetGDISurface枚举指定进程PID的主表面(原来DX接口是个链表)接口,找到后用QueryInterface取得新的DX对象新接口,并释放原DX接口和查找到主表面接口。
4、查询新DX对象接口的显示模式,即GetDisplayMode,比较是不是8位色彩。
5、再次枚举主表面,将枚举到的主表面保存。
6、锁定主表面
7、检测操作系统版本,尝试取DINPUT.DLL,枚举所有存在的线程,对游戏进程句柄复制,创建新线程,在新线程中再次锁定游戏主表面,暂停线程(这儿我的测试代码有问题,好像金山对所有线程暂停后又能马上恢复了)。
8、替换原游戏的WNDPROC消息过程,在新消息过程中涉及绘制的全返回0。
终于可以创建对话框了....,金山在这的代码还很长,没分析完。
以上是大概金山的流程,我写了个测试代码,可以在大富翁4和星际1.08是弹出对话框,但有点问题--只要移动对话框,背影全是对话框的影子,在魔兽3中弹不出来,游戏锁死,这段还分析中...。
目前只是完成了一部分工作,至少能在2D游戏中弹出了,成功后放出测试代码。
感谢,南充电业局的贾雨果(烟都让我抽了不少)和成都电业局的西风X。
帖出IDA的片段:
text:1002D43A call sub_1001C920 ; 取得DirectDrawCreate地址,放在1006da2c
.text:1002D43F test eax, eax
.text:1002D441 jz loc_1002D50E
.text:1002D447 mov edx, [esp+78h+arg_0]
.text:1002D44B push edx
.text:1002D44C call sub_1001C9D0 ; 创建DX对象并查找主表面接口,返回新DX对象接口
.text:1002D451 add esp, 4
.text:1002D454 cmp eax, ebp
.text:1002D456 mov dword_1006D960, eax
.text:1002D45B jz loc_1002D50E
.text:1002D461 push eax
.text:1002D462 call sub_1001CA60 ; 取得新DX接口的显示模式,即GetDisplayMode
.text:1002D467 mov dword_1006D970, eax
.text:1002D46C mov eax, dword_1006D960
.text:1002D471 push eax
.text:1002D472 call sub_1001C980 ; 查找新DX对象接口的主表面
.text:1002D477 mov esi, eax
.text:1002D479 add esp, 8
.text:1002D47C cmp esi, ebp
.text:1002D47E jz short loc_1002D4F9
.text:1002D480 push edi
.text:1002D481 mov ecx, 1Bh
.text:1002D486 xor eax, eax
.text:1002D488 lea edi, [esp+7Ch+var_6C]
.text:1002D48C push ebp
.text:1002D48D lea edx, [esp+80h+var_6C]
.text:1002D491 rep stosd ; memset(&gameDdsd,0,sizeof(gameDdsd));
.text:1002D493 mov ecx, [esi]
.text:1002D495 push 1
.text:1002D497 push edx
.text:1002D498 push ebp
.text:1002D499 push esi
.text:1002D49A mov [esp+90h+var_6C], 6Ch ; gameDdsd.dwSize = sizeof(gameDdsd);
.text:1002D4A2 call dword ptr [ecx+64h] ; Lock主表面,返回锁定的显存指针
.text:1002D4A5 test eax, eax
.text:1002D4A7 pop edi
.text:1002D4A8 jnz short loc_1002D4B4 ; 此处跳转
.text:1002D4AA mov eax, [esi]
.text:1002D4AC push ebp
.text:1002D4AD push esi
.text:1002D4AE call dword ptr [eax+80h] ; Unlock主表面
.text:1002D4B4
.text:1002D4B4 loc_1002D4B4: ; CODE XREF: sub_1002D3A0+108j
.text:1002D4B4 push esi ; lpParameter
.text:1002D4B5 call sub_100233E0 ; 复制进程句柄,创建新线程,暂停目标进程线程
.text:1002D4BA mov ecx, [esi]
.text:1002D4BC add esp, 4
.text:1002D4BF push esi
.text:1002D4C0 call dword ptr [ecx+8] ; 释放主表面接口
.text:1002D4C3 mov edx, [esp+78h+arg_8]
.text:1002D4CA push edx
.text:1002D4CB push ebx
.text:1002D4CC call sub_1002D290 ; 创建新的窗口并显示它(最复杂、困难,没对其分析)
.text:1002D4D1 call sub_10023480 ; 恢复目标进程线程
.text:1002D4D6 mov eax, dword_1006D960
.text:1002D4DB cmp eax, ebp
.text:1002D4DD jz short loc_1002D4EB
.text:1002D4DF mov ecx, [eax]
.text:1002D4E1 push eax
.text:1002D4E2 call dword ptr [ecx+8] ; 释放新DX对象接口
- 标 题:金山游侠弹出窗口背后的秘密
- 作 者:lankerr
- 时 间:2010-11-20 15:10:24
- 链 接:http://bbs.pediy.com/showthread.php?t=125162