Lab15-01 常用的反彙編總結
在《惡意代碼分析實戰》的第十五章總結了一些常見的反彙編案例,包括線性返回編譯器和非線性返回編譯器的對抗。這裏總結了其中提到的幾個原理,每個都配合着實驗了說明,這篇筆記只是我在做分析時的一些總結,方便後續回來看。
相同目標跳轉指令
問題
在x86彙編指令中,無條件跳轉指令jmp
是跳轉指令之一。在一些惡意樣本中會針對的插入一些指令來完成這個無條件跳轉,如下
從上面的指令看處,jz jnz
都是跳轉到了call
的下一條指令,但是這裏有一個問題,如果跳轉指令要跳轉到一個函數,不可能從函數的第二條指令開始執行,應該是從頭開始執行,同時這個跳轉地址也是紅色的,因此這裏的call
指令是一個對抗指令。
解決
解決的辦法是手動patch掉這個調用指令,每個call
對應的機器碼都是5個長度的指令,爲了能正確時程序變得正常
-
首先用鼠標選擇
call
指令 -
選中後按下
D
按下後程序會變爲數據的形式,但是
0xE8
會被單獨提出來,剩下的指令會單獨成一個快,類似如下jz short near ptr loc_4011C5 jnz short near ptr loc_4011C5 db 0E8h loc_4011C5: db xxx db xxx
-
如上的形式後,從
loc_4011C5
開始使用C
鍵轉爲指令,如下
這裏需要關注的是跳轉指令跳轉到每一個函數快的入口應該是從第一條指令開始執行,不是從第二條指令。
固定目標跳轉
問題
固定目標的跳轉是程序會永遠都會執行跳轉,即永遠爲真的情況如下
這裏的xor eax,eax
會將eax
置位零,同時修改ZF=1
,導致jz
指令會永遠執行,這裏同樣的注意到,跳轉指令
jz shor near ptr loc_4011C4+1
loc_4011C4:
jmp near ptr 94A8D521h
解決
和相同目標跳轉
類似,這裏考慮跳轉指令還是會執行到loc_4011C4
的下一個指令,這是不合理的,解決辦法爲
-
首先用鼠標選擇
jmp
指令 -
選中後按下
D
按下後程序會變爲數據的形式,但是
0xE8
會被單獨提出來,剩下的指令會單獨成一個快,類似如下xor eax,eax; jz loc_4011C5; db 0E9h loc_4011C5: db xxx db xx
-
如上的形式後,從
loc_4011C5
開始使用C
鍵轉爲指令,如下
這裏還是會忽略掉0E9h
這個數據轉爲指令。
總結1
相同目標跳轉指令和固定目標跳轉這兩個技巧都是在jx x可以是z nz ,..,
跳轉指令後插入0E8(call) / 0E9 (jmp)
一個字節,如下
;原始指令
jz tartget+1
jmp invalid_address
;修改後
jz target_2
db 0E9h
target:
xxx
這兩個技巧可以統稱爲流氓字節
案例1
這個案例樣本是Lab15-01.exe
,要求如下
首先使用PEView
看到這個SubSytem=IMAGE_SUBSYSTEM_WINDOWS_CUI
即這個是一個命令執行的程序,將程序拖入ida後,如下
很多特徵符合了流氓字節技術,因此這裏採用上述提到的😨解決中提到的步驟完成後,先第一個call
處理,後續都一樣
在unk_401011
處按下C
之後,如下
接着從mov eax, [ebp+0Ch]
開始,每個出現數據的位置都用C
完成轉化指令
後續使用同樣的方式處理後得到如下
看到了正常的字符串被應用
分析後知道,這個程序要求輸入
.\Lab15-01.exe pdq
就能得到正確的輸出
無效指令
無效指令通常是什麼也不做的NOP
指令,和流氓字節不同的是不能使用上述的方式來處理,因爲並不知道哪一塊的程序是可用的,哪一塊不能用,這需要結合上下文來做實際的處理並選擇忽略那些指令。
案例
這裏使用Lab15-02.exe
作爲分析。首先使用ida打開程序,發現程序有一塊數據沒有轉爲指令,如下
同時看到jmp
指令出現了上面提到的流氓指令干擾
,這裏先處理這個指令,選中後按下D
,變爲如下
可以看到40115E
的位置第一個機器碼爲0E9h
這個是jmp
類指令的機器碼,這裏可以採用修正流氓指令
的方式,這裏選擇unk_40114F
轉爲指令,其他的不做處理,變如下
看到程序被修正了一部分,繼續往下看到了比較標準的流氓指令
同樣使用同樣的方法修正這個指令,
接着來到下一個塊在jmp
後跟着很大一塊數據
這裏處理的方法是先將jmp
指令轉爲數據,之後變成了如下
這裏轉爲指令需要的一個技巧就是要跳過第一個字節0E8h
,在第二個字節0FFh
出開始按下C
轉爲指令,否則還是和沒轉一樣,接着後續的都是一樣的處理方法,最後完成的指令完成如下
分析
在修正完了程序後開始分析代碼的功能,有歷史原因這個樣本給的網絡地址不能訪問,因此這裏不做動態分析,直接靜態分析。
首先看到程序先初始化了網絡環境,接着獲取主機名稱
在獲取到主機名稱後,開始處理獲取的數據,假設本機名稱返回的內容是
ZESKTOP-O7FCL6A
在經過一些數據的校驗後,循環判斷每個字節,如果等於Z
,則替換對應的位置爲A
,如果等於z
則替換爲a
,如果等於9
則替換爲0
,如下
這裏等價於
void test_hostname()
{
int size = 100;
char name[100];
gethostname(name,size);
printf("origin ---> hostname:%s\n",name);
int len = strlen(name);
for (int i = 0; i < len; ++i) {
if (name[i] == 'Z') {
name[i] = 'A';
}
else if (name[i] == 'z') {
name[i] = 'a';
}
else if (name[i] == '9')
{
name[i] = '0';
}
else {
char tmp = name[i] + 1;
}
}
printf("after ---> hostname:%s\n", name);
}
接着使用獲取到的主機名稱獲取一個網絡請求對象
接着在sub_401386
函數內獲取url
在sub_401386
內的內容是
整理後得到請求地址爲
url="http://www.practicalmalwareanalysis.com/bamboo.html"
之後發起網絡請求並判斷內容是包含了Bamboo::
和::
滿足條件後再次發起網絡請求,這一次會讀取一個可執文件,保存在本地的名稱是
整理後得到Account Summary.xls.exe
,接着寫入內容到本地
最後調用ShellExecuteA
函數執行
到此個樣本分析完成。
總結
有些樣本是經過了一些處理在分析的時候如果發現程序不對,可以適當的修正,這些情況都需要根據實際的調整,重點還是多練習即可。