最近接手的一個樣本,樣本中使用了大量的xor加密,由於本身樣本不全,無法運行(好吧我最稀飯的動態調試沒了,樣本很有意思,以后有時間做票大的分析),這個時候就只好拜托idapython大法了(當然用idc也一樣),期間遇到幾個問題,遂記錄一番。
樣本加密的字符如下,很簡單,push壓棧之后,反復調用sub_1000204D解密。
此時,要寫腳本的話,我們希望這個腳本能夠足夠通用,通常樣本中的加密都是由一個函數實現,函數本身實現解密,傳入的參數通常是解密字符,和key兩個參數(當然肯定也有其他的模式),那么在寫一個較為通用腳本前需要解決已下幾個問題:
- 如何獲取所有調用解密函數的地址
- 如何獲取需要解密的字符
- 解密算法如何
- 解密之后的處理(最簡單的比如注釋)
首先針對第一個問題,如何獲取調用解密函數的地址。
在ida中針對這一需求其實提供了一個函數XrefsTo,該函數會返回一個地址的所有引用,在ida中通過一下兩句腳本可以測試一下。
for x in XrefsTo(0x1000204D,flags = 0):
print hex(x.frm)
測試結果如下:
第二個問題,如何獲取加密的的字符串。
在本例中函數的調用如下。
此時我們需要用到幾個函數
第一個函數為PrevHead,該函數用於獲取一段代碼段中的指令,ea為開始,mines為結尾,注意這個函數的搜索為降序搜索,說白了就是往前找。通過這個函數我們就可以獲取解密函數之前的指令,即push offset xxxxx指令所在的代碼區域了
long PrevHead (long ea, long minea);
第二個函數為GetMnem,用於獲取ea指定地址附近的指令
string GetMnem (long ea);
第三個函數為GetOpnd,用於獲取操作指定地址ea附近指令的操作碼,注意此處的n為操作碼的編號,由0開始,比如指令push offset xxxxx,0號操作碼為push
string GetOpnd (long ea,long n);
第四個函數為GetOperandValue,用於獲取指定地址ea附近指令的操作數,通用n為操作數的編號,由0開始,比如指令push offset xxxxx,0號操作碼為xxxxx
long GetOperandValue (long ea,long n);
通過這幾個函數就可以獲取壓棧指令push壓如的加密字符了,以下為參數獲取函數
測試效果如下:
但是此處我們只是獲取了加密字符的地址,此處還需要計算出加密字符串的截止地址。
第三個問題,解密字符。
由於此處只是簡單的xor解密,含簡單,當然以后有其他的加密方式,直接增加函數即可。
第四個問題,注釋
可以通過函數MakeComm()實現。ea為注釋地址,comment為注釋類容。
Success MakeComm (long ea,string comment); // give a comment
至此把所有的內容整合起來即可
運行腳本之后的結果。