Java 代码编译后生成的 .class 中包含有源代码中的所有信息(不包括注释),尤其是在其中保存有调试信息的时候。所以一个按照正常方式编译的 Java .class 文件可以非常轻易地被反编译。通常情况下,反编译可以利用现有的工具jd-gui.exe或者jad.exe。
有些情况下,为了保护java源码不被别人看到,通常会使用加密手段对java源码进行加密,加密的方式可以利用加密工具(比如java代码混淆工具)、使用加密算法(如DES算法)修改classloader对编译好的.class文件进行加密。
(注:这里推荐一款java代码混淆器,可以混淆函数变量、类、方法名以实现代码加密:proGuard:
一、用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
-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,进入你建的文件夹下,如下图。
- 然后输入命令语句:java -jarproguard.Jar @a 然后回车,如下图。
- 混淆成功,在产生TheFirstDesktopApplication1_out.jar如下图。
- 混淆器后,利用反编译器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 -->
< target name="obfuscate">
-injars in.jar
-outjars out.jar
-libraryjars ${java.home}/lib/rt.jar
-printmapping out.map
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-keepattributes *Annotation*
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
-keepclasseswithmembernames class * {
native ;
}
-keepclassmembers class * extends java.lang.Enum {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-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();
}
< /target>
< /project>