内存与调试-用WinDbg从虚拟/线性地址查找出物理地址

一、内存映射规则

从虚拟地址(也叫线性地址),转换到物理地址,必须先要弄明白映射规则。影响内存映射规则的有:

  • 系统位数(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

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments