当前位置:文档之家› 过DNF TP 驱动保护2

过DNF TP 驱动保护2

过DNF  TP 驱动保护2
过DNF  TP 驱动保护2

06、干掉NtReadVirtualMemory 中的InLine Hook:

前面已经干掉了TP 对NtOpenProcess 以及TP对NtOpenThread 所做的Hook,这样的话,我们已经可以使用OD 或者CE 看到DNF 的游戏进程了,弄过一些游戏方面内容的朋友应该都是知道CE 的,这东西是开源的,不过是基于Delphi 的,工具做得很不错,可以通过CE 来修改一些游戏进程的内存数据,比如可以修改一些简单的游戏的血值啊之类的,但是,此时我们可以用CE 来扫描一下DNF 游戏进程的内存,你会发现根本扫描不到任何数据,其实原因也很简单,TP 对NtReadVirtualMemory 进行了浅层的InLine Hook,从而可以达到防止其他进程读取DNF 游戏进程内存的目的,而CE 的话,在Ring3 下是通过ReadProcessMemory 来读取游戏内存的,而ReadProcessMemory 进入Ring0 后又是调用的NtReadVirtualMemory,由于NtReadVirtualMemory 被TP干掉了,所以自然用CE 是扫描不出任何东西的,要干掉TP 对NtReadVirtualMemory 所作的浅层InLine Hook 其实是比较简单的,因为TP并没有对NtReadVirtualMemory 做检测,所以可以直接用SSDT 来对抗掉浅层的InLine Hook 就OK。

至于原理的话,很简单,直接用SSDT Hook 替换掉系统服务NtReadVirtualMemory,然后在SSDT Hook NtReadVirtualMemory 这个我们自己写的系统服务中判断,如果是DNF 进程的话,直接调用原来的SSDT 系统服务就好,如果不是DNF 进程的话,我就跳过TP 对NtReadVirtualMemory 所做的InLine Hook,也就是跳过前面7 个字节就OK 了。

对于这种干掉InLine Hook 的原理,堕落天才的文章讲的最清楚了,我这里就不再班门弄斧了。对于用SSDT Hook 干掉浅层的InLine Hook 可以参考文章名称:《SSDT Hook 的妙用- 对抗Ring0 InLine Hook》。有的初学者可能问,咱是如何知道NtReadVirtualMemory 被TP 干掉了呢?很简单,还是采用前面的做法,用Kernel Detective 就可以看到了,具体可以看下面的截图:

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

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

https://www.doczj.com/doc/6e10917143.html,/BoyXiao/archive/2011/09/03/2164574.html

https://www.doczj.com/doc/6e10917143.html,/BoyXiao/archive/2011/09/04/2166596.html

https://www.doczj.com/doc/6e10917143.html,/BoyXiao/archive/2011/09/05/2168115.html

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

1: /*****************************************************************/

2: /* 安装钩子从而过掉TP 保护所Hook 的NtReadVirtualMemory - 让TP 失效*/ 3: /* 保存NtReadVirtualMemory第4,5,6,7 个字节(就是一个ULONG 跳转地址) */ 4: /* 因为这几个字节在不同的XP上会改变,所以在SSDT Hook 之前保存下来*/ 5: /* 从而避免在此处进行硬编码

6: /*********************************************************************/ 7: VOID InstallPassTPNtReadVirtualMemory()

8: {

9: if(g_SSDTHookNtReadVirtualMemory > 0)

10: {

11: /* 获得NtReadVirtualMemory 的地址*/

12: ULONG uNtReadVirtualMemoryAddr =

oldSysServiceAddr[g_SSDTHookNtReadVirtualMemory];

13:

14: /* 如果是DNF 进程,则跳到NtReadVirtualMemory 执行,即不处理,从

而让DNF InLine Hook 生效*/

15: uTPHookedNtReadVirtualMemoryJmpAddr = uNtReadV irtualMemoryAddr; 16: /* 如果不是DNF 进程,则跳过TP 的InLine Hook,从而使TP 失效*/ 17: uMyHookedNtReadVirtualMemoryJmpAddr = uNtReadVirtualMemoryAddr + 7;

18: /* 保存下未Hook 之前的NtReadVirtualMemory 的第4,5,6,7 个字节*/ 19: uNtReadVirtualMemoryAddr_3 = *((ULONG *)(uNtReadVirtualMemoryAddr + 3));

20:

21: InstallSysServiceHookByIndex(g_SSDTHookNtReadVirtualMemory,

SSDTHookNtReadVirtualMemory);

22:

23: KdPrint(("Pass TP - NtReadVirtualMemory Installed."));

24: }

25: }

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

1:

/************************************************************************/ 2: /* 自定义的NtReadVirtualMemory,用来实现SSDT Hook Kernel API

3:

/************************************************************************/ 4: NTSYSHOOKAPI VOID SSDTHookNtReadVirtualMemory()

5: {

6: /* 开始过滤*/

7: if(V alidateCurrentProcessIsDNF() == TRUE)

8: {

9: __asm

10: {

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

TP Hook 的NtReadV irtualMemory

*/

12: jmp uTPHookedNtReadVirtualMemoryJmpAddr

13: }

14: }

15:

16: __asm

17: {

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

19: 如果不是DNF 进程调用的话,则跳过TP Hook 的

NtReadVirtualMemory

*/

20: push 0x1C

21: push uNtReadVirtualMemoryAddr_3

22: jmp uMyHookedNtReadVirtualMemoryJmpAddr

23: }

24: }

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

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

07、干掉NtWriteVirtualMemory 中的InLine Hook:

上面又干掉了TP 对NtReadVirtualMemory 的InLine Hook 了,从而实现了CE 读取DNF 进程的内存。但是你可以试着用CE 修改DNF 进程的内存,你很快就会发现,虽然可以扫描内存,但是并不可以读取内存,而后你也肯定能够想到,既然有防止读取内存,那肯定也有防止写入内存,而后你又自然会找到NtWriteVirtualMemory 上来,等你找到NtWriteVirtualMemory 后,你又基本能够确定,搞定这个API 和搞定NtReadVirtualMemory 应该是差不多的,因为这两个API 就是一对啊,一个读,一个写,所以TP肯定也是采用相同的做法来处理这两个API,当然,你上面的猜想都是正确的,所以咱还是用SSDT 来干掉TP对NtWriteVirtualMemory 所做的InLine。代码和上面的NtReadVirtualMemory 差不多,这里也还是贴出来一下吧,俺先放两幅截图,然后再贴代码出来:

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

1:

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

4: /* 因为这几个字节在不同的XP上会改变,所以在SSDT Hook 之前保存下来5: /* 从而避免在此处进行硬编码

6:

/************************************************************************/ 7: VOID InstallPassTPNtWriteVirtualMemory()

8: {

9: if(g_SSDTHookNtWriteVirtualMemory > 0)

10: {

11: /* 获得NtWriteVirtualMemory 的地址*/

12: ULONG uNtWriteVirtualMemoryAddr = oldSysServiceAddr[g_SSDTHookNtWriteVirtualMemory];

13:

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

15: uTPHookedNtWriteVirtualMemoryJmpAddr = uNtWriteVirtualMemoryAddr; 16: /* 如果不是DNF 进程,则跳过TP 的InLine Hook,从而使TP 失效*/ 17: uMyHookedNtWriteVirtualMemoryJmpAddr = uNtWriteVirtualMemoryAddr + 7;

18: /* 保存下未Hook 之前的NtReadVirtualMemory 的第4,5,6,7 个字节*/ 19: uNtWriteV irtualMemoryAddr_3 = *((ULONG *)(uNtWriteVirtualMemoryAddr + 3));

20:

21: InstallSysServiceHookByIndex(g_SSDTHookNtWriteVirtualMemory,

SSDTHookNtWriteVirtualMemory);

22:

23: KdPrint(("Pass TP - NtWriteV irtualMemory Installed."));

24: }

25: }

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

1:

/************************************************************************/ 2: /* 自定义的NtWriteVirtualMemory,用来实现SSDT Hook Kernel API

3:

/************************************************************************/ 4: NTSYSHOOKAPI VOID SSDTHookNtWriteVirtualMemory ()

5: {

6: /* 开始过滤*/

7: if(V alidateCurrentProcessIsDNF() == TRUE)

8: {

9: __asm

10: {

11: /* 如果是DNF 进程调用的话,则调用已经被TP Hook 的NtWriteVirtualMemory */

12: jmp uTPHookedNtWriteVirtualMemoryJmpAddr

13: }

14: }

15:

16: __asm

17: {

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

19: /* 如果不是DNF 进程调用的话,则跳过TP Hook 的NtWriteVirtualMemory */

20: push 0x1C

21: push uNtWriteVirtualMemoryAddr_3

22: jmp uMyHookedNtWriteVirtualMemoryJmpAddr

23: }

24: }

好,到这里就已经拿下了TP对NtWriteV irtualMemory 所做的InLine Hook了,

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

08、干掉KiAttachProcess 中的InLine Hook:

前面已经干掉NtOpenProcess 和NtOpenThread 了,按道理来说,咱可以开始用OD 来调试DNF 游戏进程了,不过你可以用OD 尝试附加一下DNF 的游戏进程,而后你会发现根本附加不上去,这又是为何呢?

首先需要明白Ring3 在何种操作下,会导致内核调用KiAttachProcess,从字面意思上看,就是附加进程,在Ring3 下的附加进程操作一般会出现在调试进程的时候,比如用OD 附加进程来进行调试,或者用V isual Studio 附加进程进行调试,其实咱猜的没错,就是当附加进程的时候会导致内核调用KiAttachProcess,TP对这个未导出的API 进行了InLine

Hook,从而使得DNF 游戏进程不能被附加,这样的话,咱的OD 或者V isual Studio 都是不能够附加上DNF 的游戏进程来进行调试了。正如前面分析的NtReadVirtualMemory 和NtWriteVirtualMemory 这两个API 一样,TP 对KiAttachProcess 也是做的浅层的InLine Hook,也就是只是Hook 了函数头7 个字节,且TP 对KiAttachProcess 的InLine Hook 也没有检测,所以干掉这个API 还是比较简单的,不过我们不可以像干掉NtRead/WriteVirtualMemory 一样用SSDT Hook 来对抗掉,因为KiAttachProcess 并没有在SSDT 表中,不过我们可以直接恢复TP对KiAttachProcess 的Hook 即可。前面也提到了KiAttachProcess 是一个未导出的内核API,所以我们不能使用

MmGetSystemRoutineAddress

来获得它的地址,不过好在KeAttachProcess 这是一个导出的内核API,

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

在KeAttachProcess 的内部实质上是调用的KiAttachProcess 来完成功能的,所以咱可以通过KeAttachProcess 来定位到KiAttachProcess 的地址,并且让人欣喜的是在KeAttachProcess 中的第一个call 就是call KiAttachProcess,所以搜索特征码也更加简单了,直接搜索第一个e8 就OK。如果用WinDbg 的话,你可以输几个命令就可以把KeAttachProcess 的地址打印出来,但是现在咱走点弯路,在驱动里面用KdPrint 打印出KeAttachProcess 的地址,然后我们再分析。

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

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

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

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

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

1:

/************************************************************************/ 2: /* 获取函数 KiAttachProcess 的地址

3: /* KiAttachProcess 在 KeAttachProcess 中的第一个 Call(e8 指令) 位置

4:

/************************************************************************/ 5: ULONG GetKiAttachProcessAddr()

6: {

7: ULONG uCallAddr = 0;

8: ULONG uKeAttachProcessAddr = 0;

9: ULONG uKiAttachProcessAddr = 0;

10: CHAR szCode[1] =

11: {

12: (char)0xe8

13: };

14:

15: /* 获取KeAttachProcess 的地址*/

16: uKeAttachProcessAddr = MmGetSystemFunAddress(L"KeAttachProcess");

17:

18: /* 搜索特征码e8 */

19: uCallAddr = SearchFeature(uKeAttachProcessAddr, szCode, 1);

20: if (uCallAddr == 0)

21: {

22: uKiAttachProcessAddr = 0;

23: }

24: else

25: {

26: /* 获取KiAttachProcess 的地址*/

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

28: }

29:

30: return uKiAttachProcessAddr;

31: }

得到了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 所做的InLine Hook。

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

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

1: PUCHAR pKiAttachProcessAddr = NULL;

2:

3: pKiAttachProcessAddr = (PUCHAR)GetKiAttachProcessAddr();

4:

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

6:

7: /* 保存KiAttachProcess 被DNF Hook 之前的头API_HOOK_HEADER_LEN 个字节*/

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

9: {

10: szKiAttachProcessOriginCode[uIndex] = pKiAttachProcessAddr[uIndex]; 11: }

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

1:

/************************************************************************/ 2: /* 恢复KiAttachProcess 头9 个字节从而恢复KiAttachProcess - 让TP失效

3: /* 这里使用了硬编码,去掉硬编码的思路如下:

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

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

6:

/************************************************************************/ 7: VOID RecoveryTPHookedKiAttachProcess()

8: {

9: ULONG uIndex = 0;

10: ULONG uOldAttr = 0;

11:

12: KIRQL kOldIRQL = PASSIVE_LEVEL;

13: PUCHAR pKiAttachProcessAddr = NULL;

14:

15: /* 获取到KiAttachProcess 的地址*/

16: pKiAttachProcessAddr = (PUCHAR)GetKiAttachProcessAddr();

17:

18: EnableWriteProtect(&uOldAttr);

19: kOldIRQL = KeRaiseIrqlToDpcLevel();

20:

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

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

23: {

24: pKiAttachProcessAddr[uIndex] = szKiAttachProcessOriginCode[uIndex]; 25: }

26:

27: KeLowerIrql(kOldIRQL);

28: DisableWriteProtect(uOldAttr);

29:

30: KdPrint(("Pass TP - KiAttachProcess Installed."));

31: }

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

戏进程试试看了,此时你会发现咱可以将OD 附加上去了,不过可惜的是,就算附加上去了,离使用OD 来调试DNF 还远着呢,因为TP对DNF 游戏进程还有其他的保护措施,它在内核里面Hook 的API 可不止这么点哦。

总结:

《过DNF TP驱动保护》的第二篇到这里就结束了,经过上面的处理,我们已经过掉了TP 所做InLine Hook 的 5 个API 了,首先是NtOpenProcess 和NtOpenThread 的深层InLine Hook,然后是SSDT 系统服务函数NtReadVirtualMemory 和NtWriteVirtualMemory 的浅层次InLine Hook,最后我们也干掉了TP 对未导出内核函数KiAttachProcess 所做的浅层次InLine Hook。虽然也干掉了不少TP 在内核中Hook 的API 了,但是这离过DNF TP 驱动保护还比较远的,详情还得留到下回分解了。

相关主题
文本预览
相关文档 最新文档