自定义类加载器

为什么要自定义类加载器?

 

  1. 加密:.class文件可以轻易的被反编译,如果你需要把自己的代码进行加密以防止反编译,可以先将编译后的代码用某种加密算法加密,类加密后就不能再用Java的ClassLoader去加载类了,这时就需要自定义ClassLoader在加载类的时候先解密类,然后再加载
  2. 从非标准的来源加载代码:如果你的.class文件是放在数据库、甚至是在云端,就可以自定义类加载器,从指定的来源加载类。

以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理。这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出在Java虚拟机中运行的类

如何自定义类加载器?

①如果你看系统进行类加载的源码,调用loadClass时会先根据双亲委派模型在父加载器中加载,如果加载失败,则会调用当前加载器的findClass来完成加载。

②因此我们自定义的类加载器只需要继承ClassLoader,并覆盖findClass方法

③其中defineClass方法可以把二进制流字节组成的文件转换为一个java.lang.Class(只要二进制字节流的内容符合Class文件规范)。

例如:我们用自定义的类加载器去加载加密后的class文件

 

DES,即Data Encryption Standard的缩写,即数据加密算法。 3DES也叫 Triple DES,它是DES加密算法的一种模式,使用3条56位的密钥对数据进行三次加密。简单来说,由于计算机的运算能力的增强,原版DES密码的密钥容易被暴力破解,3DES即是用来提供一种相对简单的方法,通过增加DES的密钥长度来避免类似的破解。

/**

 * 使用3DES 算法对目标数据执行加解密

 * 

 * @author ljheee

 */

public class Use3DES {

private static final String ALGORITHM = "DESede";// 定义加密算法

/**

* @param key 192位的加密Key

* @param src 明文数据

* @return

*/

public static byte[] encrypt(byte[] key, byte[] src) {

byte[] value = null;

SecretKey deskey = new SecretKeySpec(key, ALGORITHM);

try {

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.ENCRYPT_MODE, deskey);

value = cipher.doFinal(src);

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (NoSuchPaddingException e) {

e.printStackTrace();

} catch (InvalidKeyException e) {

e.printStackTrace();

} catch (IllegalBlockSizeException e) {

e.printStackTrace();

} catch (BadPaddingException e) {

e.printStackTrace();

}

return value;

}

/**

* 解密

* @param key 192位的加密Key

* @param src 待解密数据

* @return

*/

public static byte[] decrypt(byte[] key, byte[] src) {

byte[] value = null;

SecretKey deskey = new SecretKeySpec(key, ALGORITHM);

try {

Cipher cipher = Cipher.getInstance(ALGORITHM);

cipher.init(Cipher.DECRYPT_MODE, deskey);

value = cipher.doFinal(src);

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (NoSuchPaddingException e) {

e.printStackTrace();

} catch (InvalidKeyException e) {

e.printStackTrace();

} catch (IllegalBlockSizeException e) {

e.printStackTrace();

} catch (BadPaddingException e) {

e.printStackTrace();

}

return value;

}

// 测试

public static void main(String[] args) {

byte[] key = "01234567899876543210abcd".getBytes();

 

byte[] encoded = encrypt(key, "554278".getBytes());

System.out.println("加密后" + encoded);

System.out.println("解密后" + new String(decrypt(key, encoded)));

}

}

 

 

 

public class MyClassLoader extends ClassLoader {

// 目标字节码路径

private String byteCode_Path;

// 密钥

private byte[] key;

public MyClassLoader(String byteCode_Path, byte[] key) {

this.byteCode_Path = byteCode_Path;

this.key = key;

}

protected Class findClass(String name) throws ClassNotFoundException {

BufferedInputStream bis = null;

byte bys[] = null;

try {

bis = new BufferedInputStream(new FileInputStream(byteCode_Path + name + ".class"));

bys = new byte[bis.available()];

bis.read(bys);

} catch (Exception e1) {

e1.printStackTrace();

} finally {

try {

bis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

bys=Use3DES.decrypt(key, bys);

// defineClass方法可以将byte数组转化为一个类的Class对象实例

return this.defineClass(bys, 0, bys.length);

}

public static void main(String[] args) throws Exception {

// 对原来的字节码进行加密处理

BufferedInputStream bis = null;

BufferedOutputStream bos = null;

byte[] bys = null;

byte[] key=null;

try {

bis = new BufferedInputStream(new FileInputStream("D:/People.class"));

bys = new byte[bis.available()];

// 把原字节码文件读到bys字节数组

bis.read(bys);

//设置24位密钥数组

key = "01234567899876543210abcd".getBytes();

// 将字节码加密后写到"D:/encrypt"目录下

bos = new BufferedOutputStream(new FileOutputStream("D:/encrypt/People.class"));

bos.write(Use3DES.encrypt(key, bys));

} catch (Exception e) {

e.printStackTrace();

} finally {

bis.close();

bos.close();

}

//如何用自定义的加载器加载加密后的字节码文件(目标字节码)

MyClassLoader mcl = new MyClassLoader("D:/encrypt",key);

System.out.println("加载目标类的类加载器:" + mcl.getClass().getName());

System.out.println("自定义类加载器的父类加载器:" + mcl.getParent().getClass().getName());

}

}

输出结果:

加载目标类的类加载器:cn.jikun.action.MyClassLoader

自定义类加载器的父类加载器:sun.misc.Launcher$AppClassLoader

自定义类加载器_第1张图片

你可能感兴趣的:(jvm)