逆向分析教程(一)調試代碼
1.靜態分析法
靜態分析法是在不執行代碼文件的情形下,對代碼進行靜態分析的一種方法。靜態分析時并不執行代碼,而是觀察代碼文件的外部特征,獲取文件的類型(EXE、DLI、DOC、ZIP等)、大小、PE頭信息、Import/ExportAPI內部字符串、是否運行時解壓縮、注冊信息、調試信息、數字證書等多種信息。此外,使用反匯編工具(Disassembler)查看內部代碼、分析代碼結構也屬于靜態分析的范疇。我們通過靜態分析方法會獲得多種信息,這些信息是進行動態分析的重要參考資料,對代碼的動態分析非常有幫助。
2.動態分析法
動態分析法是在程序文件的執行過程中對代碼進行動態分析的一種方法,它通過調試來分析代碼流,獲得內存的狀態等。通過動態分析法,我們可以在觀察文件、注冊表(Registry)、網絡等的同時分析軟件程序的行為。此外,動態分析中還常常使用調試器(Debugger)分析程序的內部結構與動作原理。在逆向分析代碼時,通常先采用靜態分析法收集代碼相關信息,然后通過收集到的信息推測程序的結構與行為機制。這些推測對動態分析具有非常高的參考價值,能為動態分析提供很多創意。對程序代碼進行逆向分析的過程中,靈活使用靜態與動態兩種分析方法,動靜結合,可以極大地提高代碼的分析效率,增加分析的準確性,縮短代碼分析時間。
了解完上述概念后,我們嘗試進行代碼調試。源文件附文末。
調試hello word 程序
源代碼
#include "windows.h"
#include "tchar.h"
int _tmain(int argc, TCHAR *argv[]){
MessageBox(NULL,
"Hello Word!",
"bylibrary!",
MB_OK
);
return 0;
}
首先使用OllyDbg打開Hello world.exe程序

代碼窗口默認用于顯示反匯編代碼,還用于顯示各種注釋、標簽,分析代碼時顯示循環、跳轉位置等信息
寄存器窗口實時顯示CPU寄存器的值,可用于修改特定的寄存器
數據窗口以Hex/ASCII/Unicode值的形式顯示進程的內存地址,也可在此修改內存地址
棧窗口實時顯示ESP寄存器指向的進程棧內存,并允許修改
入口點
調試器停止的地點即為HelloWorld.exe執行的起始地址(4011A0),它是一段EP(EntryPoint,入口點)代碼,如下所示。(建議初學者不要自己build exe文件.....會暈的.......)

地址進程的虛擬內存地址(Virtual Address,VA)
指令IA32(或x86)CPU指令
反匯編代碼將OPcode轉換為便于查看的匯編指令
注釋調試器添加的注釋(根據選項不同,顯示的注釋略有不同)
接下來繼續調試,請記住,我們的目標是在mainO函數中找出調用MessageBox0函數的代碼。EP(EntryPoint,入口點)EP是Windows可執行文件(EXE、DLL、SYS等)的代碼入口點,是執行應用程序時最先執行的代碼的起始位置,它依賴于CPU。
OllyDbg基本指令

跟蹤40270C函數
在EP代碼的地址處使用Step Into(F7)指令,進入40270C函數 。

不理解上述的匯編代碼沒有關系,因為我們尚未掌握匯編語言。我們繼續往下看,我們的目標是main()函數
4027A1地址處有一條RETN指令,它用于返回到函數調用者的下一條指令,一般是被調用函數的最后一句。
我們不停的按F7執行,在4027A1地址處的RETN指令上執行Step over(F8)或Execute till Return(Ctrl+F9)命令,繼續操作。按F7/F8執行RETN指令,程序會跳轉到4011A5地址處。\
跟蹤40104F
執行4011A5處的跳轉命令JMP 0040104F,跳轉至0040104F,結果如圖所示:

代碼看上去比較復雜,他是visual C++的啟動函數,跟蹤這些代碼,就能發現我們要查找的main函數。
PS:第一次接觸上述代碼,你可能會覺得比較陌生,甚至分不清他們是用戶代碼,還是啟動函數。但是反復調試代碼的過程中你會發現,由visual C++編寫的可執行文件大都與上述形式類似。熟悉了這些啟動函數后,再調試代碼時就能很快識別并跳過。不同的開發工具生成的啟動函數不同,即使同一種開發工具,產生的啟動函數也隨版本不同而不同。
查找main()函數
從上圖的40104F地址處,每執行1次Step Info(F7)命令就下移1行代碼,移動到401056地址處的CALL402524函數調用指令時,執行Step Info(F7)命令,進入402524函數。


正如上圖所示,我們很難把402524函數稱為main()函數,因為在它的代碼中并未發現調用MessageBox() API的代碼。執行Execute till Return(ctrl+F9),跳轉到402568處的RETN指令,然后執行F7或F8執行RETN指令,跳出402524函數,返回至40105B處。

同樣,在40104F地址處執行F7命令調試,遇到函數調用就進入函數查看代碼(F7),確認是否為main()函數。若不是main()函數,則使用ctrl+F9命令跳出相關函數,繼續以相同方式調試。
調試過程中會遇到以下代碼
4010E4處的call 指令是調用Win32 API的代碼。現在我們還不需要進入被調用的函數直接使用F8跳過。

PS: 4010EE地址處是調用00401C5A函數的指令,執行后進入函數,再按ctrl+F9跳出函數,由于00401C5A函數中含有循環語句,所以跳出函數時需要花費一些時間。
如果調試一切正常,你會看到以下代碼

401144地址處有一條CALL 401000指令,用于調用401000函數,使用Step Into(F7)命令進入401000函數,如下圖

401000函數內部出現了調用MessageBoxW()API的代碼,該API函數的參數為“www.reversecore.com”與“Hello World!”兩個字符串。這與我們前面的源代碼內容一致,由此可以斷定,401000函數就是我們一直在查找的main()函數。