|
本文将提及到两种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指令才行。
- void Hook (PVOID Func,PVOID New_Func,PVOID Proxy_Func)
- {
- PMDL MdlForFunc;
- PVOID Msct;
- PVOID HookCode=NULL;
- ULONG PatchSize;
- KIRQL oldIrql;
- BYTE g_HookCode[5]={0xE9,0,0,0,0};//相对跳转
- BYTE Jmp_Orig_Code[7]={0xEA,0,0,0,0,0x08,0x00 }; //绝对地址跳转
- PatchSize=GetPatchSize(Func,5);//获得要Patch的字节数
- //构造Proxy_Func
- RtlCopyMemory((PBYTE)Proxy_Func,(PBYTE)Func,PatchSize);//实现原函数头
- *((PULONG)(Jmp_Orig_Code+1))=(ULONG)((PBYTE)Func+PatchSize );//原函数+N 地址
- RtlCopyMemory((PBYTE)Proxy_Func+PatchSize,Jmp_Orig_Code,7);//绝对地址跳转
- *((ULONG*)(g_HookCode+1))=(ULONG)New_Func-(ULONG)Func-5;//计算JMP 地址
- HookCode=ExAllocatePool(NonPagedPool,PatchSize);
- RtlCopyMemory(HookCode,g_HookCode,5);
- memset((PVOID)((ULONG)HookCode+5),0x90,PatchSize-5);
- MdlForFunc=MmCreateMdl(NULL,Func,PatchSize);
- if(MdlForFunc)
- {
- MmBuildMdlForNonPagedPool(MdlForFunc);
- MdlForFunc->MdlFlags=MdlForFunc->MdlFlags|MDL_MAPPED_TO_SYSTEM_VA;
- __try
- {
- MmProbeAndLockPages(MdlForFunc,KernelMode,IoWriteAccess);
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- IoFreeMdl(MdlForFunc);;
- }
- Msct=MmMapLockedPagesSpecifyCache(MdlForFunc,KernelMode,MmWriteCombined,NULL,FALSE,0);
- oldIrql=KeRaiseIrqlToDpcLevel();
- RtlCopyMemory(Msct,HookCode,PatchSize);
- KeLowerIrql(oldIrql);
- MmUnmapLockedPages(Msct,MdlForFunc);
- MmUnlockPages(MdlForFunc);
- IoFreeMdl(MdlForFunc);
- }
- ExFreePool(HookCode);
- }
复制代码
还有UnHook的代码:
- void UnHook (PVOID Func,PVOID Proxy_Func)
- {
- PMDL MdlForFunc;
- PVOID Msct;
- ULONG PatchSize;
- KIRQL f_oldirql;
- PatchSize=GetPatchSize(Proxy_Func,5);
- MdlForFunc=MmCreateMdl(NULL,Func,PatchSize);
- if(MdlForFunc)
- {
- MmBuildMdlForNonPagedPool(MdlForFunc);
- MdlForFunc->MdlFlags=MdlForFunc->MdlFlags|MDL_MAPPED_TO_SYSTEM_VA;
- __try
- {
- MmProbeAndLockPages(MdlForFunc,KernelMode,IoWriteAccess);
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- IoFreeMdl(MdlForFunc);
- }
- Msct=MmMapLockedPagesSpecifyCache(MdlForFunc,KernelMode,MmWriteCombined,NULL,FALSE,0);
- f_oldirql=KeRaiseIrqlToDpcLevel();
- RtlCopyMemory(Msct,Proxy_Func,PatchSize);
- KeLowerIrql(f_oldirql);
- MmUnmapLockedPages(Msct,MdlForFunc);
- MmUnlockPages(MdlForFunc);
- IoFreeMdl(MdlForFunc);
- }
- }
复制代码
说白了这里只是补充了第一期TP的学习笔记中《TP的学习笔记:实现安全Inline Hook模块+动态确定SSDT服务号(NT5)》一文的代码而已。并且还修正了NT6系列操作系统蓝屏的问题,也补充了修复指令屑BUG的问题。
接下来是Call Hook。
其实Call Hook就没啥说的了,同样是把暴力修改cr0寄存器改成了映射MDL,不过我发现上次的TP的学习笔记中使用自旋锁是没必要的,因此改良后代码是这样的:
- void CallAddrHook(PVOID StartAddr,PVOID OldAddr,PVOID NewAddr)
- {
- PUCHAR cPtr, pOpcode;
- ULONG Length,Tmp;
- PMDL pMdl;
- PVOID Msct;
- for (cPtr=StartAddr;(ULONG)cPtr<(ULONG)StartAddr+0x1000;cPtr += Length)
- {
- Length = SizeOfCode(cPtr, &pOpcode);//计算当前指令长度
- if (!Length) break;
- if (Length ==5 && *cPtr==0xE8)// 当前长度5 且第一字节为E8
- {//因为CALL用的是相对偏移 所以我们还需要进行计算相对偏移
- if((ULONG)OldAddr-(ULONG)cPtr-5==*(PULONG)(cPtr+1)) //判断当前是否为OldAddr的CALL相对地址
- {
- Tmp=(ULONG)NewAddr-(ULONG)cPtr-5;//我们的CALL地址相对偏移
- pMdl=MmCreateMdl(NULL,(PVOID)(cPtr+1),4);
- if(pMdl)
- {
- //进行HOOK操作
- MmBuildMdlForNonPagedPool(pMdl);
- pMdl->MdlFlags=pMdl->MdlFlags|MDL_MAPPED_TO_SYSTEM_VA;
- __try
- {
- MmProbeAndLockPages(pMdl,KernelMode,IoWriteAccess);
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- IoFreeMdl(pMdl);
- }
- Msct=MmMapLockedPagesSpecifyCache(pMdl,KernelMode,MmWriteCombined,NULL,FALSE,0);
- f_oldirql=KeRaiseIrqlToDpcLevel();
- InterlockedExchange(Msct,Tmp);//直接替换为我们的FAKE函数地址
- KeLowerIrql(f_oldirql);
- MmUnmapLockedPages(Msct,pMdl);
- MmUnlockPages(pMdl);
- IoFreeMdl(pMdl);
- }
- }
- }
- }
- }
复制代码
希望这篇文章发表后,我不会再看到那些改cr0的Hook代码了。。。。。。 |
评分
-
查看全部评分
|