標籤:
0x00 前言
靜態反組譯碼之王,毫無疑問就是Ida pro,大大降低了反組譯碼工作的門檻,尤其是出色的“F5外掛程式”Hex-Rays可以將彙編代碼還原成類似於C語言的虛擬碼,大大提高了可讀性。但個人覺得“F5外掛程式”只能作為一項輔助手段,在結合動態調試和靜態分析之後,瞭解了整個函數的流程再利用F5看“C語言”代碼才是最佳的手段。而這篇文章就是學習如何手寫”花指令“,來幹擾ida的靜態分析和”F5外掛程式“。
0x01 反組譯碼引擎
反組譯碼引擎就是將二進位程式翻譯成了彙編的工具。主流的反組譯碼演算法主要是兩種:線性掃描反組譯碼和遞迴下降反組譯碼。
線性掃描演算法是將一條指令的結束作為另一條指令的開始,從第一個位元組開始,以線性模式掃描整個程式碼片段,逐條反組譯碼每天指令,直到完成整個程式碼片段的分析。主要優點是可以覆蓋程式的所有程式碼片段,但是卻沒有考慮到代碼中可能混有的資料,容易出錯。
遞迴下降演算法依據程式的控制流程,根據一條指令是否被另一條指令引用來決定是否對其進行反組譯碼。例如遇見條件跳轉指令,反組譯碼器從true或者false兩個分支處選擇一個進行反組譯碼,如果是正常的代碼,反組譯碼器優先選擇true分支或者false分支,輸出的彙編代碼並沒有任何區別,但是在遇見人工編碼的”花指令“後,同一塊代碼的兩個分支經常會產生不同的反組譯碼結果。當衝突時,反組譯碼器會優先選擇信任的分支,而大多數面向程式控制流程的反組譯碼器會首先選擇false分支。
更多的具體關於反組譯碼引擎的介紹請參考看雪論壇的文章:
《各種開源引擎,反組譯碼引擎的對比》 :http://bbs.pediy.com/showthread.php?p=1401094#post1401094
0x02 欺騙“F5” Hex-Rays
簡單的”push+ret”組合(和jmp一樣)根本不能騙過ida ,很輕易的就被f5還原出了”C語言”。而多出來的memset()函數是f5將編譯器自動開闢棧的空間的代碼還原了。
我們繼續變化,將”push+ret”組合換成另一種形式:
結果令人有點失望,還是被f5直接還原了。
那我們繼續修改,向下跳轉後再向上跳轉,ida會不會以為是迴圈?
好像是成功了,欺騙了ida的f5。但是稍微看一眼彙編代碼就很容易看出這個迴圈跳轉
但通過以上的例子可以總結出ida f5外掛程式的一些特性:
(1)對於jmp指令的分析完全沒有問題
(2)“push+ret”指令的組合直接當成jmp處理
(3)向下跳轉再向上跳轉,會認為是迴圈
(4)對於手動通過寄存器將值置於棧上的分析能力較弱,但簡單的還是可以直接分析出。
之前都是在函數內部跳轉,也可以改變跳轉的方式,做函數間的長跳轉。
而點進去saveregs會發現是這樣的
很好,看來又成功欺騙了f5外掛程式。但是讀彙編代碼會發現
雙擊進入_next,還是被發現了我們的真正的代碼。
0x03 針對反組譯碼引擎
之前都是用跳轉指令來迷惑”F5”外掛程式,那可不可以讓啟動並執行結果和ida分析的彙編完全不同呢?這裡我們就需要插入一些機器碼來迷惑反組譯碼引擎,比如經常會用到在代碼中間插入一些資料,讓ida無法對資料和代碼進行有效區別,最普通的就是0xE8,因為這是call指令的第一個位元組。
當”f5”還原時,彈出對話方塊,顯示無法”Decompilation”。
反組譯碼的結果顯示將0xE8作為call指令的第一個位元組解釋,然後成為了一個call指令,但是ida已經標註出為紅色了,有經驗的人一看就知道這塊代碼是被”加花”了的.
主要這裡的xor eax , eax 和jz這兩句,這本就是個跳轉,為什麼不直接寫成jmp呢?因為之前說到過的面向控制流程的反組譯碼引擎的策略是遇見jmp直接跳轉,0xe8就會就被識別,這裡人為的寫成“條件跳轉”,以此來達到混淆的目的。機器碼的插入方法有很多,但一些機器碼既可以作為前一條指令的結尾,又可以作為下條指令的開始,比如說剛剛的e8指令,盡量不要用在CPU可以執行的地方,不然很容易讓程式崩潰。我們可以來看稍微複雜的指令插入
可以看到ida的分析結果有點令人失望,”f5”之後也沒什麼用。
我們可以藉助更多的機器碼達到欺騙ida的目的
反組譯碼的彙編代碼:
這裡ida將0x66 0xb8識別為mov指令的前兩個位元組了,然後導致之後的分析錯誤。而在0xe8的中間還可以加入大量的其它花指令。
0x04 SEH
SEH 結構化異常處理,這裡就不多做介紹了,可以閱讀之前的文章Windows x86 SEH 學習,需要說明的是編譯器實現的SEH和普通的不一樣。
0x05 破壞棧幀分析
Ida試圖分析一個函數來確定其棧幀結構,特別是遇到ret/retn就認為到達一個函數結尾,因此很容易偽造棧幀來阻止靜態分析。給之前的代碼加上一個ret 0xff
Ida f5 的結果,認為有63個參數。
還有就是在函數中改變esp的值:比如說這裡的"cmp esp,0x1000",後面的"add esp , 0x102"是永遠不會執行的,在這裡可以改變esp,也可以做其他的很多混淆手段。
最後f5顯示棧幀已經被破壞了,是不是很熟悉,和之前在函數中調用pop,eax的結果一樣,都顯示棧幀已經被破壞了。
0x06 小結
列舉了非常基本的幾種針對ida 和 f5外掛程式的混淆代碼,雖然很基礎,但是可以將非常非常多的混淆代碼進行疊加,形成龐大的”花指令”,花指令的目的就是增加分析的成本。編寫混淆代碼最重要的一點就是堆棧平衡。如果對於代碼混淆,保護做更進一步學習,可以加入GitHub上的開源項目 WProtect 利用”虛擬機器技術”來保護代碼。關於彙編的分析,個人還是覺得不能太依靠ida和Hex-Rays外掛程式,要自己先動態走一遍流程,熟悉整個架構以後再藉助ida 和"F5"外掛程式來提高效率。
參考資料:
《IDA Pro 權威指南》
《惡意程式碼分析實戰》
《加密與解密》
Windows x86 下的 靜態代碼混淆