详解Windows内存分页机制
生活随笔
收集整理的這篇文章主要介紹了
详解Windows内存分页机制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
昨天新買了兩本書,?看到了
內存分頁
部分,?特此記錄下,?沒什么技術含量,?錯誤之處還請大牛指點.
大多數現代的操作系統都支持虛存,?這使得系統上的每個程序都擁有自己的地址空間.?每當程序讀取內存時,?都必須指定一個地址.?對于每個進程,?該地址必須轉換為實際的物理內存地址.?
例如,?若我們的MzfHips.exe?程序需要的數據在虛擬內存地址的0x0041FF10處,?則實際的物理地址可能被映射為0x01EE2F10.?
如下圖:
圖1:?虛擬地址轉物理地址示意圖?(圖中的數據僅僅是為了演示)
內存地址的轉換主要通過一個稱為頁表目錄的特殊表來完成.?Intel?x86?CPU將頁表目錄的指針存儲在特殊寄存器CR3中.?該寄存器指向一個包含1024個32位值的數組,?稱為頁目錄.?每個數組元素稱為頁目錄項,?它指定了頁表在物理內存中的基地址,?還通過狀態位指示該頁表當前是否存在于內存中.?從頁表中可以獲得實際的物理地址.
圖2:?在內存中尋找頁面
下面我們來看下虛擬地址的組成:
由圖可知,?虛擬地址的前10位用來定位頁目錄項,?中間10位用來定位頁表項,?最后12位得到具體物理地址的偏移.
到了這里,?我們來總結下具體的步驟:
1.??CPU查詢CR3寄存器以找到頁表目錄的基地址
2.??操作系統根據所請求的虛擬地址的前10位(如圖3),?來定位頁目錄項,?從而在內存中找到相應的頁表.
3.??頁表根據中間的10位定位該頁相應的物理內存首地址
4.??根據虛擬地址的后12位得到具體的物理地址相對于首地址的偏移量.
5.??最后得到的物理地址即包含我們要請求的數據
知道了前面的知識,?下面我們來看下具體的頁目錄項和頁表項中的內容.
由前面我們知道,?CR3寄存器指向頁目錄的首地址,?而頁目錄是由最多1024個可能的頁目錄項組成.
下面我們看下頁目錄項的地址組成:
當訪問頁目錄項時,?要檢查U位(第2位),?若U位為0,?則意味著正在處理的頁表只能用于內核.
還要檢查W位(第1位),?若W位為0,?則內存是只讀的.
頁目錄項指向整個頁表,?即整個頁面集合,?因此,?頁目錄項中的設置應用于整個內存頁范圍.
下面來看下頁表項:
當訪問頁表項時,?仍然首先要檢查U位(第2位),?若U位為0,?則只有內核模式的程序才能夠訪問該內存頁.
還要檢查W位(第1位),?以判斷讀寫訪問權限.
最后還要判斷P位(第0位),?若它設置為0,?則當前內存頁被換出在磁盤上.?若它設置為1,?則內存是常駐,?并且當前是可用的.
在將內存頁換出后,?內存管理器在成功訪問它之前必須將該頁換入內存.
還有最后一個問題就是,?系統上的大多數可執行程序的其實地址都是0x00400000.?多個進程如何能使用同一個虛擬地址,?而不會在物理內存中發生沖突?那是因為系統上的每個進程都維護一個獨立的頁目錄,?都擁有自己私有的CR3寄存器的值.
當線程發生切換時,?舊線程的狀態會被保存起來.?若當前調度運行的線程不屬于剛才的進程,?則當前進程的頁目錄地址會被加載到CR3寄存器中.?頁目錄地址可以在進程的KPROCESS結構中找到.
分析下MmIsAddressValid函數,?加深下對分頁機制的了解.(參考combojiang大叔)
下面是ida?看到的ntoskrnl.exe中導出的MmIsAddressValid。
.text:0040C661?;?BOOLEAN?__stdcall?MmIsAddressValid(PVOID?VirtualAddress)
.text:0040C661?????????????????public?MmIsAddressValid
.text:0040C661?MmIsAddressValid?proc?near??????????????;?CODE?XREF:?sub_40D65E+Cp
.text:0040C661?????????????????????????????????????????;?sub_415459:loc_415470p?...
.text:0040C661
.text:0040C661?VirtualAddress??=?dword?ptr??8
.text:0040C661
.text:0040C661?;?FUNCTION?CHUNK?AT?.text:0041B84E?SIZE?00000007?BYTES
.text:0040C661?;?FUNCTION?CHUNK?AT?.text:0044A4F2?SIZE?00000019?BYTES
.text:0040C661
.text:0040C661?????????????????mov?????edi,?edi
.text:0040C663?????????????????push????ebp
.text:0040C664?????????????????mov?????ebp,?esp
.text:0040C666?????????????????mov?????ecx,?[ebp+VirtualAddress]?;取出虛擬地址
.text:0040C669?????????????????mov?????eax,?ecx
.text:0040C66B?????????????????shr?????eax,?14h????????;?右移20位
.text:0040C66E?????????????????mov?????edx,?0FFCh??????;?取高10位
.text:0040C673?????????????????and?????eax,?edx
.text:0040C675?????????????????sub?????eax,?3FD00000h??;?加上0xc0300000
.text:0040C675?????????????????????????????????????????;?PDE?=?((VA?>>?22)?<<?2?)&?0xffc?+?0xc0300000
.text:0040C67A?????????????????mov?????eax,?[eax]
.text:0040C67C?????????????????test????al,?1???????????;?頁目錄項的第0位,?即P位
.text:0040C67E?????????????????jz??????loc_41B84E
.text:0040C684?????????????????test????al,?al
.text:0040C686?????????????????js??????short?loc_40C6AC?;?判斷page?size位
.text:0040C688?????????????????shr?????ecx,?0Ah????????;?右移10位
.text:0040C68B?????????????????and?????ecx,?3FFFFCh
.text:0040C691?????????????????sub?????ecx,?40000000h
.text:0040C697?????????????????mov?????eax,?ecx????????;?PTE?=?((VA?>>?12)?<<?2?)?&?0x3FFFC?+?0xc0000000
.text:0040C699?????????????????mov?????ecx,?[eax]??????;?ecx?=?PTE?Context
.text:0040C69B?????????????????test????cl,?1???????????;?判斷present位
.text:0040C69E?????????????????jz??????loc_41B84E
.text:0040C6A4?????????????????test????cl,?cl
.text:0040C6A6?????????????????js??????loc_44A4F2??????;?判斷page?size位
.text:0040C6AC
.text:0040C6AC?loc_40C6AC:?????????????????????????????;?CODE?XREF:?MmIsAddressValid+25j
.text:0040C6AC?????????????????????????????????????????;?MmIsAddressValid+3DE9Fj
.text:0040C6AC?????????????????mov?????al,?1
.text:0040C6AE
.text:0040C6AE?loc_40C6AE:?????????????????????????????;?CODE?XREF:?MmIsAddressValid+F1EFj
.text:0040C6AE?????????????????pop?????ebp
.text:0040C6AF?????????????????retn????4
.text:0040C6AF?MmIsAddressValid?endp
.text:0040C6AF
Ps:上面說的理論是在未開啟PAE模式下的一般情況,?在開啟了PAE的情況下,?可能會有所不同。
大多數現代的操作系統都支持虛存,?這使得系統上的每個程序都擁有自己的地址空間.?每當程序讀取內存時,?都必須指定一個地址.?對于每個進程,?該地址必須轉換為實際的物理內存地址.?
例如,?若我們的MzfHips.exe?程序需要的數據在虛擬內存地址的0x0041FF10處,?則實際的物理地址可能被映射為0x01EE2F10.?
如下圖:
圖1:?虛擬地址轉物理地址示意圖?(圖中的數據僅僅是為了演示)
內存地址的轉換主要通過一個稱為頁表目錄的特殊表來完成.?Intel?x86?CPU將頁表目錄的指針存儲在特殊寄存器CR3中.?該寄存器指向一個包含1024個32位值的數組,?稱為頁目錄.?每個數組元素稱為頁目錄項,?它指定了頁表在物理內存中的基地址,?還通過狀態位指示該頁表當前是否存在于內存中.?從頁表中可以獲得實際的物理地址.
圖2:?在內存中尋找頁面
下面我們來看下虛擬地址的組成:
由圖可知,?虛擬地址的前10位用來定位頁目錄項,?中間10位用來定位頁表項,?最后12位得到具體物理地址的偏移.
到了這里,?我們來總結下具體的步驟:
1.??CPU查詢CR3寄存器以找到頁表目錄的基地址
2.??操作系統根據所請求的虛擬地址的前10位(如圖3),?來定位頁目錄項,?從而在內存中找到相應的頁表.
3.??頁表根據中間的10位定位該頁相應的物理內存首地址
4.??根據虛擬地址的后12位得到具體的物理地址相對于首地址的偏移量.
5.??最后得到的物理地址即包含我們要請求的數據
知道了前面的知識,?下面我們來看下具體的頁目錄項和頁表項中的內容.
由前面我們知道,?CR3寄存器指向頁目錄的首地址,?而頁目錄是由最多1024個可能的頁目錄項組成.
下面我們看下頁目錄項的地址組成:
當訪問頁目錄項時,?要檢查U位(第2位),?若U位為0,?則意味著正在處理的頁表只能用于內核.
還要檢查W位(第1位),?若W位為0,?則內存是只讀的.
頁目錄項指向整個頁表,?即整個頁面集合,?因此,?頁目錄項中的設置應用于整個內存頁范圍.
下面來看下頁表項:
當訪問頁表項時,?仍然首先要檢查U位(第2位),?若U位為0,?則只有內核模式的程序才能夠訪問該內存頁.
還要檢查W位(第1位),?以判斷讀寫訪問權限.
最后還要判斷P位(第0位),?若它設置為0,?則當前內存頁被換出在磁盤上.?若它設置為1,?則內存是常駐,?并且當前是可用的.
在將內存頁換出后,?內存管理器在成功訪問它之前必須將該頁換入內存.
還有最后一個問題就是,?系統上的大多數可執行程序的其實地址都是0x00400000.?多個進程如何能使用同一個虛擬地址,?而不會在物理內存中發生沖突?那是因為系統上的每個進程都維護一個獨立的頁目錄,?都擁有自己私有的CR3寄存器的值.
當線程發生切換時,?舊線程的狀態會被保存起來.?若當前調度運行的線程不屬于剛才的進程,?則當前進程的頁目錄地址會被加載到CR3寄存器中.?頁目錄地址可以在進程的KPROCESS結構中找到.
分析下MmIsAddressValid函數,?加深下對分頁機制的了解.(參考combojiang大叔)
下面是ida?看到的ntoskrnl.exe中導出的MmIsAddressValid。
.text:0040C661?;?BOOLEAN?__stdcall?MmIsAddressValid(PVOID?VirtualAddress)
.text:0040C661?????????????????public?MmIsAddressValid
.text:0040C661?MmIsAddressValid?proc?near??????????????;?CODE?XREF:?sub_40D65E+Cp
.text:0040C661?????????????????????????????????????????;?sub_415459:loc_415470p?...
.text:0040C661
.text:0040C661?VirtualAddress??=?dword?ptr??8
.text:0040C661
.text:0040C661?;?FUNCTION?CHUNK?AT?.text:0041B84E?SIZE?00000007?BYTES
.text:0040C661?;?FUNCTION?CHUNK?AT?.text:0044A4F2?SIZE?00000019?BYTES
.text:0040C661
.text:0040C661?????????????????mov?????edi,?edi
.text:0040C663?????????????????push????ebp
.text:0040C664?????????????????mov?????ebp,?esp
.text:0040C666?????????????????mov?????ecx,?[ebp+VirtualAddress]?;取出虛擬地址
.text:0040C669?????????????????mov?????eax,?ecx
.text:0040C66B?????????????????shr?????eax,?14h????????;?右移20位
.text:0040C66E?????????????????mov?????edx,?0FFCh??????;?取高10位
.text:0040C673?????????????????and?????eax,?edx
.text:0040C675?????????????????sub?????eax,?3FD00000h??;?加上0xc0300000
.text:0040C675?????????????????????????????????????????;?PDE?=?((VA?>>?22)?<<?2?)&?0xffc?+?0xc0300000
.text:0040C67A?????????????????mov?????eax,?[eax]
.text:0040C67C?????????????????test????al,?1???????????;?頁目錄項的第0位,?即P位
.text:0040C67E?????????????????jz??????loc_41B84E
.text:0040C684?????????????????test????al,?al
.text:0040C686?????????????????js??????short?loc_40C6AC?;?判斷page?size位
.text:0040C688?????????????????shr?????ecx,?0Ah????????;?右移10位
.text:0040C68B?????????????????and?????ecx,?3FFFFCh
.text:0040C691?????????????????sub?????ecx,?40000000h
.text:0040C697?????????????????mov?????eax,?ecx????????;?PTE?=?((VA?>>?12)?<<?2?)?&?0x3FFFC?+?0xc0000000
.text:0040C699?????????????????mov?????ecx,?[eax]??????;?ecx?=?PTE?Context
.text:0040C69B?????????????????test????cl,?1???????????;?判斷present位
.text:0040C69E?????????????????jz??????loc_41B84E
.text:0040C6A4?????????????????test????cl,?cl
.text:0040C6A6?????????????????js??????loc_44A4F2??????;?判斷page?size位
.text:0040C6AC
.text:0040C6AC?loc_40C6AC:?????????????????????????????;?CODE?XREF:?MmIsAddressValid+25j
.text:0040C6AC?????????????????????????????????????????;?MmIsAddressValid+3DE9Fj
.text:0040C6AC?????????????????mov?????al,?1
.text:0040C6AE
.text:0040C6AE?loc_40C6AE:?????????????????????????????;?CODE?XREF:?MmIsAddressValid+F1EFj
.text:0040C6AE?????????????????pop?????ebp
.text:0040C6AF?????????????????retn????4
.text:0040C6AF?MmIsAddressValid?endp
.text:0040C6AF
Ps:上面說的理論是在未開啟PAE模式下的一般情況,?在開啟了PAE的情況下,?可能會有所不同。
總結
以上是生活随笔為你收集整理的详解Windows内存分页机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 5种IO模式形象的比喻
- 下一篇: Event事件控制