自定义类加载器的编写,实现对加密class文件进行加载的过程

GitHub

我们都知道类加载器是采用双亲委派模型工作的,我们来自定义一个类加载器,来实现一个小的案例(Class文件的解密加载过程) 来深化对ClassLoader加载机制的理解

首先我们要编写一个解码(解密)类加载器(DecodeClassLoader) 实现对指定Class的加载

首先我们先了解下classloader的基础知识:

1.自定义类加载器必须继承ClassLoader。

2.了解ClassLoader中的loadClass方法 , findClass方法 , 以及defineClass方法。

然后我们查看源码

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

因为自定义ClassLoader继承自ClassLoader类,所以继承了ClassLoader的loadClass方法,该方法调用过程是这样的:

1.首先查找该加载器是否已经加载过这个类,如果加载过直接返回。

2.然后判断是否有父类加载器 如果有则父加载器对类进行加载,或者调用bootstrap加载器对类进行加载

3.如果父加载器及bootstrap加载器都没找到指定的类,那么调用当前类加载器的findClass方法来完成对类的加载

接下来我们来完成自定义类加载器的实现,首先我们定义需要被加密二进制文件的源文件类

/**
 * Created with IntelliJ IDEA.
 * Description: 被加密class文件的源文件
 * User: zhubo
 * Date: 2018-03-24
 * Time: 10:10
 */
public class ClassLoaderAttachment {

    public void say(){
        System.out.println("ClassLoaderAttachment Say Hello !");
    }

}

然后定义加解密工具类,完成加密文件的生成:

/**
 * Created with IntelliJ IDEA.
 * Description: 加解密工具类 及 生成加密文件
 * User: zhubo
 * Date: 2018-03-24
 * Time: 10:25
 */
public class GenerateEncryp {

    public static void cypher(InputStream ips , OutputStream ops) throws IOException {
        int b = -1;
        while((b = ips.read()) != -1){
            ops.write(b ^ 0xff);
        }
    }
    public static void uncypher(InputStream ips , OutputStream ops) throws IOException {
        int b = -1;
        while((b = ips.read()) != -1){
            ops.write(b&0xff );
        }
    }

    /**
     * 现在要调用加密的类,对某个class文件进行加密.
     * 那么要传递一个要加密文件及路径,和要保存加密文件的路径
     * @param args
     */
    public static void main(String[] args) throws IOException{

        // 源文件路径
        String srcPath = "D:\\workspace\\quartz_dir\\algorithm\\target\\classes\\com\\jvm\\classloader\\ClassLoaderAttachment.class";
        // 目标文件的目录
        String descDir = "D:\\workspace";
        // 目标文件名称
        String descFileName = srcPath.substring(srcPath.lastIndexOf("\\"));
        String descPath = descDir + descFileName;
        FileInputStream fis = new FileInputStream(srcPath);
        FileOutputStream fos = new FileOutputStream(descPath);
        cypher(fis,fos);
        fis.close();
        fos.close();

    }

}

我们执行main函数 会在D://workspace 下生成ClassLoaderAttachment.class 文件的加密文件,接下来我们要完成对加密文件的加载工作。

首先我们自定义类加载器DecodeClassLoader 继承ClassLoader: 其中我们沿用父类的loadClass方法,同样采用双亲委派模型来加载类。但是需要覆盖findClass方法,在findClass方法中实现对类的加载过程:

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: zhubo
 * Date: 2018-03-24
 * Time: 9:40
 */
public class DecodeClassLoader extends ClassLoader {

    private String pathDir;

    public DecodeClassLoader(String pathDir) {
        this.pathDir = pathDir;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String classFileName = pathDir + "\\" + name.substring(0,name.lastIndexOf(".")) + ".class";
        System.out.println(classFileName);
        try{
            FileInputStream fis = new FileInputStream(classFileName);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            GenerateEncryp.cypher(fis,bos);
            //GenerateEncryp.uncypher(fis,bos);
            fis.close();
            byte[] bytes = bos.toByteArray();
            return defineClass(null,bytes,0,bytes.length);
        }catch (Exception e){
            e.printStackTrace();
        }
        return super.findClass(name);
    }
}

然后我们对经过加密的.class文件进行类的加载过程:

/**
 * Created with IntelliJ IDEA.
 * Description: 编解码调度类
 * User: zhubo
 * Date: 2018-03-24
 * Time: 10:17
 */
public class ClassLoaderTest {

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

        DecodeClassLoader dcl = new DecodeClassLoader("D:\\workspace");
        Class<?> aClass = dcl.loadClass("ClassLoaderAttachment.class");
        Object o = aClass.newInstance();
        System.out.println(o.getClass().getName());
        System.out.println(o.getClass().getClassLoader());
        aClass.getMethod("say",null).invoke(o,null);

    }

}

输出:

D:\workspace\ClassLoaderAttachment.class
com.jvm.classloader.ClassLoaderAttachment
com.jvm.classloader.DecodeClassLoader@6d6f6e28
ClassLoaderAttachment Say Hello !

 

 

 

 

 

转载于:https://my.oschina.net/LucasZhu/blog/1667660

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值