?

采用隱式跳轉的控制流混淆技術

2021-10-28 05:52陳耀陽
計算機工程與應用 2021年20期
關鍵詞:控制流靜態代碼

陳耀陽,陳 偉

南京郵電大學 計算機學院,南京 210023

近年來,隨著計算機技術的發展,針對軟件本身的保護逐漸引起人們的關注。對于軟件的攻擊形式有很多種,一般而言,軟件保護技術主要對以下三種類型[1]的攻擊進行防護:軟件盜版、逆向工程以及軟件篡改。在這幾種攻擊中,逆向工程是相對比較基礎同時也是危害性最大的一種攻擊形式。

逆向工程[2]是指對一項目標產品進行逆向分析和研究,在無法輕易獲得必要產品信息的情況下,直接從成品分析,推導產品的設計原理。在計算機領域中,特別是針對程序的二進制代碼進行的逆向工程也稱“代碼逆向工程”。一次成功的逆向,對于競爭者而言可以輕易獲取產品中的敏感數據、算法以及設計思想;而對于惡意攻擊者來說,則可以獲取到軟件中漏洞,從而加以利用,造成嚴重后果。

靜態分析往往是逆向分析的第一步。以Java為代表的語言,需要編譯成與平臺無關的字節碼形式,所以可以通過解析字節碼文件輕易還原出源程序的實現信息。而對于以C語言為代表的需要編譯成機器碼的語言,也可以通過翻譯機器碼從而轉化為匯編指令來進行代碼分析。所以,通過靜態分析可以輕易地構建軟件的控制流信息,未經保護的控制流信息暴露了包括源程序靜態結構、代碼邏輯在內的大量信息,因此對于許多逆向工具而言,控制流圖都是必須構造的數據結構。本文研究的主要目的是抵御靜態代碼分析。

抵抗靜態代碼分析特別是控制流分析的主要技術是代碼混淆,這個概念最早由Collerg等[3]提出并加以分類及實現。代碼混淆技術是將一些結構良好、易于理解的代碼轉換為難以閱讀分析的代碼,但是還能完整地保留其所實現的功能,著名的國際C語言混亂代碼大賽[4]就是典型的例子。一般而言,混淆技術可以分為4類:結構混淆、數據混淆、控制流混淆以及動態混淆。其中控制流混淆的主要目的就是抵御逆向工具對代碼控制流信息的分析,目前應用比較廣泛的控制流混淆技術有指令替換、虛假控制流、控制流平坦化等。但是目前這些技術都存在一些缺點,如通用性差、性能消耗過大、控制流信息隱藏不徹底等。

鑒于這些現狀,本文提出一種通用的、輕量級的、細粒度代碼保護方案。通過對代碼的控制流信息進行分析并建立原始控制流圖,之后從基本塊跳轉、函數調用與變量引用入手,隱藏這些敏感信息,減少靜態分析時所能獲取到的有價值信息,實現對程序的保護。同時通過構建狀態轉移模型和實施基于環境密鑰的兩階段加密方案,解決了密鑰安全和密文重復出現問題,彌補了其他方案的不足,提高了軟件保護的能力。

1 相關工作

代碼混淆的概念由來已久,在20世紀90年代末這個概念就已經被提出。它的形式有很多,其中最簡單的一種形式是符號混淆,它通過將源碼中的函數名、類名以及變量名替換成一些無意義的符號,來增加攻擊者的理解難度,具有代表性的項目是ProGuard[5],由于其并不改變原代碼的結構,其抗逆向能力非常差,所以現在多作為一種優化工具或者其他混淆技術的輔助工具來使用。

由于簡單的符號混淆并不能滿足代碼保護的要求,一些研究人員又提出了結構混淆的概念。結構混淆是從代碼的類、函數等組成入手,破壞其整體結構,增加靜態分析的復雜度。這方面比較典型的是Foket等人[6]的研究成果,他們以Java語言為例闡述并實現了包括類繼承結構平坦化、方法合并、接口合并以及對象創建工廠化在內的多種結構混淆技術。雖然結構混淆能起到一定的抗逆向效果,但是其混淆的粒度較大,實際的逆向工程中,攻擊者很少會逆向全部代碼,一般都是從一部分關鍵代碼入手,也被稱為“局部攻擊”,這時就需要更細粒度的混淆。

控制流混淆是目前較為流行的方案,它通過修改程序控制流來阻礙攻擊者對代碼進行靜態分析。常用的控制流混淆技術主要有同義指令替換、不透明分支以及控制流平坦化以及等。

同義指令替換[7]多是將一些簡單的指令替換為有相同功能但形式非常復雜的指令,來增大代碼理解難度,如公式(1)所示;但是這種混淆方法有很大的局限性:首先并不是所有的指令都可以替換,多用在算術運算上;其次一般所替換的指令都比較復雜,也降低了程序的性能。

虛假控制流又稱為插入不透明謂詞[8],它通過在程序的控制流中插入一些結果恒定的布爾表達式來引入虛假分支,如圖1所示;由于被插入的布爾表達在運行過程中值恒等不變,所以虛假分支并不影響程序運行,所以這是一種低成本高收益的混淆技術。生成虛假控制流的不透明謂詞可以分為靜態不透明謂詞[9]、上下文不透明謂詞[10]以及動態不透明謂詞[11]等。但是由于不透明謂詞插入后的特征比較明顯,現在已有很多方案[12]可以去識別和去除。虛假控制流混淆雖然改變了代碼的控制流信息,但只是在局部上的修改,難以全局應用,并且過多的不透明謂詞也會大幅降低程序性能。

圖1 虛假控制流Fig.1 Bogus control flow

控制流平坦化[13]混淆如圖2所示,是通過構造分發器,將原本控制流重構為一個類似switch-case的結構,由分發器在運行時決定下一個將要執行的基本塊。這樣可以徹底打亂原有的控制流圖,具有很強的反逆向能力,但是這種方法只是將控制流信息從形式上打亂,其實際的控制流信息還是不變,通過分析case的值,也可以局部或者整體還原代碼的控制流信息,重構原始的控制流圖。

圖2 控制流平坦化Fig.2 Control flow flattening

前面介紹的控制流混淆方案大多都是通過引入額外基本塊來修改源程序控制流圖中基本塊之間的關系,從而實現代碼混淆。除此之外,還可以通過修改基本塊的跳轉形式來實現這個目的,也就是將顯示跳轉改為隱式跳轉。隱式跳轉又稱間接跳轉,是將源程序中的直接跳轉形式改為間接形式,這樣無論是反編譯工具還是人為分析,都不能輕易分析任意基本塊的前后關系,這樣也就阻止了靜態分析,實現了程序保護。這方面比較典型的是Hikari[14]項目,它通過將程序中跳轉指令的目標地址由明文改為數組匹配的方式來實現隱式跳轉。但作為一種混淆策略,其實現形式過于簡單而導致安全性較差(詳見2.1節分析),同時也僅處理了基本塊之間的跳轉,對于其他敏感信息并未做相關的安全保護,所以在實際應用中價值較低。

2 基于隱式跳轉的混淆技術

前一章介紹的幾種代碼保護技術中,都只是在宏觀上對控制流進行修改,實際各個基本塊之間的跳轉關系還會保留,而且也不能保護函數調用以及變量引用這些敏感信息。因此,本文通過隱藏基本塊之間的跳轉關系,并在此基礎上對程序其他敏感信息如函數的調用以及變量引用也加以隱藏,從而實現程序的控制流混淆,以此來保護程序。

2.1 基本概念

控制流圖是一個程序的抽象表示,最早由Frances E.Allen提出,它利用圖的形式將一個程序的所有可能執行路徑表示出來,不僅是靜態分析的重要工具,也是現代編譯器所需要維護的一種重要數據結構。一個控制流圖可以表示為,其中V表示基本塊的集合,E則表示連接兩個基本塊之間的路徑的集合,也就是控制流?;緣K是人為地將源程序劃分為一個個基本的功能單元,通常一個函數或者一個代碼塊包含若干個基本塊,基本塊包含若干條指令,而指令則被認為是程序的最小單元。連接兩個基本塊就是控制流,控制流是一個抽象的概念,在實際代碼中并不會出現,而是人為地根據一些跳轉指令去構建,它表示了程序在執行過程中是如何從一個基本塊轉移到另外一個基本塊的。在代碼被編譯過后,無論是編譯為某種字節碼文件或者是二進制文件,都可以根據指令的含義輕松地構建控制流圖。圖3(b)與圖3(c)就是圖3(a)中程序所對應的匯編代碼和控制流圖,通過控制流圖可以清晰的知道這段程序可以簡單分為4個基本塊,基本塊A之后有兩條分支路徑,對應的就是源碼中的if-else結構。

圖3 控制流圖示例Fig.3 Example of control flow graph

在控制流圖中,控制流從一個基本塊到另外一個基本塊的轉移多是通過一系列跳轉指令實現,所要跳轉的目標地址在原始情況下是以明文方式作為指令的操作數出現的,這樣的跳轉形式稱之為顯示跳轉,以圖3(b)為例,一共出現了兩個跳轉指令,分別是地址為040056B處的條件跳轉指令和地址為0400585處的無條件跳轉指令,這兩條指令的操作數都是直接的明文地址(圖中顯示的是LABEL偽指令,表示的是某個地址,目的是便于閱讀),由于是明文地址,無論從哪一個基本塊開始都可以輕松地推斷出程序接下來的流程。

與顯示跳轉對應的是隱式跳轉,這種形式下,跳轉的目的地址需要通過一系列計算得出,圖4所示的是圖3(a)中的代碼經過Hikari的間接分支處理后的部分匯編代碼,對應的就是圖3(c)中的基本塊A,但是與之不同的是圖4中的基本塊最后的跳轉指令的操作數并不是一個直接地址,而以一個寄存器表示,根據寄存器中存儲的值,去跳轉的相應地址,至于寄存器中所存儲的地址則是在跳轉前計算出來的,這就是隱式跳轉的一種形式。這里所做的處理是將某個基本塊的所有可能后繼基本塊插入一個全局跳轉表中,然后修改原始基本塊的內容,將原來的明文地址替換為數組尋址的方式,如圖4中地址0400575處所示。這種隱式跳轉方法,由于隱藏了目標地址,所以一些工具如IDA Pro[15]就不能通過靜態分析去構建程序的控制流圖,僅能顯示如圖4所示的控制流圖的第一個基本塊。

雖然這種形式的隱式跳轉雖然能在一定程度上阻礙控制流圖被構建,但是若對跳轉前部分指令的含義進行簡單分析還是可以推斷出該基本塊的后繼。以圖4為例,在輸入值與10做減法之后,根據EFLAGS寄存器的ZF標志位的情況,在_LcondInBrTable數組中取不同的值存入rsi寄存器中進行跳轉,由此知道當輸入等于10時,取數組中第二個元素,否則取第一個元素。而_LcondInBrTable數組中存儲的都是明文地址,由此還是可以構建出局部或者全局的控制流圖。

2.2 控制流的隱式跳轉

前一節中Hikari實現了較為初級的隱式跳轉,但是依舊是將地址明文存儲到全局跳轉表中,這樣的效果等同于做了一次稍微復雜的間接尋址,雖然可以欺騙一些靜態分析工具,但是并沒有達到理想的保護效果。本文通過對地址加密來增強保護,但是由于對軟件的靜態分析是處于一種MATE[16](Man At The End)環境下,此時攻擊者完全掌握軟件運行環境,可以對軟件進行徹底的反編譯和監控,傳統的加密并不能明顯提升保護效果,所以本文通過構建狀態轉移模型來確保密鑰安全,利用二者的結合來實現代碼保護。

S:狀態集合;

S0:初始狀態;

I:輸入集合;

O:輸出集合;

T:轉移函數,描述系統中各個狀態之間轉移的規則;

G:輸出函數,描述系統在狀態轉移后的輸出。

首先定義一個程序控制流圖由n個基本塊構成:,控制流圖的入口為BB0。假設控制流內部的跳轉是根據基本塊的地址定位的,第i個基本塊的地址表示為Ai,該地址對應的加密后密文表示為,其對應的密鑰表示為key i,密鑰是在編譯期隨機生成的,不直接存儲在代碼中。

系統的各部分定義如下:系統的狀態集合即為全體密鑰的集合S={}key i|0≤i≤n,當程序要從BB i跳轉到BB j時,系統的當前狀態即為k eyi,將來狀態為key j,系統的初始狀態為key0;系統某次狀態轉移時的輸入由兩部分組成,一部分用于計算新狀態,定義為k ij,該值直接存儲在BB i中;另一部分用于計算輸出,即BB j的密文;故系統的輸入可以用如下二元組的集合表示,系統在轉移后的輸出即基本塊地址的集合,O={A j|0≤i≤n}。

系統的輸出函數描述的就是狀態轉移后系統產生的一個輸出,這里以輸入的密文以及當前狀態為參數并輸出基本塊地址,所以輸出函數就是解密函數,它和編譯時的加密函數互為反函數。若加密函數定義為如下形式:

則輸出函數的形式為:

關于加解密函數的具體實現沒有特殊要求,但是由于需要在指令層面進行運行時解密,為了保證運行時性能,要盡量選擇運算量少的算法,如異或運算。

系統的轉移函數描述了狀態轉移規則,其形式如下:

轉移函數實際上是以迭代的形式描述了如何從一個狀態轉移到下一個狀態,這種形式的定義可以保證在靜態分析時中間狀態的隱蔽性,從而間接保證目標地址的安全。攻擊者在對程序進行靜態分析構建控制流圖時,由于完整的控制流圖一般都比較龐大,構建起來耗時耗力,所以攻擊者一般更愿意從某個感興趣的基本塊入手,構建局部的控制流圖,此時需要完成的目標有如下兩點:

(1)確定某個基本塊的所有直接后繼塊;

(2)確定某個基本塊的所有直接前驅塊。

在未處理之前,指令中所有目標地址都是明文出現的,所以目標1可以通過分析基本塊中的跳轉指令及相鄰基本塊的邏輯關系而實現,目標2可以通過匹配全局的絕對跳轉地址和相對跳轉地址來實現。在使用本文方案之后,聯合轉移函數與輸出函數,若從BBi轉移到BB j,目標基本塊地址需要經過如下計算:

當攻擊者從控制流圖中某一基本塊開始靜態分析時,所能獲取到的信息只有該基本塊的地址A i,以及所有可能的k ij和。由公式(5)可知,還缺少參數keyi,而keyi是系統的當前狀態,它在程序中的表現是一個可讀寫的全局變量,它隨著控制流的轉移而更新,而直接從中間某一基本塊入手時,是無法直接獲得當前基本塊對應狀態值,所以不能計算出下一基本塊的地址,這樣目標1就很難完成。另外,由于在基本塊中,原始狀態下所有目標地址都是以密文形式呈現的,當攻擊者知道某一基本塊的明文地址,而要計算對應的密文地址時需要進行如下式的運算(假設BB k是BBi的一個前驅塊):

根據系統的狀態轉移模型,key k是在執行到基本塊BB k時的狀態,k ki的值也僅存在于BB k內部的,所以在前驅塊未知的情況下,想要計算當前基本塊對應的密文信息,以及以此為基礎去尋找所有前驅塊是比較困難的,所以目標2也難以實現。

前文分析了模型在抵御靜態分析時的能力,證明了當從控制流圖的非起始位置入手時,并不能有效地還原出程序的控制流圖。但是,當從控制流入口開始靜態分析時,系統狀態能否安全地初始化決定了程序控制流圖能否被順利構建。目前,程序中類似的安全初始化問題依舊是亟待解決的,不過一些現有的方法可以在一定程度上解決這個問題,如白盒加密、外部輸入以及從環境元素生成狀態信息等。即使在無法保證安全初始化的情況下,在經過本方案處理過之后,攻擊者也只能從控制流圖的入口開始分析,當程序足夠龐大時,這將是一個漫長的過程。另外本方案關注于隱藏控制流的跳轉信息,所以可以通過增加冗余的虛假基本塊、對基本塊進行分裂或者結合已有的控制流混淆技術來增大靜態分析的難度。

2.3 隱式調用與隱式引用

除了控制流信息是抵抗靜態分析時需要保護的信息,函數的調用與變量的引用也是一類需要保護敏感信息。例如通過對關鍵函數的調用及特殊字符串的搜索可以快速定位到關鍵部分,提高靜態分析的效率。傳統的關于這兩類信息的保護都注重于內容的保護,如對函數進行包裝、對字符串內容加密等。這樣的處理不僅有較大性能損耗,同時也并不能達到理想的效果。本文在隱式跳轉的基礎上從對象與指令間的關系入手對這兩類信息進行保護。

與基本塊的跳轉類似,在指令層面函數的調用與變量的引用都是以地址為基礎。如圖3(b)中的幾處call指令和包括0400571地址在內的幾處變量引用指令,都是把目標對象的地址直接作為操作數放在指令后。所以可以推廣隱式跳轉的思想,將對應的地址加密隱藏,實現函數的隱式調用和變量的隱式引用。同樣在上一節構建的狀態轉移系統的基礎上,依賴系統當前狀態與輸入參數在運行時解密出真實地址,而不直接存儲密鑰,使得靜態分析時無法確定真實地址,以此切斷相關對象和程序的關聯,也就無法利用特殊的函數和變量去定位關鍵邏輯。另外,也可以插入相似的冗余函數和變量,進一步干擾攻擊者的靜態分析。

2.4 環境密鑰與兩階段加密

前文介紹的模型雖能較好在靜態分析時保護程序各種敏感信息,但是各種加密行為都是在編譯期完成的,所以在后續的指令修改中,同樣的密文可能多次出現,這樣做是有一定風險的。如在基本塊的隱式跳轉中,若BB j是BB i的直接后繼,雖然在BB i中無法直接計算出BB j的實際地址,但是將會出現在所有BB j的前驅塊中,此時通過搜索可以找到BB j的所有前驅節點。同樣的問題也出現在函數隱式調用與全局變量隱式引用的處理中,利用對密文的全局搜索可以找到調用相同函數或引用相同變量的所有指令,再結合一些統計學的知識,還是可以獲取一些有價值信息。

為了解決這個問題,這里引入環境密鑰與兩階段加密的概念,基本思路是在不同環境中(即不同的基本塊中)表示出不同的密文。以基本塊隱式跳轉為例,除了使用主密鑰keyi,還需要一個環境密鑰ckeyi,每個基本塊對應一個環境密鑰,為了保證唯一性,比較簡單的就是取基本塊的地址作為環境密鑰。在編譯期進行加密時使用兩個加密函數進行兩階段加密,分別是使用環境密鑰進行的預加密和使用主密鑰進行的正式加密,這里定義預加密函數如下:

預加密函數需要保證在給出相同的A i,對于任意兩個ckey j,其結果一定不相同。此時結合2.2節中定義的加密函數,完整的加密運算如下所示(表示BBi的地址在BB j環境下所對應的密文):

注意這里選取的預加密函數P可以和F一樣,但要保證函數對解密順序敏感,也就是解密時若先用環境密鑰再用主密鑰時不能獲得正確結果,以防靜態分析時可以對密文進行預處理。在公式(8)中對于同一明文A j,對應不同的ckey j則有不同的結果,也就實現同一個基本塊在不同的環境下展示不同的密文。

同樣對于函數的隱式調用和全局變量的隱式引用,也可以使用環境密鑰和兩階段解密實現密文不重復出現。但是對于這兩者,還存在一種特殊情況,也就是在同一個基本塊內多次調用同一個函數或引用同一個全局變量,這樣仍然會出現密文重復,有效的解決方法是對基本塊進行分裂,在兩個相同的函數調用或者變量引用之間插入無條件跳轉指令,將一個基本塊分裂為多個基本塊,保證兩次相同的調用或引用不出現在一個基本塊內,再進行隱式轉換,就可以保證密文的唯一。

利用環境密鑰的兩階段加密沒有必要對全部對象都使用,在使用前可以統計對象在源程序中的出現次數,若僅出現一次,就可以省去兩階段加密以減少性能損耗。

3 實驗分析

為了評估本文所提出的方案,這里選取了一些樣本進行測試,并與原始程序和其他已有方案進行比較從而得出結論,本文的方案實現是基于OLLVM[17]實現的。

3.1 測試樣本與實驗環境

本文從編譯后程序的空間開銷和時間開銷兩個維度進行測試。這兩個維度使用不同的樣本集,分別是GNU Coreutils[18]內的部分模塊以及排序、散列、加密以及壓縮等領域中有代表性的程序,樣本源碼語言都為C語言。另外關于方案的正確性與通用性可以通過觀察樣本是否能正確編譯以及正確執行來判斷。具體樣本信息如表1所示。

表1 樣本詳情Table 1 Sample details

在實驗中分別對每個樣本都進行如表2所述的幾組實驗。

表2 實驗內容Table 2 Experiment details

其中實驗B、C因為可以實現類似效果,所以有較直觀的對比。本次實驗的環境如表3所示。

表3 實驗環境Table 3 Experimental environment

3.2 結果與分析

按表2描述的四種處理方法對10個樣本進行編譯,首先各個樣本均能通過編譯并正常運行,這一點說明本文方案對一般源代碼程序的處理具有較好的通用性和正確性,具體編譯后可執行文件的大小如表4所示。

表4 可執行文件大小Table 4 Executable file size Byte

通過表4可以看出,任何一種處理手段都會伴隨出現文件體積增大現象。其中,僅做控制流隱式跳轉處理的對照組中,文件體積平均增大29%左右,在此基礎上若對函數調用與變量引用也做處理,文件體積再增加15%左右。

通過分析編譯后程序的匯編指令,可以得出文件增大的原因。以實驗B為例,若要實現一個簡單的無條件跳轉指令從顯式到隱式的轉換,需要在基本塊中添加:當前系統狀態讀取、輔助變量讀取與密鑰計算、密文讀取與解密、系統狀態更新以及跳轉指令替換等操作,在實際轉換中,這些操作將在原基本塊中增加約10條指令。另外,對于有條件跳轉指令及函數調用指令等一些較為復雜的指令,在實際轉換將會增加更多指令。其次,隨著基本塊數量的增多,控制流圖中邊的數量也越多,要轉換的指令也越多,所以編譯后文件體積會有一定的增加。

雖然本文方案最后文件體積會有一定增加,但相比控制流平坦化而言,在達到類似效果的基礎上,實際實驗中二者文件的體積上并沒有明顯的差異。而且原始的控制流平坦化方案只是在形式上打亂了控制流,若要更加安全地保護控制流信息則需要對分發器的邏輯復雜化,這樣只會進一步增加文件體積。

實驗的第二項內容是測試經過處理后程序的性能對比,關于性能可以通過程序運行時間得到直觀的表現。這里對后四種樣本進行測試,其中每組實驗之后得到的二進制文件都執行如表5所示的一定操作并記錄執行時間,重復執行100次,最后取平均時間。

表5 操作詳情Table 5 Operation details

各個樣本的最終運行時間如圖5所示。

圖5 運行時間Fig.5 Execution time

通過圖5可知,在經過控制流扁平化處理之后的程序耗時是最多的,本文所提供的方案中,若只進行控制流隱式跳轉,則平均增加了44%的耗時,若全部處理,則再增加約15%的耗時,雖然最后運行時間相對原始程序都有一定增加,但是相對于控制流平坦化,執行耗時上平均減少約23%,有較大的提升。

通過前面的分析可知由于增加了額外指令,所以在運行時不可避免地增加了運行時間。雖然本文所提方案與控制流平坦化方案都是通過增加額外指令實現控制流混淆,但是本文所增加的額外指令都直接插入到原始的基本塊中,而且與原基本塊內的指令在地址上是相鄰的,同時大多數是一些簡單的數據存儲指令。而控制流平坦化方案中由于匯編指令無法直接實現類似switch結構的分發器,所以只能通過增加大量子分發器將控制流圖轉為一個多層的樹型結構,這樣控制流從主分發器出發,要通過大量子分發器經過層層比較與跳轉才能到達源程序的有效邏輯塊,另外這些子分發器在地址上多數都是不相鄰的,也會造成一定影響。所以相比較來看控制流平坦化方案比本文的方案會造成更大的影響。

通過上面兩方面的實驗可以得出,不管何種保護方法都是有一定負面效應的,不過這也是不可避免的,由于在實驗中默認對全部代碼都進行保護處理,所以影響比較明顯,實際過程中可以有選擇性地對關鍵代碼進行保護處理,從而降低對性能的影響。

4 結束語

本文提出并實現了一種采用隱式跳轉的控制流混淆方案,它不僅能隱藏程序的控制流信息,同時也能保護包括函數調用及變量引用在內的多種敏感信息,增強程序的抗靜態分析能力。由于是建立在抽象的控制流圖基礎上,所以該方案不受具體編程語言及代碼結構的限制,也不需要對源碼進行任何修改,是一種通用的控制流混淆方案。并且還能結合已有的混淆方案保護實現更好的保護效果。未來的研究工作將從如下兩點進行:首先是優化狀態轉移系統進一步減小編譯后文件體積的大??;其次是優化轉移函數和輸出函數,使性能損耗降到最低。

猜你喜歡
控制流靜態代碼
最新進展!中老鐵路開始靜態驗收
抵御控制流分析的Python 程序混淆算法
工控系統中PLC安全漏洞及控制流完整性研究
抵御控制流分析的程序混淆算法
創世代碼
創世代碼
創世代碼
創世代碼
具7μA靜態電流的2A、70V SEPIC/升壓型DC/DC轉換器
基于控制流隱藏的代碼迷惑
91香蕉高清国产线观看免费-97夜夜澡人人爽人人喊a-99久久久无码国产精品9-国产亚洲日韩欧美综合