1 《Undocumented Windows 2000 Secrets》翻译 --- 第二章( 四 )


// Import SDT pointer
extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
// Create SDT reference
PSERVICE_DESCRIPTOR_TABLE psdt = KeServiceDescriptorTable;
列表 2-2 访问系统服务描述符表
SDT 中的每个 SST 的 ServiceTable 成员都是一个指针,指向一个由函数指针构成的数组,此函数指针的类型为: NTPROC,这为 Native API 提供了占位符,这种方式和在 Win32 编程中使用的 PROC 类型很相似 。NTPROC 的定义在前面的 列表 2-1 中给出 。Native API 函数通常返回一个 NTSTATUS 类型的代码并且使用 NTAPI 调用方式,NTAPI 实际上就是 _stdcall。ServiceLimit 成员保存在 ServieTable 数组中发现的入口地址的个数 。在 Windows 2000 中,其默认值为 248。ArgumentTable 成员是一个 BTYE 类型的数组,它和 ServiceTable 所指的数组一一对应,并给出其中每个函数指针所需的参数在调用者的堆栈中的字节数 。此信息随 EDX 寄存器提供的指针一起使用 。当内核从调用者的堆栈中复制参数到自己的堆栈时就需要这些信息 。CounterTable 成员在 Windows 2000 的 Free Build 版中不被使用 。在 Debug Build 版中,该成员指向一个 DWORD 类型的数组,作为每个函数的使用计数器( usage counters ) 。This information can be used for profiling purposes.
使用 Windows 2000 的内核调试器可方便的显示 SDT 中的内容 。如果你还没有设置好这个有用的程序,那请参考第一章 。在 示列 2-2 中,我首次使用了 dd KeServiceDescriptorTable 命令 。调试器会将此公开符号解析为 0x8046AB80,同时显示该地址之后的 32 个 DWORD 的 16 进制转储 。不过仅有前面的四行才是有意义的,它们分别对应 列表 2-1 中的四个 SDT 成员 。为了更清晰些,它们都将以黑体显示 。如果你仔细观察,你会发现第五行与第一行十分相像,这是另一个 SDT 吗?这是测试内核调试器的 ln 命令的好机会 。在示列 2-2 中,在显示完 KeServiceDescriptorTable 的十六进制 dump 之后,我输入 ln 8046abc0 命令 。显然,调试器知道地址 0x8046abc0,它将此地址转化为对应的符号 KeServiceDescriptorTableShadow 可以看出,这是内核维护的第二个 SDT。二者之间的显著区别是:第二个 SDT 包含 Win32k.sys 的入口地址 。这两个表的的第三和第四个成员都是空的 。Ntoskrnl.exe 提供了一个函数 KeAddSystemServiceTabel() 来填充这两个成员 。
注意,我截断了 ln 命令的输出信息,仅保留了基本的信息 。
从地址 0x8046ab88 开始,是 KeServiceDescriptorTable 的十六进制转储,在那儿可以找到 ServiceLimit 成员,可看到其值为 0xF8 (十进制 248 ),这和我们预期的一样 。ServiceTable 和 ArgumentTable 的值分别指向地址 0x804704d8 和 0x804708bc。用 ln 命令察看着两个地址,可得到其符号: KiServiceTable 和 KiArgumentTable。这两个符号都没有从 ntoskrnl.exe 中导出,但是调试器可通过察看 Windows 2000 的符号文件识别它们 。ln 命令还可应用到 Win32k SST 指针上,针对其 ServiceTable 和 ArgumentTable 成员,调试器分别给出了其对应的符号 w32pServiceTable 和 W32pArgumenTable。这两个符号都来自 Win32k.sys 的符号文件 。如果调试器无法解析这些地址,可使用 .reload 命令强制重新加载所有可用符号文件,然后再进行解析 。
示例 2-2 的剩余部分是 KiServiceTable 和 KiArgumentTable 最前面的 128 个字节的十六进制转储 。到目前为止,如果我说的有关 Native API 的东西都是正确的,那么 NtClose() 函数的地址应位于 KiServiceTable 数组的第 24 个位置上,其地址为 0x80470538。在该地址处,可发现其值为 0x8044c422,在 dd KiServiceTable 的输出中,该地址以黑体标记 。用 ln 察看 0x8044c422,会看到其对应的符号正是 NtClose()。
kd> dd KeServiceDescriptorTable

推荐阅读