将虚拟地址转换成物理地址

大多数调试器命令的输入参数和输出结果使用虚拟地址,而不使用物理地址。不过,有时候可能用得上物理地址。

有两个方法将一个虚拟地址转换成一个物理地址:使用 !vtop 扩展和使用 !pte 扩展。在Windows NT 4.0中还可以使用 !vpdd 扩展。

使用 !vtop 进行地址转换
假设你正在调试一台正在运行MyApp.exe进程的目标计算机,而且你想要调查虚拟地址0x0012F980。使用 !vtop 扩展确定对应的物理地址,步骤如下。

使用 !vtop 将虚拟地址转换成物理地址
确保你是工作在十六进制中。如若不然,用 N 16 命令设定当前基数。
确定地址的字节索引byte index。这个数值等于虚拟地址的最低12位。因此,虚拟地址 0x0012F980 的字节索引是0x980。
使用 !process 扩展来确定该地址的目录基址directory base:
kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
....
PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
    DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
    Image: MyApp.exe

确定目录基址的页框架号page frame number。只须把目录基址去掉尾部三个十六进制零就是了。本例中,目录基址是 0x098FD000 ,因此页框架号是 0x098FD。
使用 !vtop 扩展。这个扩展的第一个参数应该是页框架号。 !vtop 的第二个参数应该是正被讨论的虚拟地址:
kd> !vtop 98fd 12f980
Pdi 0 Pti 12f
0012f980 09de9000 pfn(09de9)

最后一行显示的第二个数值是物理页开始的物理地址。

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

你能够通过显示每个地址的内存来验证这个计算结果是正确的。!d* 扩展显示一个指定物理地址上的内存:

kd> !dc 9de9980
# 9de9980 6d206e49 726f6d65 00120079 0012f9f4 In memory.......
# 9de9990 0012f9f8 77e57119 77e8e618 ffffffff .....q.w...w....
# 9de99a0 77e727e0 77f6f13e 77f747e0 ffffffff .'.w>..w.G.w....
# 9de99b0 .....

d* (显示内存) 命令以一个虚拟地址作为它的参数:

kd> dc 12f980
0012f980  6d206e49 726f6d65 00120079 0012f9f4  In memory.......
0012f990  0012f9f8 77e57119 77e8e618 ffffffff  .....q.w...w....
0012f9a0  77e727e0 77f6f13e 77f747e0 ffffffff  .'.w>..w.G.w....
0012f9b0  .....

结果是相同的,所以这表明物理地址 0x09DE9980 的确对应虚拟地址 0x0012F980。

使用 !pte 进行地址转换
再次假定你正在调查属于MyApp.exe进程的虚拟地址0x0012F980。使用 !pte 扩展确定对应的物理地址,步骤如下:

使用 !pte 将虚拟地址转换成物理地址
确保你是工作在十六进制中。如若不然,用 N 16 命令设定当前基数。
确定地址的byte index。这个数值等于虚拟地址的最低12位。因此,虚拟地址0x0012F980的字节索引是0x980。
把需要的进程设定为进程上下文环境process context:
kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
....
PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
    DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
    Image: MyApp.exe

kd> .process /p ff779190
Implicit process is now ff779190
.cache forcedecodeuser done

以虚拟地址作为参数使用 !pte 扩展。显示两个栏的信息。左栏描述这个地址的页目录项(PDE),右栏描述它的页表项(PTE):
kd> !pte 12f980
               VA 0012f980
PDE at   C0300000        PTE at C00004BC
contains 0BA58067      contains 09DE9067
pfn ba58 ---DA--UWV    pfn 9de9 ---DA--UWV

在右栏最后一列看到记号“pfn 9de9”出现。数值0x9DE9是这个PTE的page frame number (PFN)。把页框架号乘以0x1000 (例如,把它左移12位)。所得乘积0x09DE9000是页开始的物理地址。
把字节索引加上页开始的地址:0x09DE9000 + 0x980 = 0x09DE9980。即是所求的物理地址。

这与前一个方法获得的结果相同。

手动转换地址
虽然 !ptov 和 pte 扩展提供最快速的方法将虚拟地址转换成物理地址,但我们也可以手动做这个转换。对这一过程的描述会让你搞清楚虚拟存储结构的某些细节。

存储结构因处理器和硬件配置而有不同大小。这里以一个不启用物理地址扩展(PAE)的x86系统为例。

还是用0x0012F980作为虚拟地址,首先你需要将它转换成二进制,手动或使用 .formats (显示格式化数值) 命令均可:

kd> .formats 12f980
Evaluate expression:
  Hex:     0012f980
  Decimal: 1243520
  Octal:   00004574600
  Binary:  00000000 00010010 11111001 10000000
  Chars:   ....
  Time:    Thu Jan 15 01:25:20 1970
  Float:   low 1.74254e-039 high 0
  Double:  6.14381e-318

这个虚拟地址是三个域的组合。位 0 到 11 是字节索引。位 12 到 21 是页表索引。位 22 到 31 是页目录索引。分开这些域,得:

0x0012F980  =  0y  00000000 00   010010 1111   1001 10000000

这展现该虚拟地址的三个部份:

页目录索引 = 0y0000000000 = 0x0
页表索引 = 0y0100101111 = 0x12F
字节索引 = 0y100110000000 = 0x980

然后你需要关于你的系统的另外三个的信息。

每个PTE的尺寸。在非PAE的x86系统上它是4个字节。
页尺寸。它是0x1000个字节。
PTE_BASE虚拟地址。在一个非PAE系统上,它是0xC0000000。

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

PTE address   =   PTE_BASE  
                + (page directory index) * PAGE_SIZE
                + (page table index) * sizeof(MMPTE)
              =   0xc0000000
                + 0x0   * 0x1000
                + 0x12F * 4
              =   0xC00004BC

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

kd> dd 0xc00004bc L1
c00004bc  09de9067

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

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

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值