向 飛 鞏道福 劉粉林
(信息工程大學(xué) 河南 鄭州 450000)(數(shù)學(xué)工程與先進計算國家重點實驗室 河南 鄭州 450000)
隨著軟件產(chǎn)業(yè)的迅猛發(fā)展,軟件在發(fā)揮巨大社會和經(jīng)濟效益的同時,安全問題也隨之產(chǎn)生。通過對商業(yè)軟件進行逆向分析和破解,進而盜用軟件或剽竊核心算法,將對軟件的知識產(chǎn)權(quán)造成嚴重侵害,破壞市場的公平正義。因此,軟件安全已經(jīng)成為軟件產(chǎn)業(yè)界的研究熱點。Collberg等[1]最早提出代碼混淆的軟件保護技術(shù),通過對程序代碼實施混淆變換,在保持程序語義功能等價的基礎(chǔ)上,使其形式變得更加復(fù)雜和難以理解,能夠抵抗靜動態(tài)逆向分析,提高軟件破解的時間成本,進而增強軟件安全性能[1]。
攻擊者對目標程序進行逆向分析時,通常重點關(guān)注實現(xiàn)特定功能的核心代碼。通過靜態(tài)反匯編或動態(tài)跟蹤執(zhí)行,能夠獲取和分析核心代碼,進而理解程序功能或?qū)嵤┐鄹钠平狻R虼?,研究保護程序核心代碼抵抗攻擊者逆向分析,對于保護程序安全具有重要意義。Kulkarni等[2]提出將程序重要代碼進行切片,針對每個代碼片段克隆多個等價片段且生成多條隨機執(zhí)行路徑,增加代碼執(zhí)行路徑的隨機多樣性,使得攻擊者難以恢復(fù)和分析原始代碼。Xie等[3]提出針對程序代碼設(shè)計重疊指令和嵌入跳轉(zhuǎn)指令,函數(shù)執(zhí)行過程跳轉(zhuǎn)到重疊指令中間執(zhí)行,能夠降低代碼反匯編的準確程度。Behera等[4]提出針對函數(shù)代碼進行篡改并嵌入自修改指令,程序執(zhí)行時動態(tài)恢復(fù)執(zhí)行原始代碼,能有效擾亂靜態(tài)反匯編。陳喆等[5]利用隨機森林分類的思想混淆程序重要代碼的路徑信息,將分析路徑分支的難度轉(zhuǎn)化為提取隨機森林規(guī)則的難度。蘇慶等[6]提出基于混沌映射和二次映射的混沌不透明表達式構(gòu)造方法,進而構(gòu)造不透明謂詞插入到重要代碼的混淆,能夠明顯提升軟件代碼的復(fù)雜度。Falcarin等[7]提出將程序重要代碼放置于攻擊者不可控的遠程可信實體,利用網(wǎng)絡(luò)數(shù)據(jù)的流動性使程序執(zhí)行過程動態(tài)獲取代碼,減少攻擊者對程序代碼的可見度。上述方法實現(xiàn)了不同角度的程序代碼保護,然而保護后代碼依然存在于目標程序,容易被逆向分析獲取,或是通過網(wǎng)絡(luò)傳輸執(zhí)行代碼嚴重依賴于網(wǎng)絡(luò)環(huán)境,可用性大打折扣。
針對傳統(tǒng)的直接在進程??臻g注入可執(zhí)行代碼的緩沖區(qū)溢出漏洞攻擊方式,操作系統(tǒng)實現(xiàn)諸多防御機制,如:通過修改可執(zhí)行文件的內(nèi)存布局使得堆棧不可執(zhí)行;通過硬件支持使得進程映像的內(nèi)存空間不能同時可寫入和可執(zhí)行;通過設(shè)置不可執(zhí)行頁限制程序生成可執(zhí)行代碼;通過進程地址空間布局隨機化技術(shù)(ASLR)使堆棧首地址隨機化等。因此攻擊者又提出新型的代碼復(fù)用攻擊方式,不再直接向進程棧空間注入可執(zhí)行代碼,而是充分利用內(nèi)存空間已有的代碼進行執(zhí)行,主要有RIL(Return-into-libc)技術(shù)和ROP(Return-oriented-programming)技術(shù)等。RIL技術(shù)直接復(fù)用內(nèi)存空間的庫函數(shù),通過連續(xù)調(diào)用特定的庫函數(shù)可以實現(xiàn)復(fù)雜的攻擊。ROP技術(shù)是RIL技術(shù)的提升,其以內(nèi)存空間更細粒度的指令片段為復(fù)用對象,能夠?qū)崿F(xiàn)任意圖靈完備的攻擊。具體來說,ROP技術(shù)通過在??臻g預(yù)設(shè)返回地址。使得目標指令片段結(jié)尾處的返回指令(RET指令)直接返回到指定內(nèi)存地址繼續(xù)執(zhí)行下一個指令片段,進而實現(xiàn)指令片段的動態(tài)連續(xù)執(zhí)行。兩種代碼復(fù)用攻擊技術(shù)執(zhí)行的都是進程內(nèi)存空間正常的代碼,因此不會被系統(tǒng)檢測出異常,能夠突破現(xiàn)有的安全防御機制。
由于ROP技術(shù)的代碼組織方式和調(diào)用過程跟傳統(tǒng)的代碼順序執(zhí)行有很大的不同,能夠以較為隱蔽的方式驅(qū)動代碼執(zhí)行,使得ROP技術(shù)在代碼保護方面能夠發(fā)揮一定的作用。已有相關(guān)研究將ROP技術(shù)應(yīng)用于代碼保護,實現(xiàn)較好的保護效果。Ma等[8]實現(xiàn)了基于ROP的動態(tài)軟件水印技術(shù),通過秘密輸入觸發(fā)執(zhí)行精心設(shè)計的ROP指令片段,實現(xiàn)目標水印功能。Mu等[9]實現(xiàn)了混淆工具ROPOB,將函數(shù)基本塊轉(zhuǎn)化為ROP指令片段,通過ROP返回指令將直接控制轉(zhuǎn)移轉(zhuǎn)化為間接控制轉(zhuǎn)移,能夠抵抗攻擊者靜態(tài)分析函數(shù)控制流。ROPOB主要針對基本塊間的控制轉(zhuǎn)移指令進行混淆,沒有考慮基本塊內(nèi)部的普通指令。Lu等[10]實現(xiàn)了混淆系統(tǒng)RopSteg,將目標指令代碼轉(zhuǎn)化為隱蔽的ROP指令片段,然后構(gòu)造ROP生成器實現(xiàn)動態(tài)計算ROP指令片段地址和返回地址。同時構(gòu)造ROP跳板實現(xiàn)將ROP返回地址壓棧再轉(zhuǎn)到ROP指令片段執(zhí)行,能夠有效隱藏目標指令代碼,抵抗靜態(tài)逆向分析。RopSteg主要使用單個等價的ROP指令片段進行混淆,沒有充分結(jié)合ROP技術(shù)在攻擊場景的應(yīng)用特性,實現(xiàn)多個ROP指令片段組合執(zhí)行。
本文提出一種新的基于ROP技術(shù)的代碼混淆方法,用以保護程序內(nèi)部核心代碼避免暴露給逆向攻擊過程。利用程序內(nèi)存空間隨機分布的若干gadget指令片段的動態(tài)組合執(zhí)行,實現(xiàn)目標代碼的等價功能,進而實現(xiàn)隱藏目標代碼的目的,抵抗攻擊者通過靜動態(tài)手段獲取和分析目標代碼功能。
程序執(zhí)行過程中,每個函數(shù)調(diào)用具有獨立的棧幀結(jié)構(gòu),其內(nèi)存空間布局如圖1所示。緩沖區(qū)溢出漏洞的產(chǎn)生是因為在函數(shù)內(nèi)部針對拷貝給局部變量的輸入字符串缺少安全檢查,使得攻擊者能夠通過外部輸入注入二進制可執(zhí)行代碼到??臻g而且把函數(shù)返回地址覆蓋為可執(zhí)行代碼地址,導(dǎo)致函數(shù)執(zhí)行完畢返回到攻擊者注入的代碼進行執(zhí)行,進而實現(xiàn)惡意攻擊目的。
圖1 函數(shù)棧幀結(jié)構(gòu)的內(nèi)存布局
ROP攻擊技術(shù)不直接向函數(shù)棧空間注入可執(zhí)行代碼,而是另辟蹊徑,充分利用內(nèi)存空間共享庫代碼中以ret指令結(jié)尾的指令片段(稱為gadget)。ret指令的功能是彈出棧頂?shù)?字節(jié)數(shù)據(jù)并賦給指令指針寄存器EIP作為下一條執(zhí)行指令的地址。ROP技術(shù)將若干gadget的地址和數(shù)據(jù)按照固定順序注入到函數(shù)??臻g,通過執(zhí)行前一個gadget結(jié)尾的ret指令可跳轉(zhuǎn)至棧中設(shè)定的后一個gadget繼續(xù)執(zhí)行,進而實現(xiàn)gadget的動態(tài)連續(xù)調(diào)用,不動聲色地達到攻擊目的。下面舉例說明ROP技術(shù)的實現(xiàn)過程,圖2為實現(xiàn)0x10與0x20的加法操作。
圖2 ROP技術(shù)示例
圖2左側(cè)為ROP技術(shù)利用緩沖區(qū)溢出漏洞向函數(shù)??臻g注入的數(shù)據(jù),其中g(shù)adget1、gadget2和gadget3分別為內(nèi)存空間共享庫代碼的3個gadget的地址,gadget1所在位置指向函數(shù)返回地址。圖2中間分別為地址gadget1、gadget2和gadget3指向的gadget指令片段。實施ROP攻擊后的程序執(zhí)行過程為:函數(shù)執(zhí)行完畢返回到gadget1執(zhí)行,pop eax指令取出0x10到eax寄存器,ret指令取出gadget2作為返回地址執(zhí)行;然后pop ebx指令取出0x20到ebx寄存器,ret指令取出gadget3作為返回地址執(zhí)行,add eax,ebx指令實現(xiàn)0x10與0x20相加;結(jié)果保存到eax寄存器,ret指令退出當前執(zhí)行過程。圖2通過精心構(gòu)造數(shù)據(jù)注入到函數(shù)??臻g,實現(xiàn)3個gadget的連續(xù)調(diào)用執(zhí)行,最終實現(xiàn)0x10與0x20的加法操作。相比傳統(tǒng)的直接注入可執(zhí)行代碼的攻擊方式,ROP技術(shù)通過復(fù)用程序內(nèi)存空間代碼,不僅減少了注入的數(shù)據(jù)量,而且提高了漏洞攻擊的隱蔽性,能夠繞過操作系統(tǒng)的安全防御機制??紤]到ROP技術(shù)在驅(qū)動大量代碼片段連續(xù)執(zhí)行等方面具有獨特的實現(xiàn)方式和較好的隱蔽效果,因此本文將ROP技術(shù)應(yīng)用到程序核心代碼的混淆,進而提出新的基于ROP技術(shù)的代碼混淆方法。
借鑒ROP攻擊技術(shù)的代碼復(fù)用思想,本文提出一種基于ROP技術(shù)的代碼混淆方法,具體的流程框架如圖3所示。方法提取目標程序基本塊內(nèi)部需要保護的核心代碼,利用內(nèi)存空間實現(xiàn)等價功能的gadget指令序列予以混淆替換,進而達到隱藏核心代碼和抵抗靜動態(tài)分析的目的。其中g(shù)adget指令序列通過搜索系統(tǒng)共享函數(shù)庫或等價指令變換構(gòu)造等方式進行獲取。
圖3 基于ROP技術(shù)的代碼混淆方法流程框架
首先定義指令代碼的完全語義等價和條件語義等價。
定義1(完全語義等價):設(shè)目標指令I(lǐng),指令序列IS={I1,I2,…,In},若IS能夠?qū)崿F(xiàn)I的等價功能,則稱IS與I完全語義等價,記作I≌IS。如針對目標指令mov eax,1,執(zhí)行push edx, mov edx,1, mov eax,edx, pop edx能夠?qū)崿F(xiàn)相同的語義功能,則有mov eax,1≌{(diào)push edx, mov edx,1, mov eax,edx, pop edx}。
定義2(條件語義等價):設(shè)目標指令I(lǐng),指令序列IS={I1,I2,…,In},數(shù)據(jù)集DS={d1,d2,…,ds}。動態(tài)執(zhí)行時,DS預(yù)先存儲在棧空間,d1到ds自棧頂開始向棧底方向連續(xù)分布,若IS通過調(diào)用DS能夠?qū)崿F(xiàn)I的等價功能,則稱IS與I條件語義等價,記作I∽IS@DS。如針對目標指令mov eax,1,棧頂數(shù)據(jù)為1時,執(zhí)行pop eax能夠?qū)崿F(xiàn)相同的語義功能,則有mov eax,1∽{pop eax}@{1}。
混淆方法通過調(diào)用完全語義等價或條件語義等價的指令序列實現(xiàn)核心代碼的等價功能,下面描述混淆實現(xiàn)過程。
圖4 程序執(zhí)行路徑
算法1ROP混淆實現(xiàn)過程算法
1.functionRopObf (K)
3.forifromnto1do
4.forjfrommito1do
8.endfor
9.endif
11.endfor
12.endfor
13. InsertInstruction(ret)
14.endfunction
混淆后程序執(zhí)行路徑如圖5所示。
圖5 混淆后程序執(zhí)行路徑
經(jīng)過前述混淆過程,指令代碼K混淆成連續(xù)調(diào)用執(zhí)行的gadget指令序列。為了增強混淆效果,針對指令代碼K的每條指令I(lǐng)i,同時選取ri組實現(xiàn)等價功能的gadget進行混淆,程序動態(tài)執(zhí)行時隨機選擇一組gadget執(zhí)行,進而實現(xiàn)程序執(zhí)行路徑和執(zhí)行代碼的隨機多樣化,增加逆向分析的難度。隨機多樣化混淆后的程序執(zhí)行效果如圖6所示。
圖6 隨機多樣化混淆效果
混淆方法利用程序內(nèi)存空間的gadget指令序列替換實現(xiàn)原始核心代碼的等價功能。提出兩種方法獲取混淆所需要的gadget:一種是在目標程序代碼或所調(diào)用的系統(tǒng)共享函數(shù)庫代碼中,搜索以ret指令結(jié)尾的gadget;另一種是有針對性的構(gòu)造以ret指令結(jié)尾的gadget,嵌入到目標程序或自定義共享函數(shù)庫。下面分別介紹兩種gadget獲取方法。
程序執(zhí)行時,在內(nèi)存空間駐留的大量的可執(zhí)行代碼,包括程序自身代碼以及系統(tǒng)共享函數(shù)庫代碼,都可以被直接調(diào)用執(zhí)行。共享函數(shù)庫通常在程序運行時加載到內(nèi)存空間,提供函數(shù)給程序調(diào)用,如Windows操作系統(tǒng)的kernel32.dll、user32.dll等動態(tài)鏈接庫。共享函數(shù)庫含有大量豐富的代碼,能夠用來提取混淆需要的gadget。因為目標程序或共享函數(shù)庫的代碼段具有可執(zhí)行權(quán)限,故而指定在代碼段搜索gadget。下面給出逆序搜索獲取gadget的算法。
在代碼段定位所有的ret指令,ret指令對應(yīng)的十六進制字節(jié)是0xC3,因此直接搜索全部字節(jié)0xC3。從每個字節(jié)0xC3的位置開始,逆向搜索若干字節(jié),若是有效的機器指令則進行記錄,然后從當前位置繼續(xù)逆向搜索若干字節(jié),如此循環(huán)往復(fù),直到不能得到有效的機器指令,或者搜索深度長度超過指定閾值。將按上述過程搜索得到的指令組織成以ret指令為根節(jié)點的指令序列樹。每個節(jié)點都是一條指令,每個子節(jié)點指令是父節(jié)點指令前面緊鄰的指令,每個父節(jié)點指令是子節(jié)點指令后面緊鄰的指令。每個節(jié)點可能具有多個子節(jié)點,因為對于一條指令前面緊鄰的字節(jié),不同長度的字節(jié)可能翻譯成不同的指令。每個非根節(jié)點到根節(jié)點的路徑經(jīng)過的所有指令按順序串聯(lián)起來即構(gòu)成一個gadget指令序列。
設(shè)ret指令對應(yīng)的十六進制字節(jié)為b0,以b0結(jié)尾的字節(jié)流為BS=(…b2b1b0),采用遞歸算法構(gòu)造指令序列樹T,初始化T的根節(jié)點為ret指令。定義遞歸函數(shù)GenerateTree(Instruction ins, Index pos, Short depth),參數(shù)pos是指令ins的首個字節(jié)bpos的索引編號,depth是指令ins位于指令序列樹T的深度,設(shè)根節(jié)點的深度為0。函數(shù)實現(xiàn)的功能是判斷若指令ins的深度depth小于或等于閾值threshold,則把位于指令ins前面的字節(jié)流(…bpos-2bpos-1)構(gòu)造成以ins指令為根節(jié)點的指令序列樹,作為T的子樹,否則直接退出。輸入二進制字節(jié)流BS,構(gòu)造指令序列樹T的偽代碼如算法2所示。
算法2指令序列樹構(gòu)造算法
INPUT: (…b2b1b0) whereb0is disassembled into ret
OUTPUT:T
1. let ret be the root node of T
2. GenerateTree(ret, 0, 0)
3.functionGenerateTree(Instruction ins, Index pos, Short depth)
4.ifdepth≤thresholdthen
5.forstepfrom1tomax_lendo
6.if(bpos-step…bpos-1) can be disassembled into a valid instruction childinsthen
7. letchildinsbe the child ofinsinT
8. GenerateTree(childins,pos-step,depth+1)
9.endif
10.endfor
11.endif
12.endfunction
指令序列樹T構(gòu)造完成后,把每個非根節(jié)點(包括葉子結(jié)點和內(nèi)部節(jié)點)到根節(jié)點的路徑所經(jīng)過的所有節(jié)點指令按順序串聯(lián)起來,即得到以ret指令結(jié)尾的gadget指令序列。T的葉子結(jié)點和內(nèi)部節(jié)點的數(shù)量等于在字節(jié)流BS中提取到的gadget的數(shù)量。
圖7為指令序列樹T,設(shè)I1=(b2b1),I2=(b3b2b1),I3=(b5b4b3),I4=(b5b4),I5=(b6b5b4),I6=(b7b6),I7=(b7b6),可以提取7個gadget指令序列,分別為{I1,ret},{I2,ret},{I3,I1,ret},{I4,I2,ret},{I5,I2,ret},{I6,I3,I1,ret},{I7,I4,I2,ret}。
雖然通過搜索能夠獲取到豐富多樣的gadget,但是難以保證混淆過程需要的gadget都能匹配到,因此提出采用構(gòu)造的方法獲取gadget。通過對目標指令進行等價變換得到完全語義等價或條件語義等價的指令序列,在末尾添加ret指令即生成gadget,然后嵌入到目標程序的空閑空間或新增區(qū)塊,或者嵌入到自定義共享函數(shù)庫的導(dǎo)出函數(shù)內(nèi)部。程序運行時加載到內(nèi)存空間的gadget能夠被調(diào)用執(zhí)行。
針對目標指令直接應(yīng)用等價指令變換能夠生成完全語義等價的指令序列。生成條件語義等價的指令序列的步驟如下:提取目標指令的常量操作數(shù)并假定常量操作數(shù)已經(jīng)存儲在棧頂空間;構(gòu)造pop指令依次提取棧頂?shù)某A坎僮鲾?shù)保存到寄存器;構(gòu)造指令使用寄存器操作數(shù)替換常量操作數(shù)實現(xiàn)目標指令的等價功能;應(yīng)用等價指令變換即生成條件語義等價的指令序列,如表1所示。
表1 目標指令的等價指令序列
下面給出幾種等價指令變換方法,如表2所示。
表2 等價指令變換方法示例
等價指令替換:使用單條指令實現(xiàn)目標指令等價的語義功能。
指令寄存器替換:針對目標指令的通用寄存器進行替換而不影響語義功能,進而變換出等價指令序列。
垃圾指令插入:在目標指令的前后位置分別插入若干垃圾指令而不影響語義功能,進而變換出等價指令序列。
指令位置變換:若目標指令序列存在若干指令沒有執(zhí)行依賴關(guān)系,則變換指令前后位置不會改變指令序列執(zhí)行功能,進而變換出多樣化的等價指令序列。
通過應(yīng)用多樣化的等價指令變換方法進行迭代變換,能夠生成更加復(fù)雜的完全語義等價或條件語義等價的指令序列,增加逆向分析的難度。算法3給出針對單條指令的基于迭代的等價指令變換算法實現(xiàn)過程的偽代碼。其中:Match(I,R)表示根據(jù)等價指令變換規(guī)則R匹配指令I(lǐng)的等價指令序列;Replace(EIS,I, Match(I,R))表示把指令序列EIS的指令I(lǐng)替換成匹配到的等價指令序列。
算法3基于迭代的等價指令變換算法
INPUT: Target instructionI, equivalent instruction transformation ruleR, iteration depth thresholdD
OUTPUT: Equivalent instruction sequenceEIS
1.functionTransform(I,R,D)
2.EIS={I}
3.ifD==0orMatch(I,R)==NULLthen
4.returnEIS
5.elsethen
6.EIS=Repalce(EIS,I, Match(I,R))
7.foreachiinEISdo
8.EIS=Replace(EIS,i, Transform(i,R,D-1))
9.endfor
10.endif
11.returnEIS
12.endfunction
圖8 隱蔽嵌入gadget效果
本文提出的基于ROP技術(shù)的代碼混淆方法,能夠在一定程度上保護程序內(nèi)部代碼避免暴露給逆向工程。下面分別從有效性、空間開銷和時間開銷三個方面分析和評價方法的性能。
攻擊者通過靜態(tài)分析能夠輕易獲取程序內(nèi)部核心代碼,通過動態(tài)分析能夠跟蹤核心代碼的執(zhí)行功能?;煜椒ɡ肦OP技術(shù)復(fù)用內(nèi)存空間的指令代碼,能夠有效隱藏程序內(nèi)部原始核心代碼,導(dǎo)致攻擊者難以通過靜態(tài)分析判斷核心代碼存在及獲取核心代碼。
通過使用多樣化的等價指令變換方法針對目標指令進行迭代變換,能夠生成形式多樣、長度膨脹、執(zhí)行復(fù)雜的等價指令序列,增加攻擊者分析代碼的難度,同時通過隱蔽嵌入gadget指令序列,能夠有效抵抗靜態(tài)反匯編分析。
程序動態(tài)執(zhí)行時,混淆指令序列隨機分布在程序內(nèi)存空間的不同位置,使得程序執(zhí)行軌跡在內(nèi)存空間不斷跳變,執(zhí)行過程的上下文環(huán)境不斷變化,能夠增加攻擊者動態(tài)跟蹤分析的難度。
原始核心代碼K只有唯一執(zhí)行路徑,而經(jīng)過隨機多樣化混淆后,代碼執(zhí)行路徑數(shù)P如下:
程序每次動態(tài)執(zhí)行的路徑動態(tài)隨機變化,攻擊者想要分析代碼的執(zhí)行功能,需要把全部的P條執(zhí)行路徑分析清楚,因此隨機多樣化的混淆策略能夠進一步增加逆向分析的難度和時間成本。
綜上分析,混淆方法能夠有效隱藏和保護程序內(nèi)部核心代碼,抵抗多種特定的逆向分析手段,在靜態(tài)和動態(tài)兩方面能夠發(fā)揮較好的保護作用。
混淆后程序相比原始程序增加數(shù)據(jù)和代碼,使得程序的空間開銷和執(zhí)行時間開銷相應(yīng)增大?;煜^程給目標程序增加的空間開銷主要包括如下幾部分:首先是通過等價變換生成的gadget指令代碼,混淆階段嵌入到程序內(nèi)部或自定義共享函數(shù)庫;其次是連續(xù)的壓棧操作代碼,實現(xiàn)gadget指令序列地址及數(shù)據(jù)依次壓棧;最后是實現(xiàn)加載函數(shù)庫以及獲取內(nèi)存地址等功能的輔助代碼。設(shè)各部分混淆代碼的大小分別為S1、S2、S3,則混淆后程序增長的空間開銷約為:
S=S1+S2+S3
混淆過程給目標程序增加的時間開銷主要是代碼S1、S2、S3的執(zhí)行引起的。設(shè)混淆代碼S1、S2、S3的平均執(zhí)行時間分別為T1、T2、T3,則混淆后程序增長的時間開銷約為:
T=T1+T2+T3
根據(jù)混淆過程可知,混淆增加的空間開銷應(yīng)主要由構(gòu)造嵌入的gadget指令代碼所影響,在處理器運算速度極快的條件下,混淆代碼的執(zhí)行不會增加過多時間開銷。可以推算,混淆不會給程序造成嚴重的空間和時間開銷,應(yīng)具有可接受的開銷性能,后續(xù)通過實驗進一步驗證和分析。
本節(jié)通過實驗驗證方法的有效性并評價方法的性能。實驗環(huán)境為32位Windows 7操作系統(tǒng),3.10 GHz Intel Core 5處理器以及4 GB內(nèi)存。實驗首先選取5款常用的系統(tǒng)共享函數(shù)庫,在代碼段遞歸搜索以ret指令結(jié)尾的gadget指令序列,分別設(shè)置搜索深度為1到4,記錄搜索到的gadget數(shù)量,如表3所示??梢钥吹剑到y(tǒng)共享函數(shù)庫包含大量的gadget,混淆過程可以根據(jù)需要隨機選擇可用的gadget進行混淆。為了保證總能獲得混淆需要的gadget,實驗同時通過等價變換構(gòu)造大量實現(xiàn)目標功能的gadget。
表3 gadget指令序列搜索結(jié)果
實驗選取6款測試程序進行混淆,分別為在VS2010環(huán)境下編譯生成的3款Debug版本程序,包括冒泡排序程序Bubble.exe、漢諾塔程序Hanio.exe和八皇后程序Queue.exe,以及Windows7操作系統(tǒng)下的3款輕量級系統(tǒng)應(yīng)用程序,包括計算器程序Calc.exe、網(wǎng)絡(luò)測試程序Ping.exe和記事本程序Notepad.exe。實驗選取測試程序的部分功能代碼進行混淆,例如選取的冒泡排序程序代碼以及針對其中兩條指令的混淆示例。如圖9所示,通過在??臻g預(yù)設(shè)指令地址和數(shù)據(jù),實現(xiàn)gadget指令序列的連續(xù)調(diào)用執(zhí)行。
圖9 冒泡排序程序混淆示例
混淆實驗結(jié)果如表4所示,分別列出混淆的目標代碼數(shù),混淆前后程序體積大小及混淆后程序的執(zhí)行情況,其中冒泡排序程序輸入數(shù)組規(guī)模為2 000(將從大到小排列的數(shù)組通過冒泡排序排列成從小到大排列的數(shù)組),漢諾塔程序輸入規(guī)模為24,設(shè)置八皇后程序棋盤大小為12×12?;煜蟪绦蚪?jīng)過反復(fù)測試執(zhí)行,均能實現(xiàn)原始程序的正常功能,證明混淆方法具有可行性,能夠保持程序語義功能等價。
表4 混淆前后程序的執(zhí)行和開銷情況
在時間開銷方面,記錄混淆前后的冒泡排序、漢諾塔和八皇后程序的精確執(zhí)行時間以及另外三個程序的執(zhí)行時間變化情況。實驗結(jié)果顯示冒泡排序、漢諾塔和八皇后程序的執(zhí)行時間增長都非常小,另外三個程序正常執(zhí)行過程均沒有明顯時間變化,說明混淆方法沒有帶來巨大時間開銷,具有較好的時間開銷性能。在空間開銷方面,混淆后程序體積適當增長,而且隨著混淆的目標代碼數(shù)量越多,程序體積增長越大。然而程序載體通常具有足夠的存儲和處理資源,適當?shù)捏w積增長基本不會影響程序的存儲、加載和運行等過程,因此混淆方法依然具有較好的空間開銷性能。
由于沒有統(tǒng)一的混淆強度度量標準,因此本文根據(jù)混淆方法的實際保護效果,提出適用本文方法的混淆強度指標并結(jié)合實驗結(jié)果進行分析。首先混淆后程序的每個核心代碼塊的執(zhí)行變成很多個gadget代碼塊的等價執(zhí)行,與混淆前攻擊者相比,需要分析數(shù)量更多的代碼塊以及更加復(fù)雜的控制轉(zhuǎn)移關(guān)系,因此可以使用混淆代碼塊數(shù)量比例RB度量混淆方法在代碼塊層面的保護強度。設(shè)NKB表示混淆的原始程序核心代碼塊的數(shù)量,NGB表示混淆后程序gadget代碼塊的數(shù)量。RB的計算如下:
RB=NGB/NKB
混淆使得攻擊者需要分析的指令數(shù)量大大增加,因此可以使用指令數(shù)量比例RI度量混淆方法在指令層面的保護強度。設(shè)NKI表示原始程序核心代碼的指令數(shù)量,NGI表示混淆后程序gadget指令序列的指令數(shù)量。RI的計算如下:
RI=NGI/NKI
混淆所調(diào)用的gadget指令序列的二進制字節(jié)序列可能隱藏在正常指令代碼的字節(jié)序列內(nèi)部,使得靜態(tài)反匯編獲取不到實際執(zhí)行的gadget指令序列,進而達到迷惑和干擾反匯編的效果。因此可以使用正確反匯編的gadget指令數(shù)量比例RD度量混淆方法抵抗靜態(tài)反匯編的保護強度。設(shè)NDGI表示能夠正確反匯編的gadget指令數(shù)量。RD的計算如下:
RD=NDGI/NGI
根據(jù)RB、RI、RD的定義可知,RB和RI越大,攻擊者需要分析的代碼塊和指令數(shù)量相對越多,需要分析gadget之間的控制轉(zhuǎn)移關(guān)系越復(fù)雜;RD越小,攻擊者靜態(tài)反匯編能夠正確獲取的指令數(shù)量相對越少。實驗分別統(tǒng)計6款測試程序混淆前后的NKB、NGB、NKI、NGI、NDGI值,計算相應(yīng)的RB、RI、RD值,結(jié)果如表5所示。圖10更直觀地對比展示了混淆前后的統(tǒng)計結(jié)果。
表5 混淆前后程序相關(guān)數(shù)據(jù)
(a)
(b)圖10 混淆前后代碼塊數(shù)量和指令數(shù)量對比
由表5的實驗結(jié)果可以看到,RB的取值范圍為14.4~18.4,平均值為16.9,意味著攻擊者需要分析的混淆后代碼塊數(shù)量是混淆前的16.9倍。RI的取值范圍為5.36~9.45,平均值為7.09,意味著攻擊者需要分析的混淆后指令數(shù)量是混淆前的7.09倍。RD的取值范圍為0.42~0.63,平均值為0.54,意味著通過靜態(tài)反匯編只能正確得到54%的混淆后gadget指令。實驗結(jié)果證明,混淆方法能夠有效增加靜動態(tài)獲取和分析核心代碼的難度,在一定程度實現(xiàn)代碼隱藏的保護效果。
本文針對程序核心代碼容易暴露給逆向攻擊的問題,提出一種基于ROP技術(shù)的代碼混淆方法。方法借鑒ROP攻擊技術(shù)的代碼組織和調(diào)用方式,通過在??臻g預(yù)設(shè)指令地址和數(shù)據(jù),利用程序內(nèi)存空間隨機分布的gadget指令序列動態(tài)組合執(zhí)行,實現(xiàn)目標代碼的等價功能。同時方法采取搜索和構(gòu)造兩種方法獲取混淆所需要的gadget指令序列,進一步實現(xiàn)執(zhí)行代碼和路徑的隨機多樣化。實驗和分析證明,方法能夠有效增加攻擊者獲取和分析核心代碼的難度,在靜態(tài)和動態(tài)兩方面實現(xiàn)較好的保護效果,具有較好的時間和空間開銷性能。