win7 x64 inline hook的尝试

最近因为虚机性能问题,需要验证下是不是因为内核态加锁时间过长导致,所以需要在内核态hook两个内核函数:
KeAcquireSpinLockAtDpcLevel和KeReleaseSpinLock,虚机的操作系统是win7 64位。
所以在内核态hook,我采用inline hook的方式,有借鉴的blog:

https://blog.csdn.net/u013761036/article/details/66477613

这篇博客对原理讲的比较清楚,博客的作者说那段代码会蓝屏,他没有具体说是什么现象的蓝屏,所以我也不清楚到底他指的蓝屏是什么,但是我在实际使用过程中发现有两个蓝屏问题:

patch guard导致的蓝屏

我利用博客代码对KeAcquireSpinLockAtDpcLevel和KeReleaseSpinLock两个函数进行了hook,欣喜的是能顺利hook到两个函数里面,但是不一会儿就蓝屏了,蓝屏界面如下:


这个蓝屏导致的原因是win7 64位系统的patch guard机制,系统会不定时检测内核是否被篡改,如果有篡改就会促发蓝屏。

(1)对破解软件的尝试,我尝试了网上说的一些方法,比如我下载了no_pg_ds_v3这个工具,然后按照文档进行部署,部署成功后重启,会提示如下界面:


这时候选中“PatchGuard Disabled V3”,然后按F8去掉驱动程序签名强制,这时候就进入系统了,然而并没有什么卵用,系统还是会触发一样的蓝屏。

(2)对于调试模式的尝试,据说微软在调试模式会自动去掉patch guard机制,要不然windbg怎么做到打断点之类的功能的,于是我设置了一个调试模式的引导项,可以参照https://blog.csdn.net/chenyujing1234/article/details/8090297,重启后进入该引导项(上图的DebugEntry引导),还是没解决问题,最后找到了一篇外国的博客https://www.codeproject.com/Articles/28318/Bypassing-PatchGuard,需要在调试模式下再加一条命令: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 data
	head_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 function
	ori_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 code
	tmpv = (UINT64)Proxy_ApiAddress;
	memcpy(jmp_code + 6, &tmpv, 8);

	//step 4: Fill NOP and hook
	irql = 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);
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
x64 Inline Hook(内联钩子)是一种在x64架构下实现的钩子技术,用于在程序运行时对函数进行修改或者监控。钩子技术可以用于实现一些高级功能,如函数拦截、行为修改和调试等。 Inline Hook的主要原理是通过修改函数的机器码,将目标函数的执行流程改变到一个特定的钩子函数,从而实现我们所需的功能。这个钩子函数可以进行一系列的操作,如记录参数、修改参数、替换返回值等。 x64 Inline Hook实现相对复杂,因为x64架构下的指令集更加复杂,并且x64架构引入了新的寄存器和指令,如RAX、R10、R11,还有新的调用惯例等。因此,在实现x64 Inline Hook前,我们需要对x64汇编指令和调用惯例有深入的了解。 具体实现Inline Hook主要包括以下几个步骤: 1. 定位到目标函数的地址。可以通过符号表、导入表或者动态调试等方式获取目标函数的地址。 2. 备份目标函数的原始字节码。为了在后续操作中恢复目标函数的完整执行流程,我们需要保留原始字节码。 3. 修改目标函数的字节码。通过修改目标函数的机器码,将执行流程转移到我们的钩子函数。 4. 编写钩子函数。钩子函数的参数和返回值需要与目标函数保持一致,并实现所需的功能。 5. 恢复目标函数的原始字节码。在钩子函数执行完毕后,需要将目标函数的字节码恢复到原始状态,以确保程序正常运行。 6. 跳回目标函数。在钩子函数执行完成后,我们需要将执行流程跳转回原始的目标函数。 需要注意的是,Inline Hook的实现需要考虑到多线程的情况,并且要保证对内存的修改是线程安全的,以及在恢复原始字节码时要避免潜在的问题。 总的来说,x64 Inline Hook是一种强大的技术,可以用于实现程序的函数修改和监控等高级功能。但它的实现相对复杂,需要对x64架构和汇编指令有深入的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值