3.缺页异常
P: 當前頁面是否有效
當CPU訪問一個地址,其PTE的P位為0,此時會產生缺頁異常
缺頁異常Windows每一秒都在發生,Windows使用缺頁異常可以更加有效的使用這個物理頁。
比如你當前有效的物理內存只有2M,在某個地方被使用了就會一直被占用,必須要它釋放我們才能用,這樣的話效率是非常低的。
Windows是只有正在被使用的線性地址才會給你掛上物理頁,如果你的線性地址隔了一段時間沒使用或者當前的物理頁快被占用完了,這時它會將你這些物理頁的數據拿出來存到硬盤上。
右鍵我的電腦 -> 屬性 -> 高級 -> 性能下的設置 -> 高級 ->虛擬內存更改
設置虛擬內存后它會在你的c盤下生成一個pagefile.sys,它的大小剛好是你設置的虛擬內存大小。
當你的物理頁不夠用了,這時系統會將物理頁里的數據放到pagefile.sys這個文件中,再將這個物理頁跟程序使用。
如果我們在某個程序中使用了0x12345678這個線性地址,它的物理頁被存放的pagefile.sys了,如果我門在次使用這個地址就出問題了,這時就需要用到缺頁異常了
無效PTE的4種情況
圖a:位于頁面文件中
當你的線性地址的物理頁被存放到頁面文件(pagefile.sys)中的時候,你的PTE就會變成這樣
CPU訪問了這地址你的p:0,進入缺頁異常處理程序,缺頁異常位于idt表里的E號中斷。
進入缺頁異常處理它會回頭查看你的這個PTE,這時地址時發現你的1-9位,12-31位都是有值的,它就會知道你這個線性地址是有效的,只不過數據放到頁面文件里了
異常處理程序會到pagefile.sys中,按照PTE上描述的頁面文件偏移將頁的數據取出來掛到一個新的物理頁上,將12-31位改為新的物理頁地址,再將p=1
圖b:要求0頁面
頁面尚未分配,下次訪問時請求一個0頁面
圖c:轉移
頁面在物理內存中,但已被轉移到某個物理頁面鏈表中,可以通過查詢_MMPFN數據庫獲取實際情況
圖d:
缺頁異常處理發現你PTE全部為0就會去查VAD,發現這個線性地址已經分配了它會幫你把物理頁掛上,如果這個線性地址沒有分配就會報0xC0000005。(具體看 “保留與提交的誤區” )
保留與提交的誤區
LPVOID VirtualAlloc(LPVOID lpAddress, // 要分配的內存區域的地址DWORD dwSize, // 分配的大小DWORD flAllocationType, // 類型:MEM_RESERVE MEM_COMMITDWORD flProtect // 該內存的初始保護屬性 );MEM_RESERVE:保留線性地址 MEM_COMMIT:提交線性地址 (可以有物理頁,但不是立即有 或一直有) void main() {LPVOID pAddr = VirtualAlloc(NULL, 4096 * 8, MEM_COMMIT, PAGE_READWRITE);printf("%x", pAddr);getchar();*(PDWORD)pAddr = 0x12345678;getchar();getchar(); }
這時PTE的值是空的,說明它現在沒掛物理頁,只有在你使用時才會掛物理頁,下面我按下回車
寫拷貝(EXECUTE_WRITECOPY)
先將PTE的R/W=0,_MMVAD_FLAGS設為EXECUTE_WRITECOPY
當你HOOK一些屬性為EXECUTE_WRITECOPY的模塊時:
如果寫驅動程序將它的PTE.R/W強行修改為1,這樣它就不會觸發缺頁異常,可實現A進程中hook了這個模塊,所有使用這個模塊的進程也會被HOOK。
總結