將虛擬位址轉換為實體位址
大部分偵錯工具命令都會使用虛擬位址,而非實體位址作為其輸入和輸出。 不過,有時候擁有實體位址可能很有用。
有兩種方式可將虛擬位址轉換成實體位址:使用 !vtop 擴充功能,以及使用 !pte 擴充功能。
如需 Windows 中虛擬位址的概觀,請參閱 虛擬位址空間。
使用 !vtop 轉換位址
假設您正在偵錯執行 MyApp.exe 進程的目的電腦,而且您想要調查虛擬位址0x0012F980。 以下是您要搭配 !vtop 延伸模組來判斷對應實體位址的程式。
使用 !vtop 將虛擬位址轉換為實體位址
請確定您使用的是十六進位。 如有必要,請使用 N 16 命令設定目前的基底。
判斷位址的 位元組索引 。 此數位等於虛擬位址的最低 12 位。 因此,虛擬位址0x0012F980具有位元組索引0x980。
使用!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
判斷目錄基底 的頁面框架編號 。 這只是不含三個尾端十六進位零的目錄基底。 在此範例中,目錄基底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* (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 將虛擬位址轉換為實體位址
請確定您使用的是十六進位。 如有必要,請使用 N 16 命令設定目前的基底。
判斷位址的 位元組索引 。 此數位等於虛擬位址的最低 12 位。 因此,虛擬位址0x0012F980具有位元組索引0x980。
將 進程內容 設定為所需的進程:
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 (PFN) 的頁面框架編號 。 例如,將頁面框架編號乘以0x1000 (,將它向左移 12 位) 。 結果0x09DE9000是頁面開頭的實體位址。
將位元組索引新增至頁面開頭的位址:0x09DE9000 + 0x980 = 0x09DE9980。 這是所需的實體位址。
這是先前方法所取得的相同結果。
手動轉換位址
雖然 !ptov 和 pte 延伸模組提供將虛擬位址轉換為實體位址的最快方式,但也可以手動完成此轉換。 此程式的描述將詳細說明虛擬記憶體架構的一些詳細資料。
記憶體結構的大小會根據處理器和硬體組態而有所不同。 此範例取自未啟用實體位址延伸模組的 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。 這是先前方法所取得的相同結果。