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


8046ab80 804704d800000000 000000f8 804708bc
8046ab90 00000000 00000000 00000000 00000000
8046aba0 00000000 00000000 00000000 00000000
8046abb0 00000000 00000000 00000000 00000000
8046abc0 804704d800000000 000000f8 804708bc
8046abd0 a0186bc0 00000000 0000027f a0187840
8046abe0 00000000 00000000 00000000 00000000
8046abf0 00000000 00000000 00000000 00000000
kd> ln 8046abc0
(8046abc0) nt!KeServiceDescriptorTableShadow
kd> ln 804704d8
(804704d8) nt!KiServiceTable
kd> ln 804708bc
(804708bc) nt!KiArgumentTable
kd> ln a0186bc0
(a0186bc0) win32k!W32pServiceTable
kd> ln a0187840
(a0187840) win32k!W32pArgumentTable
kd> dd KiServiceTable
804704d8 804ab3bf 804ae86b 804bdef3 8050b034
804704e8 804c11f4 80459214 8050c2ff 8050c33f
804704f8 804b581c 80508874 8049860a 804fc7e2
80470508 804955f7 8049c8a6 80448472 804a8d50
80470518 804b6bfb 804f0cef 804fcb95 8040189a
80470528 804d06cb 80418f66 804f69d4 8049e0cc
80470538 8044c42280496f58 804ab849 804aa9da
80470548 80465250 804f4bd5 8049bc80 804ca7a5
kd> db KiArgumentTable
804708bc 18 20 2c 2c 40 2c 40 44-0c 18 18 08 04 04 0c 10 . ,,@,@D........
804708cc 18 08 08 0c 08 08 04 04-04 0c 04 20 08 0c 14 0c ........... ....
804708dc 2c 10 0c 1c 20 10 38 10-14 20 24 1c 14 10 20 10 ,... .8.. $... .
804708ec 34 14 08 04 04 04 0c 08-28 04 1c 18 18 18 08 18 4.......(.......
804708fc 0c 08 0c 04 10 00 0c 10-28 08 08 10 00 1c 04 08 ........(.......
8047090c 0c 04 10 00 08 04 08 0c-28 10 04 0c 0c 28 24 28 ........(....($(
8047091c 30 0c 0c 0c 18 0c 0c 0c-0c 30 10 0c 0c 0c 0c 10 0........0......
8047092c 10 0c 0c 14 0c 14 18 14-08 14 08 08 04 2c 1c 24 .............,.$
kd> ln 8044c422
(8044c422) nt!NtClose
示例 2-2 检查服务描述符表
译注:
在 Windows XP 中,KeServiceDescriptorTable 和 KeServiceDescriptorTableShadow 和 Windows 2000 有所区别 。在 XP 中,后者位于前者的前面,而在 W2K 中,后者位于前者的后面 。
INT 2eh 系统服务处理例程( System Service Handler )
隐藏在内核模式中的 INT 2eh 中断处理例程为 KiSystemService()。再强调一次,这是一个内部符号,ntoskrnl.exe 并没有导出该符号,不过,它却包含在 Windows 2000 的符号文件中 。因此,内核调试器可以正确的解析该符号 。从本质上来看,KiSystemService() 将执行如下操作:
1. 从当前线程的控制块( thread"s control block )中检索 SDT 指针 。
2. 通过测试 EAX 寄存器中的分派 ID 的第 12 、 14 位来确定使用 SDT 中的那个 SST ( SDT 中有四个 SST ) 。如果分派 ID 位于 0x0000-0x0FFF,将选择 ntoskrnl 表;位于 0x1000-0x1FFF 则选择 Win32k 表 。0x2000-0x2FFF 和 0x3000-0x3FFF 由 SDT 的 Table3 和 Table4 保留 。如果分配 ID 超过了 0x3FFF,在分派前多余的位将被屏蔽掉 。
3. 通过检查分派 ID 的 0 到 11 位来确定该 ID 在所选 SST 中对应的 ServiceLimit 成员 。如果 ID 超出了范围,将返回错误代码: STATUS_INVALID_SYSTEM_SERVICE。在一个未使用的 SST 中,ServiceLimit 成员始终是 0,从而为所有可能的分派 ID 产生一个错误代码 。
4. 通过检查 EDX 中保存的参数堆栈指针,来取得 MmUserProbeAddress 的值 。这是由 ntoskrnl.exe 导出的一个公开变量 。参数指针通常会与 0x7FFF0000 进行比较 。如果没有低于该地址,那么将返回 STATUS_ACCESS_VIOLATION。
5. 根据在 SST 的 ArgumentTable 中查找到的参数堆栈的字节数,将所有函数参数从调用者堆栈中复制到当前的内核堆栈中 。
6. 在从服务调用( Service Call )中返回后,将控制权传递给内部函数 KiServiceExit()
非常有趣的是 INT 2eh 中断处理例程并不使用全局 SDT (即 KeServiceDescriptorTable ),而是使用线程专属的指针替代之 。显然,每个线程可以拥有不同的 SDT。在线程初始化时,KeInitializeThread() 会将 KeServiceDescriptorTable 的指针写入线程控制块( Thread Control Block )中 。不过,此默认值在稍后可能会改变,如改为指向 KeServiceDescriptorTableShadow。

推荐阅读