9 《Undocumented Windows 2000 Secrets》翻译 --- 第四章

第四章 探索 Windows 2000 的内存管理机制
翻译: Kendiv( fcczj@263.net)
更新: Tuesday, February 22, 2005
声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利 。
Windows 2000 的分段和描述符
w2k_mem.exe 的另一个很棒的选项是e ,该选项将显示和说明处理器的段寄存器和描述表的内容 。示列 4-13 给出了其典型输出 。CS 、 DS 和 ES 段寄存器的内容非常清晰的证明了 Windows 2000 为每个进程提供了平坦的 4GB 地址空间:起始于 0x00000000 ,终止于 0xFFFFFFFF。示列 4-13 中最右边的标志符用来表示段的类型,该段的类型由它的描述符的 Type 成员给出 。代码和数据段的 Type 属性可分别符号化为“ cra ”和“ ewa ” 。省略号“ - ”意味着相应的属性没有设置 。一个任务状态段( Task State Segment , TSS )仅能有“ a ”(可用)和“ b ”(忙)两种属性 。表 4-5 给出了所有可用的属性 。示列 4-13 展示了 Windows 2000 的 CS 段的不一致性, CS 段允许执行和读取,而 DS 、 ES 、 FS 和 SS 段的属性则是可扩展和读 / 写访问 。另一个不明显但十分重要的细节是 CS 、 FS 和 SS 段的 DPL 在用户模式和内核模式并不相同 。DPL 是描述符特权级别( Descriptor Privilege Level ) 。对于代码段( CS ),仅当调用者位于其 DPL 指定的特权级时才能调用该段中的代码(参考 Intel 1999c, pp. 4-8f ) 。在用户模式, CS 段的 DPL 为 3 ;在内核模式,其 DPL 为 0。对于数据段( DS ),其 DPL 是最低的特权级,在用户模式下,所有特权级都可访问它,而在内核模式下,仅允许特权 0 访问 。
示列 4-13. 显示 CPU 信息
IDT 和 GDT 寄存器的内容显示了 GDT 的范围是: 0x8003F000 --- 0x8003F3FF ,紧随其后的就是 IDT ,其地址范围是: 0x8003F400 --- 0x8003FBFF。由于每个描述符占用 64 位,故 GDT 和 IDT 分别包含 128 和 256 个项 。注意, GDT 可容纳 8,192 个项,但 Windows 2000 仅使用了其中的一小部分 。
表 4-5 代码和数据段的 Type 属性

属 性
描 述
【9 《Undocumented Windows 2000 Secrets》翻译 --- 第四章】CODE
c
使段一致(低特权的代码可能进入)
CODE
r
允许读访问(和仅执行访问相斥)
CODE
a
段可以访问
DATA
e
向下扩展段(堆栈段的典型属性)
DATA
w
允许写访问(和仅读取访问相斥)
DATA
a
段可以访问
TSS32
a
任务状态段可用
TSS32
b
任务状态段繁忙
W2k_mem.exe 还提供了两个很有特色的选项 ---- g 和i ,这两个选项可显示 GDT 和 IDT 的更多细节 。示列 4-14 示范了g 选项的输出 。它很类似于 示列 4-13 中的“ kernel-model segment: ”一节,但列出了在内核模式下所有可用的段选择子( selector ),而不仅仅是存储在段寄存器中的那些 。W2k_mem.exe 通过遍历整个 GDT 来获取所有的段选择子,可通过 IOCTL 函数 SPY_IO_SEGMENT 来指示 Spy 设备查询段信息 。仅显示有效的选择子 。比较 示列 4-13 和 4-14 中的 GDT 选择子将十分有趣, GDT 的选择子定义于 ntddk.h 中,汇总在 表 4-6。显然,它们与 w2k_mem.exe 的输出是一致的 。
示列 4-14. 显示 GDT 描述符
表 4-6. 定义于 ntddk.h 中的 GDT 选择子( selector )
符 号

注 释
KGDT_NULL
0x0000
空的段选择子(无效)
KGDT_R0_CODE
0x0008
内核模式的 CS 寄存器
KGDT_R0_DATA
0x0010
内核模式的 SS 寄存器
KGDT_R3_CODE
0x0018
用户模式的 CS 寄存器
KGDT_R3_DATA
0x0020
用户模式的 DS 、 ES 和 SS 寄存器,内核模式的 DS 和 ES 寄存器

推荐阅读