• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看 ?

      基于Java編譯器的Maven混淆插件的設(shè)計與實現(xiàn)

      2018-06-02 08:50:48傅曉巍
      電腦知識與技術(shù) 2018年10期

      傅曉巍

      摘要:Java編程語言被大量的工程項目使用,對Java源代碼進行保護,防止其被竊取和篡改是非常有必要的。該文以O(shè)penJDK和Oracle JDK的編譯器Javac為基礎(chǔ),以編譯器插件的形式設(shè)計和實現(xiàn)了一個作用于Java源代碼的混淆器。該混淆器通過修改由編譯器提供的抽象語法樹和實現(xiàn)訪問者模式達到混淆源代碼的目的。該文介紹了名稱變換、包修改和數(shù)組下標同態(tài)計算三種混淆方法。同時,該混淆器被包裝成Maven插件,以方便實際項目的使用。

      關(guān)鍵詞:Java編譯器;Maven插件;混淆

      中圖分類號:TP311 文獻標識碼:A 文章編號:1009-3044(2018)10-0065-03

      Abstract: The Java programming language is used by many engineering projects and it is necessary to protect the Java source code against theft and tampering. Based on compiler Javac of OpenJDK and Oracle JDK, this paper designs and implements an obfuscator that acts on Java source code in the form of compiler plug-in. The obfuscator achieves the purpose of obfuscating the source code by modifying the abstract syntax tree provided by the compiler and implementing the visitor pattern. This article introduces the three obfuscation methods of name conversion, package modification, and array index homomorphic calculation. Meanwhile, the obfuscator is packaged as a Maven plugin to facilitate the use of actual projects.

      Key words: java compiler; maven plugin; obfuscate

      在所有的軟件中,以Java語言編寫的程序正在日益成為盜版問題的重災(zāi)區(qū)。Java語言是當(dāng)前軟件編寫最常用的編程語言,它有著優(yōu)于其他大多數(shù)編程語言的可移植性與平臺無關(guān)性,從而使Java語言越來越被大多數(shù)企業(yè)接受來研發(fā)產(chǎn)品。Java語言在以下兩個行業(yè)里起著核心作用:1)Android軟件行業(yè)。Android手機操作系統(tǒng)使用由Google公司使用Java語言開發(fā)的手機端OS,所有Android手機APP必須使用Java語言開發(fā);2)互聯(lián)網(wǎng)行業(yè)。Java語言有著極其優(yōu)秀的可移植性,同時易于學(xué)習(xí),成為許多互聯(lián)網(wǎng)大公司開發(fā)的首選。這些公司使用Java語言后,常常會開發(fā)可以提供給其他人使用的工具,反過來更進一步地促進了Java語言本身的發(fā)展。現(xiàn)在大部分互聯(lián)網(wǎng)框架都是使用Java實現(xiàn)的。為了實現(xiàn)可移植性,Java語言使用中間代碼發(fā)布。這種特性,導(dǎo)致了Java語言所編寫的軟件比起其他軟件更容易被破解,從而嚴重威脅開發(fā)者的知識產(chǎn)權(quán)及使用者的軟件安全。

      Maven是當(dāng)前十分常用的Java項目管理與發(fā)布框架,有必要開發(fā)一個能夠?qū)υ创a進行混淆[1-2]的Maven插件。

      1 混淆插件的設(shè)計

      1.1 Maven插件開發(fā)

      Java語言在執(zhí)行代碼時,會先由編譯器將源代碼編譯成字節(jié)碼,然后由虛擬機解釋執(zhí)行字節(jié)碼。把一個項目下所有源代碼、資源、配置等文件編譯、打包成字節(jié)碼的過程稱作項目構(gòu)建。如果項目比較簡單,我們可以借助IDE甚至直接使用編譯器來構(gòu)建項目。在實踐中,Java項目一般會比較復(fù)雜,比如多個項目之間有依賴關(guān)系、需要導(dǎo)入第三方的庫、有特殊的發(fā)布需求等。

      對于復(fù)雜項目的構(gòu)建,一般需要使用項目構(gòu)建工具:

      1)Ant是最早出現(xiàn)的項目構(gòu)建工具,使用腳本來實現(xiàn)配置,其中腳本文件使用XML格式編寫。但是XML文件是層次型的結(jié)構(gòu),不是很適合過程型的腳步,當(dāng)項目比較大的時候,Ant文件就會非常復(fù)雜。

      2)Maven具有非常強大的功能,是當(dāng)下Java項目比較流行使用的。Maven也使用XML文件作為配置文件,該配置文件名稱是pom.xml。和Ant不同的是,Maven配置的結(jié)構(gòu)是層次化的。

      3)Gradle兼具了Ant和Maven的特點。Gradle不使用XML,而是使用基于Groovy語言的DSL。Gradle可以使用Maven插件。

      考慮到Maven插件可以同時被Maven和Gradle兩種項目構(gòu)建工具使用,我們把混淆插件開發(fā)成Maven插件的形式。

      Maven使用配置Maven倉庫以及依賴的方式解決依賴管理。先把包發(fā)布到Maven倉庫中,倉庫包括Apache Maven官方倉庫、第三方倉庫和自己的倉庫。然后在需要使用該依賴包的項目中配置上這個包的倉庫地址和名稱。這樣,通過配置文件和模塊的方式配置項目依賴,極大地減少了項目開發(fā)過程中依賴管理的開銷。

      Maven完成項目的編譯、測試、發(fā)布等任務(wù)時,同樣也通過配置文件,組合使用Maven豐富的功能插件,完成特定的任務(wù)。Maven自己只是框架,運行時以插件構(gòu)成,比如測試的插件、編譯的插件等等。Maven官方本身提供了非常豐富的插件,網(wǎng)上也有很多可以使用的第三方插件,同時我們也可以開發(fā)自己的Maven插件。如圖1。

      要開發(fā)自己的Maven插件,只需要繼承org.apache.maven.plugin.AbstractMojo類,然后選擇把該項目以Maven plugin的格式打包發(fā)布。之后就可以在需要使用的項目的pom.xml配置插件并使用了。

      1.2 Java插件開發(fā)

      Java編譯器是Java編程語言的編譯器,用于編譯Java源代碼。Java編譯器輸出的是包含平臺無關(guān)的Java字節(jié)碼的Java類文件。Java類文件可以運行在Java虛擬機JVM上。

      Javac是OpenJDK和Oracle JDK的編譯器。Javac本身是用Java編寫的,也可以被編程調(diào)用。

      開發(fā)Javac插件,是通過實現(xiàn)Plugin接口的方式來完成的。開發(fā)好插件之后,在META-INF目錄下配置com.sun.source.util.Plugin文件,Javac會使用Java的ServiceLoader機制來獲得插件的配置。之后就可以在Javac的命令中使用自己開發(fā)的插件了。通過-XPlugin:[插件的名字] <參數(shù)>的方式來調(diào)用。

      當(dāng)我們在啟動Javac的時候,Javac會調(diào)用Plugin.init方法進行初始化。我們需要在JavacTask中添加我們自己的監(jiān)聽器。之后在Javac的運行過程中調(diào)用,會在每個步驟調(diào)用我們的TaskListener。如圖2。

      在執(zhí)行的過程中,在每個階段都會調(diào)用。其中編譯的內(nèi)容會以抽象語法樹的形式呈現(xiàn)。我們可以使用source包下的工具分析抽象語法樹。如果需要獲取更進一步的信息,甚至要修改抽象語法樹,需要使用tools下面的工具。

      1.3 插件的設(shè)計

      我們的插件使用了Javac,雖然可以作為編譯器使用,但是我們在實際使用時還是只作為混淆功能使用。我們可以只對代碼進行修改,然后再把源代碼產(chǎn)生。之后讓Maven使用標準的Java編譯器來把我們產(chǎn)生的代碼編譯成Class文件。因此我們的插件是在預(yù)處理階段使用的,不是編譯階段。如圖3。

      2 混淆器實現(xiàn)

      2.1 抽象語法樹

      Javac是Oracle JDK和OpenJDK中的Java編譯器。Javac在編譯時會把源代碼解析成抽象語法樹(Abstract Syntax Tree,AST),然后在抽象語法樹上執(zhí)行編譯的任務(wù)(如圖4):

      [public class Main {

      public static void main(String[] args) {

      System.out.println

      ("Hello World!");

      }

      }]

      以上是一段簡單的Java程序的語法樹結(jié)構(gòu)。

      在Parse階段,Javac會把源代碼解析成語法樹。之后在Enter階段,Javac會把語法樹中對應(yīng)的符號表建立。在之后的Analyze階段,把生產(chǎn)的符號和使用的地方對應(yīng)。我們的修改工作在Analyze階段之后,Generate階段之前。Analyze階段之后,語法樹中的信息是最多的,同時語法樹的結(jié)構(gòu)還保留著語法糖,當(dāng)我們把代碼寫回新文件時,結(jié)構(gòu)最好。在Analyze階段之后,會開始去語法糖和生成字節(jié)碼的任務(wù),語法樹結(jié)構(gòu)會開始被修改。

      抽象語法樹中的節(jié)點都是JCTree類的子類。這些子類使用了設(shè)計模式中的訪問者模式。通過使用Visitor,可以遍歷抽象語法樹。

      我們對源代碼的修改,主要是通過許多個Visitor對語法樹的遍歷來實現(xiàn)的。如圖5。

      2.2 名稱變換

      名稱變化主要是指變量名、函數(shù)名和內(nèi)部類名的變換。包名和外部類名的修改因為涉及了物理文件,我們在2.3節(jié)中介紹。

      對名稱的修改由兩個階段組成:

      2.2.1 修改符號

      為了能夠找到每個名字所對應(yīng)的變量、函數(shù)、類,Javac會為此建立一個符號表,當(dāng)某個名字被使用時,可以通過符號表查找來確定時那個符號。在之后產(chǎn)生字節(jié)碼的時候,為這些使用同一個符號的指令分配同一個內(nèi)存地址。

      1)VarSymbol

      VarSymbol是變量的符號,用來記錄變量信息。一般情況下,一個類內(nèi)部的變量名時不重復(fù)的。但是不同的類之間的變量名時互不干擾的。

      2) MethodSymbol

      MethodSymbol是函數(shù)的符號,記錄函數(shù)的信息,比如名稱、參數(shù)類型、返回值類型、泛型、異常等等。MethodSymbol中沒有函數(shù)體的信息,函數(shù)體完全由抽象語法樹表示。

      3)ClassSymbol

      ClassSymbol是類的符號,記錄了類的信息,包括了類名和類內(nèi)部所有成員的符號。修改內(nèi)部類的名稱只需要像變量和函數(shù)一樣修改,但是修改外部類的名稱還需要同時修改頂層語法樹。

      2.2.2 修改語法樹

      修改符號,只需要重設(shè)符號的name字段就能完成。但是語法樹建立的時候,各個語法樹節(jié)點的名字已經(jīng)確定了。我們在修改后,這些變動不能應(yīng)用在符號被使用的地方,我們需要自己使用Visitor去使名稱的修改生效。

      1)JCIdent

      這是一個符號常會被使用的地方。例如語句i=0;中的就是一個JCIdent節(jié)點。

      2)JCFieldAccess

      這種節(jié)點對應(yīng)語法是一個類中選擇成員的表達式,比如person.name。

      我們使用Visitor對語法樹進行深度優(yōu)先搜索,把所有使用了這個符號的語法樹節(jié)點名稱變成符號的名稱。

      2.3 包修改

      包和外部類因為涉及了物理文件,因此修改步驟要比簡單名稱變換復(fù)雜很多。

      2.3.1 修改符號和語法樹

      1)外部類

      外部類的符號修改和內(nèi)部類一致。類和子類的符號的關(guān)系是類包含了子類,因此子類的信息在父類的符號表中全部都有。對類和子類的訪問是一種從上到下的方式進行的。

      2)包

      包的符號修改則和類的符號不同。包和類的符號的關(guān)系是由類來存儲上層的包的符號,包和上一級的包也是這種關(guān)系。因此,對包的訪問是一種從下往上的方式進行的。同時,包的語法樹中并沒有符號PackageSymbol。對包的語法樹修改無法使用Visitor,我們需要自己手動修改。

      2.3.2 寫回

      在我們修改完包和外部類的名稱后,編譯產(chǎn)生的外部類的物理地址也會改變。我們需要修改存儲的物理節(jié)點的信息。但是由于包是沒有直接對應(yīng)的語法樹節(jié)點的,我們必須要修改該包下所有的類的名稱。

      2.4 數(shù)組下標同態(tài)計算

      數(shù)組下標是整形,同時數(shù)組的長度在產(chǎn)生后是固定的,可以使用同態(tài)計算[3][4][5]混淆數(shù)組下標:

      1) 對一個長度為n的數(shù)組A,隨機產(chǎn)生一個整數(shù)m,要求m>n,并且m和n互質(zhì)。

      2) 把所有對A進行下標訪問的A[i]都修改成A[i×m mod n]。

      以下是具體的實現(xiàn)的步驟:

      a)使用Visitor找到所有對數(shù)組A的下標訪問。對數(shù)組進行下標訪問的語法樹節(jié)點是JCArrayAccess。

      b)在下標訪問的表達式外側(cè)添加同態(tài)計算的語法樹。使用JCIdent和JCBinary。其中JCBinary需要使用Resolve工具來得到乘法和求模的MethodSymbol。

      3 結(jié)論

      本文以Javac編譯器為基礎(chǔ),用插件的形式,實現(xiàn)了一個基于抽象語法的混淆器。并且實現(xiàn)了名稱修改、包修改、數(shù)組下標同態(tài)計算等混淆方法。

      同時,我們把混淆器包裝成Maven插件,使混淆器可以在實踐中被有效的使用。

      參考文獻:

      [1] Cohen F B. Operating system protection through program evolution[J]. Computers & Security, 1993, 12(6): 565-584.

      [2] Collberg C, Thomborson C, Low D. A taxonomy of obfuscating transformations[R]. Technical Report, 1997.

      [3] Brakerski Z, Gentry C, Halevi S. Packed ciphertexts in LWE-based homomorphic encryption[M]//Public-Key Cryptography–PKC 2013. Springer Berlin Heidelberg, 2013: 1-13.

      [4] Dalla Preda M, Giacobazzi R. Control code obfuscation by abstract interpretation[C]//Third IEEE International Conference on Software Engineering and Formal Methods (SEFM'05). IEEE, 2005: 301-310.

      [5] Gentry C, Sahai A, Waters B. Homomorphic encryption from learning with errors: Conceptually-simpler, asymptotically-faster, attribute-based[M]//Advances in Cryptology–CRYPTO 2013. Springer Berlin Heidelberg, 2013: 75-92.

      莱芜市| 随州市| 岢岚县| 商河县| 晋州市| 大丰市| 胶南市| 偃师市| 循化| 宜都市| 女性| 五峰| 平凉市| 海淀区| 林西县| 司法| 贵德县| 全椒县| 金平| 米泉市| 定西市| 石阡县| 内江市| 封丘县| 岳阳市| 峨眉山市| 南澳县| 岗巴县| 饶平县| 昭觉县| 宁津县| 襄垣县| 澎湖县| 黔西县| 鄂托克旗| 永昌县| 临武县| 胶州市| 桂阳县| 乌拉特后旗| 临洮县|