IDA加載文件過程
在IDA中打開可執行文件時使用靜態分析器分析該文件,也稱為Loader。在這種裝載程序模式下,該程序將不會執行而是交給IDA靜態分析,並最終創建一個.idb文件,分析過程中存儲信息(包括重命名)的數據庫。變量,函數名,標題...都存在這個文件里。
而.idb文件將是分析過程間產生成的5個文件(.id0,.id1,.nam,.id2和.til)融合在一起:
IDA不具有“撤消”功能,分析過程中所做的任何更改都不會撤消,而是直接保存。但是這些更改僅是存儲在idb文件里,不會直接影響到正在分析的原始二進制文件。
在加載程序模式下,沒有“寄存器”窗口,“堆棧”等窗口以及加載程序使用的內存模塊列表。在Debugger模式下執行和調試程序時,這些信息才會出現。
寄存器知識
寄存器被稱為內置在處理器中的小型存儲區(易失性內存-僅在計算機仍處於活動狀態時才保存數據)。CPU執行命令時,必須從內存中檢索指令和對指令進行解碼,然后執行與指令目的相對應的操作。
在32位架構中,使用的寄存器是EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI和EIP,而64位架構會多出幾個寄存器。
通用寄存器:
- EAX(寄存器寄存器-累加器):最常用於算術,邏輯和數據傳輸指令、乘法和除法運算使用此寄存器。對於Windows API函數,函數的返回值通常將存儲在EAX寄存器中。
- EBX(基址寄存器):EBX寄存器可以直接訪問存儲器數據,它也是一個通用寄存器。
- ECX(計數寄存器):ECX是一個共享寄存器,可以用作各種命令的計數器。它還可能包含內存中的數據未對齊。使用計數器的命令是順序,循環和LOOP / LOOPD指令。
- EDX(數據寄存器):是一個通用寄存器,用於包含乘法結果或除法結果的一部分。它還可以直接訪問內存中的數據地址。
- EDI(目標索引):EDI通常用於處理字符串或數組的工作。該寄存器將指向目標字符串。此外它也是一個通用寄存器。
- ESI(源索引):與EDI一樣,ESI也經常用於處理字符串或數組的操作。該寄存器將指向源字符串。
- EBP(基本指針):EBP指向內存位置,除了被共享外,還用作訪問函數堆棧中的參數和局部變量的幀指針。
- ESP(堆棧指針):該寄存器始終指向當前堆棧頂部。根據堆棧的工作原理,該寄存器將被定向到低位地址。
因此共有8個通用的32位寄存器,即EAX,EBX,ECX,EDX,ESP,EBP,ESI和EDI。另外這些寄存器可以細分為16位和8位寄存器,如下所示:
例如,如果EAX寄存器的值為0x12345678,則AX是包含最后四位數字的16位寄存器:
AX寄存器可以被分成2個8位寄存器,它們是一對寄存器:AH包含兩個數字5和6以及AL所包含的最后兩個數字7和8:
可以想象,32位EAX寄存器被拆分為一個16位寄存器,稱為AX。AX被分為兩個稱為AH和AL的 8位寄存器。同樣,對於EBX寄存器(BX,BH和BL),ECX(CX,CH和CL)和EDX(DX,DH和DL),其余寄存器僅分為16位寄存器,不再細分為8位寄存器:
特殊寄存器
除了上面的通用寄存器,還有特殊寄存器,包括:
- EIP(指令指針):這是一個特殊的寄存器,它始終指向要執行的下一條指令。與其他寄存器不同,EIP不受指令直接影響。
另一個重要的寄存器是EFLAGS(標志寄存器),每個位用於反映操作的特定狀態。根據計算結果啟用這些標志寄存器,並根據這些標志來執行程序的執行分支。
零標志(ZF)是逆向中最常用的標志。通常用於條件分支指令中,根據先前的命令結果更改執行流程。
接下來是段寄存器,指向可執行文件的不同部分,例如CS = CODE,DS = DATA等。
使用寄存器和內存時,另一個重要的細節是最常用數據類型的大小:
重要的是要記住,BYTE為1字節,WORD為2字節,DWORD為4字節。
匯編(asm)指令
每個不同的系統/平台都會有自己的一套Asm命令。
IDA使用與調試器(例如OllyDbg / x64dbg)用不同的多種語法來解析ASM命令,因此熟悉用OllyDbg的人都會發現有點區別。
數據傳輸命令
- MOV
MOV dest,src:將源操作數(src)的內容復制到目標(dest)。操作:dest <-src。用於在寄存器之間,寄存器和存儲單元之間傳輸數據或直接將數字傳輸到寄存器或存儲單元。mov命令可以對應於高級語言中的assignment命令。
例子:第一步是將值從一個寄存器轉移到另一個寄存器。
MOV EAX,EDI;EAX接收EDI的值;EDI不變,沒有變化。
通常只能將數據值直接傳送到寄存器或寄存器傳送到寄存器,但EIP寄存器不能是目的或源。我們無法執行以下語句:
MOV EIP,EAX;此聲明完全無效。
下一個示例將常量實現到寄存器中,如下所示:
MOV EAX,1;如果將數字1發送到EAX寄存器,則EAX寄存器的原先值將被覆蓋(替換為新值)。
接下來是執行地址值傳輸到寄存器的mov語句。
下圖是VEViewer.exe文件中的匯編指令(在此處下載:https://mega.nz/#!CLIgmS5S!s5qrzoxbRP5W9xblRf8bgVz5UWRcR9yGoICF-PpJbR4 )
在上面的示例中,EAX寄存器現在將獲取一個內存地址的值。前面的偏移量前綴表示必須使用地址,而不是存儲單元的內容。按IDA快捷鍵Q,IDA會將此語句轉換為:
MOV EAX,46f038h;這是一個類似於OllyDbg的命令,但沒有提供任何有關46f038h地址內容的信息。如果我們右鍵單擊地址46f038,我們可以看到IDA顯示的原始指令:
按IDA快捷方式G輸入地址可以跳轉到這條地址的位置:
這是在HEX選項卡內的信息,地址處存儲的字節值為0x00,是一個DWORD:
如果返回反匯編選項卡並雙擊該地址,來到這里:
dword前綴在地址之前,這意味着地址的內容是DWORD,然后dd數據類型對應於DWORD,隨后的0值存儲在這個位置。
因此IDA告訴我們這個程序在使用這條地址存儲DWORD,在右側可以看到使用DWORD代碼區域的引用。
如圖所示,有兩個參考點。每個箭頭都是一個位置,當鼠標指針放在那里時,可以在每個位置中預覽代碼。
按快捷健X鍵,IDA可以顯示引用於該地址的函數地址:
圖中的第一條匯編指令讀取我們在上面看到的地址dword_46F038,並將其保存到eax寄存器中。第二條語句是在地址0x46F038的內存內容中寫入一個DWORD(也就是eax的值)。
總結以上的內容:
mov eax,偏移量dword_46F908
將地址0x46F908傳輸到EAX寄存器,即EAX = 0x46F908
mov eax,dword_46F908
將該地址指向的內容或值傳遞到EAX寄存器中,即EAX = 0x0
、
熟悉使用OllyDbg的話,這條命令在OLLY中顯示是帶有方括號的:
MOV EAX,DWORD PTR DS:[46f908]。
在IDA中當地址的前面有一個偏移量前綴時,它是指地址的數字值,而當用dword前綴是在使用內容/值。
如果遇到是方括號里用寄存器是啥?觀察下圖:
圖中的命令使用方括號[],因為還不知道寄存器可以獲取的靜態值,也不知道從哪個方向獲取更多信息。在這種情況下,如果EDI寄存器指向0x10000,那么這條命令是在這條內存地址中找到內容並復制到ECX寄存器中。
所以當IDA在地址前面使用偏移量前綴時,是對存儲地址的引用,而不考慮存儲地址上的內容。
再舉一個例子:
在上圖中,可以看到EAX接收0x45f4d0,因為它的前面有一個偏移量前綴unk_,說明IDA無法識別哪種數據類型會以unk(未知)作為前綴。
在圖中標記的命令中,執行0x46fc50內容的第一個命令是DWORD值,使用這條命令下面的語句重定向自身,也就是0x46FC50指向的數值。
IDA可以看到存儲在這條地址的值,地址0x42f302這里的mov語句將什么值傳輸到EAX ,雙擊0x46FC50可以看到以下內容:
如果沒有執行引用列表中的另一個eax賦值命令,那么這條命令會將0值分配給EAX寄存器,並將另一個值存儲在到0x46fc50這條地址里。
圖中突出顯示的語句會將DWORD值保存到內存地址,而其他命令只讀取帶偏移前綴的地址或讀出地址當前存儲的值。
除了上面的示例,當然也可以像我們之前看到的那樣將常量分配給16位和8位寄存器:
上面的命令將值1分配給AL寄存器,並保留以前可從EAX寄存器獲得的原始值。在這種情況下,僅更改寄存器的低字節。
上面的命令將內存地址0x459c24的內容分配給AX寄存器,並告訴我們檢索到的值是WORD。
如圖所示,初始值為0,但程序被執行時值將被更改。
在上圖中,AX寄存器的值分配給EBX寄存器指向的地址內容。使用方括號[]表示寫入EBX的內容。
上述命令是AX寄存器的值分配給ESI + 8的內容。
逆向環節-IAT表
繼續逆向VEViewer.exe文件:
雙擊圖片中顯示出來很長的名稱,IDA會跳轉到這里:
IAT表是在執行文件在.idata或.rdata節中存儲導入函數地址信息的表。如果在IDA的“十六進制視圖(HEX View)”上查看,是沒有函數值的,因為IAT表只在IDA執行程序調試時才會有。
IDA打開默認設置可能不太一樣。要進行轉換可以到“ Options ”菜單-“Demangle Names”,然后選擇“ Names”:
要知道該函數來自哪個函數,雙擊QMetaObject 。向上滾動結果發現這些函數是從庫QtCoreX.dll導入的,並且上面還有許多其他dll:
通過本文可以學習到MOV命令在IDA顯示的不同例子。可以使用提供在文章里的VEViewer.exe文件在IDA進行練習和查看。
X86與X64文件架構的區別
x64體系結構被設計為x86的擴展,並且與x86指令集有很強的相似性。從代碼分析的角度來看,存在一些差異:
- 32位(4字節)通用寄存器eax,ebx,ecx,edx,esi,edi,ebp和esp擴展為64位(8字節);這些寄存器分別命名為rax,rbx,rcx,rdx,rsi,rdi,rbp和rsp。
- 新增加的8個寄存器是r8,r9,r10,r11,r12,r13,r14和r15。
- 程序可以以64位(rax,rbx等),32位(eax,ebx等),16位(ax,bx等)或8位(al,bl,...)訪問寄存器。 )。
- 通過在寄存器名稱后面添加b,w,d或q,以字節,字,dword或qword的形式訪問寄存器r8-r15。
- 在x86架構中,函數的參數在調用函數之前被壓入堆棧,而在x64架構中,前四個參數傳遞給寄存器rcx,rdx,r8和r9。
PS:即使與x86不同,也是先壓棧參數再提升堆棧分配內存給局部變量。(感謝大佬勘誤,哈哈
附件文件下載
VEViewer.exe文件 https://mega.nz/#!CLIgmS5S!s5qrzoxbRP5W9xblRf8bgVz5UWRcR9yGoICF-PpJbR4