引子:
一直在研究惡意代碼方向與逆向軟件方向,面試聊了windows內核與保護模式相關知識,有不少沒有回答上來,確實研究過相關資料,可是沒有深刻研究,加上長時間沒有複習,有些遺忘了
基本功不紮實,畢竟很久沒寫過驅動編程與複習內核/保護模式相關的知識,因此靜下心來複習一下吧。
4GB的虛擬內存結構:面試
虛擬內存地址範圍 | 描述 |
---|---|
0x00000000~0x0000FFFF | 64kb大小的空指針區域,固然就不能夠訪問了 |
0x00001000~0x7FFFFFFF | 加上上述的空指針區域,低2GB的用戶態空間 |
0x80000000~0xFFFFFFFF | 高2GB的內核態空間 |
更多的詳細劃分請參考這篇博客:https://blog.csdn.net/wang010366/article/details/52730052編程
一個進程地址如何映射到物理地址的?
圖片一:映射關係
上述圖片只是片面的闡釋,一個虛擬內存地址經過頁錶轉換,映射到物理內存地址,多個進程其實都是經過這種機制映射到物理內存。
圖片二:地址映射過程
圖片二是虛擬地址映射,注意:缺乏了分頁的層級,頁表中每一項都是一個分頁。映射的物理地址過程如何實現的?先介紹Cr0系列的控制寄存器,面試的時候忘的一乾二淨,那就在學一遍:小程序
寄存器名稱 | 描述 |
---|---|
CR0 | 包含處理器標誌控制位,如PE,PG,WP等 |
CR1 | 保留 |
CR2 | 專門用於保存缺頁異常時的線性地址 |
CR3 | 保存進程頁目錄地址 |
CR4 | 擴展功能(如判斷物理地址擴展模式等),Pentium系列(包括486的後期版本)處理器中才實現 |
圖片三:控制寄存器windows
➀什麼是PE,PG,WP呢?
一、PE:CR0寄存器的第0位,Protection Enable,啓用保護標誌。若是該位爲1,開啓了保護模式,反之關閉,當開啓保護模式的時候PE\PG都會置位。
二、PG:CR0寄存器的第31位,Paging,分頁標誌位。若是爲1則開啓分頁機制,禁止分頁的話線性地址等同於物理地址,若開啓標誌位意味着須要開啓保護模式。
三、WP:CR0寄存器的第16位,Write Proctect,寫保護標誌。WP==1的時候意味着只讀頁面不可執行寫操做,wp==0的時候意味着只讀頁面可執行寫操做。
➁CR3寄存器保存了每一個進程的頁目錄地址,什麼叫作頁目錄呢?
Windows下開啓保護模式與分頁機制後,當前CR0寄存器的屬性PE == 1 AND PG == 1,意味着進程中的虛擬地址將經過頁錶轉換映射相對應的物理地址上,如圖二所示,咱們手工的獲取來學習:
首先介紹一下分頁機制其中一種記錄方式:數組
非物理地址擴展模式 | 物理地址擴展模式 |
---|---|
非PAE模式 | PAE模式 |
PAE模式:Physical address extension,物理擴展模式。可以在32位操做系統訪問超過4GB尋址大小的模式,容許將最多64GB 的物理內存用做常規的4 KB 頁面,並擴展內核能使用的位數以將物理內存地址從32擴展到36。
非PAE模式:在非物理擴展模式下,32位最大隻能4GB因此,即便你有8G的內存條,也是白費。
那麼在非PAE模式下,操做系統分頁機制如何實現的?每一個分頁4kb,一共4GB的內存,4194304KB大小也就是一共1048576個分頁,那麼如何高效的管理這些分頁呢?
1024(PDT) × 1024(PTT) × 4096 = 4GB
1024(PTT) × 1024(PTE) × 4 = 4MB
1024(PDT) ×1024(PTE) = 1MB
如上述公式所示,就是經過這種方式來管理4GB的內存分頁,PDT,PTT,PTE又是什麼,以下所示數據結構
名稱 | 描述 |
---|---|
頁目錄索引表(PDT) | 一級索引 |
頁表索引表(PTT) | 二級索引 |
頁表項(PTE) | 頁表項 PDT(1024項PDE),PTT(1024項PTE) |
圖片四:地址解析ide
須要配合圖二一塊兒理解,操做系統會經過CR3寄存器獲取當前進程的頁表目錄地址,而後根據虛擬地址拆分爲10,10,12比例,找到頁目錄,找到頁表,而後找到分頁加上對應的偏移(物理內存),爲了方便理解,固然也是動手寫個小程序,在windbg下一探究竟。學習
➀編寫測試代碼,以下所示:測試
int main() { printf("虛擬地址:0x%X\n", "hello world"); cout << "hello world" << endl; system("pause"); }
➁編譯後拖入虛擬機,開啓雙擊調試(測試環境win7 32位),運行測試程序(不要關閉回車),windbg下輸入!process 0 0查看所有進程及各部分說明,以下所示:
圖片五:雙擊調試
➂上述進程說明中咱們看到DirBase地址,這個就是當前進程指向的頁目錄,咱們看看到底對不對?須要明確的字段PROCESS 0x86ca5c18是EPROCESS的地址,輸入指令dt 0x86ca5c18 _EPROCESS來看一看,以下所示:
操作系統
圖片六:EPROCESS
➃一個進程的頁目錄怎樣找?在CreateProcess的第二個階段,會初始化進程的執行體層EPROCESS數據結構與微內核層KPROCESS數據結構,系統DLL映像目標用戶空間且初始化PEB操等等,來看_KPROCESS結構+0x18字段是什麼?以下所示:
圖片七:DirectoryTableBase
➄經過上述_KPROCESS獲取了PDT的地址,與解析出來PDT數據同樣的。每當CPU切片執行進程時候,CR3就會被系統切換,CR3是否是讀取當前進程DirectoryTableBase字段做爲切換數值有待研究,看一看PDT也就是頁錶轉換的第一層結構,以下所示:
圖片八:虛擬地址
➅解釋兩個dd,由於這個之前也老是被同窗問起,dd怎麼啥東西都找不到,在windbg命令下,d系列命令只能查看虛擬地址, 查看物理地址須要使用!d系列命令,PDT是物理地址,以下所示:
圖片九:物理地址
➆根據上述一些理論性知識,如圖九中所展現的每項即是頁表地址(物理地址),根據虛擬地址,測試是否能經過頁錶轉換找到映射的物理存儲數據,因此第二步中沒輸出字符串虛擬地址(圖是昨天的),從新來一下(已經關閉了隨機基址),以下所示:
圖片十:輸出字符串在虛擬內存地址
➇根據圖片四把上述的虛擬地址進行分割,以下所示:
圖片十一:虛擬地址轉換
➈對應的二進制換算16進制 (1 <--> 19 <--> B30),其中1表明是頁目錄表中的第一項,查看頁目錄表以前須要對地址頁目錄的PTE瞭解,以下所示:
➉如上圖所示,低12位是屬性,高位是地址, 而後頁表索引是19,數組元素是保存的指針,須要乘以4字節,以下所示:
圖片十二:頁表查找
⑪怎麼什麼都沒有,還記着咱們上述說過,這一臺記錄方式PAE與非PAE,咱們如今所處的環境到底是怎樣,咱們打開cmd,利用bcdedit命令,先作了解以下所示:
圖片十三:bcdedit
⑫修改當前pae模式以及nx模式,pae咱們知道是物理擴展模式,nx是緩解機制,使某些內存區域不可執行,並使可執行區域不可寫DEP,咱們也要改成Always Off模式,以下所示:
修改指令以下:
名稱 | 關閉指令 | 開啓指令 |
---|---|---|
PAE | bcdedit /set pae ForceDisable | bcdedir /set forceEnable |
NX | bcdedit /set nx AlwaysOff | bcdedit /set nx OptIn |
修改後屬性以下:
圖片十四:屬性調整
⑬重啓系統後,再次按照上述步驟查找具體的分頁數據,以下所示:
圖片十五:非PAE下目錄表
⑭那麼解析虛擬地址以後,如何經過也目錄找到具體頁表呢?咱們須要瞭解一下頁目錄中的每一項PDE數據,也就是指針如何分解的,以下所示:
圖片十六:頁表地址解析
⑮經過上圖所示,咱們知道低位12位是屬性,高位纔是地址,意味着咱們只須要BaseAddress + 第幾項PTT × 4(指針大小)就能夠找到相對的頁表指針,以下所示:
圖片十七:頁表
⑯找到了具體的頁表地址,也就是0x342f6025,加上具體的偏移(虛擬地址分解出的低12位)就能夠找到映射的物理內存數據保存,固然地址仍是要把地位屬性去掉,用地址+偏移便可,以下所示:
圖片十八:物理內存
整個過程解析了虛擬地址將一個地址如何映射到物理內存,他們之間的存在的轉換映射關係,固然省略不少機制內部機制。片面的理解保護模式下分頁的重要性,咱們跟多層面去學習研究虛擬內存與物理內存關係。