大多數調試器命令的輸入參數和輸出結果使用虛擬地址,而不使用物理地址。不過,有時候可能用得上物理地址。
有兩個方法將一個虛擬地址轉換成一個物理地址:使用 !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。這跟以上方法獲得的結果相同。
將虛擬地址轉換成物理地址
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.