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

过 DNF TP 驱动保护(二)

2012-06-12 09:04 405 查看
文章目录:

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清零:

共四篇,本篇为第二篇。

06.干掉NtReadVirtualMemory中的InLineHook:

前面已经干掉了TP对NtOpenProcess以及TP对NtOpenThread所做的Hook,

这样的话,我们已经可以使用OD或者CE看到DNF的游戏进程了,

弄过一些游戏方面内容的朋友应该都是知道CE的,这东东是开源的,不过是基于Delphi的,

工具做得很不错,可以通过CE来修改一些游戏进程的内存数据,比如可以修改一些简单的游戏的血值啊之类的,

但是,此时我们可以用CE来扫描一下DNF游戏进程的内存,你会发现根本扫描不到任何数据,

其实原因也很简单,TP对NtReadVirtualMemory进行了浅层的InLineHook,

从而可以达到防止其他进程读取DNF游戏进程内存的目的,

而CE的话,在Ring3下是通过ReadProcessMemory来读取游戏内存的,

而ReadProcessMemory进入Ring0后又是调用的NtReadVirtualMemory,

由于NtReadVirtualMemory被TP干掉了,所以自然用CE是扫描不出任何东西的,

要干掉TP对NtReadVirtualMemory所作的浅层InLineHook其实是比较简单的,

因为TP并没有对NtReadVirtualMemory做检测,所以可以直接用SSDT来对抗掉浅层的InLineHook就OK。

至于原理的话,很简单,直接用SSDTHook替换掉系统服务NtReadVirtualMemory,

然后在SSDTHookNtReadVirtualMemory这个我们自己写的系统服务中判断,

如果是DNF进程的话,直接调用原来的SSDT系统服务就好,如果不是DNF进程的话,

我就跳过TP对NtReadVirtualMemory所做的InLineHook,也就是跳过前面7个字节就OK了。

对于这种干掉InLineHook的原理,堕落天才的文章讲的最清楚了,我这里就不再班门弄斧了。

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

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

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

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

有的童鞋可能会问,咱是如何知道NtReadVirtualMemory被TP干掉了呢?

很简单,还是采用前面的做法,用KernelDetective就可以看到了,具体可以看下面的截图:









至于如何安装SSDTHook或者SSDTHook是啥玩意来着的话,大家有兴趣的可以参考我的下面博文系列:

《进程隐藏与进程保护(SSDTHook实现)》系列,共三篇。

/article/4910401.html

/article/4910402.html

/article/4910403.html

下面先贴出安装SSDT钩子的代码,该代码用来干掉TP对NtReadVirtualMemory的InLineHook:

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

[code]/*安装钩子从而过掉TP保护所Hook的NtReadVirtualMemory-让TP失效
/*保存NtReadVirtualMemory第4,5,6,7个字节(其实就是一个ULONG跳转地址)

/*因为这几个字节在不同的XP上会改变,所以在SSDTHook之前保存下来

/*从而避免在此处进行硬编码
/************************************************************************/

VOIDInstallPassTPNtReadVirtualMemory()

{

if(g_SSDTHookNtReadVirtualMemory>0)

{

/*获得NtReadVirtualMemory的地址*/

ULONGuNtReadVirtualMemoryAddr=oldSysServiceAddr[g_SSDTHookNtReadVirtualMemory];


/*如果是DNF进程,则跳到NtReadVirtualMemory执行,即不处理,从而让DNFInLineHook生效*/

uTPHookedNtReadVirtualMemoryJmpAddr=uNtReadVirtualMemoryAddr;

/*如果不是DNF进程,则跳过TP的InLineHook,从而使TP失效*/

uMyHookedNtReadVirtualMemoryJmpAddr=uNtReadVirtualMemoryAddr+7;

/*保存下未Hook之前的NtReadVirtualMemory的第4,5,6,7个字节*/

uNtReadVirtualMemoryAddr_3=*((ULONG*)(uNtReadVirtualMemoryAddr+3));


InstallSysServiceHookByIndex(g_SSDTHookNtReadVirtualMemory,SSDTHookNtReadVirtualMemory);


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

}

}

[/code]

下面再给出SSDTHook的中继API的实现代码:

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

[code]/*自定义的NtReadVirtualMemory,用来实现SSDTHookKernelAPI
/************************************************************************/

NTSYSHOOKAPIVOIDSSDTHookNtReadVirtualMemory()

{

/*开始过滤*/

if(ValidateCurrentProcessIsDNF()==TRUE)

{

__asm

{

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

jmpuTPHookedNtReadVirtualMemoryJmpAddr

}

}


__asm

{

/*已经做了针对硬编码的处理*/

/*如果不是DNF进程调用的话,则跳过TPHook的NtReadVirtualMemory*/

push0x1C

pushuNtReadVirtualMemoryAddr_3

jmpuMyHookedNtReadVirtualMemoryJmpAddr

}

}

[/code]

好,到这里就已经干掉了TP对NtReadVirtualMemory所做的InLineHook了,

对此最直白的效果就是用CE打开DNF游戏进程进行内存扫描,你会发现,OnYear,可以正常扫描到DNF内存了。









07.干掉NtWriteVirtualMemory中的InLineHook:

上面又干掉了TP对NtReadVirtualMemory的InLineHook了,从而实现了CE读取DNF进程的内存。

但是你可以试着用CE修改DNF进程的内存,你很快就会发现,虽然可以扫描内存,但是并不可以读取内存,

而后你也肯定能够想到,既然有防止读取内存,那肯定也有防止写入内存,

而后你又自然会找到NtWriteVirtualMemory上来,等你找到NtWriteVirtualMemory后,

你又基本能够确定,搞定这个API和搞定NtReadVirtualMemory应该是差不多的,

因为这两个API就是一对啊,一个读,一个写,所以TP肯定也是采用相同的做法来处理这两个API,

当然,你上面的猜想都是正确的,所以咱还是用SSDT来干掉TP对NtWriteVirtualMemory所做的InLine。

代码和上面的NtReadVirtualMemory差不多,这里也还是贴出来一下吧,俺先放两幅截图,然后再贴代码出来:









下面先贴出安装SSDT钩子的代码,该代码用来干掉TP对NtWriteVirtualMemory的InLineHook:

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

[code]/*安装钩子从而过掉TP保护所Hook的NtWriteVirtualMemory-让TP失效
/*保存NtWriteVirtualMemory第4,5,6,7个字节(其实就是一个ULONG跳转地址)

/*因为这几个字节在不同的XP上会改变,所以在SSDTHook之前保存下来

/*从而避免在此处进行硬编码
/************************************************************************/

VOIDInstallPassTPNtWriteVirtualMemory()

{

if(g_SSDTHookNtWriteVirtualMemory>0)

{

/*获得NtWriteVirtualMemory的地址*/

ULONGuNtWriteVirtualMemoryAddr=oldSysServiceAddr[g_SSDTHookNtWriteVirtualMemory];


/*如果是DNF进程,则跳到NtWriteVirtualMemory执行,即不处理,从而让DNFInLineHook生效*/

uTPHookedNtWriteVirtualMemoryJmpAddr=uNtWriteVirtualMemoryAddr;

/*如果不是DNF进程,则跳过TP的InLineHook,从而使TP失效*/

uMyHookedNtWriteVirtualMemoryJmpAddr=uNtWriteVirtualMemoryAddr+7;

/*保存下未Hook之前的NtReadVirtualMemory的第4,5,6,7个字节*/

uNtWriteVirtualMemoryAddr_3=*((ULONG*)(uNtWriteVirtualMemoryAddr+3));


InstallSysServiceHookByIndex(g_SSDTHookNtWriteVirtualMemory,SSDTHookNtWriteVirtualMemory);


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

}

}

[/code]

下面再给出SSDTHook的中继API的实现代码:

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

[code]/*自定义的NtWriteVirtualMemory,用来实现SSDTHookKernelAPI
/************************************************************************/

NTSYSHOOKAPIVOIDSSDTHookNtWriteVirtualMemory()

{

/*开始过滤*/

if(ValidateCurrentProcessIsDNF()==TRUE)

{

__asm

{

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

jmpuTPHookedNtWriteVirtualMemoryJmpAddr

}

}


__asm

{

/*已经做了针对硬编码的处理*/

/*如果不是DNF进程调用的话,则跳过TPHook的NtWriteVirtualMemory*/

push0x1C

pushuNtWriteVirtualMemoryAddr_3

jmpuMyHookedNtWriteVirtualMemoryJmpAddr

}

}

[/code]

好,到这里就已经拿下了TP对NtWriteVirtualMemory所做的InLineHook了,

对此最直白的效果大家也都可以想象得到了,那就是直接用CE打开DNF游戏进程进行内存修改,

你会发现,此时可以正常修改掉DNF游戏的内存了。





08.干掉KiAttachProcess中的InLineHook:

前面已经干掉NtOpenProcess和NtOpenThread了,按道理来说,咱可以开始用OD来调试DNF游戏进程了,

不过你可以用OD尝试附加一下DNF的游戏进程,而后你会发现根本附加不上去,这又是为何呢?





首先需要明白Ring3在何种操作下,会导致内核调用KiAttachProcess,

从字面意思上看,就是附加进程,在Ring3下的附加进程操作一般会出现在调试进程的时候,

比如用OD附加进程来进行调试,或者用VisualStudio附加进程进行调试,

其实咱猜的没错,就是当附加进程的时候会导致内核调用KiAttachProcess,

TP对这个未导出的API进行了InLineHook,从而使得DNF游戏进程不能被附加,

这样的话,咱的OD或者VisualStudio都是不能够附加上DNF的游戏进程来进行调试了。

正如前面分析的NtReadVirtualMemory和NtWriteVirtualMemory这两个API一样,

TP对KiAttachProcess也是做的浅层的InLineHook,也就是只是Hook了函数头7个字节,

且TP对KiAttachProcess的InLineHook也没有检测,所以干掉这个API还是比较简单的,

不过我们不可以像干掉NtRead/WriteVirtualMemory一样用SSDTHook来对抗掉,

因为KiAttachProcess并没有在SSDT表中,不过我们可以直接恢复TP对KiAttachProcess的Hook即可。

前面也提到了KiAttachProcess是一个未导出的内核API,

所以我们不能使用MmGetSystemRoutineAddress来获得它的地址,

不过好在KeAttachProcess这是一个导出的内核API,

(一般Kixxx都是未导出的API,而Kexxx则是导出的API)

在KeAttachProcess的内部实质上是调用的KiAttachProcess来完成功能的,

所以咱可以通过KeAttachProcess来定位到KiAttachProcess的地址,

并且让人欣喜的是在KeAttachProcess中的第一个call就是callKiAttachProcess,

所以搜索特征码也更加简单了,直接搜索第一个e8就OK。

如果用WinDbg的话,你可以输几个命令就可以把KeAttachProcess的地址打印出来,但是现在咱走点弯路,

在驱动里面用KdPrint打印出KeAttachProcess的地址,然后我们再分析。


KdPrint(("KeAttachProcess:%x.",MmGetSystemFunAddress(L"KeAttachProcess")));







好,这里得到了KeAttachProcess的地址了,

那么咱就可以在KernelDetective中来看看KeAttachProcess的反汇编代码了,

具体的就看图说话,俺也就不多说了,因为截图里面都明明白白摆着在哪里,





















下面给出获取KiAttachProcess地址的代码:

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

[code]/*获取函数KiAttachProcess的地址
/*KiAttachProcess在KeAttachProcess中的第一个Call(e8指令)位置
/************************************************************************/

ULONGGetKiAttachProcessAddr()

{

ULONGuCallAddr=0;

ULONGuKeAttachProcessAddr=0;

ULONGuKiAttachProcessAddr=0;

CHARszCode[1]=

{

(char)0xe8

};


/*获取KeAttachProcess的地址*/

uKeAttachProcessAddr=MmGetSystemFunAddress(L"KeAttachProcess");


/*搜索特征码e8*/

uCallAddr=SearchFeature(uKeAttachProcessAddr,szCode,1);

if(uCallAddr==0)

{

uKiAttachProcessAddr=0;

}

else

{

/*获取KiAttachProcess的地址*/

uKiAttachProcessAddr=*((ULONG*)uCallAddr)+uCallAddr+4;

}


returnuKiAttachProcessAddr;

}

[/code]

得到了KiAttachProcess的地址,那么下面就要来干掉KiAttachProcess了,

为了简单实现,我一开始干掉KiAttachProcess的做法是采用的硬编码,

在得到KiAttachProcess地址后,可以用Xuetr来反汇编这个地址,

从而看到KiAttachProcess的反汇编指令,所以我的做法就是,

直接将Xuetr中KiAttachProcess的头7个字节以硬编码的形式保存在数组中,

然后等TP启动后,我用保存下来的这7个字节直接去恢复KiAttachProcess就OK,

这种方式在我的虚拟机XP里面是OK的,因为我就是从这台XP上获取的7个字节的硬编码,

但是在别的XP系统上就不OK了,原因是KiAttachProcess头7个字节并不是所有的XP都相同的,

直接拿不一致的硬编码去恢复肯定是会BSOD的,不过后来我用了一种简单的办法就干掉这个问题了,

办法很简单,在TP启动之前,我动态去读取KiAttachProcess的头7个字节,并且保存在数组中,

等TP启动后,我就用数组中的这7个字节去恢复TP对KiAttachProcess所做的InLineHook。

实现的具体代码很简单,下面也贴出来:

先在TP启动之前保存KiAttachProcess的头7个字节:


PUCHARpKiAttachProcessAddr=NULL;

[code]
pKiAttachProcessAddr=(PUCHAR)GetKiAttachProcessAddr();


KdPrint(("KiAttachProcess:%x.",uKiAttachProcessAddr));


/*保存KiAttachProcess被DNFHook之前的头API_HOOK_HEADER_LEN个字节*/

for(uIndex=0;uIndex<API_HOOK_HEADER_LEN;uIndex++)

{

szKiAttachProcessOriginCode[uIndex]=pKiAttachProcessAddr[uIndex];

}

[/code]

TP启动之后恢复被TP修改掉的KiAttachProcess的头7个字节:

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

[code]/*恢复KiAttachProcess头9个字节从而恢复KiAttachProcess-让TP失效
/*这里使用了硬编码,去掉硬编码的思路如下:

/*在TP未启动之前,先保存下KiAttachProcess的头9个字节

/*然后在TP启动之后,恢复这9个字节就OK
/************************************************************************/

VOIDRecoveryTPHookedKiAttachProcess()

{

ULONGuIndex=0;

ULONGuOldAttr=0;


KIRQLkOldIRQL=PASSIVE_LEVEL;

PUCHARpKiAttachProcessAddr=NULL;


/*获取到KiAttachProcess的地址*/

pKiAttachProcessAddr=(PUCHAR)GetKiAttachProcessAddr();


EnableWriteProtect(&uOldAttr);

kOldIRQL=KeRaiseIrqlToDpcLevel();


/*恢复KiAttachProcess的头API_HOOK_HEADER_LEN个字节*/

for(uIndex=0;uIndex<API_HOOK_HEADER_LEN;uIndex++)

{

pKiAttachProcessAddr[uIndex]=szKiAttachProcessOriginCode[uIndex];

}


KeLowerIrql(kOldIRQL);

DisableWriteProtect(uOldAttr);


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

}

[/code]

到这里,我们又把KiAttachProcess给搞定了,所以此时咱可以用OD来附加DNF游戏进程试试看了,

此时你会发现咱可以将OD附加上去了,不过可惜的是,就算附加上去了,离使用OD来调试DNF还远着呢,

因为TP对DNF游戏进程还有其他的保护措施,它在内核里面Hook的API可不止这么点哦。

总结:

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

我们已经过掉了TP所做InLineHook的5个API了,

首先是NtOpenProcess和NtOpenThread的深层InLineHook,

然后是SSDT系统服务函数NtReadVirtualMemory和NtWriteVirtualMemory的浅层次InLineHook,

最后我们也干掉了TP对未导出内核函数KiAttachProcess所做的浅层次InLineHook。

虽然也干掉了不少TP在内核中Hook的API了,但是这离过DNFTP驱动保护还比较远的,

详情还得留到下回分解了。

现已支持过掉最新版本的TP保护(2013年04月23日),

如有需要者(有偿提供),请联系QQ:1751048662

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