c++實現的一種代碼膨脹變形殼
本帖最後由 xxx9638527410 於 2017-12-29 21:17 編輯主要實現3個功能:1.代碼膨脹2.代碼變形3.對地址常量包括字符串常量進行加密
代碼膨脹:代碼膨脹無非就是指令等價替換,不過這裡沒條指令最好能有多個膨脹規則,這樣會加大還原難度。原始程序大小為6kb,經過5次混淆後,大小變為66kb.
混淆前代碼:
混淆後代碼:
從上圖會發現有大量的垃圾代碼生成。
說一下代碼變形:1.有分支跳轉改成無分支跳轉。在逆向分析時主要是通過條件跳轉來確定函數的流程,根據跳轉的目標地址來確定這是一個分支還是一個循環。如果將所有條件跳轉改成無分支跳轉,那麼程序只有在動態執行時,才能確定流程。這大大提高了逆向分析的難度。另外,ida在進行還原偽c代碼時,遇到無分支跳轉,會進行截斷,導致後面指令無法還原偽c代碼。這對靠f5吃飯的人說就gameover了。因為此時已經控制了代碼流程, 如果在後面加一些垃圾指令,會導致後面的代碼全部識別錯亂,只有運行時才確定要跳到哪個位置。
另外對jmp imm, call imm和call (一般這種間接call都是api調用) 也改成無分支跳轉。本來沒打算對這類指令進行處理,但是發現效果還挺好,乾脆就加上吧。因為jmp imm也可以作為判斷分支或者循環的依據,而call也是一個比較關鍵的指令,尤其是call api,在逆向分析時,通過觀察api的前後代碼來確定代碼到底在幹嘛。這樣一處理,你靜態分析時看不到任何條件跳轉,看不到任何call調用(除了call reg,當然了,靜態分析你也看不出來call reg)。
另外對條件跳轉和call這類指令的下一條指令加一些垃圾代碼,會導致後面的整段指令識別錯誤。也會給別人留下個坑,比如一般人想步過這個函數調用,會在函數的下一條指令地址處下斷點,但這條指令實際上永遠不會執行。
實現思路:1.將跳轉目標地址保存到一個地址數組表裡面,在建一個索引表記錄地址表的索引,在對索引進行隨機加密。運行時根據條件碼得到正確的索引表地址,在對索引進行解密,得到正確的目標地址偏移。代碼變形前:
代碼變形後:
兩幅圖對比發現call memset 變成了一大串指令,最後以ret結尾。這一大串做了一個事情,去索引表找到地址表的索引,在根據這個索引去地址表找到正確偏移值,加上基地址,得到目標地址。同時會把返回地址壓棧,實際上返回地址是可以隨意更改的,我是按照代碼塊進行處理的,隨意加一些垃圾指令, 把後面的代碼塊往下移動一點就好了,這個自己改,另外索引加密這個我註釋掉了,去掉就可以。大家發現這裡先push了2個寄存器,在這裡偷了點懶,實際上最好應該是用反彙編引擎掃一下當前哪些寄存器是被佔用的,再從沒被佔用的寄存器中隨機分配2個寄存器。如果沒有可利用的寄存器,在這麼做。
call memset是一個立即數,再來看下scanf (call )代碼變形前:
代碼變形後:
再來看下f5後的代碼:代碼變形前:
代碼變形後:
從上圖可以發現變形後,ida根本就沒有識別完整個函數,只識別了一點點。ida遇到無條件跳轉會截斷當前函數。
對地址常量包括字符串常量進行加密:
在進行逆向分析時,很多人第一反應會去看看有沒有一些敏感字符串,根據ida的交叉引用來確定目標地址。另外一些地址值可能也比較關鍵,比如回調函數。而這類常量賦值一般都是mov指令和push指令,對mov imm,push imm這類指令的立即數做隨機加密,就可以起到一個保護的作用。加密前:
加密後:
以上純屬個人見解,有對代碼保護(代碼膨脹變形,vmp)比較感興趣的,可以去wprotect群(群號:210887170)互相交流。在這裡提前祝大家元旦快樂。
轉至看雪
by淡淡的熒光
頁:
[1]