1. 程式人生 > >IDA Pro 權威指南學習筆記(十四) - 操縱函數

IDA Pro 權威指南學習筆記(十四) - 操縱函數

禁用 not 當前 函數 reg 代碼區 字節 strong 掃描

IDA 無法定位一個函數調用,由於沒有直接的方法到達函數,IDA 將無法識別它們

IDA 可能無法正確確定函數的結束部分,需要手動幹預,以更正反匯編代碼中的錯誤

如果編譯器已經將函數分割到幾個地址範圍,或者在優化代碼的過程中,編譯器為節省空間,將兩個或幾個函數的共同結束序列合並在一起,這時 IDA 同樣無法確定函數的結束部分

新建函數

在某些情況下,可以在沒有函數的地方創建新函數

新函數可以由已經不屬於某個函數的現有指令創建,或者由尚未被 IDA 以任何其他方式定義(如雙字或字符串)的原始數據字節創建

將光標放在將要包含在新函數中的第一個字節或指令上,然後選擇 Edit -> Functions -> Create Function,即可創建一個新函數,快捷鍵為 Alt+P

在必要時,IDA 會將數據轉換成代碼

接下來,它會向前掃描,分析函數的結構,並搜索返回語句

如果 IDA 能夠找到正確的函數結束部分,它將生成一個新的函數名,分析棧幀,並以函數的形式重組代碼

如果它無法找到函數的結束部分,或者發現任何非法指令,則這個操作將以失敗告終

刪除函數

可以使用 Edit -> Functions -> Delete Function 命令刪除現有函數

技術分享圖片

點 Yes,當前函數將被刪除

技術分享圖片

點擊 Yes 後

技術分享圖片

函數塊

在由 Microsoft Visual C++ 編譯器生成的代碼中,經常可以找到函數塊

編譯器移動不常執行的代碼段,用以將經常執行的代碼段“擠入”不大可能被換出的內存頁,由此便產生了函數塊

如果一個函數以這種方式被分割,IDA 會通過跟蹤指向每個塊的跳轉,嘗試定位所有相關的塊

多數情況下,IDA 都能找到所有這些塊,並在函數的頭部列出每一個塊

技術分享圖片

有時候,IDA 可能無法確定與函數關聯的每一個塊,或者函數可能被錯誤地識別成函數塊,而非函數本身

在這種情況下,需要創建自己的函數塊,或刪除現有的函數塊

在反匯編代碼清單中,函數塊就叫做函數塊;在 IDA 的菜單系統中,函數塊叫做函數尾(function tail)

要刪除現有的函數塊,將光標放在要刪除的塊中的任何一行上,然後選擇 Edit -> Functions -> Remove Function Tail

在初次將文件加載到 IDA 時,取消選擇 Create function tails 加載器選項,IDA 將不創建函數塊

如果禁用了函數尾,已經包含函數尾的函數將包含指向函數邊界以外區域的跳轉,IDA 會在反匯編代碼清單左側的箭頭窗口中用紅線和箭頭突出顯示這些跳轉

函數特性

IDA 為它識別的每一個函數提供許多特性

函數屬性對話框可用於編輯其中的某些特性

技術分享圖片

Name of function 為函數名稱,提供另外一種更改函數名稱的方法

Start address 為起始地址,函數中第一條指令的地址

通常,IDA 會在分析過程中,或根據創建函數時所使用的地址,自動識別這個地址

End address 為結束地址,函數中最後一條指令之後的地址

通常,它是函數的返回語句之後的指令的地址

這個地址並不是函數的一部分,而是函數的最後一條指令之後的地址

Local variables area 為局部變量區,函數的局部變量(如下圖)專用的棧字節數

技術分享圖片

多數情況下,IDA 會通過分析函數的棧指針的行為,自動計算出這個值

Save registers 為保存的寄存器

為調用方保存寄存器(如上圖)所使用的字節數,IDA 認為保存的寄存器區域放在保存的返回地址頂部、與函數有關的所有局部變量的下方

一些編譯器選擇將寄存器保存在函數局部變量的頂部

IDA 認為保存這些寄存器所使用的空間屬於局部變量區域,而非保存的寄存器區域

Purged bytes 為已刪除字節

已刪除字節表示當函數返回調用方時,IDA 從棧中刪除的參數的字節數

對 cdecl 函數而言,這個值始終為0

對 stdcall 函數來說,這個值表示傳遞到棧上的所有參數占用的空間

在 x86 程序中,如果 IDA 觀察到程序使用了返回指令的 RET N 變體,它將自動確定這個值

Frame pointer delta 為幀指針增量

有時候,編譯器可能會對函數的幀指針進行調整,使其指向局部變量區域的中間,而不是指向保存在局部變量區域底部的幀指針

調整後的幀指針到保存的幀指針之間的這段距離叫做幀指針增量

多數情況下,IDA 會在分析函數的過程中自動計算出幀指針增量

使用增量的目的,是在離幀指針 1 字節(帶符號)的偏移量(-128 ~ +127)內保存盡可能多的棧幀變量

復選框為 IDA 自動分析得到的結果,以下是可啟用也可禁用的屬性

Does not return 為不返回,函數不返回到它的調用方

如果調用這樣的函數,在相關的調用指令之後,IDA 認為函數不會繼續執行

Far function 為遠函數

這個屬性用於在分段體系結構上將一個函數標記為遠函數

在調用該函數時,函數的調用方需要指定一個段和一個偏移值

是否使用遠調用,應由程序中使用的內存模式決定

Library func 為庫函數

這個屬性將一個函數標記為庫代碼

庫代碼可能包括靜態鏈接庫中的編譯器或函數所包含的支持例程

將一個函數標記為庫函數後,該函數將以分配給庫函數的顏色顯示,從而與非庫代碼區分開來

Static func 為靜態函數,靜態函數只在函數的特性列表中顯示靜態修飾符

BP based frame 為基於BP的幀

這個特性表示函數利用了一個幀指針

如果選擇了這個特性,一定要相應地調整保存的寄存器的大小(通常指根據保存的幀指針的大小增大)和局部變量的大小(通常指根據保存的幀指針的大小減少)

對基於幀指針的幀而言,使用幀指針的內存引用被格式化,以利用符號棧變量名稱,而非數字偏移量

如果沒有設置這個特性,則認為棧幀引用與棧指針寄存器有關

BP equals to SP 為 BP 等於 SP

它的作用等同於將幀指針增量的大小設置為等於局部變量區域

一些函數將幀指針配置為在進入一個函數時指向棧幀(以及棧指針)的頂端,這時候需要設置該屬性

棧指針調整

IDA 會盡其所能跟蹤函數內每一條指令上的棧指針的變化

如果 IDA 無法確定一條指令是否更改了棧指針,就需要手動調整棧指針

如果一個函數調用了另一個使用 stdcall 調用約定的函數,就會出現上述情況,這是最簡單的一種情況

如果被調用的函數位於 IDA 無法識別的共享庫中,IDA 不知道該函數使用了 stdcall 調用約定,也就無法認識到:被調用的函數會將棧指針修改後返回

進行棧調整,首先選中進行調整的地址,選擇 Edit -> Functions -> Change Stack Pointer(快捷鍵為 Alt+K),然後指定棧指針更改的字節數

IDA Pro 權威指南學習筆記(十四) - 操縱函數