有不少人看到這個标題會說,部落客瘋了,走吧走吧,不看了。學過 C 語言的人都知道,0 位址是不可能被讀寫的。
為了能夠狡辯,我不得不提前把實驗結果貼在下面。

圖1 讀寫空指針
請原諒我,無論你在自己的 VC6.0 執行多少次,你都不會成功,但是我成功了。我确實做了手腳。難道你不想知道嗎?聰明的你也許根本不需要繼續往下讀,就能完成這個功能(如果你真的搞定了前面的分頁知識的話)。
0 位址分析
動手能力強的你,第一件事情是應該按照前面的方法去分析
0x00000000
這個線性位址轉換後的實體頁是多少。不妨我們打開圖1的程式,來看看。
- 在第一行下斷點,讓程式停下
圖2 在這裡下斷
- 中斷到 WinDbg,輸入指令
,找到你的程式,一般是最後一個。我這裡是 demo6.exe。!process 0 0
圖3 中斷到 WinDbg
- 将線性位址 0 轉換為實體位址,發現 PTE 的值是 0,是以這是一個無效線性位址。還記得PDE和PTE屬性嗎?P位為1才能說明實體頁有效。
- 圖4 發現 0 位址是一個無效位址
- 轉換過程可以用下面的圖來表示。我們發一同,PTT 中的第一個頁表項PTE是個空的。
- 圖5 轉換過程
給 0 号頁表的 PTE 挂上實體頁
既然已經找到問題的“症狀”,何不對症下藥?我們把PTT中的第一個面表項手動補上,在這裡安放一個實體頁的索引号,一切不就搞定了嗎?
可是,我怎麼知道哪個實體頁可以用?為了不破壞作業系統,我們可以使用目前程式堆棧所在的實體頁。
- 檢視堆棧所在實體頁
可以在 WinDbg 中輸入指令
g
,讓虛拟機中的 xp 恢複運作。
圖6 檢視寄存器
- 檢視 esp 中的值,為 0x0012ff30
- 圖7 檢視ESP
- 找到 0x0012ff30 是以的實體頁
- 圖8 檢視 0012FF30 線性位址所在的實體頁
- 使用 ed 指令,修改 PTT 的第一項
- 圖9 給 PTT 的第一個頁表項安裝上實體頁 0x05b40
- 修改後的頁目錄、頁表全貌
- 圖10 修改 PTT 中的第一個 PTE
最終,我們讓 0 位址指向的實體頁和堆棧指針 ESP 指向相同的實體頁。從圖10清晰的就可以看到。
修改完成後,回到虛拟機,讓你的程式 go on 吧,記得在 return 0 位置下個斷點,不然程式就跑飛啦。