Java程式碼加密與反編譯(一):利用混淆器工具proGuard對jar包加密
Java 程式碼編譯後生成的 .class 中包含有原始碼中的所有資訊(不包括註釋),尤其是在其中儲存有除錯資訊的時候。所以一個按照正常方式編譯的 Java .class 檔案可以非常輕易地被反編譯。通常情況下,反編譯可以利用現有的工具jd-gui.exe或者jad.exe。
(這兩個反編譯工具在我的資源裡有下載:
有些情況下,為了保護java原始碼不被別人看到,通常會使用加密手段對java原始碼進行加密,加密的方式可以利用加密工具(比如java程式碼混淆工具)、使用加密演算法(如DES演算法)修改classloader對編譯好的.class檔案進行加密。
一、用java混淆器工具proGuard實現加密
這裡使用proGuard對jar包進行加密。
1. 解壓下載的proguard,解壓後進入lib檔案把proguard.jar拷貝到自己新建的資料夾裡如圖:
2. 把需要混淆的jar和jar所依賴的包也放到新建的資料夾,都放在一起,如下圖。
3. 寫一個配置檔案,名稱自己定,例如”a”檔案,舉個簡單配置檔案例子(那個proguard.map是過後自己生成的),內容如下,其中-injars:是你需要混淆的jar,-outjars:是你混淆後輸出的jar,-libraryjars:是你混淆的jar需要所依賴的jar包,後面的不在一一說明,可以參考proguard文件,配置檔案可以參考文件來對自己混淆的需求來寫配置檔案。
-injars TheFirstDesktopApplication1.jar
-outjars TheFirstDesktopApplication1_out.jar
-libraryjars <java.home>/lib/rt.jar
-libraryjars appframework-1.0.3.jar
-libraryjarsswing-worker-1.1.jar
-printmappingproguard.map
-overloadaggressively
-defaultpackage ''
-allowaccessmodification
-dontoptimize
-keep public class*
{
public protected *;
}
-keep public classorg.**
-keep public classit.**
4. 把配置檔案儲存到你建的資料夾下,如下圖。
5.點選開始,執行,輸入cmd,進入你建的資料夾下,如下圖。
6. 然後輸入命令語句:java -jarproguard.Jar @a 然後回車,如下圖。
7. 混淆成功,在產生TheFirstDesktopApplication1_out.jar如下圖。
8. 混淆器後,利用反編譯器jad對沒TheFirstDesktopApplication1_out.jar反編譯,多了好多a,b,c之類的類檔案,對反編譯的java檔案是很難編譯的,即說明混淆成功。
用上面方法試了一下,發現其實混淆效果並不好,使用jd-gui反編譯工具就可以輕易看到原始碼。總結一下,網上找了幾個程式碼混淆工具效果都不好,其實現成工具看來也並不是那麼好用。
然後想想,就換了一種方式,直接使用加密演算法對java程式碼進行解密。在下篇文章裡再寫。
ProGuard是一個免費的java類檔案壓縮,優化,混淆器.它探測並刪除沒有使用的類,欄位,方法和屬性.它刪除沒有用的說明並使用位元組碼得到最大優化.它使用無意義的名字來重新命名類,欄位和方法.ProGuard的作用:
1.建立緊湊的程式碼文件是為了更快的網路傳輸,快速裝載和更小的記憶體佔用.
2.建立的程式和程式庫很難使用反向工程.
3.所以它能刪除來自原始檔中的沒有呼叫的程式碼
4.充分利用java6的快速載入的優點來提前檢測和返回java6中存在的類檔案.
引數:
- -include {filename} 從給定的檔案中讀取配置引數
- -basedirectory {directoryname} 指定基礎目錄為以後相對的檔案名稱
- -injars {class_path} 指定要處理的應用程式jar,war,ear和目錄
- -outjars {class_path} 指定處理完後要輸出的jar,war,ear和目錄的名稱
- -libraryjars {classpath} 指定要處理的應用程式jar,war,ear和目錄所需要的程式庫檔案
- -dontskipnonpubliclibraryclasses 指定不去忽略非公共的庫類。
- -dontskipnonpubliclibraryclassmembers 指定不去忽略包可見的庫類的成員。
保留選項
- -keep {Modifier} {class_specification} 保護指定的類檔案和類的成員
- -keepclassmembers {modifier} {class_specification} 保護指定類的成員,如果此類受到保護他們會保護的更好
- -keepclasseswithmembers {class_specification} 保護指定的類和類的成員,但條件是所有指定的類和類成員是要存在。
- -keepnames {class_specification} 保護指定的類和類的成員的名稱(如果他們不會壓縮步驟中刪除)
- -keepclassmembernames {class_specification} 保護指定的類的成員的名稱(如果他們不會壓縮步驟中刪除)
- -keepclasseswithmembernames {class_specification} 保護指定的類和類的成員的名稱,如果所有指定的類成員出席(在壓縮步驟之後)
- -printseeds {filename} 列出類和類的成員-keep選項的清單,標準輸出到給定的檔案
壓縮
- -dontshrink 不壓縮輸入的類檔案
- -printusage {filename}
- -whyareyoukeeping {class_specification}
優化
- -dontoptimize 不優化輸入的類檔案
- -assumenosideeffects {class_specification} 優化時假設指定的方法,沒有任何副作用
- -allowaccessmodification 優化時允許訪問並修改有修飾符的類和類的成員
混淆
- -dontobfuscate 不混淆輸入的類檔案
- -printmapping {filename}
- -applymapping {filename} 重用對映增加混淆
- -obfuscationdictionary {filename} 使用給定檔案中的關鍵字作為要混淆方法的名稱
- -overloadaggressively 混淆時應用侵入式過載
- -useuniqueclassmembernames 確定統一的混淆類的成員名稱來增加混淆
- -flattenpackagehierarchy {package_name} 重新包裝所有重新命名的包並放在給定的單一包中
- -repackageclass {package_name} 重新包裝所有重新命名的類檔案中放在給定的單一包中
- -dontusemixedcaseclassnames 混淆時不會產生形形色色的類名
- -keepattributes {attribute_name,...} 保護給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
- -renamesourcefileattribute {string} 設定原始檔中給定的字串常量
Ant Example:
- < !-- This Ant build file illustrates how to process applications,
- by including ProGuard-style configuration options.
- Usage: ant -f applications2.xml -->
- <projectname="Applications"default="obfuscate"basedir="../..">
- <targetname="obfuscate">
- <taskdefresource="proguard/ant/task.properties"
- classpath="lib/proguard.jar"/>
- <proguard>
- <!-- Specify the input jars, output jars, and library jars. -->
- -injars in.jar
- -outjars out.jar
- -libraryjars ${java.home}/lib/rt.jar
- <!-- -libraryjars junit.jar -->
- <!-- -libraryjars servlet.jar -->
- <!-- -libraryjars jai_core.jar -->
- <!-- ... -->
- <!-- Save the obfuscation mapping to a file, and preserve line numbers. -->
- -printmapping out.map
- -renamesourcefileattribute SourceFile
- -keepattributes SourceFile,LineNumberTable
- <!-- Preserve all annotations. -->
- -keepattributes *Annotation*
- <!-- Preserve all public applications. -->
- -keepclasseswithmembers public class * {
- public static void main(java.lang.String[]);
- }
- <!-- Preserve all native method names and the names of their classes. -->
- -keepclasseswithmembernames class * {
- native <methods>;
- }
- <!-- Preserve the methods that are required in all enumeration classes. -->
- -keepclassmembers class * extends java.lang.Enum {
- public static **[] values();
- public static ** valueOf(java.lang.String);
- }
- <!-- Explicitly preserve all serialization members. The Serializable
- interface is only a marker interface, so it wouldn't save them.
- You can comment this out if your library doesn't use serialization.
- If your code contains serializable classes that have to be backward
- compatible, please refer to the manual. -->
- -keepclassmembers class * implements java.io.Serializable {
- static final long serialVersionUID;
- static final java.io.ObjectStreamField[] serialPersistentFields;
- private void writeObject(java.io.ObjectOutputStream);
- private void readObject(java.io.ObjectInputStream);
- java.lang.Object writeReplace();
- java.lang.Object readResolve();
- }
- <!-- Your application may contain more items that need to be preserved;
- typically classes that are dynamically created using Class.forName -->
- </proguard>
- < /target>
- < /project>