这是我在阅读看雪论坛上一些资料的时候做的笔记,而且为了理解的比较透彻,里边的实验片段都亲自动手操作了一遍,现在贴出来,希望对大家有所帮助
SSDT即系统服务描述符表,它的结构如下:
Typedef struct _SYSTEM_SERVICE_TABLE
{
PVOID ServiceTableBase; //这个指向系统服务函数地址表
PULONG ServiceCounterTableBase;
ULONG NumberOfService; //服务函数的各数NumberOfService*4就是真个地址表
//的大小
ULONG ParamTableBase;
}SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE;
Typedef struct _SERVICE_DESCRIPTOR_TABLE
{
SYSTEM_SERVICE_TABLE ntoskrnel; //ntoskrnel.exe的服务函数
SYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数,gdi.dll/user.dll的
//内核支持
SYSTEM_SERVICE_TABLE NotUsed1;
SYSTEM_SERVICE_TABLE NotUsed2;
}SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE;
内核中有两个系统服务描述表,一个是KeServiceDescriptorTable(由ntoskrnl.exe导出),另一个是KeServiceDescriptorTableShadow(没有导出)。两者的区别是:KeServiceDescriptorTable仅有ntoskrnel一项,KeServiceDescriptorTableShadow包含了ntoskrnel以及win32k。一般的Native API的服务地址由KeServiceDescriptorTable分派,gdi.dll/user.dll的内核APIZ调用服务地址由KeServiceDescriptorTableShadow分派。还要清楚一点的是win32k.sys只有在GUI线程中才加载,一般情况不加载,所以Hook KeServiceDescriptorTableShadow的话,一般是用一个GUI程序通过IoControlCode来触发。
SSDT Hook的原理非常简单,下面先实际看看KeServiceDescriptorTable是什么样子的。
kd> dd KeServiceDescriptorTable
80553fa0 80502b8c 00000000 0000011c 80503000
80553fb0 00000000 00000000 00000000 00000000
80553fc0 00000000 00000000 00000000 00000000
80553fd0 00000000 00000000 00000000 00000000
在windbg.exe中可以看的很清楚,KeServiceDescriptorTable中就只有第一项有数据,其他都是0,其中80502b8c就是KeServiceDescriptorTable.ntoskrnel.ServiceTableBase,服务函数个数为0x11c个。我们在看看80502b8c地址里是什么东西:
kd> dd 80502b8c
80502b8c 8059a948 805e7db6 805eb5fc 805e7de8
80502b9c 805eb636 805e7e1e 805eb67a 805eb6be
80502bac 8060cdfe 8060db50 805e31b4 805e2e0c
80502bbc 805cbde6 805cbd96 8060d424 805ac5ae
如上,8059a948 805e7db6 805eb5fc 805e7de8这些就是系统服务函数的地址。比如我们在ring3调用OpenProcess时,进入sysenter的ID就是0x7A(xp sp2),然后系统查询KeServiceDescriptorTable,大概是这样KeServiceDescriptorTable.ntoskrnel.ServiceTableBase(80502b8c) + 0x7A * 4 = 80502D74,然后用windbg.exe查询地址80502D74的内容:
kd> dd 80502D74
80502d74 805c2296 805e49fc 805e4660 805a0722
80502d84 8060c254 805ba77a 805c2522 805e4a1a
80502d94 805e47d0 8060e1b0 8063cc78 805c0346
80502da4 805eedce 805eaa16 805eac02 805aea08
获得该地址的内容,这个就是OpenProcess服务函数所在,在跟踪看看:
kd> u 805c2296
nt!NtOpenProcess:
805c2296 68c4000000 push 0C4h
805c229b 68a8aa4d80 push offset nt!FsRtlLegalAnsiCharacterArray+0x2008 (804daaa8)
805c22a0 e86b6cf7ff call nt!wctomb+0x45 (80538f10)
805c22a5 33f6 xor esi,esi
805c22a7 8975d4 mov dword ptr [ebp-2Ch],esi
805c22aa 33c0 xor eax,eax
805c22ac 8d7dd8 lea edi,[ebp-28h]
805c22af ab stos dword ptr es:[edi]
原来805c2296就是NtOpenProcess函数所在的起始地址。
如果把805c2296改为指向我们函数的地址,比如MyNtOpenProcess,那么系统就会直接调用MyNtOpenProcess,而不是原来的NtOpenProcess了,这就是SSDT Hook原理所在。
No comments:
Post a Comment