保護模式篇之PAE分頁,詳細介紹 2-9-9-12 分頁
此系列是本人一個字一個字碼出來的,包括示例和實驗截圖。由于系統核心的複雜性,故可能有錯誤或者不全面的地方,如有錯誤,歡迎批評指正,本教程将會長期更新。 如有好的建議,歡迎回報。碼字不易,如果本篇文章有幫助你的,如有閑錢,可以打賞支援我的創作。如想轉載,請把我的轉載資訊附在文章後面,并聲明我的個人資訊和本人部落格位址即可,但必須事先通知我。
你如果是從中間插過來看的,請仔細閱讀 羽夏看Win系統核心——簡述 ,友善學習本教程。
看此教程之前,問幾個問題,基礎知識儲備好了嗎?上一節教程學會了嗎?上一節課的練習做了嗎?沒有的話就不要繼續了。
🔒 華麗的分割線 🔒
本次答案均為參考,可以與我的答案不一緻,但必須成功通過。
1️⃣ 拆兩個程序的<code>4GB</code>實體頁。
🔒 點選檢視答案 🔒
自己拆吧,也不是真讓你把所有的都拆了。這玩意建議還是寫個驅動來進行拆解。不過我的教程沒寫,之後才會講解。故拆幾個比較有特點的就行了,之後學了驅動後可以回來再把這道題給完整地做了。
首先讨論我們怎麼拆,一個實體頁有<code>4KB</code>的大小,如果線性位址在同一個實體頁,那麼它的高20位一定是相同的。故如果完整的拆完,我們需要拆<code>0x1000 * n</code>線性位址。怎麼拆已經給你說明白了。
需要拆解的線性位址類型:0x0 - 0x10000 和 0x10000 - 0x7FFFFFFF 和 高2G三部分,每個部分拆解2-3個即可。這裡就不拆了。
2️⃣ 定義一個隻讀類型的變量,再另一個線性位址指向相同的實體頁,通過修改<code>PDE</code>/<code>PTE</code>屬性,實作可寫。
這題目說實話還是有一些坑,主要是獨自編寫驗證代碼上。可以點選下方“檢視代碼”進行檢視。
首先運作我們的代碼,報記憶體通路錯誤,這個是正常現象,因為它在所謂的常量區。

先讓它跑起來,看到常量所在的線性位址,如下圖所示:
然後我們拆分線性位址,為了圖省事,可以用電腦或者自己寫個工具。如下圖所示:
然後轉到<code>WinDbg</code>中,找到它的程序結構體,找到<code>CR3</code>:
根據<code>10-10-12</code>分頁結構進行檢視,最終看到如下圖所示結果:
最後發現是因<code>PTE</code>屬性限制導緻資料無法修改,故用<code>!ed 41795088 410e4027</code>修改它,使它具有可寫屬性。
然後我們就能成功的通路常量隻讀位址了:
🔒 點選檢視代碼 🔒
3️⃣ 分析<code>0x8043F00C</code>線性位址的<code>PDE</code>屬性。
在虛拟機打開一個<code>notepad</code>程序,然後轉到<code>Windbg</code>暫停虛拟機找到它的<code>CR3</code>(我的是<code>0x1b262000</code>)。然後輸入<code>!dd 1b262000+0x201*4</code>找到該線性位址對應的<code>PDE</code>,值為<code>004001e3</code>,故該<code>PDE</code>為一個大頁,有效可寫,并為僅超級使用者可用,是全局的,且被通路過和寫過。
4️⃣ 修改一個高2G線性位址的<code>PDE</code>/<code>PTE</code>屬性,實作<code>Ring3</code>可讀。
既然是做了第三題了,那我們直接拿第三題給的線性位址開刀好了。首先必須在合适的地方下斷點,運作我們的代碼,擷取的<code>CR3</code>是<code>4a818000</code>,故<code>!dd 4a818000+0x201*4</code>得到<code>PDE</code>後值為<code>004001e3</code>,但為了更好的實驗,故把它指向的實體頁的偏移的值改為<code>0x1234</code>。那麼如何改呢?這個是個大頁,故後<code>22</code>位直接是實體頁的偏移。故<code>!ed 0043F00C 1234</code>即可。
然後我們繼續進行檢驗,如下圖所示:
<code>4660</code>就是16進制的<code>0x1234</code>,故實驗成功。
5️⃣在<code>0</code>線性位址挂上實體頁并執行<code>shellcode</code>調用<code>MessageBox</code>。
這道題還是有一點坑,不過坑不太深,自己能跳出來。代碼我提供了且有注釋,自己打開看看。
通過檢視<code>0 位址</code>不能通路是因為沒有正确的<code>PTE</code>,如果挂上正确的<code>PTE</code>,那麼這個位址就可以通路了。那我們開始用代碼進行試驗。首先在合适的地方下斷點,運作我們的代碼,擷取的<code>CR3</code>是<code>3daa3000</code>,且申請的一個實體頁的位址是<code>0x3D0000</code>。故按照分頁模式找到實體頁的<code>PTE</code>,值為<code>3db54067</code>。然後把它填到<code>0 位址</code>的地方。
我們成功彈出了一個資訊框,故實驗成功。
6️⃣ 逆向分析<code>MmIsAddressValid</code>函數。
本題目主要目的是為了如何查詢<code>PDE</code>和<code>PTE</code>。逆向參考結果如下:
<code>PAE</code>分頁是啥,其實他就是<code>2-9-9-12</code>分頁的英文縮寫。為什麼要有<code>2-9-9-12</code>分頁,其實還是實體頁不夠用了,需要擴充。但想要足夠的實體頁,位數在那裡,你想大也大不了。那麼我就需要擴充實體頁位址的位數,于是乎<code>2-9-9-12</code>分頁誕生了,它整體分頁的結構如下:
與<code>10-10-12</code>分頁不同的地方就是,多了一層名為<code>頁目錄指針表</code>的東西,英文縮寫為<code>PDPTT</code>。每個<code>PDE</code>和<code>PTE</code>被擴充為8個位元組,實體位址描述的位數擴充為<code>24位</code>,故可以描述更多的實體頁,但個數減半,變成了512個。下面詳細檢視它們的結構。
首先看<code>PDPTT</code>的結構。由<code>2-9-9-12</code>的<code>2</code>可知第一部分由兩位二進制組成,那麼最多有4種結果。也就是為什麼有五個成員,它的結構如下圖所示:
然後是<code>PDE</code>,既然學過了<code>10-10-12</code>分頁,直接看下面的結構示意圖吧:
非大頁
大頁
然後是<code>PTE</code>,同理不多說了:
我們之前做一道作業題目知道,我寫的<code>shellcode</code>寫到一個頁上,它并沒有執行權限,但它不是代碼,仍然可以被我執行。為了彌補這個漏洞,<code>Intel</code>給我們補了一個硬體層面上的漏洞,它是一個位,處于<code>PDE</code>和<code>PTE</code>的最高位,如下圖所示:
如果最高位是<code>1</code>,說明被保護。如果這個是資料,且這個<code>X</code>位被置為<code>1</code>,則會被報出異常不能執行。反之,和正常的<code>10-10-12</code>分頁沒什麼兩樣。
一個程序的線性位址仍是<code>4GB</code>的線性空間,有再多的實體頁有啥用呢?在<code>10-10-12</code>分頁下,假設程序一啟動,就把所有的實體頁都挂上,且沒有任何交換。那麼隻能啟動一個;如果在<code>2-9-9-12</code>分頁下,同樣的情況,它可以啟動4個程序。這個就是<code>2-9-9-12</code>分頁的意義。
<code>Windows</code>也提供了基于硬體層面<code>X位</code>的保護,如下圖所示:
可以看出你自己寫的普通程式壓根和這個位無緣,但是還以啟用的。但是有些打開之後發現提出不支援基于硬體的保護,那是因為虛拟機沒開這個選項,如下圖所示,轉中如下圖選項即可:
由于本節内容和<code>10-10-12</code>分頁相似,答案不會提供,自己實作,務必把本節練習做完後看下一個講解内容。不要偷懶,實驗是學習本教程的捷徑。
俗話說得好,光說不練假把式,如下是本節相關的練習。如果練習沒做好,就不要看下一節教程了,越到後面,不做練習的話容易夾生了,開始還明白,後來就真的一點都不明白了。本節練習比較多,請保質保量的完成。
1️⃣ 定義一個隻讀類型的變量,再另一個線性位址指向相同的實體頁,通過修改<code>PDE</code>/<code>PTE</code>屬性,實作可寫。
2️⃣ 自己實驗有和沒有<code>DEP</code>保護的程式,看看效果。(本題将在下一篇提供參考)
3️⃣ 修改一個高2G線性位址的<code>PDE</code>/<code>PTE</code>屬性,實作<code>Ring3</code>可讀。
4️⃣ 在<code>0</code>線性位址挂上實體頁并執行<code>shellcode</code>調用<code>MessageBox</code>。
5️⃣ 逆向分析<code>MmIsAddressValid</code>函數。
保護模式篇——TLB與CPU緩存
本作品采用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協定 進行許可
本文來自部落格園,作者:寂靜的羽夏 ,一個熱愛計算機技術的菜鳥
轉載請注明原文連結:https://www.cnblogs.com/wingsummer/p/15364648.html