找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 8185|回复: 4

TP的学习笔记:实现安全Inline Hook模块+动态确定SSDT服务号(NT5)

[复制链接]

78

主题

190

回帖

9

精华

贵宾会员

积分
15605
发表于 2015-7-3 21:36:55 | 显示全部楼层 |阅读模式
我记得我第一次搞Hook的时候,是直接拿黑客防线09年的《Ring0中Inline Hook Shadow SSDT实现窗体保护》来搞得。当时里面的附件是Hook了ObOpenObjectByPointer实现的进程保护,但是就在某一天,它蓝屏了。。。后来才听说了暴力修改WP标志位是一种不安全不稳定的办法,于是就诞生了本文。本文提到的技术,参考了《SSDT和Shadow SSDT完全解析(二)》的文章。主要就是用MDL的方式避开只读保护罢了。本文只需要简单的修改一点点就可实现通用的Win32 Inline Hook SSDT模块。
首先先讲如何避开只读保护。
既然暴力修改WP标志位是不稳定的方法,那我们就不能用这个方法。这里选用MDL映射的方式。首先创建一个MDL,在MmCreateMdl的第二个参数填入要Hook的函数地址,第三个参数填入5。这主要是因为jmp xxxxxxxx指令是5个字节的。
MDL创建完成后,用MmBuildMdlForNonPagedPool建立一段内存区域,修改MDL->MdlFlags的值,再用MmMapLockedPages建立映射。最后就可以用RtlCopyMemory来修改前五个字节了。(顺带着说一点,如果是想用地址替换的方式实现钩子的话,建议用InterlockedExchange函数)代码如下:
  1. //HOOK函数
  2. void Hook (PVOID Func,PVOID New_Func,PVOID Proxy_Func,PMDL MdlForFunc,PVOID Msct)
  3. {
  4.         ULONG PatchSize;
  5.         BYTE g_HookCode[5] = { 0xE9, 0, 0, 0, 0 };//相对跳转
  6.         BYTE Jmp_Orig_Code[7] = { 0xEA, 0, 0, 0, 0, 0x08, 0x00 }; //绝对地址跳转
  7.         PatchSize=GetPatchSize(Func,5);//获得要Patch的字节数
  8.         //构造Proxy_Func
  9.         RtlCopyMemory((PBYTE)Proxy_Func,(PBYTE)Func,PatchSize);//实现原函数头
  10.         *((PULONG)(Jmp_Orig_Code+1))=(ULONG)((PBYTE)Func+PatchSize );//原函数+N 地址
  11.         RtlCopyMemory((PBYTE)Proxy_Func+PatchSize,Jmp_Orig_Code,7);//绝对地址跳转
  12.         *((ULONG*)(g_HookCode+1))=(ULONG)New_Func-(ULONG)Func-5;//计算JMP 地址
  13.         MdlForFunc=MmCreateMdl(NULL,Func,5);
  14.         if(MdlForFunc)
  15.         {
  16.                 MmBuildMdlForNonPagedPool(MdlForFunc);
  17.                 MdlForFunc->MdlFlags=MdlForFunc->MdlFlags|MDL_MAPPED_TO_SYSTEM_VA;
  18.                 Msct=MmMapLockedPages(MdlForFunc,KernelMode);
  19.                 RtlCopyMemory(Func,g_HookCode,5);
  20.         }
  21. }
复制代码

实现了Hook,就要实现Unhook,方法很简单,先用RtlCopyMemory恢复前五个字节,接着用MmUnmapLockedPages取消映射,再用IoFreeMdl释放掉Mdl就可以了。代码如下:
//UnHook函数
  1. void UnHook (PVOID Func,PVOID Proxy_Func,PMDL MdlForFunc,PVOID Msct)
  2. {
  3.         RtlCopyMemory(Func,Proxy_Func,5);
  4.         if(MdlForFunc)
  5.         {
  6.                 MmUnmapLockedPages(Msct,MdlForFunc);
  7.                 IoFreeMdl(MdlForFunc);
  8.         }
  9. }
复制代码

这里的Hook函数和Unhook函数参数比较多。。。如果是小白仅仅要调用这个Hook/Unhook函数,那么在Hook函数中,第一个参数填入要Hook的地址,第二个参数填入伪函数的地址,第三个参数填入代理函数的地址,第四个参数填入对应的MDL,第五个填入MSCT(其实是MappedSystemCallTable的缩写),其实后两个参数已经在Hook函数里处理完成了,调用之前不用理睬,声明一下变量就行。至于Unhook,也很简单,调用的时候,第一个参数输入被Hook的函数地址,第二个参数输入代理函数的地址,第三个参数输入为函数定义的MDL,第四个填入对应的MSCT即可。
完成了Hook和Unhook,接着就是动态确认服务号。由于Win32的SSDT和Win64的SSDT不一样,不是那种随机的,所以有些人可能会用硬编码了。我记得www.vsyide.com上有个查看SDT的小工具,可以确定多个系统的SSDT/SSSDT的函数服务号,这个工具大概长着个样子:

vsyide的SSDT查看工具

vsyide的SSDT查看工具

于是便可以惊喜的发现它只能看XP,2003,Vista,2008,win7,win8这六个系统。。。那么win10呢。。。所以用硬编码不是个好选择
那么我们如何取得Index呢?在内核里有相同数量的NtXXX函数和ZwXXX函数。那我们看看ZwTerminateProcess的反汇编结果:

windbg对ZwTerminateProcess的反汇编

windbg对ZwTerminateProcess的反汇编

可以发现第一个字节是0x8b,第二到第五个字节是0x00000101,也就是0x101,这就是我们要的服务编号!
所以我们的动态获取Index的思路就是取得ZwXXX函数的地址,然后读地址+1,长度为4的数据,这个数据就是Index了,代码如下:
  1. ULONG DynamicGetNtTerminateProcessIndex()
  2. {
  3.         UNICODE_STRING uniFuncName;
  4.         UCHAR tmp=0;
  5.         ULONG IndexOf_NtTerminateProcess=0;
  6.         //取得ZwTerminateProcess的函数地址
  7.         RtlInitUnicodeString(&uniFuncName,L"ZwTerminateProcess");
  8.         ZwTerminateProcess=MmGetSystemRoutineAddress(&uniFuncName);
  9.         //先判断一下有木有被Hook
  10.         RtlCopyMemory(&tmp,ZwTerminateProcess,1);
  11.         if(tmp==0xb8)
  12.         {
  13.                 //取得Index
  14.                 RtlCopyMemory(&IndexOf_NtTerminateProcess,(PVOID)((ULONG)ZwTerminateProcess+1),4);
  15.         }
  16.         return IndexOf_NtTerminateProcess;
  17. }
复制代码

上述代码就是取得NtTerminateProcess的Index的代码了。
要做到通用,只需要修改RtlInitUnicodeString这一行中的字符串就行了,别忘了把"Nt"改成"Zw"{:soso_e113:}
那么就开始测试结果吧,下面贴出XP和2k3的测试结果图片。

winxp的保护效果

winxp的保护效果

2k3的保护效果

2k3的保护效果

本文提及的技术,均在windows xp和windows server 2003内测试通过。

SafeHookDemo.zip

22.13 KB, 下载次数: 4886

下载代码不回帖是一种很欠扁的行为

评分

参与人数 2水晶币 +62 收起 理由
dagangwood + 2 赞一个!
Tesla.Angela + 60

查看全部评分

78

主题

190

回帖

9

精华

贵宾会员

积分
15605
 楼主| 发表于 2015-7-4 08:48:07 来自手机 | 显示全部楼层
拿我哥们的win7,win8的机子测试了一下,竟然蓝屏了。。。算了这篇文章应该加个括号,其中要注上NT5测试通过。。。有兴趣的朋友帮忙改一下吧,蓝屏提示的是只读内存发生写操作【于是就不懂了,不是用MDL映射避开了写保护了么⊙▽⊙】

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2015-7-4 10:11:55 | 显示全部楼层
1.引用我的名言而不标明出处也是一种很欠扁的行为{:soso_e113:}
2.和TP有啥关系

78

主题

190

回帖

9

精华

贵宾会员

积分
15605
 楼主| 发表于 2015-7-4 11:07:06 来自手机 | 显示全部楼层
Tesla.Angela 发表于 2015-7-4 10:11
1.引用我的名言而不标明出处也是一种很欠扁的行为
2.和TP有啥关系 ...

tangptr→tp。。。下次再表明出处

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2015-7-4 18:03:09 | 显示全部楼层
tangptr@126.com 发表于 2015-7-4 11:07
tangptr→tp。。。下次再表明出处

我还以为你说TENCENT GAME PROTECTION
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表