地址转译

x86虚拟地址转译

  • CR3寄存器,页目录物理基址
  • 标准非PAE,两级页表: 页目录索引(10位)、页表索引(10位)、字节索引(12位)
    • PDE: 每个PDE表有1K个表项,每项4字节
    • PDE: 每个PTE表有1K个表项,每项4字节
  • PAE,三级页表: 页目录指针索引(2位), 页目录索引(9位)、页表索引(9位)、字节索引(12位)
    • PDE: 每个PDE表有512个表项,每项8字节
    • PDE: 每个PTE表有512个表项,每项8字节

在非PAE模式下的地址转译

  • !vtop PFN VirtualAddress, 最快捷的方式

    首先获取PFN, 有两种方式, 从!process中查看DirBase, 或用r cr3查看, PFN就是cr3中的值右移12位 0: kd> r cr3 cr3=00185000

    0: kd> !vtop 185 845ecf68 
    X86VtoP: Virt 845ecf68, pagedir 185000
    X86VtoP: PDE 185844 - 001c4063
    X86VtoP: PTE 1c47b0 - 045ec121
    X86VtoP: Mapped phys 45ecf68
    Virtual address 845ecf68 translates to physical address 45ecf68.
        
    // 比较虚拟地址内容及物理地址内容,完全一样,所以是正确映射的
    0: kd> !dd 0x45ecf68
    # 45ecf68 fefc45c7 6affffff 56006a01 046a59e8
    # 45ecf78 c0efe800 08c2ffe6 ec458b00 8be44589
    
    0: kd> dd 845ecf68 
    845ecf68  fefc45c7 6affffff 56006a01 046a59e8
    845ecf78  c0efe800 08c2ffe6 ec458b00 8be44589
    
  • !pte, 直接获得PTE内容,然后计算物理地址

    0: kd> !pte 845ecf68 
                     VA 845ecf68
    PDE at C0300844         PTE at C02117B0
    contains 001C4063       contains 045EC121
    pfn 1c4   ---DA--KWEV   pfn 45ec  -G--A--KREV
    
    //The number 0x45ec is the page frame number (PFN) of this PTE
    physical address = 0x45ec*0x10000(4k, 页大小) + 0xf68(页偏移) = 0x45ecf68
    
  • manual convert

    0: kd> .formats 845ecf68 
    Evaluate expression:
      Binary:  10000100 01011110 11001111 01101000
    
    Page directory index = 0y1000010001 = 0x211
    Page table index = 0y0111101100 = 0x1ec
    Byte index = 0y111101101000 = 0xf68
    
    // 查看PTE内容, 两种方式
    1.  计算PTE的虚拟地址 
    PTE virsual address   =   
    PTE_BASE              (On a non-PAE system, this is 0xC0000000)
            + (page directory index) * PAGE_SIZE    (0x1000, 4K)
            + (page table index) * sizeof(MMPTE)    (This is 4 bytes on non-PAE x86 systems)
          =   0xc0000000
            + 0x211 * 0x1000
            + 0x1ec * 4
          =   0xC02117B0
    0: kd> dd C02117B0 l1
        c02117b0  045ec121
        pnf = 0x45e
    
    2.  计算PTE的物理地址
    0: kd> r cr3
    cr3=00185000
    
    PDE physical address = 0x185 * 0x1000 + 0x211 * 4 = 0x185844
        0: kd> !dd 0x185844 L1
        #  185844 001c4063  PDE content: pfn -> 0x1c4
    PTE physical address = 0x1c4 * 0x100 + 0x1ec * 4 = 0x1c47b0
        0: kd> !dd 0x1c47b0 L1
        #  1c47b0 045ec121  PTE content: pfn -> 0x45e
        
    // 计算物理地址
    physical address = pnf * 0x1000 + byte index = 0x45e000 + 0xf68 = 0x45ef68
    

在PAE模式下的地址转译

  • !vtop 失败,这个方法不好用
  • !pte

    1: kd> r cr4
        cr4=000406f9    bit 5:1  PAE开启
    
    1: kd> !pte 84e13a68 
                        VA 84e13a68
    PDE at C0602138            PTE at C0427098
    contains 00000000039C1863  contains 000000007D413963
    pfn 39c1      ---DA--KWEV  pfn 7d413     -G-DA--KWEV
    
    //The number 7d413 is the page frame number (PFN) of this PTE
    physical address = 0x7d413*0x1000(4k, 页大小) + 0xa68(页偏移) = 0x7d413f68
    
    1: kd> dd 84e13a68 
    84e13a68  00d00003 00000000 84ebc3f8 00000000
    1: kd> !dd 7d413a68
    #7d413a68 00d00003 00000000 84ebc3f8 00000000
    转译成功
    
  • manual convert

    1: kd> .formats 84e13a68 
        Binary:  10000100 11100001 00111010 01101000
    Page directory pointer index = 0y10 = 0x2
    Page directory index = 0y000100111 = 0x27
    Page table index = 0y000010011 = 0x13
    Byte index = 0y101001101000 = 0xa68
    
    计算PTE的虚拟地址 
    PTE virsual address   =   
    PTE_BASE 	(this is 0xC0000000)
            + (page directory pointer index) * (PAGE_SIZE * PAGE_ENTRY_NUM)     (0x1000, 0x200)(页大小为4k,一个页目录中页表项占8字节,共有512个页表项)
            + (page directory index) * PAGE_SIZE    (0x1000, 4K)
            + (page table index) * sizeof(MMPTE)    (This is 8 bytes on PAE x86 systems)
          =   0xc0000000
            + 0x2 * 0x1000 * 0x200
            + 0x211 * 0x1000
            + 0x13 * 8
          =   0xC027098
    
    1: kd> dd C0427098 l1
        c0427098  7d413963
        pnf = 0x7d413
    pyhsical address = pnf * 0x100 + Byte index = 0x7d413a68
    

x64虚拟地址转译

使用四级页表方案, 手动比较麻烦, !vtop不靠谱,最好用的还是!pte

1: kd> !PTE fffff803`5b2be43c
                                       VA fffff8035b2be43c
PXE at FFFFF6FB7DBEDF80    PPE at FFFFF6FB7DBF0068    PDE at FFFFF6FB7E00D6C8    PTE at FFFFF6FC01AD95F0
contains 0000000000384063  contains 0000000000345063  contains 000000000034D063  contains 00000000020BE121
pfn 384       ---DA--KWEV  pfn 345       ---DA--KWEV  pfn 34d       ---DA--KWEV  pfn 20be      -G--A--KREV

只关心PTE的pfn即可, pnf = 0x20be
pyhsical address = pnf * 0x1000 + 0x43c = 0x20be43c

1: kd> !dd  0x20be43c
# 20be43c f8b60f44 c89f8b48 0f000000 0b7477ba

1: kd> dd fffff803`5b2be43c
fffff803`5b2be43c  f8b60f44 c89f8b48 0f000000 0b7477ba
可以看到虚拟地址内容与物理地址完全相同,是映射关系

====================================================================

以上看到,最好的地址转译方式是用!pte, 只关心PTE的pnf即可

使用到的windbg命令

  • !pte [virtual address] 查看PDE和PTE内容
  • d用来查看虚拟地址下的内容,!d用来查看物理地址下的内容
  • !vtop windbg提供的地址转译命令,但是好像只有在x86且non-PAE模式不才好用
  • .formats 以不同的进制输出数据
  • r [cr*] 显示特定寄存器中的值

blog comments powered by Disqus