Tuesday, March 8, 2011

SSDT Hook原理

这是我在阅读看雪论坛上一些资料的时候做的笔记,而且为了理解的比较透彻,里边的实验片段都亲自动手操作了一遍,现在贴出来,希望对大家有所帮助
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时,进入sysenterID就是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