Windows安全之 應用層(Ring3)的內存管理(一) 進程的虛擬地址空間 與 虛擬內存(頁交換文件), 及物理內存的關係


Windows應用層,有三種內存管理
1. 進程的虛擬地址空間
2. 內存映射文件(Memory-Mapping File)
3. 堆(Heap)


本章節先剖析 WIN32進程的虛擬地址空間

一個進程的虛擬地址空間為 2^系統位數, 如32位就2^32 = 4GB , 代表每個進程擁有4GB的虛擬地址空間

但這4GB是"虛擬的" 不是實質存在, 在我的另一篇文章中寫了WINDOWS是怎麼把虛擬地址跟物理掛勾起來 實現每人也有4gb的虛擬地址空間

而這裡是說我們如何使用??

進程的虛擬地址空間 在Windows中4GB空間被劃分成以下區域



就32位Windows而言
1.1 0x00000000 - 0x0000FFFF 是空指針分區

以下代碼
int *ptr = (int*)malloc(sizeof(int));
*ptr = 5;

這個代表沒有檢測到分配內存空間不成功時侯的情況 , windows系統,針對這種情況 , 劃分這區域, 由於ptr分配失敗的時侯, ptr = NULL , 亦即0x00000000 程序就會拋出異常



1.2 0x00010000 - 0x7FFEFFFF 是用戶模式分區

1.2.1 分配虛擬地址空間 , 粒度與頁面大小限制

用戶模式分區,在32位系統中有2GB空間
當程序被系統加載時, 大部份的虛擬內存都是還沒跟物理內存掛勾起來的,或說閒置(free)的,我們必須調用VirtualAlloc函數分配區域,分配的動作稱為預訂(Reserving)
當程序預訂地址時,會確保區域的起始地址正好是分配粒度的整倍數, 大部份CPU 分配粒度也是64kb 也就是說, 分配一個區域時系統會分配的地址是64KB的整數倍
而區域的大小為頁面大小4KB

有時侯系統會以應用程序的名義來預訂區域, 例如系統會分配一塊空間用來存放系統環境塊(Process Environment Block(PEB)), PEB是一個完全由系統創建的內存塊, 當系統創建進程時, 同時都會替他在他的虛擬內存中,預訂一塊區域,存放PEB, 管理所有進程信息

系統同時會創建線程環境塊(Thread Environemnt Block(TEB))來協助管理所有線程, 系統會在創建線程時為TEB預訂區域, 並在銷毀時釋放該內存區域

雖然系統限定分配區域的首地址一定要為64KB的整數倍, 但由系統所分配的內存則不用跟隨規則 , 但分配區域為頁的大小(4kb) 還是必要的。

如應用程序 試圖預訂一塊10KB大小的空間區域, 那麼系統會自動將請求取整到頁面大小的整數倍,然後用取整後的大小預訂區域 , 意味著會取12KB大小的空間

使用VirtualFree函數完成釋放內存

1.2.2 區域調撥內存

為了使用一塊預訂好的內存區域, 我們必須給他對應到映射到相應的物理地址, 這個過程稱為調撥(Committing)

1.2.3 物理存儲器 與 頁交換文件
舊式操作系統,只有實際內存總量供電腦使用, 換句話說電腦有16MB的內存, 就所有程序共享這16MB內存, 現今的操作系統已經能讓磁盤看起來像內存一樣
硬盤上的文件,稱為頁交換文件,其中包含虛擬內存供任何進程使用

實際上我們使用VirtualAlloc分配區域時, 系統會以硬盤作為物理存儲器, 亦即是在硬盤上分配內存, 而在磁盤上的文件,就稱為頁交換文件(Paging File), 即虛擬內存。

當線程試圖訪問一個字節時, CPU必須知道字節是在硬盤還是內存中,

第一種情況,
1. 要訪問的數據已經存在於物理內存中,
2. 之後CPU會把進程中訪問該數據的虛擬地址(實際要執行的指令地址)映射到物理內存,
3. 接下來就可以訪問內存中的數據了

第二種情況,
1. 要訪問的數據,不在物理內存中,發生頁面訪問異常
2. 而是CPU查找是否在頁交換文件中的某處
3. 如果存在, 需要查找物理內存中是否有閒置頁面 ,如找不到,系統要立刻釋放一個已分配的頁面,
4. 被釋放的頁面的內容如在釋放前已經被修改, 那就必須複製到頁交換文件中
5. 最後系統定位頁交換文件的位置, 最後寫入閒置頁面
6. 最後映射指令的虛擬地址到物理內存,執行並訪問寫入內存後的數據

這就是一個Page file 與 物理內存 交換的過程

1.2.4 每個頁面的保護屬性



ps 頁面的保護屬性,一些惡意軟件將代碼寫入到用於數據的內存區域,(如線程棧), 通過謝種方式可以讓應用程序執行惡意代碼, Windows的Data Execution Protection, DEP, 為解決這問題而出現了 如執行某頁面時 , 而該頁面又沒有 PAGE_EXECUTE_*保護屬性 那CPU就拋出訪問異常

1.2.5 寫時複製

在以上圖片中, 有一個頁面屬性為 PAGE_WRITECOPY 及PAGE_EXECUTE_WRITECOPY ,
1. Windows允許兩個或以上進程同時使用同一個後備存備器(頁交換文件), 因此打開十個notepad時, 所有的進程都是共用一塊代碼頁及數據頁, 為防止寫入數據頁面時, 影響其他運行中的進程, 所以有寫時複製機制,
2. 系統把一個.exe/.dll 映射到一個虛擬地址空間中, 系統會計算這個PE文件有多少頁是可寫的, 然後就會在頁交換文件(硬盤)分配一樣空間,
3. 當一線程試圖寫入共享頁面後, 系統會在剛剛分配的頁交換文件空間中找到一個閒置頁面,把想要修改的頁面內容寫到此閒置頁面 , 屬性設為PAGE_READWRITE / PAGE_EXECUTE_READWRITE, 系統不會修改本身頁面的頁面保護屬性
4. 然後更新進程的頁面表, 指向該新頁面, 而本來的頁面就被修改了


最後 虛擬地址空間的架構可描述為 -> 區域(如PE映象文件) -> 塊(如.data塊)-> 頁

虛擬地址空間, 虛擬內存, 物理內存 是3種不同的概念, 需要區分開
以下是虛擬內存,物理內存,虛擬地址空間的一個總結:


最後補充, 虛擬地址空間 0x7FFEFFFF - 0x7FFFFFFF 是64KB禁入分區

Comments

Popular posts from this blog

Android Kernel Development - Kernel compilation and Hello World

How does Nested-Virtualization works?

Understanding ACPI and Device Tree