您的位置:首页 > 其它

编写自己的classloader加载加密过的class

2015-01-28 21:47 253 查看
1 编写一个类,该类继承Date类:

package erica.classloader;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.util.Date;

public class ClassLoaderAttachment extends Date {

@Override

public String toString() {

return "hello erica";

}

}

2 编写一个类,该类可以使得加载的class文件,生成的class文件放在D:\itunes

package erica.classloader;

import java.io.*;

public class MyClassLoader {

public static void cypher(InputStream in,OutputStream out) throws IOException{

int b=-1;

while((b=in.read())!=-1){

out.write(b^0xff);

}

}

}

3 运行生成加密以后的class

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

String srcPath="D:/workspace/WorkSpaceSpring/ReflectTest/bin/erica/classloader/ClassLoaderAttachment.class";

String descPath="D:\\itunes\\ClassLoaderAttachment.class";

FileInputStream fis=new FileInputStream(srcPath);

FileOutputStream fos=new FileOutputStream(descPath);

cypher(fis,fos);

System.out.println("success");

}



4 把生成的class覆盖原始的那个类的class文件,然后用java虚拟机特定的classloader去加载文件会报错。

package erica.classloader;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.util.Date;

public class ClassLoaderAttachment extends Date {

@Override

public String toString() {

return "hello erica";

}

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

ClassLoaderAttachment ca=new ClassLoaderAttachment();

System.out.println(ca);

}

}

报错如图所示:



5 那么就的我们自己的写的类加载器去加载加密的class了.

1:继承ClassLoader类

2:覆盖 protected Class<?>findClass(String name)throws ClassNotFoundException 方法

3:调用defineClass,将一个 byte 数组转换为 Class 类的实例,该实例就是加载一串二进制字节码的Class的对象

public class MyClassLoader extends ClassLoader{

private String dir;

public MyClassLoader(){

}

public MyClassLoader(String dir){

this.dir=dir;

}

@Override

protected Class<?>findClass(String name)throws ClassNotFoundException{

System.out.println("findClass");

String classname=dir+"/"+name+".class";

FileInputStream fis;

try {

fis = new FileInputStream(classname);

ByteArrayOutputStream out=new ByteArrayOutputStream();

cypher(fis,out);

fis.close();

byte[]bytes=out.toByteArray();

return defineClass(null,bytes,0,bytes.length);

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

}

6:用自己的类加载器加载自己的字节码

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

MyClassLoader loader=new MyClassLoader("erica");

Date d=(Date)loader.loadClass("ClassLoaderAttachment").newInstance();

//Date d=(Date)loader.loadClass("erica.classloader.ClassLoaderAttachment").newInstance();//会去加载原始的class,因为指定了包名+类名

System.out.println(d);

}

打印结果:

findClass

hello erica

打印出findClass字符串说明运行了自己的类加载器。

下面是jdk文档的自己编写类加载器的示例:

例如,应用程序可以创建一个网络类加载器,从服务器中下载类文件。示例代码如下所示:

ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();
. . .


网络类加载器子类必须定义方法
findClass

loadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法
defineClass
来创建类实例。示例实现如下:

class NetworkClassLoader extends ClassLoader {
String host;
int port;

public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}

private byte[] loadClassData(String name) {
// load the class data from the connection
. . .
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: