1、使用Java混淆工具yguard使用Java混淆工具yguard 在某些情况下,java开发者可能希望保护自己的劳动成果,防止自己编写的源代码被竞争对手或者其他组织和个人轻易获取而危害自己的利益,最简单有效的办法就是对编译后的java类文件进行混淆处理。本文介绍一款这样的工具yguard。yGruard是一个功能比较强大的java类文件的混淆工具,特别适合与ant工具集成使用。本文对yguard的基本元素做一些简单的介绍,并列举了一些简单的ant任务例子,在实际工程项目中可以参考这些样例。 1. 安装在使用yGruard之前,必须首先确保系统中已经有可以正常使用的Ant工具。Ant工具的使用的
2、介绍不属于本文的范畴。然后在官方网站解压出之后,把它放置在你的ant工具能够找到的路径中。你可以使用绝对路径,但是在下面的例子中。为了在你现有的Ant任务中使用yguard进行混淆工作,你可以采取下边两种做法之一。一、你可以在你的build脚本中直接插入下面的代码片。 二、你也可以把taskdef元素放置在obfuscate元素中,示例如下: 2. 创建初始ant任务我们从经典的helloworld示例入手,逐步学习使用yguard混淆器工具。2.1. 编写helloword程序我们先编写一个简单的HelloWorld程序,代码如下: package helloworld;public cla
3、ss HelloWorld public String publicAttribute = i am a public attrubute.; protected String protectedAttribute = i am a protected attrubute.; private String privateAttribute = i am a private attrubute.; public void publicSayHello() System.out.println(hello world in public . ); protected void protectedS
4、ayHello() System.out.println(hello world in protected . ); private void privateSayHello() System.out.println(hello world in private . ); public static void main(String args) HelloWorld hello = new HelloWorld(); hello.publicSayHello(); 这个HelloWorld程序有不同可见性的属性,不同可见性的方法。在下面的过程中,我们将逐步演示yguard的强大功能。2.2.
5、创建ant任务创建一个初始的ant脚本任务。 2.3. 执行ant任务执行这个脚本,可以看到控制台有如下相似的输出:Buildfile: D:/work/lspworkspace/helloworld/build.xmlinit:init:compile: javac Compiling 1 source file to D:/work/lspworkspace/helloworld/classesinit:compile: javac Compiling 1 source file to D:/work/lspworkspace/helloworld/classesjar: jar Buil
6、ding jar: D:/work/lspworkspace/helloworld/helloworld_temp.jarBUILD SUCCESSFULTotal time: 4 seconds如果你是完全copy的话,这个过程理论上是不会出错的,如果有错误,请考虑是不是你的环境配置问题。3. 第一个混淆任务3.1. 执行混淆任务我们按照前面讲到的安装方法,在这个可执行的Ant任务中加入混淆任务,加入的具体内容如下: 我们执行这个修改过的ant任务,在设定的输出目录下,至少会产生如下几个文件,helloworld.jar,混淆后的jar文件;helloworld_temp.jar,混淆前的原
7、始jar文件;helloworld_obf_log.xml,产生的日志文件。下面我们打开jar包,可以发现包名、类名混淆前后是不一样的,我们反编译其中class文件,这是我们在混淆之前根据编译后的class文件反编译产生的源文件。package helloworld;import java.io.PrintStream;public class HelloWorld public HelloWorld() publicAttribute = i am a public attrubute.; protectedAttribute = i am a protected attrubute.; p
8、rivateAttribute = i am a private attrubute.; public void publicSayHello() System.out.println(hello world in public . ); protected void protectedSayHello() System.out.println(hello world in protected . ); private void privateSayHello() System.out.println(hello world in private . ); public static void
9、 main(String args) HelloWorld helloworld = new HelloWorld(); helloworld.publicSayHello(); public String publicAttribute; protected String protectedAttribute; private String privateAttribute;这是我们根据混淆后的class文件产生的源代码,我们可以发现类的包名、方法名、属性名已经发生了变化。package A;import java.io.PrintStream;public class A public A
10、() B = i am a public attrubute.; A = i am a protected attrubute.; C = i am a private attrubute.; public void B() System.out.println(hello world in public . ); protected void C() System.out.println(hello world in protected . ); private void A() System.out.println(hello world in private . ); public st
11、atic void A(String as) A a = new A(); a.B(); public String B; protected String A; private String C;下面,我们来学习obfuscate及其相关元素。4. Obfuscate元素Obfuscate是整个混淆任务定义的元素,下面我们对它及其子元素进行详细的介绍。4.1. Obfuscate元素在当前版本中,Obfuscate元素有如下一些属性, mainclass:简写你的应用的主程序类名,主类的类名和它的主方法名都会被修改。你可能想仅仅暴露主方法(main),如果你的jar文件描述文件中MANIFE
12、ST.MF包含了Main-Class属性,yguard将会自动调整成混淆后的主类名。 logfile:混淆过程产生的日志文件名称,这个日志文件包含了混淆过程的任何警告信息和映射信息。 conservemanifest:(取值为boolean类型true/false),表示混淆器是否应改保持jar包的manifest清单文件不变。缺省值为false,表示这个清单文件将会被混淆器修改用来反映新的信息摘要。 replaceClassNameStrings:(也是一个boolean属性值),设定yguard是否需要取代某些硬编码的字符串。(本文英文水平有限,这个属性没有理解清楚)。4.2. inout
13、pair元素inoutpair元素,每一个混淆任务(obfuscation task)都必须至少有一个inoutpair元素。该元素指定了要被混淆的源jar包和产生的目标jar包的名称和路径,要注意的是只有class文件能够被混淆,其他的如资源文件,只是简单的从源jar包copy到目标jar包。In属性指定包含了需要被混淆jar包。Out属性指定了混淆后产生的新jar包。4.3. Externalclasses 元素如果这个被混淆的jar包需要依赖其他外部class文件或者jar包,externalclasses用来指定这些被依赖的实体的具体路径,这些实体不会被混淆。样例代码片如下:4.4.
14、Property 元素Property元素用来给混淆引擎一些提示, 不同的yGuard版本可能会有不同的提示,混淆任务可以根据这些提示来控制混淆的过程。它有两个强制的属性: Name 混淆任务能够理解的一个特定键。 Value 键对应的值。Yguard 1.5.2.0_03,支持下面的属性: Error-checking属性告诉yguard有任何错误的时候就终止正常任务。当前可用的值为: Pedantic 表示错误发生,混淆任务将失败。 Naming-scheme属性告诉yguard在混淆过程中用到的命名模式,这个属性只能取下列值之一: Small 产生尽可能短的名字,这能使产生的结果jar包
15、尽可能的小。 Best 产生的名字在反编译后看起来可能象是被过去分词化,使用该模式产生的jar包不一定能在所有的文件系统下能够被成功的解压,而且使用该模式也会占用很多的空间使得结果jar很可能变的很大(通常是两倍左右大小)。 Mix 混合了前面两种模式,它产生的jar包有一个比较合理的大小,也很难反编译。 Language-conformity 属性告诉yguard产生大多数反编译器能够被反编译的名字,换而言之,yguard产生的class文件能够被今天多数虚拟机验证和执行;但是在反编译时会产生一些完全没用的垃圾语句来混淆。该属性当前可能的取值: Compatible 产生的名字(包括java
16、、jar、manifest文件),大多数编译器都能理解,大多数文件系统能解压。 Legal 产生的名字一部分反编译器可以理解。 Illegal 产生的名字可能虚拟机工作正常,但是可能使一些工具(如jbuilder)崩溃。 Obfuscation-prefix 用指定的包名称混淆现在的包名称。 Expose-attributes 指明除标准属性之外的应该被暴露在外的属性列表,缺省情况下,yguard会从方法中删除不需要的属性,如:deprecated。这个值可能是一个逗号分割的列表,该列表在Section 4.7 of the VM Specification of the .class Fil
17、e Format中定义。 保持“deprecated”的代名片如下:4.5. Expose元素Expose是obfuscate的子元素,它用来规定classes、methods、fields、attributes这些元素是否应该被暴露。Obfuscator 任务可能会删除很多class文件不需要的信息,这些零散的信息可能不应该被反编译。有一些boolean值形式的属性来控制它们是否可以暴露,也就是不被混淆或删除。这些设置将影响所有的class文件,控制这些属性的最好办法是在classes元素中使用attribute元素。 sourcefile 原始源文件的名称信息是否应该包含在被混淆的类中,缺
18、省值为false,表示信息将被删除,如果取值为true,表示原始源文件的名称信息将保留,反编译后一般在文件头以注释的方式在头注释的最后一行出现。 Linenumbertable在混淆后的类文件中是否保存原始类文件的每个操作字节码对应的原始源文件行号信息的相关信息。缺省值为false,表示不保存。 localvariabletable 决定是否保留本地变量表,这个表包含了每一个在在原始源代码中使用的本地变量名称和混淆后的类中变量名称的映射关系。缺省值为false,表示将删除该信息。 Localvariabletypetable 是否保留本地变量类型表,这个表包含了在原始源代码中使用的本地变量的类
19、型与混淆后的类中变量的映射关系。缺省值为false,不保存,也就是说,混淆过程中将删除该信息。 4.6. Class 元素Class元素用来设定如何暴露类的相关信息,这些信息包括类的名称、方法的名称、属性的名称。下面的两个属性来决定特定的类混淆级别。 Methods属性决定可见性在什么级别的方法可以被暴露。 Fields属性决定可见性在何种级别的属性字段可以被暴露。下表列出了属性可能的取值,以及对应于该值,类的哪些元素将被暴露。*表示给定可见性的元素会被暴露,-表示相应的元素将被混淆。Value/Visibilitypublicprotectedfriendlyprivatenone-publ
20、ic*-protected*-friendly*-private*我们可以看到none表示所有的元素都会被混淆。指定类的混淆有3中方式:1 使用完全限定的java类名指定特定的类。如: 2使用patternset元素设定多个java类,patternset的include和exclude元素必须符合java语法,允许使用通配符。如: 上边的代码表示将暴露除com.mycompany.secretpackage包中类和com.mycompany.myapp.SecretBean类之外包com.mycompany及其子包中所有的类。 这段代码片表示将暴露MainClass类,org.w3c.sax1, org.w3c.sax2, org.w3c.saxb这种命名形式的包中出内部类之外的所有类。注:$符号是java中外部类和内部类的分隔符,在ant中$是一个特殊字符,如果我们想把$