Hello,大家好, 我是Shendi,这次给大家带来一系列密码学教程,这次给大家带来了加密Class文件并实现运行加密的Class
同系列博文:
先说思路,通过第二节我们学会了加密数据(文件),所以我们可以很容易的加密class文件,但是加密后如何运行呢?
我们可以通过字节流将加密后的class加载进内存
Java提供了ClassLoader 类加载器,所有类都是通过这个来加载的
通过第一节,我们知道了ClassLoader中有一个defineClass函数 可以将data数组转为一个类,
但是要使用这个函数我们就需要自己定义ClassLoader
获取到类后,我们就可以通过反射来调用此类的函数和字段了
(因为是反射调用,所以性能方面会慢一点,并且代码方面不再是平常的导入了,而全都是通过反射调用)
举个例子,有三个Class,Start,Hello,World
Start类为启动类,所以我们不能加密此类,我们只能加密Hello和World类
在Start类中,我们需要将这两个加密类加载进内存,用流的方式,在通过类加载器加载这两个类,我们就可以调用这两个类的函数
但是如果我们想在Hello类的函数中调用World的函数,则又需要重复此操作---将World类的加密形式加载成byte[]然后通过...
下面我们就来实现 Start类 Hello类 World类
(我们通过Start类调用Hello的hello函数,hello函数调用World的world函数)
首先我们先编写两个加密类,从World类开始 World类只有world函数 输出world字符串 很简单
/**
* @author Shendi
* <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
*/
public class World {
public void world() {
System.out.println(" world");
}
}
然后我们将World编译,并加密此Class(加密方法看第二节)
接下来我们编写Hello类,我们的Hello类有hello函数,并且函数内要调用World类的world函数
所以需要解密 要将解密后的数据加载成类,所以需要继承ClassLoader
/**
* @author Shendi
* <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
*/
public class Hello extends ClassLoader {
public void hello() throws Exception {
System.out.println("hello");
//我们需要调用World类 所以我们需要知道World.class的位置
//我用的dos编译 所以文件会在此类的同目录(这里为了方便 异常全都抛出了)
InputStream input = new FileInputStream("World.class");
//存储World.class的二进制形式(加密后的)
byte[] data = new byte[input.available()];
//读取
while (input.read(data) != -1);
input.close();
//解密数据(注:World.class是已经加密的)
decodeAddI(data);
//解密后我们将byte[]加载成类 这里的第一个参数为null 因为我们不知道这个类的全名
Class<?> World = defineClass(null, data,0,data.length);
//我们要调用World类的world函数 所以我们需要获取这个类的实例
Object world = World.newInstance();
//获取此方法
Method method = World.getMethod("world");
method.invoke(world);
}
/**
* -解密算法 加i算法 将所有字节减i 可和加密算法互换用
* @param encrypt 传递此参数 将此参数解密
*/
public void decodeAddI(byte[] encrypt) {
encrypt[0] -= 1;
for (int i = 1;i < encrypt.length;i++) {
encrypt[i] = (byte) (encrypt[i] - i);
}
}
}
我们的Start类是启动类,所以有main函数,并且需要解密文件,那么就需要有一个解密的函数(就用上节的字节+i法)
而且需要将class加载成流,所以要用到InputStream,并且需要将流加载成类,要继承ClassLoader,所以代码如下(详细看注释)
/**
* @author Shendi
* <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
*/
public class Start extends ClassLoader {
public Start() throws Exception {
//我们需要调用Hello类 不需要调用World类 所以我们需要知道Hello.class的位置
//我用的dos编译 所以文件会在此类的同目录(这里为了方便 异常全都抛出了)
InputStream input = new FileInputStream("Hello.class");
//存储Hello.class的二进制形式(加密后的)
byte[] data = new byte[input.available()];
//读取
while (input.read(data) != -1);
input.close();
//解密数据(注:Hello.class是已经加密的)
decodeAddI(data);
//解密后我们将byte[]加载成类 这里的第一个参数为null 因为我们不知道这个类的全名
Class<?> Hello = defineClass(null, data,0,data.length);
//我们要调用Hello类的hello函数 所以我们需要获取这个类的实例
Object hello = Hello.newInstance();
//获取此方法
Method method = Hello.getMethod("hello");
method.invoke(hello);
}
public static void main(String[] args) throws Exception {
new Start();
}
/**
* -解密算法 加i算法 将所有字节减i 可和加密算法互换用
* @param encrypt 传递此参数 将此参数解密
*/
public void decodeAddI(byte[] encrypt) {
encrypt[0] -= 1;
for (int i = 1;i < encrypt.length;i++) {
encrypt[i] = (byte) (encrypt[i] - i);
}
}
}
最后,测试运行结果,我们将三个文件都编译,放一个文件夹内,并且将Hello,World类加密
然后我们运行Start类,结果如下
加密完成!
如果对您有用的话,点个赞再走吧~
关注我,获取更多