1. 程式人生 > >【除錯:除錯工具】 Windbg的gflags.exe 和 pageheap的使用和原理分析

【除錯:除錯工具】 Windbg的gflags.exe 和 pageheap的使用和原理分析

PageHeap / Gflags 使用,溢位容易用到

 

堆除錯工具——pageheap的使用和原理分析

今天除錯一個bug,用pageheap解決,在此記錄一下。

bug症狀如下:
1:不確定性崩潰,用vs除錯啟動每次崩潰地點都在crt分配或者釋放堆的位置
2:崩潰時vs看到的呼叫棧可能不同
3:output輸出HEAP: Free Heap block 388c58 modified at 388c88 after it was freed


問題分析:
根據vs的輸出,確定問題是在一塊堆上分配的記憶體在釋放後被改寫了。由於CRT只能在下次做堆操作檢查時才會暴露出問題,所以程式崩潰的呼叫棧是不確定的。
折騰了2個小時後,啟用pageheap縮小了程式出錯到崩潰之間的距離,解決了問題。過程如下:
1:啟動pageheap
pageheap /enable mybug.exe 0x01
2:除錯啟動mybug.exe
現在程式崩潰的呼叫棧每次都相同,並且都在相同的執行緒中,根據呼叫棧資訊很輕鬆的鎖定了bug。

 

由於上面的例子過於複雜,下面寫了一些小程式分析了pageheap的原理

 

char* buffer = new char[19];        // 1
buffer[19] = 0;                     // 2
delete [] buffer;                   // 3
 

這是一個很簡單的堆記憶體越界的例子,在未啟動pageheap的情況下,我們來看看buffer的記憶體情況:
buffer = 0x00388C80
第一行執行後,buffer的記憶體

 

0x00388C80  cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  ................
0x00388C90  cd cd cd fd fd fd fd ab ab ab ab ab ab ab ab fe  ................
 


簡單說明一下,除錯模式下堆上未初始化的記憶體為cd,並且在記憶體結束處有4個fd的邊界,用於debug模式下crt做記憶體檢查,執行第2行之後,buffer的記憶體為


0x00388C80  cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  ................
0x00388C90  cd cd cd 00 fd fd fd ab ab ab ab ab ab ab ab fe  ................


可以看到4個fd的記憶體邊界中第一個fd被破壞了。但這個時候程式並沒有崩潰,繼續執行第3行,程式崩潰,提示堆錯誤,可以看到,如果第2行和第3行之間有很長的程式碼邏輯,那麼也只能在第3行執行之後程式才會崩潰。這給調式程式帶來了極大的不便。
如果第2行改為:buffer[24] = 0 程式同樣不會崩潰
如果啟用了pageheap,再來看看在debug模式下buffer的記憶體分配情況:
第一行分配記憶體後,buffer的記憶體情況:


0x01675FE8  cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  ................
0x01675FF8  cd cd cd fd fd fd fd d0 ?? ?? ?? ?? ?? ?? ?? ??  ................

可以看到,和上面一樣,在記憶體結束加上了4個fd的邊界,d0是用於填補4位元組對齊,注意buffer後面的地址(第一個??)為0x01675FF8+8 = 0x01676000,這是一個4k對齊的PAGE_NOACCESS頁面,這個時候我們執行第2行程式碼
buffer[19] = 0; 同樣不會崩潰,即使是修改buffer[19-23]的值(4個fd邊界和1個對齊d0),和未啟動pageheap一樣,程式都只會在執行第3行的時候崩潰。如果修改buffer[24]則程式會崩潰。

通過這個例子,可以得出一個結論:啟用pageheap後,堆記憶體分配在頁面的末尾,後面緊跟了一個4k的PAGE_NOACCESS屬性的頁面,這種情況下,啟用pageheap的好處是能在一定程度上檢查記憶體越界。

再來看一個例子

 

 char* buffer = new char[20];  // 1
 delete [] buffer;             // 2
 buffer[1] = 1;                // 3
 

這個例子演示了操作delete釋放後的記憶體,在未啟動pageheap的情況下,程式不會崩潰,原因同上一個例子,啟用pageheap後,buffer記憶體為:
第一行執行後:


0x01675FE8  cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd  ................
0x01675FF8  cd cd cd cd fd fd fd fd ?? ?? ?? ?? ?? ?? ?? ??  ................

 


第2行執行後:


0x01675FE8  ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??  ................
0x01675FF8  ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??  ................


可以看到,啟用pageheap後delete記憶體,分配該記憶體的整個頁面都被設定為PAGE_NOACCESS屬性,這樣操作delete後的任何記憶體程式馬上就會崩潰。

結論2:啟用pageheap很容易檢查操作delete後的記憶體的錯誤(包括2次delete)

 

總結:
1:啟用pageheap後,系統的堆管理器會把記憶體分配到4k頁面的末尾(注意需要4位元組對齊,debug模式下還存在邊界檢查的4位元組fd)
2:緊隨著的下一個頁面被設定為PAGE_NOACCESS屬性
3:啟用pageheap後,釋放記憶體把整個頁面設定為PAGE_NOACCESS屬性
4:記憶體越界和非法操作依靠非法訪問PAGE_NOACCESS屬性的頁面暴露問題
5:由於每塊記憶體都至少需要2個頁面(1個頁面分配,1個頁面PAGE_NOACCESS),在記憶體消耗較大的環境下會佔用極大的記憶體資源。
6:把pageheap和crt的堆檢查函式結合起來,能夠更好的暴露堆相關bug

 

ps.pageheap的作用是在登錄檔位置HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Image File Execution Options下生成一個項
--------------------- 
作者:xiaohyy 
來源:CSDN 
原文:https://blog.csdn.net/xiaohyy/article/details/4174493 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

 

 

Windbg的gflags.exe除錯堆疊溢位,訪問越界等問題。

gflags.exe是Windbg下的一個小工具,非常好用,對於除錯程式隱藏的bug很有幫助。

  如:我在vs2015中遇到訪問越界的問題,但程式不會在越界的地方發生崩潰中斷,而是在一個不可能存在訪問錯誤的地方發生了錯誤,以至於無法定位問題的位置。 
  
  所以在網上看到了Windbg的方法,一開始對Windbg不是很瞭解,熟悉之後發現Windbg很強大,雖然只用到了其中的一個小工具gflags.exe。

舉個栗子:

    int main()   
    {    
        char *p = new char[10];  
        for(int i = 0; i != 11; ++i)     
            p[i] = i;    
        return 0;    
    }

  這是一個非常簡單的越界程式,當i = 10時,訪問越界了。但是如果不採用測試工具,這裡是不會發生崩潰的。一般情況下,程式獲取的空間是16位元組對齊的,所以p[10]訪問到的是對齊之後增加的空間,不會導致越界崩潰。但這是隱患,為了使隱患儘早被發現,使用工具是很好的選擇。 
  gflags用來跟蹤這個程式的執行,可以設定每一次new分配的堆空間都單獨的佔有一塊空間,並且這個空間相鄰的位置被設定為不可訪問的,一旦訪問越界立即觸發訪問無效錯誤,儘早的觸發崩潰。

gflags.exe的作用:跟蹤被除錯的程式

方法: 
1、下載Debugging Tools for Windows,使用其中的gflags.exe。 
2、雙擊開啟gflags.exe,選擇Image File標籤。前兩個標籤是對所有程式進行跟蹤。 
3、在Image欄裡輸入你希望除錯的程式名。比如,mytest.exe。(按Tab重新整理)。 
4、勾選Debugger並輸入vsjitdebugger.exe。 
5、點選OK或者Apply。

注:用vc編譯出release版本的可執行檔案:mytest.exe。(注意:不是debug版本),gflags.exe工具跟蹤被監控的程式一定要是release版本的,debug版本的跟蹤的不會那麼的準確。

這個時候,已經把要監控的test.exe註冊上了。程式會中斷到發生錯誤的地方,有原始碼更好檢視,本人就是在原始碼下進行除錯。

最後、問題解決了記得關閉gflags,因為開啟gflags,除錯執行就慢了,最後會影響到程式的效能,親測效能下降非常嚴重。 
關閉方法;

HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/WindowsNT/CurrentVersion/Image File Execution Options/mytest.exe

網上看到是取消Debugger的勾選,但是無效,最後清除登錄檔後程序恢復原有速度。
--------------------- 
作者:程式碼搬運工007 
來源:CSDN 
原文:https://blog.csdn.net/bao_bei/article/details/73840674 
版權宣告:本文為博主原創文章,轉載請附上博文連結!