田大江,李成揚,黃天波,文偉平
(北京大學軟件與微電子學院,北京 102600)
軟件保護涉及政府、企業和個人的利益,盡管從20 世紀80 年代[1]至今已經出現了眾多保護技術,包括軟件防篡改[2]、代碼混淆[3]、軟件多樣性[4]等,但軟件保護仍是當今時代極具挑戰的問題之一。商業軟件聯盟(Bussiness Software Alliance,BSA)2018 年發布的全球軟件研究報告表明,個人計算機領域中使用的盜版軟件高達37%,造成全球公司近3 590 億美元損失的同時,致使用戶數據處于易被竊取的危險狀態。
源于軟件保護的需求,代碼混淆在20 世紀90 年代被提出用于保護Java 代碼,增大軟件逆向分析的難度,進而保護代碼的核心知識產權,避免泄露用戶的隱私數據。因其在安全性方面低開銷、高回報[5]的特性,在商業軟件中得到廣泛的使用[6]。雖然Barak 等[7]指出并不存在混淆器可以完全隱藏程序的內部信息,因為除程序的輸入和輸出外,逆向人員還是可以獲取很多有助于程序理解的信息。但文獻[1]從實際需求出發認為相較于抽象的完美工具,是否存在實用的混淆工具用于具體的軟件保護更加重要。
Collberg 等[8]將混淆技術分為布局混淆、數據混淆、控制流混淆和預防性混淆,本文關注布局混淆中的標識符混淆算法,在幾乎無時空開銷的前提下提高逆向分析的難度,以增強軟件抵抗靜態分析[9]的能力。為了突顯性能和跨平臺的通用性,本文主要研究基于底層虛擬機(Low Level Virtual Machine,LLVM)[10]的標識符混淆方法。
本文主要工作在于給出四種獨立的標識符混淆算法和一個融合四種技術的創新混合算法。在保證正常語義的前提下,強化標識符混淆方法的保護能力。基于LLVM 實現的標識符混淆方法不僅有著性能開銷小、隱蔽性強的優點,而且適用于LLVM 平臺所支持的所有語言[11],更具通用性和廣泛性。
代碼混淆技術[8,12]是一種軟件保護技術,在保證不改變程序原有功能的同時,通過對源代碼或者匯編碼進行修改,包括但不限于控制流和數據流方面的修改,降低源碼的可理解性,阻止逆向工具的處理,以達到軟件保護的目的。代碼混淆技術從20 世紀90 年代開始出現,最開始關注指令替換和花指令的添加[13];之后Collberg 等[8]對代碼混淆技術進行分類,并給出混淆效果的評估指標,包括混淆程度[12](potency)、混淆強度(resilience)、性能開銷(cost)和隱蔽性(stealth);為了加強安全性,隨后出現控制流混淆[14]和數據混淆[15]的方案。盡管Barak 等[7]從理論上證明并不存在足夠安全的混淆器,但隨著工業界對代碼混淆需求的上漲,后續出現了眾多實用的功能增強方案,包括:混淆中結合加密方案[16];添加垃圾指令,構建虛假控制流和虛假跳轉表阻止靜態反編譯[17];結合指針分析和數值分析的方法研究x86 可執行程序的靜態分析算法[18],防止二進制文件的惡意混淆技術的攻擊;針對切片的混淆[19];在LLVM 層實現的OLLVM(Obfuscator LLVM)[20]給出了跨平臺、跨語言混淆的可行性;同時出現了針對模型的混淆方案[21]和新的混淆參數的評定指標[22]。
廣義的代碼混淆目前的研究方向主要有兩方面:一方面是實用性混淆方法的提出,包括現有算法的強化和創新,以適用于新的場景;另一方面是理論性研究,結合密碼學的研究思路,追求可證明的混淆方式。狹義的代碼混淆可以等效理解為實用性混淆方法,本文研究的標識符混淆方法即歸屬于這一類。
標識符混淆的定義[23]:設p是一個給定的程序,Up是p中出現的所有名稱的集合,是針對混淆的名稱集合。p的標識符混淆方法是將p中的每個標識符n∈Np替換為另一個標識符n′(=t(n)),獲得混淆程序p′,其中t是一對一的映射(t:Np→Np′(Np′?Up′)),t可以視為不同的標識符混淆方法。
標識符混淆方法為了隱藏程序邏輯,降低代碼的可讀性,多數采用替換的思路。其中霍建雷[24]提出Java 標識符重命名混淆算法及其實現方式,用四種算法構造出Java 混淆器JIRO(Java Identifier Renaming Obfuscator),但在實現上存在通用性不強的缺點,僅限于Java,且未考慮算法間的協同處理以達到最優效果。Ceccato 等[25]通過具體的逆向實驗證明,標識符混淆增大了逆向的難度,使有經驗的逆向人員和經驗欠缺的人員都面臨同等棘手的問題。Al-Hakimi 等[26]提出混合混淆的策略,在字符串混淆階段,先將標識符替換為垃圾代碼,然后用Unicode 字符替換系統關鍵字,最后結合字符串加密技術實現字符串混淆,混淆方案本身取得較好的效果,但在標識符混淆實現部分,更多的是替換方案,思路過于單一。Cimato 等[27]提出針對標識符混淆的對抗方法,核心思路為針對字節碼優先進行處理,提出兩種實現思路:第一種是利用現有的工具,將字節碼文件中的標識符轉變為單一的合法標識符(如字母或數字)后,使用反混淆工具將字節碼轉變為源碼;第二種思路是實現ADAM(Another Decompilation Assistant Methodology),在處理字節碼文件時,使用實體-標識符-信息(Entity-Number-Info)的形式進行標識符重命名,再將其轉變為源碼。但思路僅限于Java 語言,較為單一且反混淆的質量取決于info,即類相關信息的抽取,而混淆可以對這部分信息進行處理。
綜上所述,現有的標識符混淆技術大多針對某一具體平臺或語言,不具有通用性;圍繞隱藏標識符信息,標識符算法主要分為替換和重載兩種思路,但現有的文章中并未對兩者結合后的理論或實際效果進行分析。針對現有問題,本文所提出的基于LLVM 的標識符混淆方法,適用于LLVM 平臺所支持的所有編程語言和后端架構,目前前端有Ada、C、C++、D、Delphi、Fortran、Haskell、Julia、Objective-C、Rust and Swift,后端有x86、x86-64、ARM、ARM64 等指令集。后文實驗部分對結合替換和重載思路的算法效果進行分析。
LLVM[10]的命名最早源自于底層虛擬機(Low Level Virtual Machine)的首字母縮寫,隨著發展,原生的內涵也發生了轉變,現在LLVM 代表著模塊化和可重用的編譯器和工具鏈技術的集合。
LLVM 是基于傳統的三段式架構(前端、優化、后端)設計[28]的編譯器。如圖1 所示,模塊間更易于解耦:一方面利于拓展新的前端和后端,支持更多的語言和設備;另一方面,可以高度復用優化階段的工作,在優化過程中對LLVM IR(Intermediate Representation)[29]的工作可以無縫鏈接到不同的前端和后端。本文方法對IR 文件進行修改和優化,因而理論上適用于LLVM 支持的所有前端和后端。

圖1 LLVM三段式設計Fig.1 LLVM three-stage design
LLVM 支持三種等效的IR 格式,如圖2 所示:可讀的匯編格式(.ll);內存中編譯IR 內存格式;適用于即時編譯(Just-In-Time compilation,JIT)快速加載的位碼格式(.bc)。為了實現程序持久性的優化,本文主要針對.ll 和.bc 文件進行操作,通過編寫趟(Pass)實現具體的混淆功能。

圖2 LLVM編譯器架構Fig.2 LLVM compiler architecture
本文針對文獻[24]提出的標識符混淆算法進行重新設計。不同于以往的算法實現,在LLVM 層進行開發,使其不再局限于Java 等某一特定編程語言;對算法細節進行調整,包括隨機標識符、非法標識符的構造,增強算法本身的效果。使用現有生活用語構造混淆后的字符:一方面隱藏真實標識符信息;另一方面增強混淆字符的隱蔽性。并對提出的四種算法進行混合,在保證程序正常執行的情況下,令四種算法效果達到最佳,在不會帶來額外開銷[30]的同時,讓攻擊者幾乎不可能將標識符恢復到原始狀態。
在源代碼中,當一個標識符被混淆時,與之相關的函數、調用等都要隨之變化,否則會影響代碼的正常執行;并且涉及到標準庫和第三方庫的方法,因為版權等方面原因,不能隨意混淆。因此,有必要提出混淆域[23]的概念:在不影響程序正常執行的前提下,可以混淆的代碼范圍。
標識符混淆的對象理論上應是混淆域內的所有標識符,但源程序中的局部變量名、注釋、自定義類型等信息在編譯后已經被去除[31]。在LLVM 層,源代碼轉化為LLVM IR 后,局部變量以“%”字符開頭,全局變量以“@”字符開頭,并且為了編譯器快速給出臨時變量,避免符號表沖突,會配合無符號整數作為標識符的名稱(如%12、@2),所以在正式混淆前,標識符已經產生變化。但程序的符號表會持有函數名稱的引用,加之函數名在程序理解中的重要作用[32],本文提出的標識符混淆方法主要對程序中的函數名進行處理。
本文標識符混淆方法針對的混淆域為當前文件或項目生成的IR 文件,混淆對象為混淆域內自定義并初始化的函數名、全局變量名和自定義的結構體,不包括庫函數和第三方應用程序接口(Application Programming Interface,API)。
混淆方法設計分為三部分,分步驟完成混淆目標:
1)中間語言處理部分。通過Clang 等前端將程序源碼編譯成對應的LLVM IR 文件,再通過LLVM-Link 或WLLVM(Whole-program-LLVM)將所有的IR 文件鏈接成一個包含源程序所有信息的IR 文件。
2)標識符混淆部分。作為整個混淆方法的核心部分,主要用于對鏈接后生成的IR 文件進行優化處理,可以分為以下3 個子步驟完成標識符混淆處理:
①全局數據處理。獲取到代碼的全局變量、函數名稱等標識符信息。
②標識符篩選。對①中獲取到的標識符進行條件篩選,排除標準庫和第三方庫方法的標識符,保留滿足混淆域要求的標識符。
③標識符混淆。對②中篩選后的標識符進行混淆處理,利用實現的LLVM Pass 對標識符進行混淆。不同的Pass 文件對應著不同的混淆算法。
3)生成部分。通過用戶指定或者目標平臺識別,將優化處理后的IR 文件,由后端編譯成適用于目標機器的可執行文件。
本文混淆方法給出四種標識符混淆算法,包括隨機標識符算法、高頻詞替換算法、異常標識符算法、重載歸納算法,最后給出了將四種算法混合使用的混合標識符算法。其中隨機標識符算法和重載歸納算法基于已有的設計[24],在LLVM 平臺實現;高頻詞算法的混淆字典、異常標識符混淆的異常字符選取屬于原創性設計,同時為了充分利用現有混淆算法,在算法的結合上進行了新的嘗試,即混合混淆算法。每種算法均為LLVM Pass 文件,且對IR 文件進行操作,生成優化后的IR 文件以達到混淆目的。

算法1 中的T即標識符重命名方法,包括隨機標識符算法、高頻詞替換算法、異常標識符算法。重載歸納算法如算法2 所示。

算法2 中初始化工作包括混淆對象的選取,主體邏輯如下:標識符替換的算法通過編寫Module Pass 進行實現,在獲取模塊(module)后首先針對全局變量和自定義的結構體名稱進行換名,module 提供對應的API 進行處理:全局變量可以通過遍歷module.begin()和module.end()進行獲取;結構體可以通過StructTypes.run(module,true)獲取相關的信息;函數名則通過遍歷模塊內的所有函數進行篩選,這里只選取用戶自定義的函數,通過LLVM 提供的API 結合函數類型和鏈接類型進行有效的判斷。
對于重載歸納算法,還要多做一步,因為在C/C++中存在名稱改寫(name mangling)機制,因此在重載時,先對函數名進行處理,獲取去除不相關字符后真正的函數名再進行處理。最后,每更改一次,都需要進行全局更新,防止后續運行時找不到鏈接的函數。
2.3.1 隨機標識符算法
隨機標識符算法:遍歷混淆域內的所有標識符,隨后通過自定義的隨機函數產生隨機且無意義的名字替代之前的標識符命名。其中隨機函數隨機選取大小寫字母和下劃線等字符,隨機組合成X位的毫無意義[33]的字符串(如統一設置11 位字符串jK2iOy3yewc)。
這里的代碼示例中源碼選擇avl-tree(https://www.geeksforgeeks.org/avl-tree-set-1-insertion/)代碼。查看混淆前后的IR 文件中的符號表信息,統計相關函數名信息如表1 所示。后文中的算法效果示例均如此。

表1 標識符混淆算法示例Tab.1 Identifier obfuscation algorithm examples
2.3.2 高頻詞替換算法
高頻詞替換算法:將生活中常見的英文單詞用于重命名標識符,在掩蓋標識符本身含義的情況下,誘導攻擊者以為程序未被混淆。使用2019 年經濟學人的詞頻統計作為源數據,在構造混淆字典時,為了更具真實性以抵抗混淆檢測算法,借鑒當前識別標識符混淆的研究,如文獻[34]將代碼中是否存在標識符長度小于3 作為是否被混淆的指標之一,因此選擇字符個數不少于3 且不屬于保留字的字符。在整理的109 932 項條目中,最后僅保留1 071 項作為混淆字典的條目。對于標識符數目龐大的代碼,實現上通過補充下劃線的方式進行擴容,使混淆庫足夠豐富,以備替換。
高頻詞替換算法產生的標識符名稱是具有現實意義的,只不過和源程序的函數意義沒有任何關聯,進而引申出追求更高層級的標識符混淆,不是去除標識符,也不是簡單地使用無意義的標識符進行替換,而是使用有意義但無實際聯系的字符進行替換,更能迷惑逆向分析人員。針對如何使用有意義但無實際聯系的標識符進行概念說明:
有意義但無實際聯系的標識符,指源于生活、相關領域認可且具有共識認知的詞匯或者表示,但和函數本身的功能不存在指向關系。應當滿足特性:首先,“有意義”體現在標識符本身是被認可的,且被該領域或相關領域的主體認同;其次,“無實際聯系”體現在標識符本身和函數本身的功能沒有任何關聯,可以沒有任何聯系,可以相反,也可以相同,因為本身混合在一個系統中,真假難辨反而更容易迷惑逆向人員。
2.3.3 異常標識符算法
異常標識符算法:針對混淆域內的所有標識符,使用形似保留字的標識符或下劃線進行替換,以混淆視聽。該算法分為兩種思路,本節將分別敘述。
異常標識符算法1,該思路旨在生成形似保留字的標識符以迷惑攻擊者。過程分為三步:第一步生成一個帶有希臘字母“保留字”的集合,先找出所有和英文字母類似的希臘字母,用這些希臘字母對保留字中的英文字母進行替換;第二步獲取程序中出現的標識符;第三步使用自定義集合里的“保留字”替代程序中的標識符,以混淆視聽。
異常標識符算法2,通過由下劃線組成的標識符(如:“__”)替代原有標識符,通過下劃線個數作區分,隨著下劃線的遞增,標識符區分度也逐漸降低。而程序可以依照個數的不同調用目標函數,實現對程序的保護目的。
2.3.4 重載歸納算法
重載歸納算法:利用面向對象語言的重載特性對標識符進行易名,使程序含有盡可能多的相同名字、不同參數類型的函數。
重載歸納算法不同于上述的替換思路,算法獲取程序中出現的函數名,對其進行排序,根據參數類型或數量不同,采用同名替換的方式使程序盡可能多地含有同名函數。程序可以采用重載的方法調用目標函數,并不會影響到正常運行,而攻擊者卻難以區分函數,可以對調用的函數起到保護作用。
不同于前三種算法,重載算法并沒有對混淆域內的所有函數名進行保護,會保留源程序的部分標識符信息。
前四種算法對混淆域內的標識符提供了一定的保護能力,為了進一步增加混淆的隱蔽性和復雜性,可以將算法進行有效的組合,即混合標識符混淆算法。
2.3.5 混合標識符混淆算法
前三種算法雖然達到隱藏標識符的目的,但是標識符依舊具有區分度;重載歸納法雖然降低了區分度,但是依舊保留了標識符的部分信息。為了充分利用現有的標識符混淆算法,取得最佳的混淆效果,將上述四種算法混合使用,命名為混合標識符混淆算法。
如果僅是線性地將四種算法進行組合,如前三種算法進行混淆后,再進行重載歸納算法混淆得到可執行文件,但使用IDA(Interactive DisAssembler professional)等逆向工具進行逆向處理時,會因為函數缺乏必要的參數信息,而對相同的函數添加后綴以示區分,所以為了對抗類似于IDA 這樣的機制,在將替換和重載兩類算法進行混合時,對前三種算法進行修改,考慮名稱改寫機制,僅處理函數名稱,保留原本的參數列表信息,再使用重載歸納算法處理。一方面因為添加重載函數名,強化第一類替換算法的效果;另一方面,替換算法進一步抹除原本的函數名信息,強化了重載算法的安全性。

算法3 的整體流程如圖3 所示,首先初始化工作,篩選程序中的標識符,獲取到四種算法可處理的混淆對象;然后,根據動態生成的隨機數在替換類算法(算法1~3)中進行隨機選擇,對全局變量、結構體和函數名稱分別進行混淆處理,同時在算法實現上進行了部分調整,在針對函數名稱替換時,保留參數列表信息;最后,針對替換類算法處理后的程序,調用重載歸納算法。基于替換后的函數名稱作進一步的復用工作,使攻擊者無法有效恢復標識符信息。因為在混淆時僅涉及標識符的替換,沒有增加額外的邏輯處理,所以理論上對時空開銷幾乎無影響。

圖3 混合標識符混淆算法過程Fig.3 Mixed identifier obfuscation algorithm process
實驗在Intel Core i7-9750H、16 GB 內存的Ubuntu18.04 64 位機上實現,基于LLVM10 release 版進行開發,使用IDA Free 7.6 進行效果的對比。實驗分為性能分析和混淆效果分析:性能分析關注混淆后程序在時空上增加的開銷[35];混淆效果分析關注混淆的標識符數量占符號表標識符總量的比率。為了保證實驗數據的準確性,性能分析中使用腳本進行數據的獲取;效果分析使用IDA Free 7.6 對混淆前后的可執行文件進行逆向處理,統計更改名稱的函數所占的比率。
其中,性能分析以C++實現的算法庫(https://github.com/xtaci/algorithms)和Rust 算法庫(https://github.com/TheAlgorithms/Rust)為測試數據:一方面說明混淆方法對算法的時空開銷;另一方面說明本文方法的通用性——LLVM支持眾多的前端。本次實驗選取目前為止始終擁有良好維護的C++和Rust 以展示效果;混淆效果分析中,選取項目文件,包括std 的map 實現、數獨游戲sudoku(https://github.com/mayerui/sudoku)、字符轉換工具flowchar(https://github.com/Gusabary/FlowChar)和Google 開源的leveldb(https://github.com/google/leveldb),以展示本文方法在多文件中的使用效果。
實驗選取C++和Rust 語言的算法文件作為測試文件,以時空增長作為測試指標,從而評估混淆的性能。本節先進行理論分析,后面輔以實驗說明。
依據Collberg 等[8]提出的混淆指標對本文方法進行理論評估,在性能代價(cost)上表現為無代價(free)。性能開銷分為dear、costly、cheap 和free 四種等級,由于本文方法僅針對標識符混淆層面,所以在性能開銷上是free 級別。
對60 個C 文件和24 個Rust 文件進行混淆處理。為了減小機器運行時造成的時間誤差,每個測試用例執行100 次求平均值作為統計的運行時間。同時,為了更好地展示不同方法間的差異,對算法庫文件單獨使用混淆算法后,對每個文件統計其時空增長倍數,然后在圖4 中以各自均值進行表示,如針對C++項目的60 個文件,使用隨機標識符算法后,時間增長倍數的均值在1.07。

圖4 性能分析Fig.4 Performance analysis
橫坐標是5 類混淆算法(異常標識符算法存在兩種實現,共6 種算法),縱坐標表示混淆后相較于混淆前的增長倍數。對應可以得到如下的結論:
1)混淆算法對C++處理后,在時空上幾乎無變化,考慮到機器運行的時間誤差,混淆增加的時間倍數可以進一步減小。
2)混淆算法對Rust 處理后,時間開銷平均增加20%的同時,極大地減小了空間開銷,空間上平均變為原本的2%。
3)雖然混淆算法針對C++和Rust 在時空開銷上影響不同,但是可以驗證本文算法的通用性。
為了更客觀地評估混淆效果,選取項目文件進行混淆。選擇不同標識符量級的項目,涵蓋幾十到幾萬量級,同時兼顧項目的不同類型,最終以C++標準庫中的map 實現,數獨游戲sudoku,字符轉換工具flowchar 和Google 開源的leveldb作為實驗數據。通過IDA 對混淆后的可執行文件逆向處理,得到混淆后的標識符所占的比例。下文先對標識符混淆的混淆強度進行理論分析,再輔以實驗說明。
依據Collberg 等[8]提出的混淆指標對本文方法進行理論評估,在混淆強度(resilience)上表現為強(strong)。混淆強度指標主要是為了度量混淆后的程序對自動化反混淆器的抵抗能力,包括兩個方面的表現:一方面是有針對性地編寫一個自動化反混淆器付出的代價;另一方面是使用自動化反混淆器進行反混淆所付出的代價[12]。
第一個方面的代價分為多項式時間復雜度和指數時間復雜度,本文提供的標識符技術復雜度是O(n2),屬于多項式時間復雜度,而對應的第二個方面所指代的反混淆付出的代價分為full、strong、weak 和trivial 四個級別,分別對應interprocess、interprocedural、global 和local 四個層面[8]。本文將所有的中間文件鏈接在一起統一對其混淆,可以確定該技術是在interprocedural 層面進行的,所以在混淆強度指標上表現為強(strong)。
從混淆算法角度出發,本文提出的6 種具體的混淆算法,又可以歸于三大類算法:1)替換算法,包括隨機標識符算法、高頻詞替換算法、異常標識符算法(所能影響的標識符數量是相同的,只是標識符替換的策略不同);2)重載算法;3)替換和重載結合的混合算法。
圖5 中白色區域表示已混淆標識符的數量,黑色區域表示未混淆標識符的數量。部分標識符未混淆,因為算法設計時僅針對用戶自定義的函數,對于庫函數和第三方API 并不進行處理。

圖5 不同混淆算法的混淆效果圖Fig.5 Obfuscation effect diagram of different identifier obfuscation algorithms
針對四個項目分別使用三類算法(第一類替換算法,運行時通過隨機數隨機指定)得到如下結論:
1)第三類算法影響的標識符數量和第一類算法是相同的,第二類算法影響的數量是最少的。如圖5 四個子圖中均存在較小的白色區域,即重載算法所占的比重。
2)第三類算法保留了前兩類算法的優點,對其各自的缺點進行了彌補:第一類算法可以混淆更多的標識符,但是標識符仍然具有唯一性,第二類算法使用重載,標識符不再具有唯一性,但是混淆的數量較少,且會保留部分源程序的語義信息。而第三類算法在取得極大混淆數量的同時,徹底去除原本的語義信息,且借助于重載使標識符不再具有唯一性。
3)針對不同標識符量級的項目,混淆算法的平均比率在77.5%,如圖6 所示。

圖6 混合混淆算法的混淆比例Fig.6 Obfuscation ratio of mixed obfuscation algorithm
4)在混淆的標識符中,重載歸納算法的比例較小,和程序本身的特性相關,極端情況下無效果。
5)混淆效果和項目的標識符數量無關聯,和程序本身自定義的函數和函數參數的設計相關。
同時,因為strip 用于去除符號表,和本文所討論的標識符替換存在關聯。對兩者進行分析,得到如下結論:
1)在Rust 程序上進行測試,除同strip 一樣可以極大減小符號表體積外,不同于strip 直接去除符號表,本文方法可保留迷惑性的信息以干擾逆向人員的分析。
2)本文方法針對自動化逆向工具分析時,目前效果不大于strip 的效果,甚至自動化工具會直接去除符號表信息,以規避標識符混淆的效果。
3)目前LLVM 支持的前端中包括靜態編譯語言和動態解釋語言,本文方法在生成靜態語言可執行文件時,可能受制于strip,但如果動態解釋語言得到進一步的優化和維護后,可以在本文方法上進行進一步的研究和推進。
基于軟件保護的應用場景和編程語言多樣的需要,本文提出基于LLVM 的標識符混淆方法。該混淆方法融合四種算法的優勢,在84 個單文件的測試用例和不同類型的項目中,均有較為穩定的混淆效果。混淆方法有效地隱藏了標識符信息,提高代碼的安全性;同時由于LLVM 的跨平臺性,方法適用于LLVM 支持的所有語言和架構。
但是對于動態調試,本文所提供的技術無法提供足夠的保護,這是接下來的工作之一。同時,本文標識符混淆方法多數停留于標識符替換層面,反編譯人員可以經過分類等方法,大致確認函數的作用。接下來的工作:一方面是增強對動態調試的抵抗力;另一方面是提高抵抗機器學習攻擊[36]的能力,消除strip 的影響,提供功能更為豐富的混淆方法也是今后的重點工作。