来学习一下系统描述符表这个结构

SSDT

SSDT的全称是System Services Descriptor Table,意为系统服务描述符表。我们可以通过ETHREAD结构体加偏移的方式进行访问。在内核文件中,有一个变量是导出的:KeServiceDescriptorTable。通过它我们可以访问SSDT

可以看看在内核中看看 SSDT 是什么样的。

1
2
3
4
5
6
7
8
9
kd> dd KeServiceDescriptorTable
83d84a80 83c7f940 00000000 00000192 83c7ff8c
83d84a90 00000000 00000000 00000000 00000000
83d84aa0 00000000 023fd0c0 000000bb 00000011
83d84ab0 5385d2ba d717548f 00000100 00000000
83d84ac0 83c7f940 00000000 00000192 83c7ff8c
83d84ad0 99e6a000 00000000 00000339 99e6b02c
83d84ae0 00000000 00000340 00000340 00000000
83d84af0 00000007 00000000 8691c9c8 8691c900

再来看看结构体

1
2
3
4
5
6
typedef struct _ServiceDescriptorTable {
PVOID ServiceTableBase;
PVOID ServiceCounterTable;
unsigned int NumberOfServices;
PVOID ParamTableBase;
}*PServiceDescriptorTable;

对应起来我们不难得到,当前系统的 SSDT 有 0x192 个函数,基址表在 83c7f940,参数个数表在 83c7ff8c,计数器表设为了 0 表示对此不感兴趣。

根据本篇章的第一节也可以看出来,我们调用的 ReadProcessMemory 系统调用号为 0x115,对应寻找一下函数基址和参数个数。

可以找到 NtReadVirtualMemory 函数地址和 0x14 参数字节数,刚好 5 个 4 字节。

该符号导出了,如果要在驱动程序中直接使用,则需要申明。

1
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;

SSDTShadow

SSDTShadowSSDT不一样的是它并没有从内核文件导出。不过我们还是可以从WinDbg找到它:

1
2
3
4
5
6
7
8
9
kd> dd KeServiceDescriptorTableShadow
83d84ac0 83c7f940 00000000 00000192 83c7ff8c
83d84ad0 99e6a000 00000000 00000339 99e6b02c
83d84ae0 00000000 00000340 00000340 00000000
83d84af0 00000007 00000000 8691c9c8 8691c900
83d84b00 8690c900 8691c838 8690c9c8 00000000
83d84b10 8690c838 00000000 00000000 83c79039
83d84b20 83c8c485 83cb29a5 00000003 86850000
83d84b30 86851000 00000120 00000000 ffffffff

它的结构和SSDT是一模一样的,只不过它多了一张表,就是少的那个与GUI相关的服务表。

SSDThook

无论是自己伪造一张表还是直接修改表,都可以达到劫持 API 的目的,然而这些已经是过去式了,现在微软已经不允许 SSDT Hook 了。由于笔者本地没有 Windows7 32位的驱动,所以这个实验也不太好做了。

参考文献