《格蠹匯編》調試筆記


以前也就是把Windbg作為一個調試所寫驅動的調試器。只進行源碼級的調試,運用的比較淺顯。

最近研讀張銀奎老師的《軟件調試》獲益良多,剛好與之配套的《格蠹匯編》提供了老師大量的調試經驗以及實驗環境。不拿來好好實踐一番簡直浪費。

 

0X01調試筆記之偵查廣告插件

俗話說:工欲善其事,必先利其器。對於調試領域來說,更是如此。我們不但要在自己的計算機中安裝有WinDbg,還應當使用JIT調試的方法。因為對於Windows系統中的應用程序的崩潰問題,JIT調試是非常有效的辦法,而且JIT調試還是Windows系統和WinDbg密切配合,從而實現高效調試的典范。這樣,當我們的程序崩潰時,調試器就能夠自動地執行,配合以相應的指令,就能夠很快地定位程序出錯的位置,從而進行修改。

本節叫偵查廣告插件,實際上是用JIT確定老發生崩潰的錯誤框是哪個程序彈出來的。

 

第一步 在注冊表中設置JIT調試
我們首先需要設置JIT調試。這里需要打開注冊表,對於32位的Windows系統而言,其位置在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug:

這里的Auto表示是否啟動JIT調試,如果這個值為1,則是啟動JIT調試,如果為0,說明不啟動。而下面的Debugger保存的是欲啟動的調試器的路徑及參數信息。

在執行 AcsVio.exe(人為制造一個崩潰,彈出錯誤提示框) 之前需設置WinDbug為默認的即時調試器,設置為在cmd行輸入C:\WinDbg\windbg_CN.exe -I 命令

 

 

這是我們執行提供的AcsVio.exe(一個崩潰的exe文件)

 

第二步 利用JIT調試來分析軟件問題

可以看到WinDbg已經自動彈出了,並且在出問題的位置斷了下來。上圖中第一個紅框說明了程序的問題:Access violation,也就是訪問違例。而第二個紅框則是給出了出問題位置的反匯編代碼。可以看到,程序將0賦給了[ecx],這個地址讀寫發生了錯誤,就出現了訪問違例的情況。

下面輸入指令:
0:000>.symfix c:\Symbols
這條語句用於設置符號路徑。然后輸入:
0:000>kPL

其中k表示顯示棧回溯的信息,P表示將所有參數也顯示出來,L用於隱藏原始代碼:

 

可以看到問題就在main函數里面。通過棧的回溯,我們就能夠看到系統都調用了那些函數,從而進行進一步的分析。

 

0X02從堆里搶救丟失的博客

相信很多使用計算機的朋友都曾經遇到過在編輯文章時,由於自己的不小心或者是計算機的問題,而丟失了剛剛編輯好的文檔的情況。 雖然說現在的文字編輯軟件一般也漸漸支持了自動存盤的功能,使得出現這樣的“悲劇”的幾率大大降低了,但是數據丟失的情況,偶爾還是會發生的, 而且自動存盤的功能也會有失靈的時候。一旦出現了這種情況,那么這就需要我們掌握一定的調試技術來嘗試恢復這些數據。因為一般來說,這些數據是保存在我們的內存中的, 理論上來說,只要這塊內存區域的數據沒有被改寫,那么我們就有辦法找到那些丟失的數據。

 

第一步 打開目標文件

我們首先打開WinDbg,然后選擇File菜單下的Open Crash Dump,載入我們這次所研究的文件ieblog.dmp。可見WinDbg已經為我們打開了文件,並且已經停下來了:

雖然說作者是在網上寫的博客文章,但是事實上這篇文章的本體依舊是存在於本地計算機內存中的某個區域中的。由於作者很清楚自己的博客中有哪些內容,因此我們可以在內存中檢索博文中相應的字符串。這里可以輸入如下指令:

>s –u 0 L800 “當年在交大”

上述命令的意思是,以Unicode的形式在內存中查找“當年在交大”這幾個字,查找范圍是從0到800。

回車后發現WinDbg並沒有返回結果,那么說明我們這里所指定的800這個范圍太小了,這里修改一下,將上述語句中的800改成8000000,然后再次嘗試查找:

 

可以看到這次檢索出了很多個結果。之所以能夠在內存中搜索到這么多的結果,有可能是作者在寫作的過程中對文章進行了多次保存,或者說是系統自動進行了保存,於是就在內存中留下了痕跡。那么我們下一步的操作就是確認究竟是哪個位置保存的是完整的博文。當然這里我們依舊可以使用s -u命令來查找博文中最后的幾個字符,從而定位博文的范圍。或者可以使用如下命令:

>du 001b5942 L1000

上述命令的意思是從內存地址為0x001b5942的位置開始,以Unicode的形式顯示內存中的內容,一共顯示800個結果。WinDbg輸出如下:

 

 很顯然已經找到了!

第二步 提取內存中文章

可以發現,這個地址正是博文真實存放的地址。既然已經在內存中找到了這篇文章,那么下一步就是 將其從內存中提取出來。可以使用如下命令:

>.writemem e:\blog_1.txt 001b5942 L1458

這行命令的意思是,將內存起始位置為0x001b5942處的內容讀取出來,一共讀取1458個字符,並命名為blog_1.txt,保存在E盤根目錄下:

然后來到E盤根目錄下,打開blog_1.txt文件:

 

 

可見雖然我們已經把博文提取出來了,但是卻是以亂碼的形式顯示的。而且雖然說是亂碼,但是可以發現這些文字已經很接近於我們的中文字了。其實之所以會出現這樣的結果,就是因為我們的系統沒能有效地識別這些編碼。為了解決這個問題,這里可以利用十六進制編輯工具,比如WinHex打開blog_1.txt文件,然后在文件開頭加上Unicode的標識符FFFE,這樣系統就能夠以Unicode字符的形式進行解析了。

 

0X03拯救發瘋的Windows 7

在我們的日常生活中,會接觸到各種各樣的軟件。這些軟件的編寫者在開發該軟件時,往往並不會對其做非常全面的測試,這就導致了當這款軟件被不同的用戶所使用時,不可避免地會出現各種各樣的問題。如果只是功能上出現問題,那么危害往往不大。但是如果是軟件中存在着致命的漏洞,那么很可能就會被別有用心者所利用,從而危害到用戶的計算機系統。甚至還可能出現這樣一種情況,有時候用戶的一些無心的輸入,而軟件中沒有相應的處理機制,於是也就導致了軟件乃至系統的崩潰。那么這些問題,其實都可以利用調試技術進行解決。

 

首先打開WinDbg,然后在File菜單下選擇Open Crash Dump,打開WERA7FB.tmp.mdmp文件。此時WinDbg就已經幫我們斷下來了:

 

在上圖的紅框中可以發現,出現問題的位置在280號進程中的2a4號線程。所出現的問題是緩沖區的溢出。由於緩沖區的溢出是與我們的棧空間緊密相關的,因此我們現在可以看一下棧上的情況。在WinDbg中輸入以下命令:

>kn

 其中的k用於顯示給定的線程中的棧幀的信息,而參數n可以顯示幀的編號。WinDbg得到如下輸出:

 

可以看到這里出現了幾個以Wer開頭的函數,wer的意思是Windows Error Report,說明這個進程在終止前調用了WER設施,這正是我們能夠得到這個轉儲文件的原因。8號棧幀中的函數是UnhandledExceptionFilter,這是位於kernel32.dll中的用於處置未處理異常的核心函數,它也是系統在終止掉一個進程前做最后處理的地方,應用程序錯誤對話框和JIT調試都是從這個函數發起的。

由張銀奎老師所編寫的《軟件調試》的第12章就深入地討論了這個問題。而在這個函數的下方,一般就是我們所要查找的導致異常的函數位置了。看一下9號棧幀,這個函數的名稱叫做_report_gsfailure,其所在的模塊為umpo.dll。說到這里我想要強調的是,我們在以后的分析過程中,如果說遇到了我們並不熟悉的模塊,那么我建議大家應當查看一下模塊的基本信息,可以在WinDbg輸入如下指令:

>lmvm umpo

上述命令中lm表示列出模塊的信息,v表示將詳細信息顯示出來,最后的m表示需要進行模塊名稱的匹配。

WinDbg的輸出如下:

 

可見,這里已經列出了關於umpo這個模塊的比較詳細的信息。我之所以強調讓大家多關注一些不太常見的模塊,就是因為很多惡意模塊往往是“三無”產品,比如對於沒有版本號、沒有廠家、沒有產品名稱等,但卻存在於Windows的重要目錄,那么這個模塊就很值得懷疑了。當然這里的umpo模塊是沒有問題的。

那么我們繼續分析棧幀。簡單來說,是umpo這個模塊中的UmpoAlpcSendPowerMessage函數出現了緩沖區溢出的情況。當這個函數要返回的時候,編譯在函數中的溢出檢查代碼檢測出了溢出,於是調用_report_gsfailure函數來報告錯誤。這種檢測溢出的方式通常稱為基於Cookie的溢出檢查,簡稱為GS機制。

簡單來說,GS機制就是在可能發生溢出的函數所使用的棧幀起始處(EBP-4的位置)存放一個稱為Cookie的整數,在函數返回時檢查這個Cookie是否完好,如果被破壞了,就說明函數中發生了溢出。部署和檢查Cookie的代碼都是編譯器在編譯時加入到函數中的。

因為我們已經知道函數UmpoAlpcSendPowerMessage出現了緩沖區溢出的錯誤,那么我們可以具體看一下當前的Cookie以及EBP等的值都是多少。可以在WinDbg中輸入如下命令:

>dd 009afb30-4 L4

上述命令中的dd表示以雙字的形式顯示內存中的內容,009afb30表示出問題函數的EBP,減去4則是Cookie值的位置,L4表明顯示4個結果。WinDbg的輸出如下:

 

 可以看到第一個00640064就是Cookie值,父函數的EBP也是00640064,而返回地址則是006a002e。可以發現,這些值都不像是正規的內存地址,反而像是ASCII碼值。看來由於出現了緩沖區溢出的問題,使得一些重要的數據都被沖掉了,變成了其它的數值。下面我們可以看一下出問題的函數的變量空間的情況。那么該如何確定這個范圍呢?首先用兩個函數的保存有EBP的位置的地址相減,也就是0x009AFB30減去0x009AF924,得出的結果為0x20C。但是對於_report_gsfailure這個函數而言,它的下方還包含有Cookie值以及EBP的地址,一共占據了8個字節的空間,所以還應當用0x20C減去8,也就是0x204,就是問題函數UmpoAlpcSendPowerMessage的變量空間了。那么下面就來看一下這個空間中發生了什么:

>db 009afb30-204 L210

上述命令的意思是以字節的形式顯示內存地址為0x009AFB30減去0x204位置的內容,顯示210個結果:

 

 

可以看到這里出現了一個超長的文件名,那么我們就可以知道,這就是出現緩沖區溢出問題的源頭了。可見上圖中第一個紅框就是EBP,而第二個紅框則是返回地址的位置。現在可以知道,因為Umpo模塊中的函數UmpoAlpcSendPowerMessage接收到了一個比預想長度還要長的參數,於是就發生了緩沖區的溢出情況,從而觸發了GS機制。既然知道了原因,那么我們現在只要把文件的名稱改短,問題也就能夠解決了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM