zoukankan      html  css  js  c++  java
  • Java中动态加载字节码的那些方法

    持续补充 ...

    URLCLassLoader

    ClassLoader#loader(URL[])远程加载class

    URLCLassLoader实际上是我们平时默认使用的AppClassLoader的父类,所以,我们解释URLClassLoader的工作过程实际上就是在解释默认的Java类加载器的工作流程。

    java 对路径的处理:

    • URL未以斜杠 / 结尾,则认为是一个JAR文件,使用 JarLoader 来寻找类,即为在Jar包中寻 找.class文件
    • URL以斜杠 / 结尾,且协议名是 file ,则使用 FileLoader 来寻找类,即为在本地文件系统中寻 找.class文件
    • URL以斜杠 / 结尾,且协议名不是 file ,则使用最基础的 Loader 来寻找类

    也就是协议不是file且以 / 结尾,会使用Loader寻找类,最常见的是http协议。可以通过这种方法直接加载远端的class文件,所以如果我们控制了目标Java ClassLoader的基础路径为一个http服务器,即可RCE

    CLassLoader#definClass 直接加载字节码

    无论加载远程class还是本地class或者jar文件,调用过程都是下面三个方法:

    • loadClass 的作用是从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机 制),在前面没有找到的情况下,执行 findClass
    • findClass 的作用是根据基础URL指定的方式来加载类的字节码,就像上一节中说到的,可能会在 本地文件系统、jar包或远程http服务器上读取字节码,然后交给defineClass
    • defineClass 的作用是处理前面传入的字节码,将其处理成真正的Java类
      核心在defineClass,决定了如何将一段字节流转变成一个Java类,Java默认的ClassLoader#defineClass是一个native方法,逻辑在JVM的C语言代码中。
      我们无法直接外部调用这些方法来加载字节码,但是有一些库中包含了部分代码完成了这个过程,我们可以利用这些库达到目的。

    加载方式一: TemplatesImpl

    非常常用的Java反序列化利用链组成部分,poc:

    public static void main(String[] args) throws Exception {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] code = base64Decoder.decodeBuffer("");
        TemplatesImpl obj = new TemplatesImpl();
        Field f1 = obj.getClass().getDeclaredField("__bytecodes");
        f1.setAccessible(true);
        f1.set(obj, new byte[][]{code});
    
        Field f2 = obj.getClass().getDeclaredField("__name");
        f2.setAccessible(true);
        f2.set(obj, "HelloTemplatesImpl");
    
        Field f3 = obj.getClass().getDeclaredField("__tfactory");
        f3.setAccessible(true);
        f3.set(obj, new TransformerFactoryImpl());
    
        obj.newTransformer();
    
    }
    

    注意:
    设置了三个属性: _bytecodes 、 _name 和 _tfactory 。

    • _bytecodes 是由字节码组成的数组;
    • _name 可以是任意字符串,只要不为null即可;
    • _tfactory 需要是一个 TransformerFactoryImpl 对象,因为emplatesImpl#defineTransletClasses()方法里有调用到tfactory.getExternalExtensionsMap(),如果是null会出错。

    另外,TemplatesImpl 中对加载的字节码是有一定要求的:这个字节码对应的类必须是 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet的子类。因此需要构造一个特殊的类。

    加载方式二: BCELClassLoader

    BCEL Classloader去哪了
    在java 8u251前可用。
    使用的是com.sun.org.apache.bcel.internal.util.ClassLoader;

    // 原生字节码转BCEL
    JavaClass cls = Repository.lookupClass(exp.class);
    String code = Utility.encode(cls.getBytes(), true);
    System.out.println(code);
    // 加载
    new ClassLoader().loadClass("exp").newInstance();
    

    待补充...

  • 相关阅读:
    java_类承继其他类的内部类例子
    java_接口和抽象类的区别
    java_数组作缓存池的不可变类实例
    C++_归并排序(纯C版)
    C++_归并排序
    C++_快速排序(纯C版本)
    C++_快速排序
    C++_直接插入排序(纯C版)
    C++_直接插入排序
    自定义比较器的用法
  • 原文地址:https://www.cnblogs.com/chengez/p/ClassLoader.html
Copyright © 2011-2022 走看看