版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40646143/article/details/84997331
创建自定义加载器的类
package com.tuogo.classlocad;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 自定义类加载器
*/
public class EncryptionClass extends ClassLoader {
private String srcFile;
public EncryptionClass(String srcFile) {
this.srcFile = srcFile;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> loadedClass = findLoadedClass(name);
if (null != loadedClass) {
return loadedClass;
} else {
//采用双亲委托机制 这里使用异常如果出错则继续向下执行
try {
loadedClass = this.getParent().loadClass(name);
} catch (Exception e) {
}
if (loadedClass != null) {
return loadedClass;
} else {
byte[] bytes = getClassDate(name);
if (bytes == null) {
throw new ClassNotFoundException();
}
loadedClass = defineClass(name, bytes, 0, bytes.length);
}
}
return loadedClass;
}
private byte[] getClassDate(String name) {
//获取class的全路径
String file = srcFile + "/" + name.replace(".", "/") + ".class";
ByteArrayOutputStream outputStream = null;
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
outputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int tmp = 0;
while ((tmp = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, tmp);
}
return outputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在测试类加载器之前 我的本地已经创建好了class文件
使用文件创建一个.java的后缀文件 ,然后利用cmd编把.java文件编译成.class文件,接下来在进行测试
测试类加载器
package com.tuogo.classlocad;
/**
*测试类加载器
* 同一类加载加载同一class文件 hashcode会相同 如hello1 hello2
* 同一个类 由不同的类加载器加载 hashcoode不相同 如hello1 hello3
*/
public class EncryptionDemo {
public static void main (String[] args) {
EncryptionClass encryptionClass1 = new EncryptionClass("E:/java");
EncryptionClass encryptionClass2= new EncryptionClass("E:/java");
try {
Class<?> hello1 = encryptionClass1.loadClass("Hello");
Class<?> hello2 = encryptionClass1.loadClass("Hello");
Class<?> hello3 = encryptionClass2.loadClass("Hello");
System.out.println(hello1.hashCode());
System.out.println(hello2.hashCode());
System.out.println(hello3.hashCode());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
效果如下
类的加密与解密方式
加密class类的类
package com.tuogo.classlocad;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 这个类实现了类的加密
*/
public class Encryption {
public static void main (String[] args) {
try {
encrypt("E:/java/Hello.class","E:/java/tmp/Hello.class");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void encrypt(String src, String dest) throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(src);
fos = new FileOutputStream(dest);
int tmp = -1;
while ((tmp = fis.read()) != -1) {
//^0xff 取反操作
fos.write(tmp^0xff);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
}
}
}
执行成功在本地的tmp包下创建一个加密后的.class文件,如下
如果直接使用类加载其进行加载,则会出现以下异常
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 889275713 in class file Hello
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at com.tuogo.classlocad.EncryptionClass.loadClass(EncryptionClass.java:37)
at com.tuogo.classlocad.EncryptionDemo.main(EncryptionDemo.java:14)
接下来我们对class类进行解密这样才能最正确的获取class类的二进制数据
改动如下
package com.tuogo.classlocad;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 自定义类加载器
*/
public class EncryptionClass extends ClassLoader {
private String srcFile;
public EncryptionClass(String srcFile) {
this.srcFile = srcFile;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> loadedClass = findLoadedClass(name);
if (null != loadedClass) {
return loadedClass;
} else {
//采用双亲委托机制 这里使用异常如果出错则继续向下执行
try {
loadedClass = this.getParent().loadClass(name);
} catch (Exception e) {
}
if (loadedClass != null) {
return loadedClass;
} else {
byte[] bytes = getClassDate(name);
if (bytes == null) {
throw new ClassNotFoundException();
}
loadedClass = defineClass(name, bytes, 0, bytes.length);
}
}
return loadedClass;
}
private byte[] getClassDate(String name) {
//获取class的全路径
String file = srcFile + "/" + name.replace(".", "/") + ".class";
ByteArrayOutputStream outputStream = null;
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
outputStream = new ByteArrayOutputStream();
int tmp = -1;
while ((tmp = inputStream.read()) != -1) {
//^0xff 取反操作
outputStream.write(tmp^0xff);
}
return outputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
测试解密
package com.tuogo.classlocad;
/**
*测试类加载器 解密
*/
public class EncryptionDemo {
public static void main (String[] args) {
EncryptionClass encryptionClass1 = new EncryptionClass("E:/java/tmp");
try {
//加载 加密后的class文件会出现 java.lang.ClassFormatError: Incompatible magic value 889275713 in class file Hello错误信息
Class<?> hello1 = encryptionClass1.loadClass("Hello");
System.out.println(hello1.hashCode());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果
总结 : 类的加密与解密 需要统一方式 不能加密使用一种方式解密使用另一种方式
加密与解密用的是^0xff 取反
比如 int 3; 按一个字节来算的话是 00000011 (3的二进制表示形式)
0 0 0 0 0 0 1 1 3 的二进制
1 1 1 1 1 1 1 1 ff取反的意思
----------------
1 1 1 1 1 1 0 0 结果