WinDbg示範IA-32 CPU下的Windows 分頁機制下的地址轉換過程

來源:互聯網
上載者:User

 今天在學習《軟體調試》的時候,練習虛擬位址轉物理地址的時候遇到了一個問題。用windbg本地調試核心功能時,!dd無法使用

用windbg命令dd的時候出現了以下錯誤:

kd> !dd 0b3c03c0
Physical memory read at b3c03c0 failed
If you know the caching attributes used for the memory,
try specifying [c], [uc] or [wc], as in !dd [c] .
WARNING: Incorrect use of these flags will cause unpredictable
processor corruption. This may immediately (or at any time in
the future until reboot) result in a system hang, incorrect data
being displayed or other strange crashes and corruption.

在網上查詢以後初步估計是360的問題,但是不想卸載,所以在VM裡邊嘗試,dd沒問題了,但是新的問題出來了,在索引頁表地址的時候,得到的頁表地址始終為0,後來想想是不是虛擬機器的原因,估計什麼地方和真是的電腦環境不一樣。沒辦法還是在XP系統中進行,刪除360殺毒,DD命令還是出錯,再刪除360安全衛士,windbg正常了,可以正常使用DD命令了,電腦系統博大精深,什麼地方造成的衝突不得而知,希望不久的將來能夠知曉。以下是本次實驗的過程,寫得很詳細所以直接轉載了。

===========以下為轉載=================

我們知道,從386開始,IA-32 CPU開始支援Paging。在啟用Paging之後,OS將線性地址空間劃分為固定大小的Page(通常為4KB或4MB)。

本文示範了如何通過WinDbg展示windows paging中的virtual address 向physical address轉換過程。 

在現代OS中,涉及到Paging的幾個概念如下(以32-bit IA CPU&Microsoft Windows OS為例): 

Page Directory (頁目錄):

Page Directory 是用來存放Page-Directory Entry(PDE)(頁目錄表項)的線性表。每個頁目錄佔一個4kb的記憶體頁(page),PD中的每個PDE長度為32Bit(其中高20bit為PDE所指向的頁表的起始地址,低12bit為該PDE的屬性)。因此每個PD中最多包含1024個PDE。

對於記憶體頁大小為4KB的頁目錄位址格式:

      其實際上只有高20Bit有用,其低12bit固定為0 

對於記憶體頁大小為4MB的頁目錄位址格式:

      其實際上只有高10Bit有用,其低12bit固定為0 

其高20(10)為該頁目錄的起始地址。

Page Table (頁表)

Page Table是用來存在頁表項(Page Table Entry, PTE)的線性表。同樣,每個PT佔用一個記憶體頁,每個PTE的長度為32bit(其中高20bit為PT所指向的物理頁的起始地址,低12bit為該物理頁的屬性),故每個PT中最多可以包含1024個PTE 

Virtual Address(虛地址)

對於一個32bit的virtual address,其格式如下所示:

 

其中高10bit為Page Directory中的index項,中間10Bit為Page Table的index項,最低12bit為頁內位移地址。  

從virtual address向physical address轉換的過程如下:

Step1:

通過CR3寄存器定位到頁目錄的起始位置(DirBase),故CR3 Regesiter又稱為頁目錄基地址寄存器

Step2:

取virtual address的高10bit作為index,在PD中尋找相應的PDE.

Step3:

根據PDE中的頁表基地址(即PDE的高20bit)定位到Page Table(頁表)

Step4:

取virtual address中第10-21bit作為索引,選取頁表中的一個PTE(頁表項)

Step5:

取PTE中的記憶體頁表基地址(高20bit)+ virtual address中的低12位offset,即可以得到實際的physical
address 了。

圖示如下:

 下面用windbg展示地址轉換過程

以windows計算機(calc.exe)為例

1.開啟calc.exe,輸入數字,如123456, 然後在user mode下開始調試calc.exe

0:002> x calc!g*
01014f08 calc!ghwndTimeOutDlg = <no type information>
01014d9c calc!g_fHighContrast = <no type information>
0100514d calc!GetKeyColor = <no type information>
01014ef8 calc!gfExiting = <no type information>
0100518d calc!GetHelpID = <no type information>
01014c70 calc!ghnoPrecNum = <no type information>
01014c08 calc!ghnoParNum = <no type information>
01014038 calc!gszSep = <no type information>
01014eec calc!ghcurOld = <no type information>
01014d38 calc!g_ahnoChopNumbers = <no type information>
01014f00 calc!ghCalcDone = <no type information>
01014db0 calc!gpszNum = <no type information>
01014f0c calc!gnPendingError = <no type information>
01014000 calc!gnDecGrouping = <no type information>
01014dc0 calc!gcio = <no type information>
01014d98 calc!ghnoLastNum = <no type information>
01014f04 calc!ghDogThread = <no type information>
01014d80 calc!g_hDecMenu = <no type information>
01014f48 calc!gbinexact = <no type information>
01014d7c calc!g_hHexMenu = <no type information>
01014efc calc!ghCalcStart = <no type information>
01014da0 calc!g_fLayoutRTL = <no type information>
01014db8 calc!gbRecord = <no type information>
010149d8 calc!gcIntDigits = <no type information>
01014d6c calc!g_hwndDlg = <no type information>
01014d4c calc!gbUseSep = <no type information>
01014d94 calc!ghnoMem = <no type information>
010044b4 calc!GroupDigits = <no type information>
01014f4c calc!gllfact = <no type information>
01014d90 calc!ghnoNum = <no type information>
01014064 calc!gldPrevious = <no type information>

0:002> dd 01014db0
01014db0  000b2ee0 00000000 00000001 00000000
01014dc0  00000000 ffffffff 00000000 00000000
01014dd0  00000006 00320031 00340033 00360035
01014de0  00000000 00000000 00000000 00000000
01014df0  00000000 00000000 00000000 00000000
01014e00  00000000 00000000 00000000 00000000
01014e10  00000000 00000000 00000000 00000000
01014e20  00000000 00000000 00000000 00000000

我們可以看看000b2ee0附近 連續記憶體空間裡面的內容:

0:002> dd 000b2ee0
000b2ee0  00320031 00340033 00360035 0000002e
000b2ef0  00030025 0008013d 000b3060 000b2f14
000b2f00  00000000 00000000 00000000 00000000
000b2f10  00000000 5443534d 614d2e46 61687372
000b2f20  746e496c 61667265 462e6563 4d656c69
000b2f30  412e7061 462e4c4d 4545482e 00464945
000b2f40  00000000 00000000 00000000 00000000
000b2f50  00000000 00000000 00000000 00000000

輸入字串變數的地址就在000b2ee0記憶體裡面
0:002> du 000b2ee0
000b2ee0  "123456."

該地址000b2ee0 裡面存放的正是我們所輸入的數字:123456。而000b2ee0  為 virtual address。那麼其physical address 到底是什麼呢?根據前面的介紹,一個32bit的virtual address由3部分組成,我們可以具體看看每一部分的值

0:002> .formats 000b2ee0
Evaluate expression:
  Hex:     000b2ee0
  Decimal: 732896
  Octal:   00002627340
  Binary:  00000000 00001011 00101110 11100000
  Chars:   ....
  Time:    Fri Jan 09 03:34:56 1970
  Float:   low 1.02701e-039 high 0
  Double:  3.62099e-318

由以上可以看出,其PDE index為高10 :0, PTE index(中間10bit): B2, 頁內位移地址:EE0

下面找出該虛地址的absolute address

再啟動一個kernal model debug -> local

lkd> !process 0 0

......

PROCESS 85185288  SessionId: 0  Cid: 0b8c    Peb: 7ffde000  ParentCid: 021c
    DirBase: 1d386000  ObjectTable: e1ff17e0  HandleCount: 187.
    Image: dllhost.exe

PROCESS 84f10da0  SessionId: 0  Cid: 049c    Peb: 7ffde000  ParentCid: 0508
    DirBase: 093ee000  ObjectTable: e2ace720  HandleCount:  49.
    Image: calc.exe

PROCESS 847e6220  SessionId: 0  Cid: 0840    Peb: 7ffde000  ParentCid: 02c4
    DirBase: 15297000  ObjectTable: e2b1fe30  HandleCount: 161.
    Image: msmsgs.exe

其中DirBase所指向的地址高20位 即為該進程calc.exe的頁目錄基地址:093ee000(低12固定為0)

下面來看PD中具體的PDE

lkd> !dd 093ee000  (顯示指定地址的頁目錄表項內容)
# 93ee000 093fb067 0c765067 1803b067 00000000
# 93ee010 14240067 00000000 00000000 00000000
# 93ee020 00000000 00000000 00000000 00000000
# 93ee030 00000000 00000000 00000000 00000000
# 93ee040 00000000 00000000 00000000 00000000
# 93ee050 00000000 00000000 00000000 00000000
# 93ee060 00000000 00000000 00000000 00000000
# 93ee070 00000000 00000000 00000000 00000000
根據virtual address中的 PDE index:0, 故其在PD中尋找PDT的index為0, 即為第1個PDE :093fb067 。

在該093fb067 地址裡面, 其高20bit (即093fb000)為其page table(頁表)起始地址,低12bit為頁表屬性,至於每個Bit代表什麼屬性,在此不作贅述。

頁表起始地址 + 頁表項在頁表內的索引,即可以得到該PTE的物理地址。從以上我們已經知道,該virtual address在PT中的索引值為B2,故PTE的地址為:

093fb000 + B2*4 (因為每個表項佔4個byte)

lkd> !dd 093fb000 + B2 * 4
# 93fb2c8 105eb067 148ec886 18aed886 0dcee886
# 93fb2d8 00000080 00000000 00000000 00000000
# 93fb2e8 00000000 00000000 00000000 00000000
# 93fb2f8 00000000 00000000 00000000 00000000
# 93fb308 00000000 00000000 00000000 00000000
# 93fb318 00000000 00000000 00000000 00000000
# 93fb328 00000000 00000000 00000000 00000000
# 93fb338 00000000 00000000 00000000 00000000

可以得到該地址內的PTE地址為105eb067 ,而該地址的高20bit( 105eb000 )為所在實體記憶體頁的起始地址,低12bit為記憶體頁屬性。

得到該物理頁的起始地址後 + virtual address的offset,即可得到其物理地址

即105eb000 + EE0 =105ebee0

下面我們看看該地址內的內容是什麼:

lkd> !dd 105ebee0
#105ebee0 00320031 00340033 00360035 0000002e
#105ebef0 00030025 0008013d 000b3060 000b2f14
#105ebf00 00000000 00000000 00000000 00000000
#105ebf10 00000000 5443534d 614d2e46 61687372
#105ebf20 746e496c 61667265 462e6563 4d656c69
#105ebf30 412e7061 462e4c4d 4545482e 00464945
#105ebf40 00000000 00000000 00000000 00000000
#105ebf50 00000000 00000000 00000000 00000000

lkd> !du 105ebee0
#105ebee0 "123456."

比對user mode下的dd 000b2ee0 ,我們可以看到, 其內容是完全相同的。

也就是說我們找到了virtual address : 000b2ee0 的準確物理地址:105ebee0。

只不過我們在user mode下使用dd時,這個轉換過程自動完成了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.