一、内存映射规则
从虚拟地址(也叫线性地址),转换到物理地址,必须先要弄明白映射规则。影响内存映射规则的有:
- 系统位数(32位还是64位)
- PSE(Page Size Extension)
- PAE(Physical Address Extension)
具体规则可以去看内存分页模型,我这边是32位的XP虚拟机。
关于PAE:打开我的电脑属性发现没有“物理地址扩展”一行,也就是说当前xp虚拟机没有开启PAE。
关于PSE:我的XP虚拟机在CR4寄存器中标记可开启PSE,但是在页目录表项PDE( page directory entries)的bit7(有bit0实际是第8位),发现是0,表示不启用PSE。
综上我的XP虚拟机采用的是传统两级分页模型。
二、32位系统常规两级分页
线性地址划分是10-10-12
特别提醒:
1、目录项和页表项中的基地址都是20位的
2、线性地址分解出的目录索引,页索引都是10位的,具体操作时=基地址 +索引数*4 【要特别注意啊】(因为32位系统一个地址占4字节,如果是64位系统,那么就是 基地址 +索引数*8 因为64位系统一个地址占8字节)
三、动手实验线性地址转物理地址
1、在虚拟测试机中编写实验代码
#include <stdio.h> int main(int argc, char* argv[]) { char testName[38] = "HelloWorld ++ to get phpsics address"; printf("testName:%x\n",testName); printf("testName:%s\n",testName); getchar(); return 0; }
编译并运行,从下面的截图中我们可以看到字符串的虚拟/线性地址是22ff40
2、虚拟主机开启调试
线性地址是22ff40,32位系统,所以线性地址实际是0022ff40。 前10位是 0000 0000 00 中10位是 10 0010 1111 后12位是 1111 0100 0000
那我们先打开WInDbg,使用KD命令行
========备注,先查找程序的 页目录物理地址 kd> !process 0 0 pse_helloworld.exe PROCESS 81b0b620 SessionId: 0 Cid: 0660 Peb: 7ffde000 ParentCid: 063c DirBase: 0da68000 ObjectTable: e195a780 HandleCount: 7. Image: pse_helloworld.exe ========备注,发现页目录物理地址是16进制的 0da68000 , ========然后因为线性地址的 页目录索引是 0 kd> !dd 0da68000 + 0x0*4 # da68000 0dd56067 0dc95067 00000000 00000000 # da68010 00000000 00000000 00000000 00000000 # da68020 00000000 00000000 00000000 00000000 # da68030 00000000 00000000 00000000 00000000 # da68040 00000000 00000000 00000000 00000000 # da68050 00000000 00000000 00000000 00000000 # da68060 00000000 00000000 00000000 00000000 # da68070 00000000 00000000 00000000 00000000 ========备注,这里找到了页表的物理地址是16进制的 0dd56067, ========基地址是前20位,即0dd56000 + 页表索引是0x22f*4 kd> !dd 0dd56000 + 0x22f*4 # dd568bc 0e1da067 0af0b025 0af0c025 00000000 # dd568cc 00000000 00000000 00000000 00000000 # dd568dc 00000000 00000000 00000000 00000000 # dd568ec 00000000 00000000 00000000 00000000 # dd568fc 00000000 0e09f067 0a260067 0e0e3067 # dd5690c 028f2067 00000000 00000000 00000000 # dd5691c 00000000 00000000 00000000 00000000 # dd5692c 00000000 00000000 00000000 00000000 ========备注,这里找到了页表项的基地址是 0e1da067的前20位即 0e1da000 ========再加上线性地址的偏移地址 0xf40,所以最终的 物理地址是 0e1da000 +0xf40 ========在这里我们成功看到了 物理地址的 内容是 HelloWorld ++ to get physics address kd> !db 0e1da000 +0xf40 # e1daf40 48 65 6c 6c 6f 57 6f 72-6c 64 20 2b 2b 20 74 6f HelloWorld ++ to # e1daf50 20 67 65 74 20 70 68 70-73 69 63 73 20 61 64 64 get phpsics add # e1daf60 72 65 73 73 00 00 40 00-78 ff 22 00 ce 13 40 00 [email protected]."...@. # e1daf70 35 00 33 00 39 00 38 00-b0 ff 22 00 4b 12 40 00 5.3.9.8...".K.@. # e1daf80 01 00 00 00 48 37 3e 00-40 29 3e 00 00 40 40 00 ....H7>.@)>..@@. # e1daf90 a4 ff 22 00 ff ff ff ff-a8 ff 22 00 01 00 00 00 .."......."..... # e1dafa0 06 00 00 00 40 29 3e 00-00 00 00 00 00 e0 fd 7f ....@)>......... # e1dafb0 c0 ff 22 00 98 12 40 00-01 00 00 00 09 00 00 00 .."...@.........
3、开启PAE后尝试查找物理地址
官网查询发现,只需要在 boot.ini中添加 /PAE 就行了,效果如下。
[boot loader] timeout=30 default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS [operating systems] multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional Test Debug" /fastdetect /PAE /debug /debugport=COM1 /baudrate=115200
xp以上的Windows版本是编辑BCD文件,
32 位元 Windows 7 開啟 PAE: Start → All Programs→ Accessories→ Command Prompt 點右鍵, 再點 Run as administrator,執行以下命令: bcdedit /set pae forceenable
特别提醒:开启 PAE 需要重新开机才能生效。
按道理这样做就应该成功了啊。但是PAE还是没有开启,因为我的电脑里属性页还是没有显示“物理地址扩展”。这又是一个坑啊。
后来我用Everest Ultimate Edition 查看主板–>内存,发现系统支持PAE,但处理器不支持,也就是说当前xp虚拟机没有开启PAE。
查询后发现,可以在VirtualBox中设设置开启PAE功能。
Select the VM in the list of VMs and click Settings->General->Advanced and there is a checkbox for PAE. It's now in System > Processor. Please, check the complete VM settings before complaining where to find something. Reading the manual is a must in this case, we have it for a reason
然后重新运行那个实验代码:发现结果虚拟地址还是22ff40,果然虚拟地址还是一样的啊。
查阅资料:发现现在的内存模型是PAE,线性地址划分是 2-9-9-12 线性地址是22ff40,32位系统,所以线性地址实际是0022ff40。 前2位是 00 页目录指针索引 是0 中前9位是 00 0000 001 页目录项索引 是1 中后9位是 0 0010 1111 页表项索引 十六进制:0x2f 十进制:47 后12位是 1111 0100 0000 页面偏移 是0xf40
特别提醒:
PAE下的【页目录指针项,页目录项,页表项】是64位的,所以用dq命令,计算索引偏移量的时候,是*8,因为64位地址是8字节的。页表项的内容就是页框,也就是页框(我叫页面了)的地址,也就是上图说的64bit的 PT entry,64位是地址编号,页框偏移是12位,也就是一个页框内可以有2^12个基本内存单元。每个内存单元是1字节,所以页框大小是4KB。
我们打开虚拟主机,进行调试看看:
kd> !process 0 0 pse_helloworld.exe PROCESS 820be708 SessionId: 0 Cid: 03ac Peb: 7ffd8000 ParentCid: 05c8 DirBase: 07200280 ObjectTable: e104da90 HandleCount: 7. Image: pse_helloworld.exe =====备注:PAE模式下分页内容中35-12位是基地址位,除了PDE.PS=1的情况,详情看内存分页机制 =====PDE 是页目录项,其中bit7也就是第8位,毕竟还有bit0呢 =====页目录指针索引,是0,所以下面没有添加 索引偏移 kd> !dq 07200280 # 7200280 00000000`09d8b001 00000000`09a0c001 # 7200290 00000000`09bcd001 00000000`09e4a001 # 72002a0 00000000`f8d212e0 00000000`07f53001 # 72002b0 00000000`07f94001 00000000`08011001 # 72002c0 00000000`11be9001 00000000`11caa001 # 72002d0 00000000`11d2b001 00000000`11b28001 # 72002e0 00000000`f8d21300 00000000`003f0001 # 72002f0 00000000`004b1001 00000000`004ae001 =====备注:页目录项索引是1 kd> !dq 0`09d8b000 + 0x1*8 # 9d8b008 00000000`0aa35067 00000000`09ab1067 # 9d8b018 00000000`00000000 00000000`00000000 # 9d8b028 00000000`00000000 00000000`00000000 # 9d8b038 00000000`00000000 00000000`00000000 # 9d8b048 00000000`00000000 00000000`00000000 # 9d8b058 00000000`00000000 00000000`00000000 # 9d8b068 00000000`00000000 00000000`00000000 # 9d8b078 00000000`00000000 00000000`00000000 =====备注:页表项索引是0x2f kd> !dq 0`0aa35000 + 0x2f*8 # aa35178 00000000`09cb7067 00000000`0b218025 # aa35188 00000000`0b1d9025 00000000`00000000 # aa35198 00000000`00000000 00000000`00000000 # aa351a8 00000000`00000000 00000000`00000000 # aa351b8 00000000`00000000 00000000`00000000 # aa351c8 00000000`00000000 00000000`00000000 # aa351d8 00000000`00000000 00000000`00000000 # aa351e8 00000000`00000000 00000000`00000000 =====备注:页内偏移是 0xf40,又一次成功看到了内存物理地址的内容 kd> !db 0`09cb7000 + 0xf40 # 9cb7f40 48 65 6c 6c 6f 57 6f 72-6c 64 20 2b 2b 20 74 6f HelloWorld ++ to # 9cb7f50 20 67 65 74 20 70 68 70-73 69 63 73 20 61 64 64 get phpsics add # 9cb7f60 72 65 73 73 00 00 40 00-78 ff 22 00 ce 13 40 00 [email protected]."...@. # 9cb7f70 35 00 33 00 39 00 38 00-b0 ff 22 00 4b 12 40 00 5.3.9.8...".K.@. # 9cb7f80 01 00 00 00 48 37 3e 00-40 29 3e 00 00 40 40 00 ....H7>.@)>..@@. # 9cb7f90 a4 ff 22 00 ff ff ff ff-a8 ff 22 00 01 00 00 00 .."......."..... # 9cb7fa0 06 00 00 00 40 29 3e 00-00 00 00 00 00 80 fd 7f ....@)>......... # 9cb7fb0 c0 ff 22 00 98 12 40 00-01 00 00 00 09 00 00 00 .."...@.........
参考:
https://bbs.pediy.com/thread-203391.htm
https://bbs.pediy.com/thread-180989.htm
https://www.twblogs.net/a/5b83db5d2b71777cb15c6302/zh-cn
https://blog.csdn.net/tutucoo/article/details/84729919
https://asemia623.pixnet.net/blog/post/36116779-%E2%98%86%E3%80%90%E5%9C%96%E8%A7%A3%EF%BD%9C%E6%95%99%E5%AD%B8%EF%BD%9C%E4%B8%8B%E8%BC%89%E3%80%91%E5%A6%82%E4%BD%95%E9%96%8B%E5%95%9Fpae%E3%80%81%E5%A6%82%E4%BD%95%E6%9F%A5
https://forums.virtualbox.org/viewtopic.php?p=44859