找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 9477|回复: 4

TP的学习笔记:用映射MDL方式实现安全的Hook引擎

[复制链接]

78

主题

190

回帖

9

精华

贵宾会员

积分
15605
发表于 2015-8-28 21:26:31 | 显示全部楼层 |阅读模式
本文将提及到两种Inline Hook,分别是修改头五个字节的jmp Hook以及修改Call指令后4个字节的Call Hook。特点在于没有内嵌汇编,纯C的代码。
首先先谈Head Inline Hook。
首先挂钩的时候要注意哪些问题呢?
1.写入保护。写入保护位于cr0寄存器第15位,为一代表开启,为零代表关闭。但实验证明修改cr0寄存器属于危险行为,而且在不使用类似于__writecr0之类的WDK内置宏的情况下,是需要内嵌汇编的。这里将使用映射MDL的方式实现绕过写入保护。
2.指令屑。其实这已经不能算是问题了,因为有反汇编引擎。但如果仅仅修改5个字节,虽然执行不存在问题,但像WinDbg之类的软件查看函数就会出现异常,而且,假设要对一个不能只Patch5个字节的函数来说,我们Hook之后,别的驱动想对这个函数进行Call Hook就会出现问题。所以,还得把剩余的字节全部填充NOP指令才行。
  1. void Hook (PVOID Func,PVOID New_Func,PVOID Proxy_Func)
  2. {
  3.         PMDL MdlForFunc;
  4.         PVOID Msct;
  5.         PVOID HookCode=NULL;
  6.         ULONG PatchSize;
  7.         KIRQL oldIrql;
  8.         BYTE g_HookCode[5]={0xE9,0,0,0,0};//相对跳转
  9.         BYTE Jmp_Orig_Code[7]={0xEA,0,0,0,0,0x08,0x00 }; //绝对地址跳转
  10.         PatchSize=GetPatchSize(Func,5);//获得要Patch的字节数
  11.         //构造Proxy_Func
  12.         RtlCopyMemory((PBYTE)Proxy_Func,(PBYTE)Func,PatchSize);//实现原函数头
  13.         *((PULONG)(Jmp_Orig_Code+1))=(ULONG)((PBYTE)Func+PatchSize );//原函数+N 地址
  14.         RtlCopyMemory((PBYTE)Proxy_Func+PatchSize,Jmp_Orig_Code,7);//绝对地址跳转
  15.         *((ULONG*)(g_HookCode+1))=(ULONG)New_Func-(ULONG)Func-5;//计算JMP 地址
  16.         HookCode=ExAllocatePool(NonPagedPool,PatchSize);
  17.         RtlCopyMemory(HookCode,g_HookCode,5);
  18.         memset((PVOID)((ULONG)HookCode+5),0x90,PatchSize-5);
  19.         MdlForFunc=MmCreateMdl(NULL,Func,PatchSize);
  20.         if(MdlForFunc)
  21.         {
  22.                 MmBuildMdlForNonPagedPool(MdlForFunc);
  23.                 MdlForFunc->MdlFlags=MdlForFunc->MdlFlags|MDL_MAPPED_TO_SYSTEM_VA;
  24.                 __try
  25.                 {
  26.                         MmProbeAndLockPages(MdlForFunc,KernelMode,IoWriteAccess);
  27.                 }
  28.                       __except(EXCEPTION_EXECUTE_HANDLER)
  29.                 {
  30.                         IoFreeMdl(MdlForFunc);;
  31.                 }
  32.                 Msct=MmMapLockedPagesSpecifyCache(MdlForFunc,KernelMode,MmWriteCombined,NULL,FALSE,0);
  33.                 oldIrql=KeRaiseIrqlToDpcLevel();
  34.                 RtlCopyMemory(Msct,HookCode,PatchSize);
  35.                 KeLowerIrql(oldIrql);
  36.                 MmUnmapLockedPages(Msct,MdlForFunc);
  37.                 MmUnlockPages(MdlForFunc);
  38.                 IoFreeMdl(MdlForFunc);
  39.         }
  40.         ExFreePool(HookCode);
  41. }
复制代码

还有UnHook的代码:
  1. void UnHook (PVOID Func,PVOID Proxy_Func)
  2. {
  3.         PMDL MdlForFunc;
  4.         PVOID Msct;
  5.         ULONG PatchSize;
  6.         KIRQL f_oldirql;
  7.         PatchSize=GetPatchSize(Proxy_Func,5);
  8.         MdlForFunc=MmCreateMdl(NULL,Func,PatchSize);
  9.         if(MdlForFunc)
  10.         {
  11.                 MmBuildMdlForNonPagedPool(MdlForFunc);
  12.                 MdlForFunc->MdlFlags=MdlForFunc->MdlFlags|MDL_MAPPED_TO_SYSTEM_VA;
  13.                 __try
  14.                 {
  15.                         MmProbeAndLockPages(MdlForFunc,KernelMode,IoWriteAccess);
  16.                 }
  17.                       __except(EXCEPTION_EXECUTE_HANDLER)
  18.                 {
  19.                         IoFreeMdl(MdlForFunc);
  20.                 }
  21.                 Msct=MmMapLockedPagesSpecifyCache(MdlForFunc,KernelMode,MmWriteCombined,NULL,FALSE,0);
  22.                 f_oldirql=KeRaiseIrqlToDpcLevel();
  23.                 RtlCopyMemory(Msct,Proxy_Func,PatchSize);
  24.                 KeLowerIrql(f_oldirql);
  25.                 MmUnmapLockedPages(Msct,MdlForFunc);
  26.                 MmUnlockPages(MdlForFunc);
  27.                 IoFreeMdl(MdlForFunc);
  28.         }
  29. }
复制代码

说白了这里只是补充了第一期TP的学习笔记中《TP的学习笔记:实现安全Inline Hook模块+动态确定SSDT服务号(NT5)》一文的代码而已。并且还修正了NT6系列操作系统蓝屏的问题,也补充了修复指令屑BUG的问题。
接下来是Call Hook。
其实Call Hook就没啥说的了,同样是把暴力修改cr0寄存器改成了映射MDL,不过我发现上次的TP的学习笔记中使用自旋锁是没必要的,因此改良后代码是这样的:
  1. void CallAddrHook(PVOID StartAddr,PVOID OldAddr,PVOID NewAddr)
  2. {
  3.         PUCHAR cPtr, pOpcode;
  4.         ULONG Length,Tmp;
  5.         PMDL pMdl;
  6.         PVOID Msct;
  7.         for (cPtr=StartAddr;(ULONG)cPtr<(ULONG)StartAddr+0x1000;cPtr += Length)
  8.         {
  9.                 Length = SizeOfCode(cPtr, &pOpcode);//计算当前指令长度
  10.                 if (!Length) break;
  11.                 if (Length ==5 && *cPtr==0xE8)// 当前长度5 且第一字节为E8
  12.                 {//因为CALL用的是相对偏移  所以我们还需要进行计算相对偏移
  13.                         if((ULONG)OldAddr-(ULONG)cPtr-5==*(PULONG)(cPtr+1)) //判断当前是否为OldAddr的CALL相对地址
  14.                         {
  15.                                 Tmp=(ULONG)NewAddr-(ULONG)cPtr-5;//我们的CALL地址相对偏移
  16.                                 pMdl=MmCreateMdl(NULL,(PVOID)(cPtr+1),4);
  17.                                 if(pMdl)
  18.                                 {
  19.                                         //进行HOOK操作
  20.                                         MmBuildMdlForNonPagedPool(pMdl);
  21.                                         pMdl->MdlFlags=pMdl->MdlFlags|MDL_MAPPED_TO_SYSTEM_VA;
  22.                                         __try
  23.                                         {
  24.                                                 MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
  25.                                         }
  26.                                         __except(EXCEPTION_EXECUTE_HANDLER)
  27.                                         {
  28.                                                 IoFreeMdl(pMdl);
  29.                                         }
  30.                                         Msct=MmMapLockedPagesSpecifyCache(pMdl,KernelMode,MmWriteCombined,NULL,FALSE,0);
  31.                                         f_oldirql=KeRaiseIrqlToDpcLevel();
  32.                                         InterlockedExchange(Msct,Tmp);//直接替换为我们的FAKE函数地址   
  33.                                         KeLowerIrql(f_oldirql);
  34.                                         MmUnmapLockedPages(Msct,pMdl);
  35.                                         MmUnlockPages(pMdl);
  36.                                         IoFreeMdl(pMdl);
  37.                                 }
  38.                         }
  39.                 }
  40.         }
  41. }
复制代码

希望这篇文章发表后,我不会再看到那些改cr0的Hook代码了。。。。。。

评分

参与人数 2水晶币 +110 收起 理由
radarhp + 10 赞一个!
Tesla.Angela + 100 赞一个!

查看全部评分

857

主题

2632

回帖

2

精华

管理员

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

积分
36130
发表于 2015-8-30 12:28:10 | 显示全部楼层
文章很好!

1

主题

23

回帖

0

精华

铜牌会员

积分
205
发表于 2015-9-8 23:35:07 | 显示全部楼层
呵呵 ,讲究的人做事态度毕竟不一样

0

主题

24

回帖

0

精华

初来乍到

积分
4
发表于 2017-7-4 13:10:36 | 显示全部楼层
文章很好!
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

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