部門小伙伴遇到一個樣本需要對動態函數調用就行批量注釋還原的問題,通過idapython可以大大的減少工作量,其實這一問題也是很多樣本分析中最耗時間的一塊,下面來看看如何解決這個問題(好吧這才是今年最后一篇技術文章!-_-).
具體情況如下,由於樣本注入的代碼都是使用的動態函數的獲取方式,因此通過ida去看的話都是以下的形式,大大增加了逆向的難度。
為了減輕逆向的難度需要對這些函數進行批量的注釋,在寫該腳本前想想我們需要解決哪些問題。
- 如何獲取所有的該類型函數調用?
- 如何判斷該函數調用為什么api(即該call eax是call writefile還是call readfile了?)
通常通過Loadlibrary和GetproAddress動態獲取api的方式都是將這些地址放到單獨的一段內存中,每四個字節為一個地址,如下圖所示:
此處首先假設我們已經將該表轉換成了對應的一個數組,就像這樣(轉換過程見下文):
![]()
首先需要獲取所有該類型動態函數的調用,通常的動態函數調用方式如下,通過mov獲取對應的函數地址,然后call該寄存器。
因此我們可以通過idapython腳本搜索對應call reg系列指令(當然並不是所有的call reg指令都是動態函數調用,我們的標准是先mov之后再call,同時mov的目的reg和call的reg要一致,此處先將所有的call找出來),如下圖所示:其中的FF D0即為call eax指令對應的十六進制碼。

現在獲取了所有的call reg地址,除了要進行過濾之外還需要知道這個call對應的api到底是啥,理論上通過ida是沒法辦到的,但是有了上文中的funclist及對應內存表中該函數的地址偏移(此處為278)就可以知道對應的函數名稱,(278->632-296(內存中的函數表偏移))/4,獲取的值即為對應funclist中對應的索引。

如下圖所示,通過這個funclist和偏移即可獲取對應call的api是什么,同時判斷call的前一條指令mov中的第一個變量是否和call的寄存器一致來進行過濾,通過mov的第二個變量獲取需要的偏移(這個地方的多個idc函數不做過多介紹,在前面的文章idapython在樣本分析中的使用-字符解密中有詳細的分析)。

最后組合起來如下:

此時運行之后每個對應函數都增加了相應的注釋,當然這個地方你也可以直接通過重命名函數直接將call reg修改為對應的call api。
最后需要解決的一個問題如何獲取上面那張funcnamelist的問題(當然不嫌累的話可以把內存中的地址一個個對應出來),其實上面已經說了idapyhon是無法解決的,但是通過調試器的腳本卻可以實現,比如我最鍾愛的windbg,通過分析可以知道保存了這些地址的內存,比如下圖,在windbg中可以通過ln命令獲取對應地址的符號。
通過ln獲取對應地址的符號,如下就可以知道這個地址對應了函數LoadLibraryA。
同樣通過windbg的python腳本就可以將這批函數對應的api名字生成一個idapython需要的funcnamelist了。

結果如下所示:
最后快元旦了,大伙新年快樂。
轉載請注明出處
