本文實驗的例子來自《windows進階調試》第6.2.2節,參考書中的方法進行。
1.通過windbg分析堆塊
(1)在指令行運作程式,輸入參數(輸入超過10個字元),在出現如下提示的時候,使用windbg attach到該程序。
(2)按任意鍵繼續執行,執行完後,程式崩潰到windbg,使用kb指令檢視堆棧如下:
(3)我們看到報的堆棧資訊是在HeapFree函數中,其實我們知道原因是wcscpy函數溢出了,但崩潰點卻不在溢出發生的地方,堆破壞的最大問題在于造成錯誤的代碼無法在發生堆破壞時被發現,我們可以通過檢視目前堆的一些情況進行分析。
(4)檢視預設堆的詳細情況,由于資訊比較多,我僅僅把最後一部分列印出來。
(5) 我們看到最後一個堆塊是有問題的,可以看下該堆的内容,我們從004e5188位址開始列印。
(6)我們看到了一系列的0x31字元,就是我們參數輸入的“1”,我們可以用du指令再列印下:
(7)果然是我們輸入的參數,而且參數越過了堆塊004e51a8,我們把該堆塊的頭列印出來:
發現堆塊的頭全都被我們輸入的參數覆寫了,這就導緻了記憶體通路異常。
2.通過windbg+普通頁堆分析
上面的程式很簡單,很容易通過分析堆塊來找出問題,然而通過分析堆塊來查找堆溢出的問題并非總是可行的,還有一種方式可以讓我們很快找到堆溢出的原因,就是頁堆,我們可以通過Application Verifier工具開啟頁堆。
通過Add Application菜單,添加我們要分析的應用程式,然後再右邊會有Heaps的選項。
右擊Heaps 選擇屬性,在彈出框中,把full去掉(我們先分析普通頁堆,之後再分析完全頁堆)。
完成後我們按照原來的方式執行,程式崩潰後,列印堆棧如下。
上面給了我們堆的記憶體資訊,要轉儲頁堆資料的内容,我們需要将該位址減去32位元組然後再轉成_DPH_BLOCK_INFORMATION結構,如下:
上述結構體最重要的一項是StackTrace,可以查找堆棧的回溯,如下:
通過上述資訊,我們很快就能找到有問題堆的配置設定棧回溯,通過分析代碼很容易發現堆的溢出情況。
3.通過windbg+完全頁堆分析
普通頁堆還不是很直覺的發現堆溢出的地方,但是開啟了完全頁堆就不一樣了,完全頁堆開啟後,程式隻要發生堆溢出就立馬崩潰,這樣就很好的發現問題所在了,開啟完全頁堆:
再次運作程式,崩潰後堆棧情況:
很快就找到問題所在了,我們可以把wcscpy拷貝的字元列印出來:
就是我們傳入的參數導緻的溢出。