Windows内核新手上路3——挂钩KeUserModeCallBack
1. 简介
在Windows系统中,提供了几种方式从R0调用位于R3的函数,其中一种方式是KeUserModeCallBack,此函数流程如下:
nt!KeUserModeCallback->nt!KiCallUserMode->nt!KiServiceExit->ntdll!KiUserCallbackDispatcher->回调函数-> int2B->nt!KiCallbackReturn-> nt!KeUserModeCallback(调用后)这是一个 ring0->ring3->ring0的过程,在堆栈准备完毕后,借用KiServiceExit的力量回到了ring3,它的着陆点是 KiUserCallbackDispatcher,然后KiUserCallbackDispatcher从PEB中取出 KernelCallbackTable的基址,再以ApiIndex作为索引在这个表中查找对应的回调函数并调用,调用完之后再int2B触发 nt!KiCallbackReturn再次进入内核,修正堆栈后跳回KeUserModeCallback,完成调用。
系统所有的消息钩子回调都是利用KeUserModeCallBack完成的。所以可以通过挂钩KeUserModeCallback用来过滤对钩子的调用。
1.1 inline hook
KeUserModeCallback没有对应的R3调用接口,所以没有在SSDT SHADOW中出现,需要用另外的方式来HOOK,可以采用的Inline Hook,即在函数头部加入一条JMP指令(机器码E9)跳入代理函数,然后过滤之后决定是否调用真实的KeUserModeCallback函数。挂钩过程如下:
ULONG StartHookKeyUserModeCallBack() { ULONG tmp; memset (Ori_Func, 0x90, 100); // nop Ori_Func[50] = 0xE9; tmp = (ULONG)ProxyFunc - (ULONG)KeUserModeCallback - 5; memcpy(jmp_bytes+1, &tmp, 4); HeadLen = GetPatchSize (KeUserModeCallback, 5); memcpy(Ori_Func, (PVOID)KeUserModeCallback, HeadLen); //原始字节 //中间跳 tmp = (ULONG)KeUserModeCallback + HeadLen - (ULONG)(&Ori_Func[50]) - 5; memcpy(&Ori_Func[51], &tmp, 4); |