关于Sysenter、Kifastcallentry、中断之类的内核入口hook技术早就烂大街了,可是对hook的检测与恢复代码却是寥寥无几,一切抛开代码将原理的行为都是耍流氓。
下面以Sysenter hook技术为例子,重点分析下这类钩子的检测与恢复技术。
Sysenter简述 :
Windows2000以前用int 2e作为中断指令进入内核发起系统调用。从Windows2000以后,准确的说是Pentium II处理器开始,为了避免int 2e指令对模式切换的巨大开销,Intel引入了一对新的指令,sysenter/sysexit,实现快速的模式切换,所以也叫快速系统调用。 关于两者之间的具体异同请参考潘爱民老师《Windows内核原理与实现》第8章Windows系统服务,再次不是分析重点,不在累赘。
sysenter使用三个MSR(Model Specific Register)寄存器来指定跳转目标地址和栈位置。操作系统在内核模式下通过rdmsr/wrmsr特权指令来设置这三个寄存器,当然必须在系统初始化时(第一次系统调用发生以前)完成。
MSR寄存器 MSR地址 含义
IA32_SYSENTRY_CS 174h 低16位值制订了特权级0的代码段和栈段的段选择符
IA32_SYSENTRY_ESP 175h 内核栈指针的32位偏移
IA32_SYSENTRY_EIP 176h 目标例程的32位偏移(Kifastcallentry地址)
根据这三个MSR寄存器的属性我们看一段代码
_asm { mov ecx,0x176 rdmsr mov KifastcalllAddress,eax }
获取Kifastcallentry地址其实只需要三行汇编就可以搞定,但是有很多人说看不懂。
RDMSR将64位由ECX寄存器指定的MSR(model specific register,模式指定寄存器)的内容读出至寄存器EDX:EAX中(在支持intel64架构的处理器中RCX的高32位忽略)。MSR的高32位内容存放在EDX寄存器中,MSR的低32位内容存放在EAX寄存器(在支持intel64架构的处理器中RDX和RAX的高32位忽略)。
说这么多其实就是把MSR寄存器地址放进ECX,然后通过RDMSR特权指令就能把相应MSR寄存器的值读进EAX中。而IA32_SYSENTRY_EIP寄存器中保存的就是Kifastcallentry地址。
Sysenter hook:
下面看一个替换IA32_SYSENTRY_EIP值进行sysentry hook小Demo。
#include "HookSysenter.h" ULONG OriginalAddress = 0; ULONG i = 0; __declspec(naked)FakeAddress() { _asm { mov i,eax } __asm { pushad push fs push 0x30 pop fs } if (i==0x101) { DbgPrint("Terminate\r\n"); } _asm { pop fs popad jmp [OriginalAddress] } } NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath) { DriverObject->DriverUnload = UnloadDriver; DbgPrint("Hello\r\n"); Hook(); return STATUS_SUCCESS; } VOID UnloadDriver(PDRIVER_OBJECT DriverObject) { UnHook(); } VOID Hook() { _asm { mov ecx,0x176 rdmsr mov OriginalAddress,eax mov eax, FakeAddress wrmsr } } VOID UnHook() { KIRQL oldIrql; oldIrql=KeRaiseIrqlToDpcLevel(); _asm { mov ecx,0x176 mov eax,OriginalAddress wrmsr } KeLowerIrql(oldIrql); }
只是替换Kifastcallentry地址,然后简单判断了下是否发起对NTterminateProcess的系统调用,很简单。
那么问题来了,我们如何通过内核文件去寻找原始的Kifastcallentry呢?
内核Ntoskrnl.exe的OEP入口函数可以理解是kisystemstartup,然后我们用WinDbg来看一看这个函数。
kd> u kisystemstartup nt!KiSystemStartup: 806907e0 0000 add byte ptr [eax],al 806907e2 0000 add byte ptr [eax],al 806907e4 0000 add byte ptr [eax],al 806907e6 0000 add byte ptr [eax],al 806907e8 0000 add byte ptr [eax],al 806907ea 0000 add byte ptr [eax],al 806907ec 0000 add byte ptr [eax],al 806907ee 0000 add byte ptr [eax],al
竟然什么都没有! 原来操作系统启动后默认为这一函数就失去了价值就把相关的内存释放了,我们自然什么都看不到,那么我们如何获得这个函数的真正信息呢? 在操作系统启动前WinDbg拦截就可以了。
kd> u kisystemstartup l 100 nt!KiSystemStartup: 806907e0 55 push ebp 806907e1 8bec mov ebp,esp 806907e3 83ec20 sub esp,20h 806907e6 8b5d08 mov ebx,dword ptr [ebp+8] 806907e9 891ddcd45480 mov dword ptr [nt!KeLoaderBlock (8054d4dc)],ebx 806907ef 0fb60de0d45480 movzx ecx,byte ptr [nt!KeNumberProcessors (8054d4e0)] 806907f6 894de8 mov dword ptr [ebp-18h],ecx 806907f9 0bc9 or ecx,ecx 806907fb 7519 jne nt!KiSystemStartup+0x36 (80690816) 806907fd c7432440375580 mov dword ptr [ebx+24h],offset nt!KiIdleThread0 (80553740) 80690804 c7431800af5480 mov dword ptr [ebx+18h],offset nt!P0BootStack (8054af00) 8069080b 6a30 push 30h 8069080d 0fa1 pop fs 8069080f 64880d30010000 mov byte ptr fs:[130h],cl 80690816 8b4324 mov eax,dword ptr [ebx+24h] 80690819 8945e0 mov dword ptr [ebp-20h],eax 8069081c 8b4318 mov eax,dword ptr [ebx+18h] 8069081f 8945e4 mov dword ptr [ebp-1Ch],eax 80690822 e8d10b0000 call nt!KiInitializeMachineType (806913f8) 80690827 807de800 cmp byte ptr [ebp-18h],0 8069082b 0f859f010000 jne nt!KiSystemStartup+0x1f0 (806909d0) 80690831 e8b216ebff call nt!GetMachineBootPointers (80541ee8) 80690836 897dfc mov dword ptr [ebp-4],edi 80690839 8975f8 mov dword ptr [ebp-8],esi 8069083c 8955f4 mov dword ptr [ebp-0Ch],edx 8069083f 8945f0 mov dword ptr [ebp-10h],eax 80690842 8d4f28 lea ecx,[edi+28h] 80690845 c6410589 mov byte ptr [ecx+5],89h 80690849 51 push ecx 8069084a ff75f4 push dword ptr [ebp-0Ch] 8069084d e81c110000 call nt!KiInitializeTSS2 (8069196e) 80690852 ff75f4 push dword ptr [ebp-0Ch] 80690855 e872fbe6ff call nt!KiInitializeTSS (805003cc) 8069085a 66b92800 mov cx,28h 8069085e 0f00d9 ltr cx 80690861 8b45f0 mov eax,dword ptr [ebp-10h] 80690864 8d4840 lea ecx,[eax+40h] 80690867 c6410585 mov byte ptr [ecx+5],85h 8069086b 66c741025000 mov word ptr [ecx+2],50h 80690871 8d4f50 lea ecx,[edi+50h] 80690874 c6410589 mov byte ptr [ecx+5],89h 80690878 ba00af5480 mov edx,offset nt!P0BootStack (8054af00) 8069087d 8bc2 mov eax,edx 8069087f 66894102 mov word ptr [ecx+2],ax 80690883 c1e810 shr eax,10h 80690886 886107 mov byte ptr [ecx+7],ah 80690889 884104 mov byte ptr [ecx+4],al 8069088c b868000000 mov eax,68h 80690891 668901 mov word ptr [ecx],ax 80690894 52 push edx 80690895 e832fbe6ff call nt!KiInitializeTSS (805003cc) 8069089a 0f20d8 mov eax,cr3 8069089d 89421c mov dword ptr [edx+1Ch],eax 806908a0 b8007f5480 mov eax,offset nt!KiDoubleFaultStack (80547f00) 806908a5 894238 mov dword ptr [edx+38h],eax 806908a8 894204 mov dword ptr [edx+4],eax 806908ab c74220ce045480 mov dword ptr [edx+20h],offset nt!KiTrap08 (805404ce) 806908b2 c7422400000000 mov dword ptr [edx+24h],0 806908b9 66c7424c0800 mov word ptr [edx+4Ch],8 806908bf 66c742583000 mov word ptr [edx+58h],30h 806908c5 8c5250 mov word ptr [edx+50h],ss 806908c8 66c742482300 mov word ptr [edx+48h],23h 806908ce 66c742542300 mov word ptr [edx+54h],23h 806908d4 8b45f0 mov eax,dword ptr [ebp-10h] 806908d7 8d4810 lea ecx,[eax+10h] 806908da c6410585 mov byte ptr [ecx+5],85h 806908de 66c741025800 mov word ptr [ecx+2],58h 806908e4 8d4f58 lea ecx,[edi+58h] 806908e7 c6410589 mov byte ptr [ecx+5],89h 806908eb ba68af5480 mov edx,offset nt!KiNMITSS (8054af68) 806908f0 8bc2 mov eax,edx 806908f2 66894102 mov word ptr [ecx+2],ax 806908f6 c1e810 shr eax,10h 806908f9 886107 mov byte ptr [ecx+7],ah 806908fc 884104 mov byte ptr [ecx+4],al 806908ff b868000000 mov eax,68h 80690904 668901 mov word ptr [ecx],ax 80690907 52 push edx 80690908 52 push edx 80690909 e8befae6ff call nt!KiInitializeTSS (805003cc) 8069090e 0f20d8 mov eax,cr3 80690911 89421c mov dword ptr [edx+1Ch],eax 80690914 b800af5480 mov eax,offset nt!P0BootStack (8054af00) 80690919 8b4038 mov eax,dword ptr [eax+38h] 8069091c 894204 mov dword ptr [edx+4],eax 8069091f 894238 mov dword ptr [edx+38h],eax 80690922 c74220fcf35380 mov dword ptr [edx+20h],offset nt!KiTrap02 (8053f3fc) 80690929 c7422400000000 mov dword ptr [edx+24h],0 80690930 66c7424c0800 mov word ptr [edx+4Ch],8 80690936 66c742583000 mov word ptr [edx+58h],30h 8069093c 8c5250 mov word ptr [edx+50h],ss 8069093f 66c742482300 mov word ptr [edx+48h],23h 80690945 66c742542300 mov word ptr [edx+54h],23h 8069094b 68007f5480 push offset nt!KiDoubleFaultStack (80547f00) 80690950 ff75e0 push dword ptr [ebp-20h] 80690953 ff75f4 push dword ptr [ebp-0Ch] 80690956 ff75fc push dword ptr [ebp-4] 80690959 ff75f0 push dword ptr [ebp-10h] 8069095c ff75f8 push dword ptr [ebp-8] 8069095f ff75e8 push dword ptr [ebp-18h] 80690962 e8630f0000 call nt!KiInitializePcr (806918ca) 80690967 8b55e0 mov edx,dword ptr [ebp-20h] 8069096a b9a0395580 mov ecx,offset nt!KiIdleProcess (805539a0) 8069096f 894a44 mov dword ptr [edx+44h],ecx 80690972 64c7051800000000000000 mov dword ptr fs:[18h],0 8069097d 64c7052804000000000000 mov dword ptr fs:[428h],0 80690988 64c7052c04000000000000 mov dword ptr fs:[42Ch],0 80690993 e83a100000 call nt!KiSwapIDT (806919d2) 80690998 b823000000 mov eax,23h 8069099d 668ed8 mov ds,ax 806909a0 668ec0 mov es,ax 806909a3 8b45f0 mov eax,dword ptr [ebp-10h] 806909a6 ff7040 push dword ptr [eax+40h] 806909a9 ff7044 push dword ptr [eax+44h] 806909ac ff7010 push dword ptr [eax+10h] 806909af ff7014 push dword ptr [eax+14h] 806909b2 8b7df0 mov edi,dword ptr [ebp-10h] 806909b5 befc0a6980 mov esi,offset nt!IDT (80690afc) 806909ba b900080000 mov ecx,800h 806909bf c1e902 shr ecx,2 806909c2 f3a5 rep movs dword ptr es:[edi],dword ptr [esi] 806909c4 8f4014 pop dword ptr [eax+14h] 806909c7 8f4010 pop dword ptr [eax+10h] 806909ca 8f4044 pop dword ptr [eax+44h] 806909cd 8f4040 pop dword ptr [eax+40h] 806909d0 f70558bd548001000000 test dword ptr [nt!KiFreezeExecutionLock (8054bd58)],1 806909da 75f4 jne nt!KiSystemStartup+0x1f0 (806909d0) 806909dc f00fba2d58bd548000 lock bts dword ptr [nt!KiFreezeExecutionLock (8054bd58)],0 806909e5 72e9 jb nt!KiSystemStartup+0x1f0 (806909d0) 806909e7 8b4de8 mov ecx,dword ptr [ebp-18h] 806909ea 64880d51000000 mov byte ptr fs:[51h],cl 806909f1 b801000000 mov eax,1 806909f6 d3e0 shl eax,cl 806909f8 64a348000000 mov dword ptr fs:[00000048h],eax 806909fe 64a334010000 mov dword ptr fs:[00000134h],eax 80690a04 ff7508 push dword ptr [ebp+8] 80690a07 ff75e8 push dword ptr [ebp-18h] 80690a0a ff1574864d80 call dword ptr [nt!_imp__HalInitializeProcessor (804d8674)] 80690a10 64a148000000 mov eax,dword ptr fs:[00000048h] 80690a16 0905d0d45480 or dword ptr [nt!KeActiveProcessors (8054d4d0)],eax 80690a1c ff75e8 push dword ptr [ebp-18h] 80690a1f e876abe6ff call nt!KiInitializeAbios (804fb59a) 80690a24 fe05e0d45480 inc byte ptr [nt!KeNumberProcessors (8054d4e0)] 80690a2a 33c0 xor eax,eax 80690a2c a358bd5480 mov dword ptr [nt!KiFreezeExecutionLock (8054bd58)],eax 80690a31 807de800 cmp byte ptr [ebp-18h],0 80690a35 751d jne nt!KiSystemStartup+0x274 (80690a54) 80690a37 ff35dcd45480 push dword ptr [nt!KeLoaderBlock (8054d4dc)] 80690a3d 6a00 push 0 80690a3f e87a00fdff call nt!KdInitSystem (80660abe) 80690a44 e8956ee6ff call nt!KdPollBreakIn (804f78de) 80690a49 0ac0 or al,al 80690a4b 7407 je nt!KiSystemStartup+0x274 (80690a54) 80690a4d 6a01 push 1 80690a4f e88481e9ff call nt!DbgBreakPointWithStatus (80528bd8) 80690a54 90 nop 80690a55 b91f000000 mov ecx,1Fh 80690a5a ff15f4864d80 call dword ptr [nt!_imp_KfRaiseIrql (804d86f4)] 80690a60 8845ec mov byte ptr [ebp-14h],al 80690a63 810dcc3c558080000000 or dword ptr [nt!KiBootFeatureBits (80553ccc)],80h 80690a6d 8b5de0 mov ebx,dword ptr [ebp-20h] 80690a70 8b55e4 mov edx,dword ptr [ebp-1Ch] 80690a73 8b45e8 mov eax,dword ptr [ebp-18h] 80690a76 83e2fc and edx,0FFFFFFFCh 80690a79 33ed xor ebp,ebp 80690a7b 8be2 mov esp,edx 80690a7d 81eca0020000 sub esp,2A0h 80690a83 6a0e push 0Eh 80690a85 ff35dcd45480 push dword ptr [nt!KeLoaderBlock (8054d4dc)] 80690a8b 50 push eax 80690a8c 64ff3520000000 push dword ptr fs:[20h] 80690a93 52 push edx 80690a94 53 push ebx 80690a95 68a0395580 push offset nt!KiIdleProcess (805539a0) 80690a9a e8d7200000 call nt!KiInitializeKernel (80692b76) 80690a9f 648b1d24010000 mov ebx,dword ptr fs:[124h] 80690aa6 c6433310 mov byte ptr [ebx+33h],10h 80690aaa fb sti 80690aab b902000000 mov ecx,2 80690ab0 ff151c874d80 call dword ptr [nt!_imp_KfLowerIrql (804d871c)] 80690ab6 c6435802 mov byte ptr [ebx+58h],2 80690aba 8b1d1cf0dfff mov ebx,dword ptr ds:[0FFDFF01Ch] 80690ac0 6a00 push 0 80690ac2 e91920ebff jmp nt!KiIdleLoop (80542ae0) 80690ac7 90 nop