Jocky混淆JAVA代码(保护你的JAVA项目)
??
??private?String?name?=?"myname";
??
??private?List?myList?=?null;
??
??public?void?SimpleBean()?{
????myList?=?new?ArrayList(10);
??}
??public?void?foo1()?{
????myList.add("name");
??}
??
??private?void?foo2()?{????
??}
??
??private?void?writeObject(java.io.ObjectOutputStream?out)
??????throws?IOException?{
????
??}
}?<未混淆的类文件反编译后的效果>
???下面是经Jocky混淆过的类文件,通过Jad反编译后产生的源文件:

??private?String?_$2;
??private?List?_$1;
??public?SimpleBean()?????{
????????_$2?=?"myname";
????????this;
????????JVM?INSTR?new?#4???<Class?ArrayList>;
????????JVM?INSTR?dup?;
????????JVM?INSTR?swap?;
????????10;
????????ArrayList();
????????_$1;
????}??
??public?void?foo1()?{
????_$1.add("name");
??}
??private?void?_$1()?{
??}
??private?void?writeObject(ObjectOutputStream?objectoutputstream){
??????throws?IOException?{
??}
}?<Jocky混淆过的类文件反编译的效果>?
???JDK 5.0在语法层面上有许多新增特色,能够为简化应用的开发带来一些便利。譬如Generics、Enhanced for Loop以及 Autoboxing/Unboxing等。但另人遗憾的是,倘若利用这些新的语法开发应用,就意味着不能够在JDK 1.4上运行,而JDK 1.4毕竟是目前最为普及的VM版本。幸运是,Jocky的另一个特色就是:通过参数配置,能够把用JDK 5.0语法编写的应用编译成JDK 1.4上的类文件版本。我们可以把经过 Jocky编译的类文件以UltraEdit打开,可以发现在第8个字节上(类文件的major version)的数值是0x30,即十进制的48,这是JDK 1.4所能够理解的类文件版本(JDK 5.0默认编译的类文件版本是49)。前提是:应用中不能够使用JDK 1.4中所没有的一些API。
???使用Jocky非常简单,获得jocky.jar以后,只需要运行java -jar jocky.jar就可以启动Jocky混淆编译器,jocky的命令行参数和javac完全相同,但增加了一个新的参数-scramble,它的用法如下:
-scramble??????????混淆所有package?private或private符号
-scrambleall???????混淆所有符号
-scramble:<level>??混淆相应级别的符号
其中<level>指定混淆级别,可以是以下几种级别:
-scramble:none????????不进行混淆
-scramble:private?????对所有private访问级别的元素进行混淆
-scramble:package?????对所有private或package?private元素进行混淆
-scramble:protected???对所有private,?package?private,?protected元素进行混淆
-scramble:public??????对所有的元素都进行混淆
-scramble:all?????????相当于-scramble:public
如果使用-scramble不带级别参数,则相当于-scramble:package
????近年来,Ant已经成为Java应用开发中打包工具的事实上的标准。在应用的开发过程中,我们往往都会有一个Ant脚本,通过该脚本,能够对应用进行编译、打包、发布等一系列过程。因此,Jocky的最佳切入点便是对Ant的支持。
????在Ant中使用Jocky非常简单:
????1. 将lib\jocky-ant.jar copy至ANT_HOME\lib目录下。
????2. 在ant脚本中加入这样一行代码,以引入Jocky Task
????3. 设置Jocky的一些基本属性,包括: jocky.jar包的位置,以及混淆级别,如下所示:
????4. 当设置jocky的enable属性为true时,此时,Ant脚本中的javac编译命令,便会被自动替换成Jocky编译器;当设置enable属性为false时,javac编译命令将恢复成正常设置,示例脚本如下:
<!--?引入Jocky?Ant?Task,要确保jocky-ant.jar位于ANT_HOME\lib目录下?-->
<taskdef?resource="jockytasks">?</taskdef>
<target?name="build">?
<!--?设置jocky.jar的位置以及混淆级别,当enable为true时,javac?task将被自动替换成Jocky混淆编译器?-->
<jocky?jar="?F:\Works2\Jocky\jocky1.0\lib\jocky.jar"?enable="?true"?level="?private">?</jocky>?
<!--?下面的编译,将使用Jocky混淆编译器?-->
<javac?destdir="bin2"?debug="on"?source="1.5"?target="1.4">?
<src?path="src"></src>
</javac>
<!--?当enable为false时,javac?task将被恢复成正常设置,?Jocky编译器不再起作用?-->
<jocky?enable="false"></jocky>
<!--?下面的编译,将使用正常的Javac编译器?-->
<javac?destdir="bin3"?debug="on"?target="1.4">?
<src?path="src"></src>
</javac>
</target>
</project><Jocky的Ant脚本示例>
<Jocky在Eclipse中的右键菜单>
????事实上,在Eclipse中使用Jocky时,Jocky也是首先针对所选工程生成Ant的Build文件(默认名称jocky_build.xml),然后再通过Ant完成混淆编译。?
????以下是Jocky在Eclipse中自动生成的Ant Build 文件示例:
<property?name="jocky.jar"?value="f:\EclipseWTP1.0.8\workspace_jdk5_apusicstudio\org.apusic.jocky\jocky.jar"></property>
<property?name="jocky.output.dir"?value="jocky"></property>
<property?name="jocky.scramble.level"?value="package"></property>
<property?name="target"?value="1.4"></property>
<path?id="project.classpath">?
<pathelement?location="bin"></pathelement>
</path>
<target?name="init">?
<jocky?jar="${jocky.jar}"?level="${jocky.scramble.level}"></jocky>
<mkdir?dir="${jocky.output.dir}"></mkdir>
<mkdir?dir="${jocky.output.dir}/bin"></mkdir>
</target>
<target?name="clean">?
<delete?dir="${jocky.output.dir}/bin"></delete>
<delete?dir="${jocky.output.dir}"></delete>
</target>
<target?depends="init"?name="build">?
<echo?message="${ant.project.name}:?${ant.file}"></echo>
<jocky?enable="true"></jocky>
<javac?destdir="${jocky.output.dir}/bin"?target="${target}">?
<src?path="src"></src>
<classpath?refid="project.classpath"></classpath>
</javac>
</target>
</project><Jocky在Eclipse中自动生成的Ant脚本示例>
/**
?2
?*?This?class?should?preserve.
?3
?*?@preserve
?4
?*/
?5
public?class?Foo?{
?6
????/**
?7
?????*?You?can?specify?which?field?should?be?preserved.
?8
?????*?@preserve
?9
?????*/
10
????private?int?x;
11
12
????/**
13
?????*?This?field?is?not?preserved.
14
?????*/
15
????private?int?y;
16
17
????/**
18
?????*?You?can?also?preserve?methods.
19
?????*?@preserve
20
?????*/
21
????public?void?hello()?{}
22
23
????/**
24
?????*?This?method?is?not?preserved.
25
?????*/
26
????private?void?collect()?{}
27
}?<使用preserved指令的示例>
???如果没有@preserve指令,则根据混淆级别及成员的访问级别来确定符号是否保留。
???对于类的符号保留指令可以附带一个保留级别参数,来控制类成员的符号保留,包括:
@preserve????????????仅对类名进行保留,类成员的保留根据-scramble命令行参数决定
@preserve?public?????保留所有public成员
@preserve?protected??保留所有public和protected成员
@preserve?package????保留所有public,?protected,?package?private成员
@preserve?private????保留所有成员
@preserve?all????????相当于@preserve?private
???事实上,即便不加@preserve指令,Jocky对Java语言特有的一些private级别的方法不进行混淆,譬如,在序列化时有特殊作用的writeObject及readObject方法等。但笔者强烈建议: 针对这些有特殊含义不能够被混淆的 private级别的方法或者字段,请以@preserve指令予以保护。
注1:建议通过IDE的JavaDoc设置,来辅助@preserve指令的书写。
???正如前文所说,Jocky是基于源代码的混淆编译器,因此,Jocky不支持分别编译,必须对所有的源文件同时进行混淆编译。但事实上,倘若混淆级别控制在private级别上,该限制便不复存在。