您的位置:首页 > 其它

初试将虚拟地址转换为物理地址

2013-06-16 17:40 1241 查看
背景:最近学习张银奎的《软件调试》,看到 2.7.5 节 使用WinDBG观察分页机制,终于看到第一个可以操作的例子,但始终不能按书上的方式正确的将虚拟地址转换为物理地址,google一下,终于解决,放到这里记录一下。

注:可以看到提示符是:kd,这里为了避免开两个windbg,直接使用的是内核调试调试虚拟机里面的XP SP3:

kd> vertarget
Windows XP Kernel Version 2600 (Service Pack 3) UP Free x86 compatible
Built by: 2600.xpsp_sp3_gdr.130307-0422
Machine Name:
Kernel base = 0x804d8000 PsLoadedModuleList = 0x80555140
Debug session time: Sun Jun 16 16:03:10.609 2013 (UTC + 8:00)
System Uptime: 0 days 0:03:49.906


一、《软件调试》中使用的方式:

1. 首先找到calc!gpszNum这个指针的值,(进程上下文设置部分省略)

kd> x calc!gpsz*
01014db0 calc!gpszNum = <no type information>
kd> dd 01014db0 l1
01014db0  000b55d0
kd> du 000b55d0
000b55d0  "123456778."
kd> .formats 000b55d0
Evaluate expression:
Hex:     000b55d0
Decimal: 742864
Octal:   00002652720
Binary:  00000000 00001011 01010101 11010000
Chars:   ..U.
Time:    Fri Jan 09 22:21:04 1970
Float:   low 1.04097e-039 high 0
Double:  3.67024e-318

可以看到,虚拟地址000b55d0的也目录索引(高10位)为0;页表索引(中间10位)即0xB5;页内偏移为(低12位)为0x5D0。

2. 找到calc进程的页目录基地址的物理地址:

kd> !process 0 0 calc.exe
PROCESS 81ad6020  SessionId: 0  Cid: 0890    Peb: 7ffda000  ParentCid: 06bc
DirBase: 04940380  ObjectTable: e1bafd30  HandleCount:  45.
Image: calc.exe
kd> !dd 04940380
# 4940380 0aace001 00000000 0ab4f001 00000000
# 4940390 06e50001 00000000 0ab8d001 00000000
# 49403a0 f8da5420 00000000 1ed41001 00000000
# 49403b0 1ecc2001 00000000 1ec3f001 00000000
# 49403c0 f8da53a0 00000000 1e861001 00000000
# 49403d0 1e7a2001 00000000 1e71f001 00000000
# 49403e0 f8da53c0 00000000 05fec001 00000000
# 49403f0 05a6d001 00000000 05cea001 00000000


到这里,问题就出来了,首先DirBase地址似乎不对,书上、网上、windbg帮助文档上的都是低12位为0,而且在 8.2.11 页目录基址 也写到“DirBase代表的是该进程的页目录基地址,即切换到该进程时,CR3寄存器的内容。***因为页目录是按4KB边界对齐的,所以DirBase的低12位总是0。”,但这里为0x380?然后,该物理地址指向的内存值似乎也不对。

3. 观察物理地址:

kd> !dd 0aace000+b5*4
# aace2d4 00000000 00000000 00000000 00000000
# aace2e4 00000000 00000000 00000000 00000000
# aace2f4 00000000 00000000 00000000 00000000
# aace304 00000000 00000000 00000000 00000000
# aace314 00000000 00000000 00000000 00000000
# aace324 00000000 00000000 00000000 00000000
# aace334 00000000 00000000 00000000 00000000
# aace344 00000000 00000000 00000000 00000000


明显不对了,物理地址是0x00 ?!
现在知道是什么原因了:电脑启用了PAE(Physical Address Extension),在拥有PAE技术支持的CPU上运行的操作系统以及应用程序被规定继续沿用以前的32位虚拟地址,通过段式转换,仍然得到32位的线性地址。而打开PAE支持的页式管理系统则负责把32位的线性地址映射到64GB物理空间的任何位置。在PAE技术支持下,系统可以拥有两种大小的物理页面:传统的4KB和2MB页面(注意,不是4MB)。同时,采用PAE技术的页式地址转换与传统的IA32方式有了非常大的变化:首先,IA32中的两级页表在PAE中变成了三层,CR3指向的不再是页目录表,而被称为页目录指针表(Page
Directory Pointer Table),它其实是个短表,只包含了4个指向页目录表的指针(在Linux的实现里,被称为中间页表PMD,Page Middle Directory),再由该页目录表指向可以选择的页表(也可以直接指向2MB的物理页面)。其次,虽然页目录表和页表仍然是4KB的大小,但是页目录项和页表项(PDE和PTE)从以前的32位变为了64位。同时,页目录表和页表所容纳的页目录项或页表项也从以前的1024个缩水到了512个。(摘自百度百科)。

二、使用!pte转换

最后没办法了,在网上搜索到了另一个方法:

kd> !pte 000b55d0
VA 000b55d0
PDE at C0600000            PTE at C00005A8
contains 000000000BE42067  contains 800000000A8AE067
pfn be42      ---DA--UWEV   pfn a8ae      ---DA--UW-V

kd> !dd a8ae5d0
# a8ae5d0 00320031 00340033 00360035 00370037
# a8ae5e0 002e0038 00000000 00040004 000c0198
# a8ae5f0 00000000 00340033 00360035 00370037
# a8ae600 0000002e 000a246a 00040153 00000010
# a8ae610 000b4190 000a0178 00200001 000a246a
# a8ae620 00000000 00000000 00000020 000a246a
# a8ae630 00000000 00000010 00000010 00000002
# a8ae640 00010001 000a246a 00000000 00000000
kd> !du a8ae5d0
# a8ae5d0 "123456778."


在右栏最后一列看到记号“pfn a8ae”出现。数值0xA8AE是这个PTE的page frame number (PFN)。把页框架号乘以0x1000 (例如,把它左移12位)。所得乘积0x0A8AE000是页开始的物理地址。

把字节索引加上页开始的地址:0x0A8AE000 + 0x5DO = 0x0A8AE5D0。即是所求的物理地址。

三、手动转换:

每个PTE的尺寸。在非PAE的x86系统上它是4个字节,PAE的x86上是8个字节。

页尺寸。它是0x1000个字节。

PTE_BASE虚拟地址。在一个非PAE系统上,它是0xC0000000。

使用这数据,你能够计算PTE本身的地址:

PTE address = PTE_BASE

+ (page directory index) * PAGE_SIZE

+ (page table index) * sizeof(MMPTE)

= 0xc0000000

+ 0x0 * 0x1000

+ 0xb5 * 8

= 0xC00005A8

这是PTE的地址。PTE是个32位双字节DWORD。调查它的内容:

kd> dd C00005A8 l1

c00005a8 0a8ae067

这个PTE的值是0x0a8ae067。它由两个域组成:

该PTE的低12位是状态标记status flags。这里,这些标记等于0x067 - 或者用二进制表示为0y000001100111。关于状态标记的说明,请看 !pte 参考页。

该PTE的高20位等于该PTE的page frame number (PFN)。这里,该PFN是0x0A8AE。

该物理页上的第一个物理地址是该PFN乘以0x1000 (左移12位)。字节索引是在该页上的偏移量。因此,你所求的物理地址是0x0A8AE000 + 0x5D0 = 0x0A8AE5D0。这跟以上方法获得的结果相同。

注:后面这两个方法引用自:/article/11425370.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: