【逆向分析】快速查找指定代码的几种方法
前言
每個人在調試中快速查找所需代碼時都有不同的方法,但是最基本最常用的有下面幾種。
學習這4種方法前我們需要思考一個問題。我們知道,運行HelloWorld.exe程序會彈出一個消息框,顯示“Hello
World!”信息。固然是因為我們編寫了代碼,可在這種情形下,只要運行一下程序,不論是誰都能輕松意識到這一點。
如果你熟悉win32 api的開發,看到彈出的消息框就會想到,這是調用MessageBox()
API的結果。應用程序的功能非常明確,只要運行一下程序,就能大致推測出其內部結構。不過前提是你已經具備了開發和分析代碼的經驗。
一、代碼執行法
我們需要查找的是main()函數中調用MessageBox()函數的代碼。在調試器中調試HelloWorld.exe(F8)時,main()函數的MessageBox()函數在某個時刻就會被調用執行,彈出消息對話框,顯示“Hello World!”這條信息。
上面就是代碼執行法的基本原理,當程序功能非常明確時,我們可以逐條執行指令來查找需要查找的位置。但是代碼執行法僅適用于被調試的代碼量不大、且程序功能明確的情況。倘若被調試的代碼量很大且比較復雜時,此種方法就不再適用了。下面使用代碼執行法來查找代碼中的main()函數。從“大本營”(40104F)開始,按F8鍵逐行執行命令,在某個時刻彈出消息對話框,顯示“Hello World!”信息。按Ctrl+F2鍵再次載入待調試的可執行文件并重新調試,不斷按F8鍵,某個時刻一定會彈出消息對話框。彈出消息對話框時調用的函數即為main()函數。如圖2-20所示,地址401144處有一條函數調用指令“CALL00401000”,被調用的函數地址為401000,按F7鍵(Step Into)進入被調用的函數,可以發現該函數就是我們要查找的main()函數。
如上圖,地址40100E處有一條調用MessageBox() API的語句。401002與401007處分別有一條PUSH語句,他把消息對話框的標題與顯示字符串(Title = “www.reversecore.com”, Text = “Hello World!”)保存到棧(Stack)中,并作為參數傳遞給MessageBox W()函數。
這樣我們就準確的查找到了main()函數。
win32應用程序中,API函數的參數是通過棧傳遞的。VC++中默認字符串是使用Unicode碼表示的,并且,處理字符串的API函數也全部變更為Unicode系列函數。
二、字符串檢索法
右鍵菜單-search for-all referenced text strings
OllyDbg初次載入待調試的程序時,都會先經歷一個預分析過程。此過程中會查看進程內存,程序中引用的字符串和調用的API都會被摘錄出來,整理到另外的一個列表中,這樣的列表對調試時相當有用的。使用all referenced text strings命令會彈出一個窗口,其中列出了程序代碼引用的字符串。
地址401007處有一條PUSH 004092A0命令,該命令中引用的004092A0處即是字符串“Hello World!”。雙擊字符串,光標定位到main()函數中調用MessageBox W()函數的代碼處。
在OllyDbg的value窗口,然后按Ctrl+G命令,可以進一步查看位于內存4092A0地址處的字符串。首先使用鼠標單擊value窗口,然后按Ctrl+G快捷鍵,打開Enter expression to follow in Dump窗口。(如果你的數據窗口不是這樣的,右鍵單機選擇HEX)
ascii前兩行即使“Hello World!”字符串,它是以unicode碼形式表示的,并且字符串的后面被填充上了NULL值(記住這塊null值的區域,我們以后還會再講的)。
VC++中,static字符串會被默認保存為Unicode碼形式,static字符串是指在程序內部被硬編碼的字符串。
上圖我們還需要注意的是4092A0這個地址,它與我們之前看到的代碼區域地址比如401XXX是不一樣的。在HelloWorld進程中,409XXX地址空間被用來保存程序使用的數據。大家要清楚一點:代碼和數據所在的區域是彼此分開的。
我們后面會慢慢學習代碼和數據在文件里是怎么保存,以及怎么加載到內存的,這些是windows PE文件格式的相關內容,我們暫時先不管他。
三、API檢索法
3.1在調用代碼中設置斷點
右鍵單擊-search for-all intermodular calls
windows 編程中,如果想讓顯示器顯示內容,則需要使用win32API向OS請求顯示輸出。換句話說,應用程序向顯示器輸出內容時,需要在程序內部調用win32 API。認真觀察一個程序的功能后,我們能夠大致推測出它在運行時調用的WIN32 API,則會為程序調式帶來極大便利。以HelloWorld.exe為例,它在運行時會彈出一個消息窗口,由此我們可以推斷出該程序調用了user_32.MessageBox W() API。(敏感詞所以加了下劃線)
在OllyDbg的預分析中,不僅可以分析出程序中使用的字符串,還可以摘錄出程序運行時調用的API函數列表。如果只想查看程序代碼中調用了哪些API函數,可以直接使用all intermodular calls命令。如下圖窗口列出了程序中調用的所有API。
可以看到調用MessageBox W()的代碼,該函數位于40100E地址處,他是user_32.MessageBox W() API。雙擊它,光標就會定位到調用它的地址處(40100E)。觀察一個程序的行為特征,若能事先推測出代碼中使用的API,則使用上述方法能夠幫助我們快速查找到需要的部分。
對于程序中調用的API,OllyDbg如何準確摘錄出他們的名稱呢?首先,他不是通過查看源代碼來摘取的,如果想要了解其中的原理,我們需要理解PE文件格式的IAT(Import
Address Table,導入地址表)結構。我們會在后面的文章中提到這些內容。
3.2在API代碼中設置斷點
鼠標右鍵菜單-search for - name in all calls
OllyDbg并不能為所有可執行文件都列出API函數調用列表。使用壓縮器、保護器工具對可執行文件進行壓縮或保護之后,文件結構就會改變,此時OllyDbg就無法列出API調用列表了(甚至連調試都會變得十分困難)。
壓縮器(Run time Packer,運行時壓縮器)
壓縮器是一個實用壓縮工具,能夠壓縮可執行文件的代碼、數據、資源等,與普通壓縮不同,它壓縮后的文件本身就是一個可執行文件。
保護器
保護器不僅具有壓縮功能,還添加了反調試、反模擬、反轉儲等功能,能夠有效保護進程。如果想仔細分析保護器,我們還需要具有更高級的逆向知識。
這種情況下,DLL代碼庫被加載到進程內存后,我們可以直接向DLL代碼庫添加斷點。API是操作系統對用戶應用程序提供的一系列函數,他們實現于C:\Windows\system32文件夾中的 *.dll文件(如kernel32.dll、user_32.dll、gdi32.dll、advapi32.dll、ws2_32.dll等)內部。簡單的說,我們編寫的應用程序執行某種操作時(如各種I/O操作),必須使用OS提供的API向OS提出請求,然后與被調用API對應的系統DLL文件就會被加載到應用程序的進程內存。
在OllyDbg菜單中選擇 View-Memory菜單(Alt+M),打開內存映射窗口。如下圖,內存映射窗口中顯示了一部分HelloWorld.exe進程內存。在圖底部可以看到user_32庫被加載到了內存。
使用OllyDbg中的Name in all modules命令可以列出被加載的DLL文件中提供的所有API。使用Name in all moudules命令打開All names窗口,單機Name欄目按名稱排序,通過鍵盤敲出MessageBox W后,光標會自動定位到MessageBox W上。
USER_32模塊中有一個Export類型的MessageBoxW函數(不同環境下函數地址不同)。雙擊MessageBoxW函數后就會顯示其代碼,它實現于USER_32.dll庫中,如圖
觀察MessageBoxW函數的地址空間可以發現,它與HelloWorld.exe使用的地址空間完全不同。在函數起始地址上按F2鍵,設置好斷點后按F9繼續執行。
如果HelloWorld.exe應用程序中調用了MessageBoxW() API,則調試時程序運行到該處就會暫停。
與預測的一樣,程序執行到MessageBoxW代碼的斷點處就停了下來,此時寄存器窗口中的ESP值為19FF18
它是進程棧的地址。在右下角的棧窗口中可以看到更詳細的信息
我們會在后面的教程中詳細說明函數調用以及站動作原理,現在可以暫時忽略
如上圖,ESP值的12FF18處對應一個返回地址401014,HelloWorld.exe的main()函數調用完MessageBoxW函數后,程序執行流將返回到該地址處。按Ctrl+F9快捷鍵使程序運行到MessageBoxW函數的RETN命令處,然后按F7鍵也可以返回到401014地址處。地址401014的上方就是地址40100E,它正是調用MessageBoxW函數的地方。
以上是我所掌握的幾種方法,大家還有其他的思路嗎?
總結
以上是生活随笔為你收集整理的【逆向分析】快速查找指定代码的几种方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单学习kali高级渗透测试思路方法
- 下一篇: 应急响应-Yara规则木马检测