hook的尝试"/>
win7 x64 inline hook的尝试
最近因为虚机性能问题,需要验证下是不是因为内核态加锁时间过长导致,所以需要在内核态hook两个内核函数:KeAcquireSpinLockAtDpcLevel和KeReleaseSpinLock,虚机的操作系统是win7 64位。
所以在内核态hook,我采用inline hook的方式,有借鉴的blog:
这篇博客对原理讲的比较清楚,博客的作者说那段代码会蓝屏,他没有具体说是什么现象的蓝屏,所以我也不清楚到底他指的蓝屏是什么,但是我在实际使用过程中发现有两个蓝屏问题:
patch guard导致的蓝屏
我利用博客代码对KeAcquireSpinLockAtDpcLevel和KeReleaseSpinLock两个函数进行了hook,欣喜的是能顺利hook到两个函数里面,但是不一会儿就蓝屏了,蓝屏界面如下:
这个蓝屏导致的原因是win7 64位系统的patch guard机制,系统会不定时检测内核是否被篡改,如果有篡改就会促发蓝屏。
(1)对破解软件的尝试,我尝试了网上说的一些方法,比如我下载了no_pg_ds_v3这个工具,然后按照文档进行部署,部署成功后重启,会提示如下界面:
这时候选中“PatchGuard Disabled V3”,然后按F8去掉驱动程序签名强制,这时候就进入系统了,然而并没有什么卵用,系统还是会触发一样的蓝屏。
(2)对于调试模式的尝试,据说微软在调试模式会自动去掉patch guard机制,要不然windbg怎么做到打断点之类的功能的,于是我设置了一个调试模式的引导项,可以参照,重启后进入该引导项(上图的DebugEntry引导),还是没解决问题,最后找到了一篇外国的博客,需要在调试模式下再加一条命令:Bcdedit /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200 /start AUTOENABLE /noumex。这样patch guard就关掉了,经过测试可用。
因为对于我来说我只是开发一个调试工具,所以调试模式对我来说是可接受的,至于如何在普通场景下绕过去的方式我目前还没找到。
反编译引擎LDE造成的蓝屏
第二个蓝屏界面如下:
一般发生在加载驱动的时候,且刚开机的时候加载驱动特别容易重现。
我通过windbg对dump文件进行分析,发现每次蓝屏模块都不一样,也不是我写的那个程序模块,这样就比较难定位了。
我通过排除法,定位到蓝屏原因出在GetPatchSize函数,他是通过国外一个网友的一个shellcode来计算指令长度。
所以我直接没有调用这个函数,比如说我要hook KeAcquireSpinLockAtDpcLevel函数,我用GetPatchSize函数获取到他的指令长度为23,因为它指令长度不会变化,所以我就写死23。 其他函数也一样,先写一个demo,使用GetPatchSize计算指令长度,然后写死就行了。
核心代码:
ULONG lock_patch_size = 23;
ULONG unlock_patch_size = 20;PVOID HookKernelApi(IN PVOID ApiAddress, IN PVOID Proxy_ApiAddress, OUT PVOID *Original_ApiAddress, IN ULONG PatchSize)
{/* 参数检查 */if (ApiAddress == nullptr || Proxy_ApiAddress == nullptr || Original_ApiAddress == nullptr) {return nullptr;}KIRQL irql;UINT64 tmpv;PVOID head_n_byte = nullptr, ori_func = nullptr;UCHAR jmp_code[] = "\xFF\x25\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";UCHAR jmp_code_orifunc[] = "\xFF\x25\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";//step 1: Read current datahead_n_byte = kmalloc(PatchSize);if (head_n_byte == nullptr) {return nullptr;}irql = WPOFFx64();memcpy(head_n_byte, ApiAddress, PatchSize);WPONx64(irql);//step 2: Create ori functionori_func = kmalloc(PatchSize + 14); //原始机器码+跳转机器码if (ori_func == nullptr) {return head_n_byte;}RtlFillMemory(ori_func, PatchSize + 14, 0x90);tmpv = (ULONG64)ApiAddress + PatchSize; //跳转到没被打补丁的那个字节memcpy(jmp_code_orifunc + 6, &tmpv, 8);memcpy((PUCHAR)ori_func, head_n_byte, PatchSize);memcpy((PUCHAR)ori_func + PatchSize, jmp_code_orifunc, 14);*Original_ApiAddress = ori_func;//step 3: fill jmp codetmpv = (UINT64)Proxy_ApiAddress;memcpy(jmp_code + 6, &tmpv, 8);//step 4: Fill NOP and hookirql = WPOFFx64();RtlFillMemory(ApiAddress, PatchSize, 0x90);memcpy(ApiAddress, jmp_code, 14);WPONx64(irql);return head_n_byte;
}VOID HookSpinlockFunctions()
{/* 加锁函数 */lock_head_n_byte = (PUCHAR)HookKernelApi(GetFunctionAddr(L"KeAcquireSpinLockAtDpcLevel"),(PVOID)Proxy_KeAcquireSpinLockAtDpcLevel,&ori_lock,lock_patch_size);/* 解锁函数 */unlock_head_n_byte = (PUCHAR)HookKernelApi(GetFunctionAddr(L"KeReleaseSpinLock"),(PVOID)Proxy_KeReleaseSpinLock,&ori_unlock,unlock_patch_size);
}
更多推荐
win7 x64 inline hook的尝试
发布评论