实际上我觉得这玩意就是个PE文件的导出表:
kd> u nt!ZwQuerySystemInformation
nt!ZwQuerySystemInformation:
81f82778 b89a000000 mov eax,9Ah
81f8277d 8d542404 lea edx,[esp+4]
81f82781 9c pushfd
81f82782 6a08 push 8
81f82784 e8dc010100 call nt!ExfUnblockPushLock+0x12c5 (81f92965)
81f82789 c21000 ret 10h
nt!ZwQuerySystemEnvironmentValueEx:
81f8278c b89b000000 mov eax,9Bh
81f82791 8d542404 lea edx,[esp+4]
kd> dd KeServiceDescriptorTable
820cf2c0 81f843b8 00000000 000001b9 81f84aa0
820cf2d0 00000000 00000000 00000000 00000000
820cf2e0 a3cd3fff 00000001 ffffffff 81f980f7
820cf2f0 00000000 00000000 00000001 00000000
820cf300 9084246c 01d435c6 00000000 00000000
820cf310 86140d80 82e89000 8603eaf8 00001000
820cf320 00010000 7ffeffff 80000000 83600000
820cf330 7fff0000 8296a000 8602c010 00001c1d
kd> dd 81f843b8
81f843b8 81eac66e 81ec934e 821a0d06 81e99a00
81f843c8 82114dca 82323a50 8218a016 8210e0a0
81f843d8 8223a612 8223a612 81f1b730 821c77e0
81f843e8 8232f409 821c7690 821a1064 822efc5c
81f843f8 82185fd4 8235cf90 8218cb92 821b7e32
81f84408 8218909e 821890c0 81f49620 82193298
81f84418 821767f8 8220a48a 8223a20a 822fe2b4
81f84428 82321564 82375032 81e91fd0 8211c150
kd> u 81eac66e
nt!RtlLookupEntryHashTable+0xbe:
81eac66e 8bff mov edi,edi
81eac670 55 push ebp
81eac671 8bec mov ebp,esp
81eac673 8b4d08 mov ecx,dword ptr [ebp+8]
81eac676 33c0 xor eax,eax
81eac678 50 push eax
81eac679 ff7524 push dword ptr [ebp+24h]
81eac67c 33d2 xor edx,edx
kd> dd 81f84620 //9Ah*4+81f843b8
81f84620 8213d7b0 8220cf4e 823741af 82189160
81f84630 82375be1 82137e46 8213f6c0 821a8a9a
81f84640 822fb5ce 8223ac9e 8218c5c4 822da5fd
81f84650 822da3d9 82182e10 823780a5 821044c2
81f84660 82179f32 821d97a0 822fa322 821e9db6
81f84670 8219ff28 820728d3 81e7d36c 81e7d366
81f84680 8213f970 8210ff80 81e7d360 821bcd60
81f84690 8232388e 8215acac 821c9870 81e7d35a
kd> u 8213d7b0
nt!NtQuerySystemInformation:
8213d7b0 8bff mov edi,edi
8213d7b2 55 push ebp
8213d7b3 8bec mov ebp,esp
8213d7b5 8b4d08 mov ecx,dword ptr [ebp+8]
8213d7b8 83f94a cmp ecx,4Ah
8213d7bb 7c1c jl nt!NtQuerySystemInformation+0x29 (8213d7d9)
8213d7bd 83f953 cmp ecx,53h
8213d7c0 7d17 jge nt!NtQuerySystemInformation+0x29 (8213d7d9)
x64如下:
计算公式如下:
Ssdt为KeServiceDescriptorTable地址,Index为索引值
FunAddr =ssdt+(ssdt+4 * Index)>>4
0: kd> uf nt!zwopenprocess
Flow analysis was incomplete, some code may be missing
nt!ZwOpenProcess:
fffff802`7fd68370 488bc4 mov rax,rsp
fffff802`7fd68373 fa cli
fffff802`7fd68374 4883ec10 sub rsp,10h
fffff802`7fd68378 50 push rax
fffff802`7fd68379 9c pushfq
fffff802`7fd6837a 6a10 push 10h
fffff802`7fd6837c 488d05fd600000 lea rax,[nt!KiServiceLinkage (fffff802`7fd6e480)]
fffff802`7fd68383 50 push rax
fffff802`7fd68384 b826000000 mov eax,26h
fffff802`7fd68389 e9b2d50000 jmp nt!KiServiceInternal (fffff802`7fd75940) Branch
nt!KiServiceInternal:
fffff802`7fd75940 4883ec08 sub rsp,8
fffff802`7fd75944 55 push rbp
fffff802`7fd75945 4881ec58010000 sub rsp,158h
fffff802`7fd7594c 488dac2480000000 lea rbp,[rsp+80h]
fffff802`7fd75954 48899dc0000000 mov qword ptr [rbp+0C0h],rbx
fffff802`7fd7595b 4889bdc8000000 mov qword ptr [rbp+0C8h],rdi
fffff802`7fd75962 4889b5d0000000 mov qword ptr [rbp+0D0h],rsi
fffff802`7fd75969 fb sti
fffff802`7fd7596a 65488b1c2588010000 mov rbx,qword ptr gs:[188h]
fffff802`7fd75973 0f0d8b90000000 prefetchw [rbx+90h]
fffff802`7fd7597a 0fb6bb32020000 movzx edi,byte ptr [rbx+232h]
fffff802`7fd75981 40887da8 mov byte ptr [rbp-58h],dil
fffff802`7fd75985 c6833202000000 mov byte ptr [rbx+232h],0
fffff802`7fd7598c 4c8b9390000000 mov r10,qword ptr [rbx+90h]
fffff802`7fd75993 4c8995b8000000 mov qword ptr [rbp+0B8h],r10
fffff802`7fd7599a 4c8d1d4f010000 lea r11,[nt!KiSystemServiceStart (fffff802`7fd75af0)]
fffff802`7fd759a1 41ffe3 jmp r11
0: kd> dq KeServiceDescriptorTable
fffff802`7ffe0740 fffff802`7ff23020 00000000`00000000
fffff802`7ffe0750 00000000`000001b9 fffff802`7ff23dec
fffff802`7ffe0760 00000000`00000000 00000000`00000000
fffff802`7ffe0770 00000000`00000000 00000000`00000000
fffff802`7ffe0780 00000000`00000000 00000000`00000000
fffff802`7ffe0790 00000000`009c19c2 00007ffe`8dd556f0
fffff802`7ffe07a0 ffffe001`015763f0 ffffe001`01578c60
fffff802`7ffe07b0 00000000`00000000 00000000`00000000
0: kd> dd fffff802`7ff23020+98h //26h*4=98h
fffff802`7ff230b8 0102d600 fdc03501 010bbc06 019ce7c7
fffff802`7ff230c8 0108c240 01a97f01 018e1600 03df8400
fffff802`7ff230d8 022720c5 014d4901 020bfe00 0211b180
fffff802`7ff230e8 01388e02 017a9b42 00f5f900 01d73707
fffff802`7ff230f8 01040800 02118100 03df6e41 0185b146
fffff802`7ff23108 02264f81 021a66c0 01450003 020cf900
fffff802`7ff23118 0208d000 0128e601 0216e140 019f3a02
fffff802`7ff23128 014d02c2 fe48c500 02460600 021eb2c1
0: kd> u fffff802`7ff23020+0102d60 //0102d600>>4=0102d60
nt!NtOpenProcess:
fffff802`80025d80 4883ec38 sub rsp,38h
fffff802`80025d84 65488b042588010000 mov rax,qword ptr gs:[188h]
fffff802`80025d8d 440fb69032020000 movzx r10d,byte ptr [rax+232h]
fffff802`80025d95 4488542428 mov byte ptr [rsp+28h],r10b
fffff802`80025d9a 4488542420 mov byte ptr [rsp+20h],r10b
fffff802`80025d9f e80c000000 call nt!PsOpenProcess (fffff802`80025db0)
fffff802`80025da4 4883c438 add rsp,38h
fffff802`80025da8 c3 ret
测试修改SSDT后是否蓝屏(patch guard作用):
0: kd> uf nt!ZwQuerySystemInformation
Flow analysis was incomplete, some code may be missing
nt!ZwQuerySystemInformation:
fffff802`c5fdc570 488bc4 mov rax,rsp
fffff802`c5fdc573 fa cli
fffff802`c5fdc574 4883ec10 sub rsp,10h
fffff802`c5fdc578 50 push rax
fffff802`c5fdc579 9c pushfq
fffff802`c5fdc57a 6a10 push 10h
fffff802`c5fdc57c 488d05fd5e0000 lea rax,[nt!KiServiceLinkage (fffff802`c5fe2480)]
fffff802`c5fdc583 50 push rax
fffff802`c5fdc584 b836000000 mov eax,36h
fffff802`c5fdc589 e9b2d30000 jmp nt!KiServiceInternal (fffff802`c5fe9940) Branch
nt!KiServiceInternal:
fffff802`c5fe9940 4883ec08 sub rsp,8
fffff802`c5fe9944 55 push rbp
fffff802`c5fe9945 4881ec58010000 sub rsp,158h
fffff802`c5fe994c 488dac2480000000 lea rbp,[rsp+80h]
fffff802`c5fe9954 48899dc0000000 mov qword ptr [rbp+0C0h],rbx
fffff802`c5fe995b 4889bdc8000000 mov qword ptr [rbp+0C8h],rdi
fffff802`c5fe9962 4889b5d0000000 mov qword ptr [rbp+0D0h],rsi
fffff802`c5fe9969 fb sti
fffff802`c5fe996a 65488b1c2588010000 mov rbx,qword ptr gs:[188h]
fffff802`c5fe9973 0f0d8b90000000 prefetchw [rbx+90h]
fffff802`c5fe997a 0fb6bb32020000 movzx edi,byte ptr [rbx+232h]
fffff802`c5fe9981 40887da8 mov byte ptr [rbp-58h],dil
fffff802`c5fe9985 c6833202000000 mov byte ptr [rbx+232h],0
fffff802`c5fe998c 4c8b9390000000 mov r10,qword ptr [rbx+90h]
fffff802`c5fe9993 4c8995b8000000 mov qword ptr [rbp+0B8h],r10
fffff802`c5fe999a 4c8d1d4f010000 lea r11,[nt!KiSystemServiceStart (fffff802`c5fe9af0)]
fffff802`c5fe99a1 41ffe3 jmp r11
0: kd> dq KeServiceDescriptorTable
fffff802`c6254740 fffff802`c6197020 00000000`00000000
fffff802`c6254750 00000000`000001b9 fffff802`c6197dec
fffff802`c6254760 00000000`00000000 00000000`00000000
fffff802`c6254770 00000000`00000000 00000000`00000000
fffff802`c6254780 00000000`00000000 00000000`00000000
fffff802`c6254790 00000000`009c19c2 00007ffb`8c4c56f0
fffff802`c62547a0 ffffe001`f0574360 ffffe001`f0576b00
fffff802`c62547b0 00000000`00000000 00000000`00000000
0: kd> dd fffff802`c6197020+d8h
fffff802`c61970f8 01040800 02118100 03df6e41 0185b146
fffff802`c6197108 02264f81 021a66c0 01450003 020cf900
fffff802`c6197118 0208d000 0128e601 0216e140 019f3a02
fffff802`c6197128 014d02c2 fe48c500 02460600 021eb2c1
fffff802`c6197138 fd030300 03e74980 0102c301 01d6c501
fffff802`c6197148 01409e03 02247680 01ef4780 02355305
fffff802`c6197158 03aeda84 016b01c0 010ceb01 021fdd81
fffff802`c6197168 012f6580 012e8240 038ee042 017aa207
0: kd> u fffff802`c6197020+0104080
nt!NtQuerySystemInformation:
fffff802`c629b0a0 4883ec38 sub rsp,38h
fffff802`c629b0a4 458bd0 mov r10d,r8d
fffff802`c629b0a7 4c8bda mov r11,rdx
fffff802`c629b0aa 83f94a cmp ecx,4Ah
fffff802`c629b0ad 7c21 jl nt!NtQuerySystemInformation+0x30 (fffff802`c629b0d0)
fffff802`c629b0af 83f953 cmp ecx,53h
fffff802`c629b0b2 7d1c jge nt!NtQuerySystemInformation+0x30 (fffff802`c629b0d0)
fffff802`c629b0b4 33d2 xor edx,edx
0: kd> ed fffff802`c61970f8 02118100
0: kd> dd fffff802`c61970f8
fffff802`c61970f8 02118100 02118100 03df6e41 0185b146
fffff802`c6197108 02264f81 021a66c0 01450003 020cf900
fffff802`c6197118 0208d000 0128e601 0216e140 019f3a02
fffff802`c6197128 014d02c2 fe48c500 02460600 021eb2c1
fffff802`c6197138 fd030300 03e74980 0102c301 01d6c501
fffff802`c6197148 01409e03 02247680 01ef4780 02355305
fffff802`c6197158 03aeda84 016b01c0 010ceb01 021fdd81
fffff802`c6197168 012f6580 012e8240 038ee042 017aa207
0: kd> g
开调试可以关patch guard,因为int3会修改内核,如果pg还发挥作用就会蓝屏,没法调试了,所以调试即可关pg。bat代码如下:
Bcdedit /debug ON
Bcdedit /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200 /start AUTOENABLE /noumex
以下是转载:
1、利用NEWBLUEPILL进入VT创建 HYPERVISOR
2、对你希望关心的系统服务函数下硬件断点
3、HYPERVISOR捕获到INT1异常以后你就可以判断是否放行 或者不放行了
4、HYPERVISOR处理完以后vmresume以后一定要记得清除RFLAG单步标志位
5、HYPERVISOR注意不要向操作系统注入INT1异常 且HYPERVISOR一定要拒绝其他代码修改DR调试寄存器
0x00 Hook技术
hook技术分为两块:
- Ring3层的Hook,俗称应用层hook技术
- Ring0层的Hook,俗称内核层Hook技术
Ring3层的hook又分为两种类型
- Windows消息的hook
- WindowsAPI的hook
如下图所示:
hook1
hook2
hook1
关于Windows消息的Hook,相信很多朋友都有接触过的,因为一个SetWindowsHookEx即可以完成消息 Hook,在这里简要介绍一下消息 Hook,消息 Hook 是通过SetWindowsHookEx可以实现将自己的钩子插入到钩子链的最前端,而对于发送给被 Hook 的窗口(也有可能是所有的窗口,即全局 Hook)的消息都会被我们的钩子处理函数所捕获到,也就是我们可以优先于窗体先捕获到这些消息,Windows 消息 Hook 可以实现为进程内消息 Hook 和全局消息 Hook,对于进程内消息 Hook,则可以简单的将 Hook 处理函数直接写在这个进程内,即是自己 Hook 自己,而对于用途更为广泛的全局消息 Hook,则需要将 Hook 处理函数写在一个 DLL 中,这样才可以让你的处理函数被所有的进程所加载(进程自动加载包含 Hook 消息处理函数的 DLL)。
对于 Windows 消息 Hook 呢,可以有个简单的邪恶应用,就是记录键盘按键消息,从而达到监视用户输入的键值信息的目的,这样,对于一些简单的用户通过键盘输入的密码就可以被 Hook 获取到,因为没当用户按下一个键时,Windows 都会产生一个按键消息(当然有按下,弹起等消息的区分),然后我们可以 Hook 到这个按键消息,这样就可以在 Hook 的消息处理函数中获取到用户按下的是什么键了。
不过消息的hook不是本文的重点。
本文要讲的SSDT hook呢其实是属于内核Hook,常见于病毒以及杀软中。
下图展示了内核hook的几个基本类型。
Kernel hook
0x01 SSDT简介
SSDT全称System Service Descriptor Table(系统描述符表),这个表用于将Ring3的Win32API和内核的API联系起来。
SSDT并不仅仅只包含一个庞大的地址索引表,它还包含一些有用的信息,如地址索引的基地址,服务函数的个数等。通过修改此表可以达到对一些关心的系统动作进行过滤以及监控的目的。
在NT4.0的windows操作系统中,默认存在两个系统服务描述符表,这两个描述符表对应了两类不同的系统服务,这两个表为:KeServiceDescriptorTable(SSDT)和KeServiceDescriptorTable(SSDT Shadow)。其中SSDT负责处理来自Ring3层的Kernel32.dll的系统调用。而SSDT Shadow则主要处理来自User32.dll和GDI32.dll的系统调用。同时SSDT在ntoskrnl.exe中是导出的,而SSDT Shadow如其名是未被Windows所导出的,而关于SSDT的全部内容都是通KeServiceDescriptorTable来完成的。
以下截图说明,KeServiceDescriptorTable是在ntoskrnl.exe中被导出的:
Export1
随后我们看看看看Windows操作系统的源码中如何定义KeServiceDescriptorTable的,通过观察WRK可知,
KeServiceDescriptorTable in WRK
这么看还是有点蛋疼啊。改写以下变量的名称吧。
typedef struct _KSYSTEM_SERVICE_TABLE{
PULONG ServiceTableBase; //SSDT的基地址指针
PULONG ServiceCounterTableBase; //SSDT中每个服务被调用次数表的基地址指针
ULONG NumberOfService; //服务函数个数,NumberOfService*4就是整个地址表的大小
ULONG ParamTableBase; //SSPT的基地址
}KSYSTEM_SERVICE_TABLE,*PKSYSTEM_SERVICE_TABLE;
typedef struct _KSERVICE_TABLE_DESCRIPTOR{
KSYSTEM_SERVICE_TABLE ntoskrnl; //ntoskrnl.exe的服务函数
KSYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数(GDI32/User32)
KSYSTEM_SERVICE_TABLE notUsed1;
KSYSTEM_SERVICE_TABLE notUsed2;
}KSERVICE_TABLE_DESCRIPTOR,*PKSERVICE_TABLE_DESCRIPTOR;
//导出由ntoskrnl.exe所导出的SSDT
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
从上述介绍可知,KeServiceDescriptorTable可以看做是一个数组,是4个KSYSTEM_SERVICE_TABLE结构形成的数组,而每个KSYSTEM_SERVICE_TABLE对应一个PE文件导出的服务描述符表,根据这些服务描述符表我们可以获得更加详细的服务信息。在应用层ntdll.dll中的API在这个系统服务描述表中都存在一个与之对应的服务,当我们的应用程序调用ntdll.dll里的API时最终可以调用对应的系统服务函数,通知给内核一个索引,内核通过该索引在SSDT中查找对应的服务,内核调用服务完成应用的API调用请求。
应用层调用Win32API流程
有了以上的SSDT基础后,我们再来看看在应用层调用Win32API(主要指ntdll.dll中的API)的流程,我们主要针对ntdll.dll中的NtQuerySystemInformation这个API的调用流程来进行阐述。
这里存在四个类似的API。
4APIs
再给出这些API的调用流程。
calling way
这里我们可以看到ntdll.dll中的nt和zw都会进入内核层去调用ntoskrnl的zw函数,而zw最终会调用nt函数,这个函数作为内核API最终去请求系统服务的执行。
用exescope工具可以打开ntdll.dll,看到NtQuerySystemInformation以及ZwQuerySystemInformation。
ntdll1
ntdll2
而实质上zw和nt都是同一函数,指向同一区域,入口地址相同。
因此Ntdll.dll中的API都是对内核API的封装,当Kernel32.dll中的API通过Ntdll.dll去调用系统API时,会进行参数检查,并调用中断(int 2Eh或SysEnter),从而从Ring3进入Ring0,并将所要调用的服务号,即SSDT数组的索引值,存放进寄存器EAX中,并且将参数地址放到指定的寄存器EDX中,再复制参数到内核地址空间,根据存放在EAX中的索引值来在SSDT数组中调用指定的服务。
经过上面步骤我们来到Ring0层。使用exescope看看ntoskrnl.exe中的ZwQuerySystemInformation以及NtQuerySystemInformation。
ntoskrnl1
ntoskrnl2
再反汇编ntoskrnl这个文件可以看到Zw函数中调用KiSystemService系统服务分发函数时往EAX中存放了索引号ADh。如图:
ZwQSystemInfor
随后根据该索引值检索SSDT项,最后根据该SSDT项中所存放的系统服务地址来调用这个系统服务。在这里就是调用KeServiceDescriptorTable[ADh]处保存的地址对应的系统服务。那就是Ring0下的NtQuerySystemInformation。
0x02 详解SSDT
这节内我们用WinDbg来调试XP系统,借此说明SSDT是个什么鬼。
据我们上文的结构定义可知,KeServiceDescriptorTable是一个指向4个KSYSTEM_SERVICE_TABLE结构首地址的指针,以下图为例吧。
dd KeServiceDescriptorTable
这里的0x80563520这一行就是ntoskrnl对应的服务描述符表结构KSYSTEM_SERVICE_TABLE。那么第一个32位的0x804e58a0则是对应ntoskrnl对应的KSYSTEM_SERVICE_TABLE中的SSDT Base,即服务描述符表的首地址。通过对该首地址的dump,我们可以看到许多以128位为一组排列的服务描述符,每个描述符中的第一个32位(0x80591bfb)对应着系统服务的入口地址。通过对该入口地址的反汇编,可以看到这是SSDT第一个系统服务NtAcceptConnectPort函数。如图:
NtAcceptConnectPort
那么知道了SSDT首地址,同时知道了索引,那么我们就可以通过索引来找到对应的系统服务入口地址了。通过计算“SSDT中系统服务地址所在的地址 = SSDT首地址 + 4 * 索引值”,可以推算出NtQuerySystemInformation的起始地址位0x80586ff1,对该地址进行反汇编,可得下图:
NtQuerySystemInformation
由此可知,SSDT就是个保存Windows系统服务地址的数组。
0x03 SSDT hook原理
从上面的分析中我们可以看到SSDT数组中保存了系统服务的地址,如Ring0下的NtQuerySystemInformation系统服务地址,就保存在KeServiceDescriptorTable[ADh]中,既然hook就是取出这个地址后替换上我们的hook函数,在hook函数中执行原函数即可。
参考文献:
http://www.cnblogs.com/boyxiao/archive/2011/09/03/2164574.html
转载的原文地址:
https://www.jianshu.com/p/28af7d0b592f