本帖最后由 上海分校-小影 于 2018-6-1 17:14 编辑
类加载器加密class文件
需求介绍:Java本身是开源的技术,那么只要拥有反编译工具和项目的.class文件就可以获取源代码内容。 那么如何在源代码级别增强安全性呢? 答:对.class文件做加密操作,让反编译工具无法反编译.class文件 那么如何开始做这个加密操作呢? 答:修改.class文件底层的字节数据 代码演示: /**
* @throws Exception
* 对Class文件进行加密
*/
@Test
public void test1() throws Exception {
FileInputStream in = new FileInputStream(new File("d:/class/MD5Utils.class"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[2048];
int len = 0;
byte mi = 1;
while ((len = in.read(buf)) != -1) {
for (int i = 0; i < buf.length; i++) {
System.out.println("第一次:" + buf);
buf = (byte) (buf + mi);
System.out.println("第二次:" + buf);
}
out.write(buf, 0, len);
}
byte[] byteArray = out.toByteArray();
FileOutputStream fout = new FileOutputStream(new File("d:/clazz/MD5Utils.class"));
fout.write(byteArray, 0, byteArray.length);
}那么加密完成之后这个文件如何运行呢? 答:使用类加载器,读取加载文件,创建类对象,调用方法
package cn.itcast.loader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class MyClassLoader extends ClassLoader{
@Override
public Class findClass(String name) {
//自定义一个类加载器:加载指定位置的.class文件(d:/class)
String path = "d:/clazz";
try {
FileInputStream in = new FileInputStream(new File(path+"/"+name+".class"));
//根据获取到的数据,创建Class对象
//需要一个将数据转换为字节数组的输出流
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len = 0;
byte[] buf = new byte[1024];
while((len = in.read(buf)) != -1){
out.write(buf, 0, len);
}
byte[] byteArray = out.toByteArray();
for (int i = 0; i < byteArray.length; i++) {
byteArray = (byte) (byteArray - 1);
}
return defineClass(name, byteArray, 0, byteArray.length);
} catch (Exception e) {
e.printStackTrace();
try {
return super.findClass(name);
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
return null;
}
}
}
}在加密的转换过程中byte数据底层加减可能出现超出数据范围的情况(例如:127+1),但是,我们的转换过程中,没有出现任何问题,这是为什么呢? 接下来我们一点点来分析下:
/**
* 问题:加密 加多少,解密,减多少——————》加密前是多少,加密后,数字也是多少?目前的效果,也是对的
*
* 问题:加法运算可能超出byte类型数据的范围,会导致加密解密失败,但是这里为什么没有失败?
* 同学们的思路:
*
* -127 1111 1111
* + 1 0000 0001
* ---------------------
* 10000 0000
* 最高丢弃 0000 0000 ————》 0
*
* 0 0000 0000
* - 1 0000 0001
* ------------------
* -1 1000 0001
*
* 问题:数据经过加减之后,尽然可以,保持原样,那么计算底层到底是怎么计算的?
*
* 1 计算底层,所有都是加法运算
*
* 1 0000 0001
* - 1 0000 0001
* ----------------
* 所有减法都是加法
*
* 1 0000 0001
* + -1 1000 0001
* -----------------
* -2 1000 0010
* 错误的结果————按照普通人类的思路
*
* 按照机器思路做减法:
*
* 1 0000 0001
* + -1 1000 0001
* -----------------
* 获取当前数据(-1)的反码:0 ————》1 1————》0,最高位不动
*
* 1 0000 0001
* + -1 1111 1110
* -----------------
* 1111 1111
* 在反码计算结果的基础上加一(补码):
* 1111 1111
* + 1 0000 0001
* ----------------
* 10000 0000
* byte数据最高位去掉:
* 0000 0000 ——————》 0
*
* 按照机器思路进行加密和解密
* -127 1111 1111
* + 1 0000 0001
* ---------------------
* 10000 0000
* byte数据最高位去掉:
* 0000 0000 ——————》 0
* 以上是加密
*
* 以下解密:
* 0000 0000
* + 1000 0001
* ----------------
*
* 反码:
* 0000 0000
* + 1111 1110
* ----------------
* 1111 1110
*
* 补码:
* 1111 1110
* + 0000 0001
* -------------------
* 1111 1111
*
* 总结:加密和解密不会导致,数据前后不一致,是因为,二进制减法计算的是使用了反码和补码的方式。
* */
通过以上分析,我们发现其实在计算的过程中,计算机使用的是二进制的补码和反码进行运算,因此,没有数据超出范围的问题。
|