Java是一個極度容易被反編譯的程式語言,因為它並非直接將程式編譯成Binary Code直接給實體機器執行,而是先翻譯成Java Bytecode再透過Java Virtual Machine來執行。Java的bytecode類似組合語言,極度容易被原封不動的顯示出來,因為Java Development Kit本身就有提供javap工具能夠將.class以bytecode的形式顯示。而這些bytecode要翻譯回原本的Java程式碼,也是蠻容易的,網路上可以找到許多工具輕易達成。



如果Java程式真的很容易被反編譯出來,那麼我們這些辛苦的程式設計師絞盡腦汁的心血結晶不是就被別人看光光了嗎?是的,如果沒有對編譯完成的Java程式進行特殊的混淆(obfuscating)處理,那你就虧大啦!

所謂的混淆,其實不是讓程式無法反編譯,而是讓程式在反編譯之後難以閱讀。它的作法是將套件、類別、方法、變數等等的這些在程式撰寫完成後便無關緊要名稱,以別種名稱取代,例如將print這個方法變成a方法、將Account這個類別變成E類別。

目前較多人使用的Java程式混淆工具為Proguard,以下是它的官方網站:

http://proguard.sourceforge.net/

Proguard本身提供GUI工具來混淆Java程式,設定項目非常煩雜,操作起來不是很方便。通常我們對程式進行混淆,是因為那個程式已經完成,之後沒有其它程式會在引用它來開發衍生的功能。這類型的程式,我們會將它封存為Jar檔保存,要執行也會比較方便(一大堆的Class檔都包在Jar檔裡面)。在Netbeans中,如果要將所有程式包成單一的Jar檔,可以參考這篇文章。如果要再將這個Jar檔進行混淆的話,需在build.xml的部份(</target></project>)之前再加上以下文字:

<!--必須設定這裡的屬性值-->
<property name="JDK根目錄" value="/usr/lib/jdk1.8.0_152" />
<property name="proguard根目錄" value="/home/magiclen/proguard6.0" />
<property name="proguard config檔案" value="${proguard根目錄}/config.cfg" />
<!-- *************** -->
<property name="proguard Jar路徑" value="${proguard根目錄}/lib/proguard.jar" />
<property name="proguard MAP路徑" value="${basedir}/${application.title}.map" />
<property name="JDK Lib路徑" value="${JDK根目錄}/lib" />
<property name="JRE路徑" value="${JDK根目錄}/jre" />
<property name="JRE Lib路徑" value="${JRE路徑}/lib" />
<property name="Runtime路徑" value="${JRE Lib路徑}/rt.jar" />
<taskdef resource="proguard/ant/task.properties" classpath="${proguard Jar路徑}" />
<delete file="${proguard MAP路徑}"/>

<!--找JavaFX的Runtime路徑-->
<condition property="jfxrt路徑" value="${JRE Lib路徑}/jfxrt.jar">
    <available file="${JRE Lib路徑}/jfxrt.jar"/>
</condition>
<condition property="jfxrt路徑" value="${JRE Lib路徑}/ext/jfxrt.jar" else="${JDK Lib路徑}/ant-javafx.jar">
    <and>
        <not>
            <isset property="jfxrt路徑"/>
        </not>
        <available file="${JRE Lib路徑}/ext/jfxrt.jar"/>
    </and>
</condition>

<proguard printmapping="${proguard MAP路徑}" ignorewarnings="true" configuration="${proguard config檔案}">
    <injar  file="${路徑}" />
    <outjar file="${暫存}"/>

    <libraryjar path="${javac.classpath}" />
    <libraryjar file="${Runtime路徑}" />
    <libraryjar file="${jfxrt路徑}"/>
</proguard>

<zip destfile="${路徑}">
    <zipfileset src="${暫存}"/> 
</zip>  
<delete file="${proguard MAP路徑}"/>
<delete file="${暫存}"/>
<echo message="混淆Jar:${路徑}"/>

注意的是,在上面這段文字中,有三個屬性要自行修改。第一個是JDK根目錄,第二個是proguard根目錄,proguard可直接到官方網站下載,第三個是proguard config檔案,可以使用筆者提供的proguard cfg檔案。設定完成後,在Netbeans建置專案,就會自動產出單個混淆過後的Jar檔案。如果嘗試反編譯這個檔案,會得到以下的結果。

一堆abcde,根本看不懂程式在寫什麼啦!如此一來就不用太擔心程式會遭人盜用了。