Windows x86 下的 靜態代碼混淆


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 利用”虛擬機技術”來保護代碼,也可以學習LLVM相關的知識,利用LLVM IR來保護代碼。關於匯編的分析,個人還是覺得不能太依靠ida和Hex-Rays插件,要自己先動態走一遍流程,熟悉整個框架以后再借助ida 和"F5"插件來提高效率。

參考資料:

《IDA Pro 權威指南》

《惡意代碼分析實戰》

《加密與解密》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM