2 《Undocumented Windows 2000 Secrets》翻译 --- 第四章( 六 )


#define X86_DESCRIPTOR_SYS_CALL32 0xC
#define X86_DESCRIPTOR_SYS_INT32 0xE
#define X86_DESCRIPTOR_SYS_TRAP32 0xF
// -----------------------------------------------------------------
#define X86_DESCRIPTOR_APP_ACCESSED 0x1
#define X86_DESCRIPTOR_APP_READ_WRITE 0x2
#define X86_DESCRIPTOR_APP_EXECUTE_READ 0x2
#define X86_DESCRIPTOR_APP_EXPAND_DOWN 0x4
#define X86_DESCRIPTOR_APP_CONFORMING 0x4
#define X86_DESCRIPTOR_APP_CODE 0x8
列表 4-5. 附加的 i386 内存管理相关定义
第二组宏和常量与 Windows 2000 的 PDE 、 PTE 数组有关 。和其他几个系统地址不同,这些数组的基地址并没有在系统启动时作为一个全局变量出现,而是被定义成了一个常量 。可以通过反编译内存管理 API 函数: MmGetPhysicalAddress() 和 MmIsAddressValid() 来证明,在这些函数里,这些地址都以“魔术数字”的形式出现 。这些常量并没有包括在 DDK 头文件中,不过 列表 4-5 展示了如何定义它们 。
l X86_PAGES 是一个硬编码的地址和指针(指向 0xC0000000 ),0xC0000000 是 Windows 2000 的 PTE 数组开始的地方 。
X86_PTE_ARRAY 等价于 X86_PAGES,但是被转型为 PX86_PE,也就是说,指向一个 X86_PE 类型的数组,X86_PE 定义于列表 4-2。
X86_PDE_ARRAY 是一个巧妙的定义,它通过 PTE 数组的位置来计算 PDE 数组的基地址,这需要用到 PTI_SHIFT 常量 。将线性地址映射为 PTE 地址的通用格式为:(( LinearAdress >> 12 ) *4 )0xC0000000,线性地址 0xC0000000 转换后的地址为页目录的基地址 。
列表 4-5 的最后两部分包括选择器和特殊类型的描述符,以及对 列表 4-2 的补充 。
l X86_SELECTOR_RPL 、 X86_SELECTOR_TI 和 X86_SELECTOR_INDEX 都是位掩码,分别对应 X86_SELECTOR 结构中的 RPL 、 TI 和 Index 成员 。
l X86_SELECTOR_SHIFT 是一个右移因子,用来使选择器的 Index 的数值向右对齐 。
l X86_SELECTOR_LIMIT 定义了选择器可使用的最大索引值,该限制为 8,191。这个值确定了描述符表的最大尺寸 。每个选择器索引均指向一个描述符,每个描述符包含 64 个位(即 8 个字节) 。所以,描述符表的最大尺寸为: 8,192*8=64KB。
l X86_DESCRIPTOR_SYS_* 是一组常量,用于定义系统描述符类型 。如果描述符的 S 位被设为 0,那么描述的 Type 成员将采用这一组类型中的某一个 。请参考 列表 4-2 中的 X86_DESCRIPTOR 的定义 。系统描述符类型在 Intel 手册中有详细介绍( Intel 1999c, pp. 3-15f ),表 4-1 给出了所有可用的系统描述符类型 。
列表 4-5 中的 X86_DESCRIPTOR_APP_* 常量也可用于定义描述符的 Type 成员,前提是描述符的 S 位不为 0。此时,该应用程序描述符可能需要引用一个代码或数据段 。因为应用程序描述符类型的属性受 Type 域的第四个位影响,所以 X86_DESCRIPTOR_APP_* 常量被定义为单位掩码( single-bit mask ),这样一些位就可针对数据和代码段有不同的解释 。
l X86_DESCRIPTOR_APP_ACCESSED 如果一个段可以被访问,则采用
l X86_DESCRIPTOR_APP_READ_WRITE 决定一个数据段是否允许只读或读 / 写访问 。
l X86_DESCRIPTOR_APP_CONFORMATING 说明一个代码段是否相匹配 。也就是说,它是否可以被以被弱特权代码( less privileged code )调用(参考 Intel 1999c,pp. 4-13ff ) 。
l X86_DESCRIPTOR_APP_CODE 用来区别代码段和数据段 。注意,堆栈属于数据段的范畴,而且必须总是可写的 。
稍后,当下一章中的 Memory Spy 程序开始运行时,我们将重温系统描述符 。表 4-1 算是 i386 内存管理的一个简短总结 。有关本话题的更多内容,请参考 Intel Pentium 手册( Intel 1999a,1999b,1999c ) 。
表 4-1. 系统描述符类型
名 称

描 述

推荐阅读