自定义类加载器+加密+解密 的这个程序需要的实验步骤如下,所用的类如下:
ClassLoaderTest 类:用来做“解密实验”的类,将Test类的加密后的.class文件加载内存,并解密后,用ClassLoader.defineClass()得到Class对象,利用反射使用Test类
MyClassLoader 类:定义自己的类加载器,重写其中的findClass方法,在该方法中定义查找.class文件的默认目录,并调用EncodeDecodeClass类的解密方法,解密Test.class,然后调用父类的defineClass方法,得到Class对象。
EncodeDecodeClass 类:定义了加密和解密方法
Test 类:定义了一个普通类,这个类的正确的.class会被加密和解密
UseTest 类:用来做“加密实验”测试的类,里面使用了加密后的Test.class
1、“加密实验”
1.0 设置好classpath的值
1.1 先用javac正常编译Test.java(用带存储路径的方式编译带包名的类,以用来正确的到包的文件夹形式,并将类存放到正确位置),得到正确的.class文件
1.2 先调用EncodeDecodeClass.encode()方法,对已经存在的正确的Test.class文件加密,得到Test_1.class
1.3 用javac 正常编译UseTest.java,得到编译后的UseTest.class (这里也可以看到这个UsetTest.class文件中只包含了UseTest类的信息,并不包含它所用到的
类Test.class的信息,即一个.class中只包含其对应的类的本类信息,不包含这个类的定义中用到的其他类的定义信息,编译器只是在编译出本类的.class文件的时候
通过用反射加载类进内存,检查被使用类身上是否有某个方法的这个方式来检查本类的源程序.java,是否是正确的,即本类是否被正确定义了,只是检查,为的是
保证运行的时候,可以正确的运行,运行的时候JVM会利用类加载器来动态加载类中使用的其他类的.class文件信息,来完成程序的运行)
1.4 将Test_1.class 改名为Test.class,将原来的那个正确的Test.class删除掉
1.5 用 java 运行UsetTest.class类,报告出异常
实验完毕,报告出异常说明了加密实验成功!!
2、“解密实验”
1.0 设置好classpath的值
1.1 先用javac编译ClassLoaderTest.java,得到ClassLoaderTest.class
1.2 再用java 运行ClassLoaderTest.class
1.3 成功调用,打印出结果:
实验完毕,打印以上信息,说明解密实验成功!!
【实际项目中,将开发好的框架(或者类)的.class文件统一进行加密,然后交给客户使用,客户如果直接拿来使用,则会出错,.class里面的数据是错误的数据,无法解析。
如果客户付费后,则可以用一个验证码的方式激活自定义的类加载器中的解密方法(if 语句判断一下用户是否获得了验证码,没有则不调用解密方法),正确加载框架中的类
,并解析他们,完成正确的使用。】
ClassLoaderTest.java
package com.heima; import java.io.File; import java.lang.reflect.Method; /*自定义类加载器,对.class文件进行加载,同时编写对.class文件进行加密和解密的程序*/ /* * * "Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 889275713 in class file com/heima/Test" ---->这个异常指的是程序中使用的已经存在的类文件(即.class文件)是有问题的。 比如,将.class文件加密后,再在主类.class中使用这个.class文件,在类加载器ClassLoader将类从.class文件中加载到内存的对类的处理过程中, 就会抛出这个异常。 incompatible :不兼容的 ,矛盾的 magic :不可思议的 ,有魔力的 * */ public class ClassLoaderTest { public static void main(String[] args) { System.out.println("ok"); try { Class clazz = new MyClassLoader().loadClass("com.heima.Test"); Method method = clazz.getMethod("print"); method.invoke(clazz.newInstance()); System.out.println("解密调用成功!"); } catch (Exception e) { e.printStackTrace(); } } }
MyClassLoader
package com.heima; import java.io.File; public class MyClassLoader extends ClassLoader { private String path ="F:\\myclass\\"; @Override protected Class findClass(String name) throws ClassNotFoundException { String tempName = name.replaceAll("\\.","\\\\"); //将类的完全限定名称中的包名之间的.转换为 File file = new File(path,tempName+".class"); //拼接出正确的类名,得到正确的抽象路径名 byte[] buf = null; System.out.println("***************** "+name+" "+file.exists()); //测试信息 System.out.println(file.toString()); if(file.exists()) { try { buf = EncodeDecodeClass.decode(file); //解密指定的文件,得到字节码数组 } catch (Exception e) { System.out.println("类文件解密出错!"); } } Class retVal = defineClass(name, buf, 0, buf.length); //得到Class对象 return retVal; //返回Class类对象 } }
EncodeDecodeClass
package com.heima; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; public class EncodeDecodeClass { public static void encode(File file)throws Exception { FileInputStream fis = new FileInputStream(file); String name = file.getName(); file.getPath(); String[] strs = name.split("\\."); System.out.println(file.toString()+" :: "+name+" :: "+strs.length); name = strs[0]+"_1."+strs[1]; file.renameTo(new File(file.getParent(),file.getName()+"_1")); File desFile = new File(file.getParent(),name); FileOutputStream fos = new FileOutputStream(desFile); byte[] buf = new byte[1024]; int len = 0; while( (len = fis.read(buf))!=-1) { for(int i=0; i<len ;i++) { buf[i] = (byte)(buf[i]^0xff);//取反加密 } fos.write(buf,0,len); } fis.close(); fos.close(); } public static byte[] decode(File file) throws Exception { FileInputStream fis = new FileInputStream(file); ByteArrayOutputStream dest = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int len = 0; while((len = fis.read(buf))!=-1) { for(int i=0; i<len ;i++) { buf[i] = (byte)(buf[i]^0xff); //取反解密 } dest.write(buf, 0, len); } fis.close(); System.out.println("ok"); return dest.toByteArray(); } public static void main(String[] args) { File file = new File("f:\\myclass\\com\\heima\\Test.class"); if(file.exists()) { try { EncodeDecodeClass.encode(file); System.out.println("加密成功!"); } catch (Exception e) { e.printStackTrace(); } } } }
Test.java
package com.heima; public class Test { public void print() { System.out.println("自定义类加载器要加载类的代码,我在被要先被加密,刚刚才解密"); } public static void main(String[] args) { System.out.println(0xff); } }
UseTest.java
package com.heima; public class UseTest { /** * @param args */ public static void main(String[] args) { Test t = new Test(); t.print(); } }