您的位置:首页 > 编程语言 > PHP开发

过 DNF TP 驱动保护(一)

2012-06-14 01:29 375 查看
文章目录:

01.博文简介:

02.环境及工具准备:

03.分析TP所做的保护:

04.干掉NtOpenProcess中的DeepInLineHook:

05.干掉NtOpenThread中的DeepInLineHook:

06.干掉NtReadVirtualMemory中的InLineHook:

07.干掉NtWriteVirtualMemory中的InLineHook:

08.干掉KiAttachProcess的InLineHook:

09.干掉NtGetContextThread中的InLineHook:

10.干掉NtSetContextThread中的InLineHook:

11.干掉DbgkpQueueMessage中的InLineHook:

12.干掉DbgkpSetProcessDebugObject中的InLineHook:

13.干掉Debug清零:

共四篇,本篇为第一篇。

01.博文简介:

本篇博文仅仅是我对过TP保护所作的一个总结,里面没有啥高深的技术,

仅仅是Hook而已,并且只有些InLineHook和SSDTHook的代码,

这些对大牛而言都是小菜一碟,所以大牛们可以直接飘过咯^_^

然后就是关于本篇博文,估计会比较长,所以我会按照上面的目录分出来一,二,三,四篇相继发表。

我先来装回逼科普下TP吧,直接从百度百科抄袭点过来:

TP系统全称TenProtect,是由腾讯自主研发推出的安全系统,可以有效保护游戏不受外挂侵犯,同时具备反木马盗号功能,

能有效的防止用户游戏帐号和虚拟财产被窃取。腾讯TP系统主要作用为外挂检测、反盗号、反非法工作室、防非法消息。

具体功能如下:

反注入:TP系统能有效的阻止非法模块对游戏进行注入;

反加速:TP系统能防止游戏客户端的非法加速功能;

反模拟按键:TP系统能有效阻止模拟按键程序;

反脱机:TP系统能针对非正常登录游戏的行为进行检测;

反调试:TP系统采用内核级反调试技术,保护游戏进程不被调试和分析;

反木马:TP系统可以保护玩家帐号不被木马程序窃取;

检测外挂功能:TP系统能对外挂功能进行检测;

指令混淆:TP系统能对正常指令进行虚拟和变形,加大外挂作者逆向难度;

特征匹配:TP系统采用特征码匹配技术,能准确检测到外挂的使用;

文件校验:TP系统可以准确检测游戏目录下的文件是否被第三方程序篡改;

游戏内存数据校验:TP系统所特有技术手段可以准确感知到游戏关键数据的异常;

游戏进程保护:TP系统可以保护游戏进程不被第三方程序读写;

游戏虚拟财产保护:在玩家因不当操作引起帐号泄漏情况下,TP系统也可以保护玩家帐号内虚拟财产不被不法份子转移;

我几个日子弄了过TP的驱动保护,算下来前前后后也弄了半来个月,

虽然比较累,但还是收获了蛮多东西,这篇博文就是将如何过掉TP做的一个总结而已,

在这篇文章中我会一一介绍过掉TP所Hook的各种API的思路,并附上简要的代码,

在过TP驱动保护的过程中以及一些思路和一些代码也很大程度上都是来自国内的几大论坛,

主要是看雪,一蓑烟雨,DebugMan等论坛,这里对我所借鉴的那些哥们说ManyThanks。

同时也得特别感谢刘总,很多地方若没有刘总的指导,则还指不定何时能够弄出来呢。

值得一提的是,我现在所做的过TP驱动保护只支持32位XP,在所有的32位XP上都可以正常运行,

不过Win7的话还不行,因为里面用到了搜索特征码来定位未导出API,而我只针对XP做了处理。

免责声明:

此文仅作为技术交流,有心之人切记不要拿来做坏事,尤其是不要拿来做伤天害理,或者伤害企鹅利益的事情,

对于那些有心要做坏事的,则所有后果或者反正是坏的方面的责任都与我无关,

如果此文伤害了某些公司的利益或者之类的,请站内消息或者留言联系我,本人看到后会第一时间关闭此文。

02.环境及工具准备:

前面也提过了,此次过TP的驱动保护仅仅只适用于XP系统,所以,首先你得准备个虚拟机,

然后装个XP的系统,至于是XPSP2还是XPSPxxx就随便了,当然,如果你喜欢BSOD的话,

也完全可以装个其他的系统,然后的话,就得准备几个专业工具了,首先一个当然是Xuetr了,

不过TP能够检测出Xuetr,所以Xuetr在XP机器上和TP同时运行时,

轻则导致TP弹出警告框,重则蓝屏,这个看个人运气了。

然后还有一个工具也很重量级,也是Rootkit检测工具,叫做KernelDetective,

并且更重要的是TP和KernelDetective是可以并存的,不会像Xuetr那样会被TP检测出来,

不过KernelDetective想比与Xuetr来说,Xuetr能够扫描内核的InLineHook,这个很强大,

这两个工具都很重要,其次就是WinDbg和OD以及CE了。

至于WinDbg的话自然是用来调试Windows内核或者调试驱动程序了,

而OD和CE的话可以用来测试咱所写的驱动是否真正的有效果,也就是测试是否真正的过了TP保护。

最后就是开发环境了,我的是VisualStudio2010+VisualDDK+WDK,这个可以随意搭建。

03.分析TP所做的保护:

如果真要分析TP所做的保护的话,还是比较麻烦的,不过好在各种论坛里面,各种前辈给指出了明路,

比如堕落天才有一篇极好的文章,不过这篇文章是2010年12月份的了,中间TP也不是吃饭的,肯定是有更新了,

(继续为堕落天才打广告)

文章名称:《散谈游戏保护那点事~就从_TP开始入手吧》

文章地址:http://bbs.pediy.com/showthread.php?t=126802

不过这篇文章的参考价值还是很大的,比如在NtOpenProcess,NtOpenThread等等系统服务的Hook上,

TP也还是差不多的,也就是变化不大,甚至很多的代码都可以拿过来直接用,而至于TP更新的一些内核函数的Hook的话,

也可以从其他论坛里面找到一些,所以最主要的一点就是放狗搜索,放狗搜索到一些资料以后,

可以用WinDbg或者KernelDetective来验证这个内核API是否真的被TP所干掉了。

具体的俺也不晓得要怎么说了,总结一句就是放狗搜索。

下面放出几张截图,我是用Xuetr进行扫描的,









04.干掉NtOpenProcess中的DeepInLineHook:

TPHookNtOpenProcess的直接效果就是咱在应用层里面调用OpenProcess(DNF进程)失败,

并且在OD或者CE里面也根本找不到DNF游戏的进程,更别提什么打开或者附加了,

这使得咱根本对DNF无从下手。研究过TP的都知道,TP在NtOpenProcess中是下了深层的InLine钩子,

这个也早已经不是什么秘密,各个论坛上的都知道,是Hook的ObOpenObjectByPointer,

对于这个,可以使用Xuetr扫描内核钩子扫描出来(TP对Xuetr好像敏感,在XP机上可能蓝屏)。

在一些简单的InLineHook中,咱都是直接拿内核API的头5个或者头7个字节做Hook,

这种Hook方式是很容易被干掉的,直接SSDTHook就可以干掉,

对于用SSDTHook干掉浅层的InLineHook可以参考看雪上堕落天才的文章:

文章名称:《SSDTHook的妙用-对抗Ring0InLineHook》

文章地址:http://bbs.pediy.com/showthread.php?t=40832

不过TP是做的DeepInLineHook,也就是Hook的是NtOpenProcess深层的地址,而不是函数头,

要想用SSDTHook来干掉的话,除非自己重写NtOpenProcess,否则很难干掉,

而且TP在对NtOpenProcess上还有检测,所以即使是重写NtOpenProcess也很麻烦,

因为在重写中也必须要绕过TP可以被TP检测到,从而弹出经典的TP警告框。

在这里咱可以在KernelDetective中看到它所做的InLineHook,

首先是启动KernelDetective,然后在SSDT子菜单中,找到NtOpenProcess,

然后在上面右键,在右键菜单中选择反汇编当前地址,从而就会跳转到NtOpenProcess的反汇编代码中了,

由于我的电脑太烂了,开个虚拟机,再跑个DNF,再主机里面开个VisualStudio的话,估计半天会没反应,

所以这里截图截的都是没有启动DNF的图,也就是在TP还没有进行Hook时候的截图,

对于电脑配置好的朋友,可以自己去测试,测试结果除了地址外,其他基本都是一样的,









那么如何实现干掉TP对NtOpenProcess所做的Hook呢?

一般干掉的意思就是恢复Hook,但是恢复Hook有一个很严重的问题,那就是很容易就被TP检测到了,

其实可以换个思路,为什么一定要干掉TP对NtOpenProcess所做的Hook呢?

就算被干掉了,还得干掉TP用来检测NtOpenProcess的Hook是否被干掉的线程之类的,

这样就比较麻烦了,为何不直接绕过TP的Hook呢?

要想绕过TP的保护的话,我们也可以下一个InLineHook,如果发现是DNF进程的话,那好啊,

咱直接跳到TP下的InLineHook中执行(这样TP还是执行它原来的代码,从而检测不出来被改变了)

而如果不是DNF进程的话,那咱就跳过TP下的InLineHook就好了,

上面这样说是说不清楚的,来点干脆的,写点伪代码比较容易看懂:

TP启动之前,也就是Hook之前的伪代码:

pushdwordptr[ebp-38]

[code]pushdwordptr[ebp-24]
callObOpenObjectByPointer

movedi,eax

leaeax,dwordptr[ebp-B8]

[/code]

TP启动之后,也就是Hook之后的伪代码:

pushdwordptr[ebp-38]

[code]pushdwordptr[ebp-24]
callTPHookedObOpenObjectByPointer//这里代表TPHookObOpenObjectByPointer的函数

movedi,eax

leaeax,dwordptr[ebp-B8]

[/code]

绕过TP所做的Hook的伪代码(DNF检测不出来自己被绕过了,要是能检测出来也就不叫绕过了):

pushdwordptr[ebp-38]

[code]pushdwordptr[ebp-24]
if(是DNF进程)

{

callTPHookedObOpenObjectByPointer

}

else

{

callObOpenObjectByPointer

}

movedi,eax

leaeax,dwordptr[ebp-B8]

[/code]

有了伪代码以后,我们要做的也就比较清楚了,要想实现“绕过TP所做的Hook的伪代码”的话,

咱得自己也下一个InLineHook,至于我们在哪里下InLineHook的话,也很明白,

至少得再callObOpenObjectByPointer之前吧,否则都已经进入TP的Hook了,还谈什么绕过呢?

下面给出一副截图来标记将要下我们自己的InLineHook的位置,





现在已经知道要在哪个位置下InLineHook了,那么下一个问题就是咱如何才能得到这个地址呢?

办法自然是搜索特征码了,具体的实现方式可以看下面的截图,通过搜索特征码咱就可以得到咱要下Hook的地址了。





既然要下InLineHook的位置也找到了,同时,如何绕过TP的InLineHook的伪代码也出来了,

那么就只需要在找到的位置处安装一个InLineHook,同时完成我们Hook时的过滤代码就OK了。

下面对如何绕过TP的InLineHook的伪代码再做一个详细点的说明,具体的都已经很简单了,

我们已经得到了0x805C0D74这个地址,这个地址+6即是0x805C0D7A,对应的就是call指令了,

所以如果是DNF进程的话,我们就直接跳到这个指令上来,从而执行callTPHookedObOpenObjectByPointer,

__asm

[code]{
pushdwordptr[ebp-38h]

pushdwordptr[ebp-24h]

jmp0x805C0D7A

}

[/code]
同时0x805C0D74+11=0x805C0D7F也就是mov指令,也就是说如果不是DNF进程的话,

咱自己实现下面的代码就OK了,也就是调用内核原始的ObOpenObjectByPointer,

ObOpenObjectByPointer这个函数是内核导出函数,可以使用MmGetSystemRoutineAddress获取其地址,

__asm

[code]{
pushdwordptr[ebp-38h]

pushdwordptr[ebp-24h]

callObOpenObjectByPointer

jmp0x805C0D7F

}

[/code]

下面是先贴出安装InLineHook的代码,用来干掉TP对callObOpenObjectPointer的Hook

/************************************************************************/

[code]/*安装钩子从而过掉TP保护所Hook的NtOpenProcess-让TP失效
/************************************************************************/

VOIDInstallPassTPNtOpenProcess()

{

CHARszCode[7]=

{

(char)0xff,

(char)0x75,

(char)0xc8,

(char)0xff,

(char)0x75,

(char)0xdc,

(char)0xe8

};


/*获取原生的NtOpenProcess和ObOpenObjectByPointer的地址*/

uOriginNtOpenProcessAddr=MmGetSystemFunAddress(L"NtOpenProcess");

uOriginObOpenObjectByPointerAddr=MmGetSystemFunAddress(L"ObOpenObjectByPointer");


/*从NtOpenProcess这个地址开始搜索长度为7的特征码字符串,得到的地址将会被安装InLineHook*/

uMyHookedNtOpenProcessAddr=SearchFeature(uOriginNtOpenProcessAddr,szCode,7)-7;


/*计算出自定义InLineHook的跳转地址*/

uMyHookedNtOpenProcessJmpAddr=uMyHookedNtOpenProcessAddr+11;


/*计算出TPInLineHook的跳转地址*/

uTPHookedNtOpenProcessJmpAddr=uMyHookedNtOpenProcessAddr+6;


/*安装一个InLineHook*/

InstallInLineHook(uMyHookedNtOpenProcessAddr,(ULONG)InLineHookNtOpenProcess);


KdPrint(("PassTP-NtOpenProcessInstalled."));

}

[/code]

下面再给出我们自己InLineHook的中继实现:

/************************************************************************/

[code]/*自定义的NtOpenProcess,用来实现InLineHookKernelAPI
/************************************************************************/

NTSYSHOOKAPIvoidInLineHookNtOpenProcess()

{
__asm

{

pushdwordptr[ebp-38h]

pushdwordptr[ebp-24h]

}


/*开始过滤*/

if(ValidateCurrentProcessIsDNF()==TRUE)

{
__asm

{

/*如果是DNF进程调用的话,则调用已经被TPHook的NtOpenProcess*/

jmpuTPHookedNtOpenProcessJmpAddr

}

}

__asm

{

/*如果不是DNF进程调用的话,则调用ntoskrnl.exe中的NtOpenProcess*/

calluOriginObOpenObjectByPointerAddr

jmpuMyHookedNtOpenProcessJmpAddr

}

}

[/code]

05.干掉NtOpenThread中的DeepInLineHook:

上面已经干掉了NtOpenProcess中的DeepInLineHook了,其实很多人都能猜得到,

既然TP搞掉了NtOpenProcess,那么TP就没有理由不搞掉NtOpenThread这个内核服务了,

不错,TP在内核中确实也干掉了NtOpenThread这个内核服务,并且同样用的DeepInLineHook,

并且跟NtOpenProcess一样,NtOpenThread中也是对ObOpenObjectByPointer做的InLineHook,

不相信的童鞋可以分别在启动DNF游戏之前和之后用KernelDetective经过反汇编查看NtOpenThread的反汇编代码,

比较两次的反汇编代码就可以看出来TP在NtOpenThread中所动的手脚了,具体的步骤可以如下:

先找到NtOpenThread的反汇编地址,然后再在反汇编代码中找到callObOpenObjectByPointer(TP启动之前),









和干掉NtOpenProcess中的DeepInLineHook一样,我们还是使用绕过去的方式来做,

由于前面已经以这种方式分析分析过NtOpenThread了,所以咱直接来分析地址就OK了,

首先我们一样搜索特征码定位到我们将要安装InLineHook的地址,





下面对如何绕过TP的InLineHook的再做一个详细点的说明,

我们已经得到了0x805C0FF6这个地址,这个地址+6即是0x805C0FFC,对应的就是call指令了,

所以如果是DNF进程的话,我们就直接跳到这个指令上来,从而执行callTPHookedObOpenObjectByPointer,

__asm

[code]{
pushdwordptr[ebp-34h]

pushdwordptr[ebp-20h]

jmp0x805C0FFC

}

[/code]
同时0x805C0FF6+11=0x805C1001也就是mov指令,也就是说如果不是DNF进程的话,

咱自己实现下面的代码就OK了,也就是调用内核原始的ObOpenObjectByPointer,

ObOpenObjectByPointer这个函数是内核导出函数,可以使用MmGetSystemRoutineAddress获取其地址,

__asm

[code]{
pushdwordptr[ebp-34h]

pushdwordptr[ebp-20h]

callObOpenObjectByPointer

jmp0x805C1001

}

[/code]

下面先贴出用来安装InLineHook的代码,用来干掉TP对CallObOpenObjectByPointer做的Hook:

/************************************************************************/

[code]/*安装钩子从而过掉TP保护所Hook的NtOpenThread-让TP失效
/************************************************************************/

VOIDInstallPassTPNtOpenThread()

{

CHARszCode[7]=

{

(char)0xff,

(char)0x75,

(char)0xcc,

(char)0xff,

(char)0x75,

(char)0xe0,

(char)0xe8

};


/*获取原生的NtOpenThread和ObOpenObjectByPointer的地址*/

uOriginNtOpenThreadAddr=MmGetSystemFunAddress(L"NtOpenThread");

uOriginObOpenObjectByPointerAddr=MmGetSystemFunAddress(L"ObOpenObjectByPointer");


/*从NtOpenThread这个地址开始搜索长度为7的特征码字符串,得到的地址将会被安装InLineHook*/

uMyHookedNtOpenThreadAddr=SearchFeature(uOriginNtOpenThreadAddr,szCode,7)-7;

uMyHookedNtOpenThreadJmpAddr=uMyHookedNtOpenThreadAddr+11;

uTPHookedNtOpenThreadJmpAddr=uMyHookedNtOpenThreadAddr+6;


InstallInLineHook(uMyHookedNtOpenThreadAddr,(ULONG)InLineHookNtOpenThread);


KdPrint(("PassTP-NtOpenThreadInstalled."));

}

[/code]

下面再给出我们自己InLineHook的中继实现:

/************************************************************************/

[code]/*自定义的NtOpenThread,用来实现InLineHookKernelAPI
/************************************************************************/

NTSYSHOOKAPIvoidInLineHookNtOpenThread()

{
__asm

{

pushdwordptr[ebp-34h]

pushdwordptr[ebp-20h]

}


/*开始过滤*/

if(ValidateCurrentProcessIsDNF()==TRUE)

{
__asm

{

/*如果是DNF进程调用的话,则调用已经被TPHook的NtOpenThread*/

jmpuTPHookedNtOpenThreadJmpAddr

}

}

__asm

{

/*如果不是DNF进程调用的话,则调用ntoskrnl.exe中的NtOpenThread*/

calluOriginObOpenObjectByPointerAddr

jmpuMyHookedNtOpenThreadJmpAddr

}

}

[/code]

总结:

《过DNFTP驱动保护》的第一篇到这里就结束了,经过上面的处理,

我们已经过掉了TP在NtOpenProcess和NtOpenThread中的InLineHook,

现在已经能在OD或CE里看到DNF游戏进程并且在Ring3下也可以调用OpenProcess打开DNF进程了,

不过完成了这些离过DNFTP驱动保护还很远,详情还得留到下回分解了。

下面给出两张截图来显示一下咱的战果:









版权所有,[b]欢迎转载,但转载请注明:转载自[/b][b]Zachary.XiaoZhen-梦想的天空[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: