博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自定义类加载器的编写,实现对加密class文件进行加载的过程
阅读量:6161 次
发布时间:2019-06-21

本文共 5537 字,大约阅读时间需要 18 分钟。

hot3.png

我们都知道类加载器是采用双亲委派模型工作的,我们来自定义一个类加载器,来实现一个小的案例(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.classcom.jvm.classloader.ClassLoaderAttachmentcom.jvm.classloader.DecodeClassLoader@6d6f6e28ClassLoaderAttachment Say Hello !

 

 

 

 

 

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

你可能感兴趣的文章
文本查看指令
查看>>
我的友情链接
查看>>
android开源项目框架大全:《IT蓝豹》
查看>>
Linux/U-Boot Git Repo
查看>>
python了解
查看>>
在写HTML和CSS时的黄金规范
查看>>
【php】用filter_var实现的简单参数验证
查看>>
Win7开发系列: Win7 UAC帮助类
查看>>
.NET Remoting开发系列:(三) Remoting服务发布方式
查看>>
100道JS构造函数面试题
查看>>
redis安装
查看>>
JQuery的定义
查看>>
linux初始化root密码
查看>>
Java 中正确获取中文字符串长度
查看>>
C# 遇到 which has a higher version than referenced assembly
查看>>
leetCode刷题(使用链表做加法)
查看>>
Python之路--------->Python介绍
查看>>
限制网速 制造测试条件
查看>>
Strtus2工作流程及原理
查看>>
字符串
查看>>