將虛擬位址轉換為實體位址

大部分偵錯工具命令都會使用虛擬位址,而非實體位址作為其輸入和輸出。 不過,有時候擁有實體位址可能很有用。

有兩種方式可將虛擬位址轉換成實體位址:使用 !vtop 擴充功能,以及使用 !pte 擴充功能。

如需 Windows 中虛擬位址的概觀,請參閱 虛擬位址空間

使用 !vtop 轉換位址

假設您正在偵錯執行 MyApp.exe 進程的目的電腦,而且您想要調查虛擬位址0x0012F980。 以下是您要搭配 !vtop 延伸模組來判斷對應實體位址的程式。

使用 !vtop 將虛擬位址轉換為實體位址

  1. 請確定您使用的是十六進位。 如有必要,請使用 N 16 命令設定目前的基底。

  2. 判斷位址的 位元組索引 。 此數位等於虛擬位址的最低 12 位。 因此,虛擬位址0x0012F980具有位元組索引0x980。

  3. 使用!process延伸模組來判斷位址的目錄基底

    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
    
  4. 判斷目錄基底 的頁面框架編號 。 這只是不含三個尾端十六進位零的目錄基底。 在此範例中,目錄基底0x098FD000,因此頁面框架編號0x098FD。

  5. 使用 !vtop 延伸模組。 此延伸模組的第一個參數應該是頁面框架編號。 !vtop的第二個參數應該是有問題的虛擬位址:

    kd> !vtop 98fd 12f980
    Pdi 0 Pti 12f
    0012f980 09de9000 pfn(09de9)
    

    最後一行中顯示的第二個數字是實體頁面開頭的實體位址。

  6. 將位元組索引新增至頁面開頭的位址: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* (Display Memory) 命令會使用虛擬位址作為其引數:

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 將虛擬位址轉換為實體位址

  1. 請確定您使用的是十六進位。 如有必要,請使用 N 16 命令設定目前的基底。

  2. 判斷位址的 位元組索引 。 此數位等於虛擬位址的最低 12 位。 因此,虛擬位址0x0012F980具有位元組索引0x980。

  3. 進程內容 設定為所需的進程:

    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
    
  4. 使用具有虛擬位址的 !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
    
  5. 查看右欄的最後一個資料列。 標記法 「pfn 9de9」 隨即出現。 0x9DE9編號是這個 PTE (PFN) 的頁面框架編號 。 例如,將頁面框架編號乘以0x1000 (,將它向左移 12 位) 。 結果0x09DE9000是頁面開頭的實體位址。

  6. 將位元組索引新增至頁面開頭的位址:0x09DE9000 + 0x980 = 0x09DE9980。 這是所需的實體位址。

這是先前方法所取得的相同結果。

手動轉換位址

雖然 !ptovpte 延伸模組提供將虛擬位址轉換為實體位址的最快方式,但也可以手動完成此轉換。 此程式的描述將詳細說明虛擬記憶體架構的一些詳細資料。

記憶體結構的大小會根據處理器和硬體組態而有所不同。 此範例取自未啟用實體位址延伸模組的 x86 系統 (PAE) 。

再次使用 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

這會公開虛擬位址的三個部分:

  • 頁面目錄索引 = 0y00000000000 = 0x0

  • 頁面資料表索引 = 0y010010111 = 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 位是 狀態旗標。 在此情況下,這些旗標等於 0x067 -- 或二進位檔 0y000001100111。 如需狀態旗標的說明,請參閱 !pte 參考頁面。

  • PTE 的高 20 位等於 PTE (PFN) 的頁面框架編號 。 在此情況下,PFN 會0x09DE9。

實體頁面上的第一個實體位址是 PFN 乘以0x1000 (左移 12 位) 。 位元組索引是此頁面上的位移。 因此,您要尋找的實體位址是0x09DE9000 + 0x980 = 0x09DE9980。 這是先前方法所取得的相同結果。