潘 雁, 祝躍飛, 林 偉
(數學工程與先進計算國家重點實驗室,河南 鄭州 450001)
據2016年軟件聯盟(the software alliance,簡稱BSA)發(fā)布的全球軟件調查顯示,2015年,全球范圍內有高達39%的已安裝軟件未經合法授權,這些非法授權軟件導致的損失高達幾千億美元.與此同時,代碼逆向分析技術的發(fā)展,使得軟件保護技術的不斷發(fā)展與創(chuàng)新尤為重要.
Collberg于1997年提出通過將源代碼中邏輯相近的變量、數組等進行物理分離[1],物理分離的思想迅速被應用于二進制代碼混淆算法中.Wroblewski提出了指令與指令序列亂序的思想[2],但其給出亂序的充分條件不夠準確;Birrer等人提出了基于程序切分的代碼混淆方法,將代碼塊切分成多個指令片段,并將其隨機打亂分布在物理地址中,利用跳轉地址表保存切片的保存順序[3].而在工程實現中,指令亂序是通過無條件跳轉的jmp、變形的短跳轉 call等連接指令片段,能較大程度影響逆向分析人員的邏輯.但隨著自動化逆向分析工具的不斷發(fā)展,Ollydbg等工具的Trace功能能夠較好地還原執(zhí)行流程,輔助逆向人員進行分析.其中,指令序列交換的思想被多次提出[2,4],但是未進行系統(tǒng)化地分析與實現,直至2012年,z0mbie提出了基于X86指令架構的對象集的概念,開發(fā)了XDE反匯編引擎分析X86指令的對象集,并簡單探討了相鄰指令交換的條件,但是不夠完善和準確.
軟件程序是由指令構成的序列,序列不同使得程序語義不同,代碼混淆即通過將指令替換、亂序、膨脹等實現與原始程序相同的語義.本文的指令亂序是通過改變一些物理相鄰但相互邏輯獨立的指令執(zhí)行序列來混淆原始程序,為了區(qū)分傳統(tǒng)的指令亂序方法,本文將傳統(tǒng)方法稱為代碼切分亂序.X86指令序列中,存在部分獨立的指令或運算邏輯可交換的指令,即相鄰的指令互換后不影響序列語義,其既與程序編寫思路又與編譯器編譯優(yōu)化相關.通過迭代交換指令,盡可能地將相鄰指令距離增大,也即通過物理分離邏輯.
本文基于Wroblewski構建的計算機架構的形式化定義并予以改進,論證相鄰指令序列交換的充分條件;在分析 X86指令的基礎上改進 XDE反匯編引擎,實現了相鄰指令交換充分條件的判斷;同時,以基本塊內的指令序列為對象實現了指令亂序算法,使得每次生成的二進制代碼具有隨機性,且能較大程度地保持與原始程序的差異性.更進一步,將指令亂序混淆算法應用于虛擬機代碼保護技術,對虛擬機解釋函數進行隨機亂序,增強其隨機性,以此為基礎設計,并實現了改進型虛擬機軟件保護系統(tǒng) IS-VMP(VM-based protection with instructions swapping).
本文的主要貢獻在于:
(1) 改進Wroblewski提出的形式化定義,論證相鄰指令序列交換的充分條件;
(2) 改進 XDE反匯編引擎,采用隨機化算法實現基本塊內的指令亂序,通過實驗驗證其可行性及其效果,為代碼克隆提供了一種新的自動化實現方法;
(3) 對虛擬機解釋函數進行指令亂序,實現兩種混淆算法的融合,增強了虛擬機保護技術的隨機性,并通過實驗驗證了其可行性及其抗逆向分析的效果.
現階段軟件保護的方法主要為源碼混淆和二進制代碼混淆.對于軟件保護者,源代碼是難以獲得的,為了更好地實現功能與混淆的剝離,研究者更多地將精力集中于二進制代碼混淆.但由于逆向分析技術及工具的發(fā)展,使得傳統(tǒng)的代碼混淆算法有效性大大降低.虛擬機代碼保護技術的出現,使得代碼保護進入了一個新的階段,也被認為是未來發(fā)展的主要方向.
虛擬機代碼保護系統(tǒng)首先將PE文件反匯編為X86指令流,并從中提取目標指令(KeyCode)序列,而后將目標匯編指令流轉換成字節(jié)碼(ByteCode).轉換之后,PE文件中被保護代碼的正確運行需要虛擬機解釋器對字節(jié)碼解釋執(zhí)行,因此,整個虛擬機其實是內嵌在PE文件的,它包括跳轉表、虛擬指令調度器(dispatcher)、字節(jié)碼和虛擬指令解釋函數(handler),各模塊名稱及意義分別如下.
· 目標指令:目標指令為待保護程序中被保護的X86指令序列;
· 字節(jié)碼:虛擬機系統(tǒng)定義的一套指令構成的指令序列;
· 虛擬指令解釋函數:用于解釋字節(jié)碼的X86指令序列;
· 虛擬指令調度器:調度虛擬指令解釋函數的執(zhí)行程序;
· 跳轉表:虛擬指令解釋函數與字節(jié)碼的對應關系;
· 虛擬機上下文(VMcontext):用于存儲真實寄存器、虛擬寄存器、跳轉表的結構.
虛擬機保護機制如圖1所示,具體保護步驟如下.
Step 1. 提取待保護程序P中使用SDK標識的KeyCode;
Step 2. 將KeyCode轉化成ByteCode;
Step 3. 構造Handler集合和跳轉表;
Step 4. 重建可執(zhí)行程序文件,將VMContext,ByteCode,Handlers,Dispatcher重新構成新節(jié)或加至最后一節(jié),并在KeyCode指令處填充垃圾代碼.
隨著逆向分析技術的發(fā)展以及逆向分析者對虛擬機結構、解釋函數的持續(xù)分析,虛擬機代碼保護技術也逐漸被攻破[5-7].與此同時,正向保護研究人員不斷將傳統(tǒng)代碼混淆技術與虛擬機代碼保護技術進行融合:房鼎益等人提出通過設計數據流混淆引擎對Handler進行數據流混淆,增大數據流結構的復雜性[8];Sebastian等人提出添加依賴于程序輸入的分支指令,以增大符號執(zhí)行的難度[9];謝鑫等人對所有 Handler進行變長切分和隨機亂序[10];吳偉明等人借鑒傳統(tǒng)混淆技術,提出虛擬花指令序列與虛擬指令模糊變換技術,對虛擬機的虛擬指令系統(tǒng)做了改進[11].都在一定程度上加強了對關鍵代碼的保護.
除此之外,研究人員基于虛擬機代碼保護技術的結構,提出將隨機化、動態(tài)多樣化思想應用于虛擬機代碼保護技術,如圖1中字體為斜體的模塊,其中包括:
(1) Handler多樣化:采用代碼克隆、語義等價等方法生成多個形態(tài)不同但語義等價的Handler序列,來增強多handler序列間的差異性,并通過隨機選擇路徑以抵御累積攻擊[6,12,13];
(2) 虛擬寄存器多樣化:使用多個虛擬寄存器代替單個,模糊虛擬寄存器與主機寄存器的關系,增大數據流分析難度[14];
(3) 指令集隨機化:每次執(zhí)行保護時打亂字節(jié)碼與解釋函數的對應關系,使得不同的保護程序中字節(jié)碼語義不同,延長攻擊者的分析時間[15,16];
(4) 調度器多樣化:使用多個虛擬機調度器,將單一的循環(huán)調度結構擴充為循環(huán)結構與鏈式結構混合調度結構[14].
本文研究基本塊內的指令亂序,并將此隨機化因素添加到Handler構造中,盡可能地減少攻擊者分析同一個虛擬機代碼保護系統(tǒng)保護的不同軟件時所擁有的先驗知識.
X86架構下的軟件程序是由 X86指令集中的指令構成的序列,千變萬化的指令序列構成了不同的程序語義,代碼混淆即通過指令序列替換、亂序、膨脹等實現與原始程序相同的語義.本文通過對基本塊中的指令進行分析,在僅改變指令序列順序的情況下保持原始程序語義,增加序列的差異性.在詳細描述指令序列交換的算法之前,先給出相關定義.
Wroblewski構建了基于系統(tǒng)指令的形式化定義[2],此形式化定義使用數學定義:集合、變量、函數、笛卡爾積、向量等描述代碼語義.為了更好地描述基于X86系統(tǒng)指令的混淆算法,本文將其定義的外沿縮小為X86系統(tǒng),并由此給出相關的形式化定義、定理與相關推論,表1是該定義中使用到的相關符號.
Table 1 Description of used notation表1 符號描述表
2.1.1 基礎定義
X86體系架構是馮·諾依曼體系架構中應用極為廣泛的一種,其核心思想在于通過二進制指令執(zhí)行處理系統(tǒng)存儲的數據,其核心的兩個要素為指令與數據.因此,可以進行如下定義.
定義2.1(計算機體系架構A(I,S)). 在計算機體系架構A(I,S)中,I={I1,I2,…,IM}為指令集合,指令實際為映射I:S→S,其中,S={(v1,v2,…,vN)|v1∈W1,…,vN∈WN}=W1×W2×…×WN是v1,v2,…,vN所有可能值構成的向量空間.
本文中,S是指令操作所依據和影響的對象構成的向量空間,簡稱對象空間,包含所有通用寄存器、標志寄存器和內存引用標志等.以X86體系架構的32位指令為例,其對象空間即為S=EAX×EBX×ECX×EDX×ESI×EDI×ESP×EBP×flags×memory,是一個 10 維向量空間.
定義2.3(輸入對象空間SI(P)). 輸入對象空間是一段程序P操作所依據或讀取的所有對象的向量空間,記為SI(P)=V1×V2×…×VN,其中,
當輸入的第i個分量經過程序P執(zhí)行后影響了某個分量的輸出,或者輸出的第i分量與輸入的第i個分量不等,則認為其在輸入對象空間重要,否則認為該分量是不重要的,即為{α}.
定義2.4(輸出對象空間SO(P)). 輸出對象空間是一段程序P執(zhí)行后影響或寫入的所有對象,記做SO(P)=V1×V2×…×VN,其中,
如果第i個分量的輸入/輸出相同,則認為其在輸出對象空間中是不重要的.
例2.1:假設計算機的狀態(tài)空間為S=W1×W2×W3,假設一段程序為如下映射:
其中,v1∈W1,v2∈W2,v3∈W3.簡單的,可以得到該程序的輸入對象空間和輸出對象空間:
根據上述定義,當程序為單條指令時,可以得到指令的輸入/輸出對象空間.本文將z0mbie提出的X86指令的對象集進行修正,為了簡潔,將對象空間簡化后結果見表2.X86指令按照功能可以分為算術運算、邏輯運算、數據傳送、串操作、控制轉移、處理器控制、保護方式指令,本文將后 3類指令視為特殊指令,其輸入/輸出對象空間均為EAX×EBX×ECX×EDX×ESI×EDI×ESP×EBP×flags×memory.
Table 2 Input context and output context of commonly used X86 instructions表2 常用X86指令的輸入對象空間和輸出對象空間
2.1.2 對象空間操作
為了分析程序與指令的輸入對象空間和輸出對象空間的關系,首先定義對象空間的并、交、差操作.
定義2.5(對象空間的并).設S1和S2是兩個對象空間,則對象空間的并可記做S1∪S2=V1×V2×…×VN,其中,
定義2.6(對象空間的交).設S1和S2是兩個對象空間,則對象空間的交可記做S1∩S2=V1×V2×…×VN,其中,
同時,利用對象空間的交定義對象空間的包含關系.
定義2.7(對象空間的包含).對象空間的包含即為集合的包含,記做S1?S2?S1∩S2=S1.
定義2.8(對象空間的差).對象空間的差即為集合的差,記做S1-S2=V1×V2×…×VN,其中,
為了便于理解,集合{α}具有空集的運算性質,也即{α}∪Wi=Wi,{α}∩Wi={α},Wi-{α}=Wi.
性質 2.1.若假設S1=V1,1×V1,2×…×V1,N,S2=V2,1×V2,2×…×V2,N,則有:
定理2.1.給定程序P=P1|P2,每段程序的輸入對象空間分別為SI(P1),SI(P2),輸出對象空間為SO(P1),SO(P2),則程序的輸入對象空間為
定理2.2.給定程序P=P1|P2,每段程序的輸出對象空間為SO(P1),SO(P2),則程序的輸出對象空間為
特別地,當P1,P2同時為指令時,也即P=I1|I2,程序的輸入/輸出對象空間分別為
恰為文獻[2]中描述的兩條指令的輸入/輸出對象空間.
例2.2:假設一個計算機的狀態(tài)空間為S=W1×W2×W3×W4,兩條指令的映射分別如下:
其中,v1∈W1,v2∈W2,v3∈W3,v4∈W4,則兩條指令的輸入對象空間分別為
輸出對象空間為
給定程序P=I1|I2,由定理2.1和定理2.2,可得程序P的輸入、輸出對象空間分別為
即程序P使用輸入v1,v2,v4改變了v2,v3.
程序語義相同的公式描述的是當狀態(tài)變量在當前程序所引用的分量上相等,則輸出的狀態(tài)變量在所影響的分量上一定相等,即相同語義的程序在其所關注的輸入相同時,輸出一定相同.
定理 2.3(程序交換充分條件).假設程序P1,P2的輸入/輸出對象空間分別為SI(P1),SI(P2),SO(P1),SO(P2),如果:
則有P12=P1|P2≡P21=P2|P1.也即:相鄰兩段程序不會引用另一段程序所影響的分量,同時兩者所影響的分量也正交,那么兩者交換不影響程序語義.
證明:定義如下集合:
由于SO(P1)∩SO(P2)=SO(P1)∩SI(P2)=SI(P1)∩SO(P2)={α}×{α}×…×{α},
對于P12和P21,其輸入對象空間和輸出對象空間相同,同為:
證明完畢.特別地,當程序為一條指令時,可以得到指令交換的充分條件.
定理2.4(指令交換充分條件).假設指令l1,l2的輸入、輸出對象空間分別為SI(l1),SI(l2)和SO(l1),SO(l2),如果:
則有P1=I1|I2≡P2=I2|I1.
例2.3:如圖2中的粗斜體指令,指令I1=movesi,eax與I2=addedx,ebp的輸入對象空間與輸出對象空間分別為(為了運算簡潔,省略特殊值{α}):
滿足條件:
也即P1=I1|I2≡P2=I2|I1.
2.1.3 討 論
定理 2.3與定理 2.4僅從輸入/輸出對象空間考慮程序語義相同的充分條件,沒有考慮指令的映射語義.而X86指令中的算術、邏輯運算等具有其特定的語義,可能滿足指令交換后語義不變的條件.
考慮到 X86指令中加減法具有交換律,因此,分析當兩條指令的操作碼為 ADD,輸出對象空間相同時,是否具有可交換的性質,以擴展指令交換的充分條件.
在輸入、輸出對象空間的指導下,本文將輸出對象空間相同的ADD指令分為3類,見表3.
Table 3 Input context and output context of the instruction ADD表3 ADD指令的輸入/輸出空間
其中,函數f是有關標志寄存器的映射關系.由指令的映射可知:I1與I2是不能交換的.而:
I2與I3是可交換的.同理,I2與I2、I3與I3也是可交換的.同時,INC指令是ADDreg1,imm的特殊情況,可以歸為ADD指令.
同理,SUB與DEC指令也滿足同樣的性質.
由于第1類指令與第3類指令的輸入/輸出對象空間條件相同,因此必須結合X86指令的操作碼進行判斷.不妨設表 3中的第 1類指令為 ADD1,第 2類指令為 ADD2,第 3類指令為 ADD3,對于 SUB指令,同樣定義SUB1,SUB2與SUB3,則ADD1與ADD2的區(qū)分條件為SI?SO;而ADD1與ADD3的區(qū)分條件為操作碼,在X86指令中,ADD1的操作碼范圍為0x00~0x05,ADD3的操作碼范圍為0x80~0x83.
而在邏輯運算中,與、或運算所滿足的結合律使得其也具有一定的可交換性,且由于任意二進制數與自身的與或結果都為自身,因此不需要如加減指令進行分類.輸出對象空間相同的AND指令或OR指令可以互換.
2.1.4 指令序列距離
為了描述經過指令互換后指令序列的差異性,借鑒漢明距離(Hamming distance),給出指令序列距離的定義.
定義2.10(指令序列距離).設P1為一個X86指令構成的基本塊:I1|I2|…|In,經過指令亂序的指令序列為P2:Ii1|Ii2|...|Iin,其中,i1,i2,…,in是1到n的一個有序排列,且滿足P1≡P2(vI)=vO,則指令序列距離為
指令序列距離并未選取距離的絕對值作為指標描述其差異性,原因在于差異性需強調經過混淆前后指令序列的距離,例如原始序列的為 1-2-3,經過混淆后有兩個序列 3-2-1與 3-1-2,若用距離的絕對值作為衡量標準,則認為兩個序列具有相同的差異度,而使用距離的平方值作為衡量標準,則認為序列3-2-1與原始序列的差異度更高,這更符合實際.
本文研究的對象為指令基本塊,是靜態(tài)分析的結果.混淆分為兩個步驟:一是對每條指令的輸入/輸出對象空間進行分析,以判斷是否可以進行指令交換;二是通過模擬退火算法最大化指令序列距離,尋找最優(yōu)交換策略.
圖3為相鄰指令交換的具體流程.
Step 1. 通過反匯編引擎將二進制代碼反匯編為匯編代碼,也即指令序列;
Step 2. 對基本塊中指令序列的每條指令,使用改進后的XDE引擎分析其輸入、輸出對象空間;
Step 3. 判斷兩條相鄰的指令是否滿足交換條件.
其中,指令交換的充分條件由定理2.4和第2.1.3節(jié)構成,可進行如下定義:
則指令交換的充分條件為[4]&&[8].
為了最大化混淆前后指令序列的差異性,問題可抽象為最優(yōu)化問題.給定由 X86指令序列構成的基本塊P=I1|I2|…|In,則問題轉化為
根據定義 2.10,該優(yōu)化問題的變量為(i1,i2,…,in),其滿足的條件為由此變量構成的序列P1≡P2,即該問題為非線性優(yōu)化問題,可以通過遍歷可行解集合求解最優(yōu)值.為了更好地判斷可行解集合的大小,本文任意選取基本塊指令,指令數分別為 40,45,50,55,60,65,遍歷以求得可行解集合大小,實驗環(huán)境為 Win7操作系統(tǒng),Intel(R) Core(TM) i7-6700 CPU@3.40GHz處理器,32G內存.計算結果如圖4,解空間與遍歷時間隨著指令數的增長呈指數型增長,如果指令數超過80,遍歷時間則難以滿足要求.
具體分析遍歷算法的復雜度,以n條指令為分析對象,其中,判斷兩條相鄰指令的交換條件為基本操作,若滿足條件則解空間增加2倍,也即基本操作增加2倍,因此,遍歷算法的時間復雜度為O(2k×n)=O(2n),其中,k×n為n條指令中可相互交換的指令數;關于空間復雜度,遍歷過程中只需額外維護一個當前最優(yōu)值的結構體,也即空間復雜度為O(n).復雜度分析結果與實驗結果相符合.
為了解決上述最優(yōu)化問題,同時增加指令亂序的隨機性,本文采用模擬退火算法的思想對指令亂序進行最優(yōu)化求解,也即:在指令交換過程中,以Metropolis準則接收新解,使用的符號見表4,具體算法步驟如下.
Step 1. 初始化溫度參數T=1,r=0.95;
Step 2. 以原始序列P為初始解,計算目標函數D(P,P)=0;
Step 3. 分析指令序列P(i)中所有可交換的相鄰指令,以第一條指令為起點,判斷是否可與后一條指令交換,若可交換,則產生新解P(i+1),計算目標函數差值ΔD=D(P,P(i+1))-D(P,P(i));
Step 4. 若差值大于0,則接收新解,仍以當前指令為對象進行Step 3;否則,以Metropolis準則接受新解:P(i)=P(i+1),同時進行降溫:T=r×T,以當前指令的下一條指令為對象進行Step 3;
Step 5. 直到所有指令分析結束,跳出循環(huán).
對于每次分析過程,對象僅為兩條相鄰語句,基本操作為判斷兩條相鄰語句的交換條件,內循環(huán)次數不超過2,大循環(huán)的次數是指令序列中指令數n,即算法復雜度為O(n);算法分析過程中所需額外內存都是以指令數為單位,因此其空間復雜度為O(n).該混淆算法能在可接受時間內獲得局部最優(yōu)解,并為算法增加一定的隨機性.
Table 4 Description of used notation in the disorder algorithm表4 指令亂序算法符號描述表
在虛擬機代碼保護的各個階段,都可融合指令亂序混淆算法.本文以解釋函數構造為例,對解釋函數進行指令亂序,這樣每次保護便能得到語義相同但序列不同的解釋函數,增加了虛擬機代碼保護的隨機性和動態(tài)性,增加了攻擊者的分析時間.
虛擬機代碼保護技術的出現,使代碼保護算法的評價更加復雜.目前,學術界并沒有統(tǒng)一標準的方法或指標來評價某種方法或某個系統(tǒng)的保護效果,大多采用Collberg提出的強度、開銷、抗逆向、隱蔽性這4個定性描述[1,17]來分析保護算法是否有效.本文基于這4個定性描述,對解釋函數指令亂序方法進行定性分析.
指令亂序的對象為代碼基本塊,混淆前后的指令數量維持不變,因此在強度屬性上無變化,例如強度屬性中的指令執(zhí)行率、控制流基本塊指標等,指令亂序混淆算法不會改變上述指標.同樣,對于空間開銷和時間開銷,由于經由混淆算法生成的保護后程序沒有增加或修改指令,只是修改指令的執(zhí)行順序,因此相較于原始程序,保護后程序幾乎不會改變任何時間和空間上的開銷.
虛擬機代碼保護技術的逆向分析集中在虛擬機保護技術的結構分析、解釋函數語義還原,而現有的商業(yè)軟件,如Themida,Code Virtualizer等,每個解釋函數的指令數為百千數量級,針對解釋函數的語義還原顯得困難重重.現有的主要方法是盡可能自動化地壓縮 Handler,而后通過符號執(zhí)行對約減后的指令進行語義分析[18],其中,自動化壓縮算法主要為模式匹配.Guillot提出:由于 Handler中大部分為算術運算與堆棧操作指令,可以通過常量傳播、常量合并、運算合并、堆棧優(yōu)化等方法對Handler進行壓縮[19].如圖5所示,可以對3條add指令進行約減.而指令亂序可能將圖中可合并的指令打亂,如圖6所示,原始程序中的add指令約減變得復雜,也即:指令亂序對此類基于模式匹配的自動化約減有較好的抵抗效果,增加了自動逆向分析的難度.
同時,對Handler指令序列進行隨機化指令亂序,使得每次保護后程序的Handler不同,結合指令集隨機化技術,極大地消除攻擊者對Handler的先驗知識,進一步延長攻擊者逆向分析的時間.
隱蔽性強調混淆后程序與原始程序的相似度,其中,謝鑫等人[9]將指令序列之間的相似度作為隱蔽性屬性的度量指標之一.而指令亂序能在對原始程序不進行語義分析的基礎上增大指令序列的差異性,結合垃圾代碼、等價指令替換等混淆方法,能極大地增大隱蔽性.
本文實驗環(huán)境為Win7操作系統(tǒng),Intel(R) Core(TM) i7-6700 CPU@3.40GHz處理器,32G內存,選用的實例指令序列為CV的一個Handler,以此分析指令亂序的效果.
由于CV的Handler序列長度過長,考慮到篇幅限制,本文截取了某個Handler的前40條指令,屬于一個基本塊,對40條指令執(zhí)行指令亂序混淆算法,其中,圖7(a)所示為通過BeyondCompare工具對比混淆前后指令序列的差異,由圖可知:兩個指令序列差異較大,約一半的指令進行了指令交換操作.
由圖 7(b)可知,部分指令與原始指令序列的位置距離較遠.例如第 1條指令經過交換后移至第 20條指令,混淆前后的指令序列距離為17.8,以逆向分析者的角度來說,兩段指令序列已經是語義不同的指令序列.
同時,本文采用的指令亂序算法是在保證局部最優(yōu)值的前提下增加了一定的隨機性,使得同一段指令序列每次經過指令亂序混淆得到的結果都不盡相同,如圖8所示,若原始指令序列長度更長,效果更為顯著.
上文主要闡述了指令亂序算法對指令亂序的效果,而代碼混淆算法的優(yōu)劣更應該從逆向分析人員的角度進行思考與分析[20-23].本文則借助IDA自動化分析逆向工具對指令亂序前后的程序進行比較,分析指令亂序抗逆向分析的效果.
以MD5.exe(標準的MD5加密算法執(zhí)行程序)為輸入,經過指令亂序算法生成MD5-IS.exe,借助IDA工具分析MD5-IS.exe相較于MD5.exe丟失的信息.經指令亂序模塊分析,MD5.exe共有10 130條匯編語句,共進行了1 027次指令交換過程,指令距離為0.3,輸出為MD5-IS.exe.
圖9是MD5String函數經過IDA還原后的偽代碼,經過指令亂序后的函數參數以及名字都有較大的信息丟失,以加大逆向分析者的還原難度.而以SHA1.exe(標準的SHA1加密算法執(zhí)行程序)為輸入時,IDA的反編譯功能對 SHA1-GO函數的偽代碼還原度極高,基本與 C++源代碼相同,對于逆向分析者的后續(xù)工作有極大的幫助;而對于SHA1-IS.exe,反編譯功能則不能執(zhí)行,對其匯編代碼無法進行轉換.
將指令亂序混淆算法與虛擬機代碼保護技術融合,本文采取的融合方法為對每條 Handler進行指令亂序,在虛擬機代碼保護系統(tǒng)My-VMP的基礎上實現IS-VMP系統(tǒng).實驗環(huán)境同上,測試用例選用了標準的加密算法MD4,MD5與 SHA1為測試用例,見表 5.在同樣的實驗環(huán)境下,對測試實例分別用商用軟件 Code Virtualizer(CV),VMProtect以及IS-VMP系統(tǒng)保護.其中:CV版本號為2.2.1.0,使用的虛擬機類型為Tiger32 White;VMP版本號為2.13.8,采用最快速度策略進行虛擬機保護.表6為保護前后文件大小變化,表7為保護前后KeyCode執(zhí)行時間變化.由于每次執(zhí)行時間都有所不同,圖表中執(zhí)行時間為 10次執(zhí)行時間的平均值.其中,MyVMP與IS-VMP的區(qū)別在于是否融合了指令亂序算法.
Table 5 Test case description表5 測試用例描述
Table 6 Comparison of file size表6 保護前后文件大小變化
Table 7 Comparison of exection time表7 保護前后KeyCode執(zhí)行時間變化
為了更加直觀地比較不同方法之間的差別,如圖10所示.
由上述圖表可知,
· IS-VMP與商用保護軟件的縱向對比:其膨脹比例與時間開銷都處在CV與VMProtect兩者之間;
· IS-VMP與MyVMP的橫向對比:融合指令亂序算法后,膨脹比例與時間開銷幾乎不變;而根據前文的分析,IS-VMP在抵抗逆向分析與消除攻擊者的先驗知識上都具有一定的效果.
本文基于Wroblewski提出的形式化定義并加以改進,論證了相鄰指令序列交換的充分條件,并在此基礎上采用模擬退火算法實現了隨機性的指令亂序算法,并以基本塊內的指令序列為對象予以實現.通過實驗驗證了混淆算法的可行性與有效性,為代碼克隆提供了一種新的自動化實現的方法.同時,分析現有的虛擬機代碼保護技術的隨機化與動態(tài)化思想,提出將指令亂序算法應用于解釋函數的混淆,并實現了 IS-VMP系統(tǒng).測試實例結果表明:指令亂序算法能有效增強解釋函數的隨機性,且不增加性能開銷.
指令亂序混淆算法屬于傳統(tǒng)代碼混淆算法,其面向對象為代碼基本塊,因此,其可融合的方向不僅僅解釋函數,研究其應用的場景將是本文未來研究的方向.針對相鄰指令交換,本文所求取的是相鄰指令交換的充分條件,其充要條件仍需更多的研究.同時,研究相鄰指令序列的交換的實現也具有很強的實際意義,也為惡意代碼多態(tài)變形技術的研究提供了借鑒意義.