加殼是對軟件內核一種很有效的保護方式。目前Linux系統(tǒng)下的加殼方法,多是直接繼承Windows 程序的加殼理論和方法, 在傳統(tǒng)加殼工具上進行了有限的擴展, 單純在LINUX 系統(tǒng)下實現的加殼工具還是很少的。如何在Linux 系統(tǒng)下盡量減少內核信息的暴露,增加有難度的反逆向手段來提升破解難度,對加殼保護程序進行很好的隱藏,都是目前主要攻克的難題。
根據加載外殼程序方式的不同將現有軟件加殼技術分為:嵌入式、附加式和包含式。嵌入式中最經典的是Upx,支持多種文件類型加殼,且壓縮算法先進。但該方法缺少反動態(tài)跟蹤功能,破解者可用動態(tài)跟蹤調試方法對Upx 進行破解[1]。文獻[2]中描述了附加式加殼(SELF 加殼):在原elf 文件格式中添加處理安全操作的代碼段,但不內置解壓縮,容易暴漏殼的位置。包含式結合了壓縮和保護兩種類型的殼,但殼加載的過程中會改變入口地址。結合上述三種加殼方法的優(yōu)缺點, 文章提出了在Linux 系統(tǒng)下一種改進的加殼保護方法—加殼并重構可執(zhí)行文件———SRELF[3]。改進后的算法將殼程序和目標可執(zhí)行文件中代碼段, 數據段等關鍵部分相結合,引入多態(tài)變形技術,使程序呈現出多態(tài)性,提高了殼程序的反破解能力,同時還很好的隱藏了加殼的信息。通過實驗證明, 改進后的方法解決了加殼中入口地址易被改變的問題,使得加殼的程序以多態(tài)的形式出現,很大程度上提高了反破解的難度。
1 加殼原理
加殼實質上就是把一段特殊程序附加到應用程序中,并把程序的執(zhí)行入口指向附加的特殊殼程序。殼的加載過程如圖1 所示, 首先殼程序需要獲得應用程序編程接口———即API 地址。在加殼程序的代碼中用顯示鏈接方式動態(tài)的加載所需的API 地址。通過殼程序后,對各個區(qū)塊的數據按照定義進行解密;若加殼時用到了壓縮技術,那么在解密之前先要進行解壓縮,然后將解壓文件映像到指定內存地址中。修改原程序文件的輸入表后填充HOOK—API 表中的代碼地址,間接的獲得程序的控制權,進行校驗和測試完后跳轉到原入口點(OEP)[3]。
現有的軟件加殼技術方法大多都改變了原有文件結構,在重定位的過程中改變程序的入口地址,加載的過程中把部分程序映射到地址空間中,若破解者知道如何在一個加殼程序中尋址,那么當文件被加載進內存時就可以找到加殼程序的信息。文章針對上述問題, 提出了一種改進的加殼方法SRELF。
2 SRELF 加殼方法
2.1 SRELF 方法原理
SRELF———加殼并重構可執(zhí)行文件,最大特點是重構變形使得重構的程序呈現多態(tài)性。首先將目標elf 文件中的核心部分提取出來,然后與準備好的解密或解壓縮程序,反靜態(tài)分析和反動態(tài)跟蹤程序結合在一起,讓加殼程序呈現出多態(tài)變形性,最后遍歷整合程序,按照elf 文件標準格式重新構造一個全新的elf 可執(zhí)行文件。
2.2 SRELF 方法實現
如圖2 所示:SRELF 加殼方法實現的基本程序框圖。首先了解應用程序二進制接口文件(即擴展名為elf 文件)結構。圖3 所示為標準elf 文件的結構圖。從圖中可以看到:一個ELF 頭在文件的開始,保存了路線圖描述了文件組織情況。隨后是一些段(segments)或者一些區(qū)段(sections)。段中包含文件運行所需的信息, 而保存著object 文件的信息,用于鏈接和重定位。
第一步:提取目標文件中的核心部分
提取核心部分的可執(zhí)行指令、動態(tài)鏈接表、段或節(jié)等信息。由于匯編程序中存在間接跳轉使得反匯編生成控制流圖中斷,影響了提取核心代碼的準確性,這里引入了一種間接跳轉程序方式[4]。
1)從殼運行到原始程序的OEP 進行單步向下跟蹤,遇到拋出異常后,修改溢出標志;
2)分析操作數的類型。若是直接尋址類型,進入4);否則進入3);
3)找到定義的語句或函數入口,設置CREAT_SUSPENDED計數器,若計數器加一,則將宿主進程作為一個掛起的子進程打開,調用GetThreadContext()獲取子進程初始化線程的上下文;
4)判斷后的程序進行輸入鎖定,在語句序列上模擬執(zhí)定義位置與目標間接跳轉運算,對獲取寄存器內容進行復制。使用間接跳轉語句獲取elf 頭文件中的信息后, 定位到GetElfCore 的頭表,然后定位到所需代碼段的核心位置,將其中的數據復制出來。
第二步:對提取的核心代碼加密并結合多態(tài)變形技術
采用進程注入加密技術,逆向阻止脫殼軟件附加在受保護的進程上。先讓CONTEXT.EBX 獲取子進程的PEB 地址,讀出PEB 子進程的映像地址后,將基礎地址參數指向檢索到的映像基址,最終完成對各種外部中斷的監(jiān)視工作。對加密后的核心代碼進多態(tài)變形技術改進,讓其改變自身代碼,從而使搜索字符串的識別技術失去效果。文章采用的代碼變換加密壓縮來隱藏自身,為了防止搜索字符串的方法檢測到,解密代碼引動代碼模塊,程序將其插入其本身,調用代碼模塊中包含的函數,移動例程周圍的指令,隨機增加無用的指令,使用不同的寄存器和操作碼,使得解密例程對應的二進制代碼在不同的感染體內完全不一樣[5]。多態(tài)變形引擎過程如圖4 所示。
第三步:將目標文件的核心部分和加殼部分整合
整合目標文件的核心部分和加殼部分需要進行精確的計算,設置正確的elf 文件頭、程序頭表、節(jié)頭表等的數據。這樣新生成的elf 文件才能正常運行。在整合elf 等數據時采用遍歷整合的方法,對前面提取的的核心代碼塊逐一進行分析。采用循環(huán)回繞整合加殼后的核心代碼。
1)先設立一個狀態(tài)表,記錄每個變量的狀態(tài)類型。記錄物理文件的大小和載入內存所占內存的大小。首先執(zhí)行函數的初始狀態(tài), 將除去入口函數的所有函數都設置為untainted。若一個變量在多個正向前序代碼段的狀態(tài)表中出現,則重新計算其大小,并更新狀態(tài)表。
2)內部執(zhí)行:按照順序逐一執(zhí)行其內部的指令,更改變量的狀態(tài)表, 將目標文件核心部分內容續(xù)寫到加殼部分的后面,當執(zhí)行到段中最后一步時形成輸出狀態(tài)表。同時檢驗程序變形狀態(tài)的安全性,傳遞接口函數參數[6]。
3)循環(huán)回繞整合部分:在核心代碼全部執(zhí)行完畢時,檢查其后繼代碼段中是否有包含變形的循環(huán)頭。如果存在,則該代碼塊是滿足條件的最外層的循環(huán)頭, 將程序頭表中屬性、大小的參數設置成新計算值,并檢查其輸入、輸出狀態(tài)表中是否有變量的類型狀態(tài)發(fā)生變化,如果存在,則重新開始回繞執(zhí)行,直到狀態(tài)表停止更新。
3 相關算法性能對比
表1 給出了新的加殼算法SRELF 與ASProtect 算法、tElock 算法、Armadillo 算法的比較,表2 給出相關符號定義。
1)安全性提升
由于SRELF 采用的是二進制代碼進行加密或壓縮,并且沒有對加殼功能程序大小進行限制,所以在代碼中可以插入足夠的花指令[7]。再加上高復雜度的加密變形壓縮算法,保證了加殼程序的高安全性。此外變形重構了elf 文件, elf 文件中的內容全部改變,對表頭文件進行靜態(tài)分析脫殼又增加了難度。而且在SRELF 中加入了充分的反動態(tài)跟蹤指令,防止被保護文件被動態(tài)跟蹤。通過上幾方面安全性分析,可以證明加殼后的elf 文件安全性得到了大幅度提高。
2)運算量降低
3)偽裝性增強
加殼后的elf 文件結構并未改變, 而且SRELF 加殼方法不需要改變程序入口地址,很好的隱藏了殼程序。
4)擴展性提升
由于SRELF 方法從理論上沒有對殼程序大小進行限制,使其具備了很好的擴展性。因此后期可以同步更新SRELF 中的加密方法,反靜態(tài)分析方法,反動態(tài)跟蹤方法,對其進行完善和堅固。
綜上所述SRELF 克服了現有加殼方法中所暴露出來的問題, 解決了改變elf 文件結構和改變程序入口地址的重大缺陷,讓加殼后的程序呈現出多態(tài)變形性,在反脫殼中增加了難度。因此,SRELF 方法是一個既具有很高的安全性同時具備良好的可行性的加殼方法。
4 結束語
文中研究了現有加殼軟件在反破解中存在的普遍難題———出現完全不符合所有已知模式的新型安全缺陷[8],總結出現有加殼方式的不足,針對不足問題提出了一種改進的加殼方法———重構變形SRELF 加殼算法。軟件加殼對重點代碼進行加密、變形、反靜態(tài)分析和反動態(tài)跟蹤相結合,同時具備較為精簡的運算量,提高加密部分的反破解能力。文中只考慮了加殼過程中引入程序變形性,使其不易被脫殼軟件脫掉,下一步工作將解決在加殼過程中程序壓縮的問題。此外,還會將改進的方法進一步應用到Linux 系統(tǒng)軟件中。
STM32/STM8
意法半導體/ST/STM
評論
查看更多