在上一篇文末,我已经告诉了你如何把虚拟机中的 xp 系统配置成 PAE 分页模式。说不定,你已经自己完成了PAE的分页实验。可是为了照顾到有些做不出来的同学,我还是得把实验演示一遍。
xp 系统改成 PAE 分页模式
打开虚拟机中的 xp 系统,把 c:\boot.ini
文件打开,然后修改成图1的样子。注意只修改了一个地方,就是把以前的 /excute=option
改成了现在的 /noexecute=optin
. 其它的部分保持不动。保存后并不会生效,要记得重启一下你的虚拟机才会生效。
图1 修改成 PAE 分页模式
PAE 分页实验
实验代码
这段代码非常简单,就是查看一下字符串 Hello, I'm PAE!
的线性地址是多少。注意程序会在 getchar() 处停下,这时候千万别回车,否则程序会运行结束。
最终,在我屏幕上打印的线性地址是 0x00423024
. 见图2.
// 文件名:PAE.cpp
int main(int argc, char* argv[])
{
char *str = "Hello, I'm PAE!";
printf("%08x\n", str);
getchar();
return 0;
}
图2 打印线性地址
线性地址分析
在我的机器上,得到的线性地址是 0x00423024
。
- 前 20 bit 分解成 2 进制是 0000 0000 0100 0010 0011,后12 bit 不做分解
- 按2-9-9-12 拆解后就是 00-00 0000 010-0 0010 0011-(024),最终的16进制形式为 0-2-23-024
那么最终这个线性地址被拆分成了四段式,即三段索引加偏移的结构。
WinDbg 中查找物理地址
要想进行转换,我们需要知道当前进程(就是前面那段代码执行的程序)的CR3存的顶级页目录(PDPT)的基址。在 WinDbg 中使用下面的命令查看。
kd> !process 0 0
图3 使用命令 !process 0 0 查看进程顶级页目录基址(只列举了部分)
通常在最末尾的位置,你就可以找到自己执行的那个进程。在我的实验里,我的进程名字就叫 PAE.exe,可以看到顶级页目录基址是 0x0c940500
。转换步骤如图4所示。
以 8 字节查看物理地址的内容的命令是:
kd> !dq <你的物理地址>
另外,在 WinDbg 中是可以直接进行做加乘运算的。
图4 转换步骤
NX 位
如果你细心观察的话,你发现最后一个 PTE 的值是 80000000-05e3a025
,上节课你已经知道了 PTE 的结构了,它的高 28 位是保留位。但是这里的最高位,也就是第 63 位是 1,这个位也并不是一点用没有。
实际上,这个位的含义是,当前物理页数据是否可以被当成代码来执行。NX 是英文的 No Execute 的缩写。如果该位被置 1,意味着,无论如何,这个PTE指向的物理页的数据都不能被翻译成机器码被 CPU 执行,否则 CPU 会报错。
它的意义在于防止注入漏洞,即把数据当成代码来执行,造成恶意攻击。
如果你拉动你的滚动条到篇首,也就是 xp 配置成 PAE 那里,也许会明白为什么那个参数要改成 /noexecute
了。