第四章 探索 Windows 2000 的内存管理机制
翻译: Kendiv( [url=http://www.pccode.net].net"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 属性
段
属 性
描 述
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 寄存器
KGDT_TSS
0x0028
位于用户和内核的任务状态段
KGDT_R0_PCR
0x0030
内核模式的 FS 寄存器(处理器控制区域)
KGDT_R3_TEB
0x0038
用户模式的 FS 寄存器(线程环境块)
KGDT_VDM_TILE
0x0040
基地址 0x00000400 ,限制 0x0000FFFF ( DOS 虚拟机)
KGDT_LDT
0x0048
本地描述符表
KGDT_DF_TSS
0x0050
Ntoskrnl.exe 变量 KiDoubleFaultTSS
KGDT_NMI_TSS
0x0058
Ntoskrnl.exe 变量 KiNMITSS
示列 4-14 中的选择子( selector )没有在 表 4-6 中列出,其中的某些选择子可以通过查找熟悉的基地址或其内存内容来确认它们。使用内核调试器可查找其中某些选择子的基地址对应的符号。 表 4-7 给出了我已经确认的选择子。
W2k_mem.exe 的 +i 选项可转储 IDT 中的门描述符( Gate Descriptor )。 示列 4-15 给出了 IDT 的门描述符的部分内容, Intel 仅定义了 IDT 中的前 20 个门描述符( Intel 1999c, pp. 5-6 )。 IDT 中的中断 0x14 到 0x1F 由 Intel 保留;剩余的 0x20 到 0xFF 由操作系统使用。
在 表 4-8 中,我给出了所有可确认的特殊的中断、陷阱和任务门。大多数用户自定义的中断都指向哑元例程 ---KiUnexpectedinterruptnNNN() ,在前面我们已经解释过它。对于某些中断处理例程的地址,内核调试器也无法解析其地址对应的符号。
表 4-7. 更多的 GDT 选择子( selector )
值
基地址
描 述
0x0078
0x80400000
Ntoskrnl.exe 的代码段
0x0080
0x80400000
Ntoskrnl.exe 的数据段
0x00A0
0x814985A8
TSS ( EIP 成员指向 HalpMcaExceptionHandlerWrapper )
0x00E0
0xF0430000
ROM BIOS 代码段
0x00F0
0x8042DCE8
Ntoskrnl.exe 函数 KiI386CallAbios
0x0100
0xF0440000
ROM BIOS 数据段
0x0108
0xF0440000
ROM BIOS 数据段
0x0110
0xF0440000
ROM BIOS 数据段
示列 4-15. 显示 IDT 门描述符
表 4-8. Windows 2000 中断、陷阱和任务门
INT
Intel 定义的描述符
拥有者
处理例程 /TSS
0x00
整除错误( DE )
ntoskrnl.exe
KiTrap00
0x01
调试( DB )
ntoskrnl.exe
KiTrap01
0x02
NMI 中断
ntoskrnl.exe
KiNMITSS
0x03
断点( BP )
ntoskrnl.exe
KiTrap03
0x04
溢出( OF )
ntoskrnl.exe
KiTrap04
0x05
越界( BR )
ntoskrnl.exe
KiTrap05
0x06
未定义的操作码( UD )
ntoskrnl.exe
KiTrap06
0x07
没有数学协处理器( NM )
ntoskrnl.exe
KiTrap07
0x08
Double Fault ( DF )
ntoskrnl.exe
KiDouble
0x09
协处理器段溢出
ntoskrnl.exe
KiTrap09
0x0A
无效的 TSS ( TS )
ntoskrnl.exe
KiTrap0A
0x0B
段不存在( NP )
ntoskrnl.exe
KiTrap0B
0x0C
堆栈段故障( SS )
ntoskrnl.exe
KiTrap0C
0x0D
常规保护( GP )
ntoskrnl.exe
KiTrap0D
0x0E
页故障( PF )
ntoskrnl.exe
KiTrap0E
0x0F
Intel 保留
ntoskrnl.exe
KiTrap0F
0x10
Math Fault ( MF )
ntoskrnl.exe
KiTrap10
0x11
对齐检查( AC )
ntoskrnl.exe
KiTrap11
0x12
Machine Check ( MC )
?
?
0x13
流 SIMD 扩展
ntoskrnl.exe
KiTrap0F
0x14-0x1F
Intel 保留
ntoskrnl.exe
KiTrap0F
0x2A
用户自定义
ntoskrnl.exe
KiGetTickCount
0x2B
用户自定义
ntoskrnl.exe
KiCallbackReturn
0x2C
用户自定义
ntoskrnl.exe
KiSetLowWaitHighThread
0x2D
用户自定义
ntoskrnl.exe
KiDebugSerice
0x2E
用户自定义
ntoskrnl.exe
KiSystemService
0x2F
用户自定义
ntoskrnl.exe
KiTrap0F
0x30
用户自定义
hal.dll
HalpClockInterrupt
0x38
用户自定义