利用ClassLoader#defineClass动态加载字节码

利用ClassLoader#defineClass直接加载字节码

不管是加载远程class文件,还是本地的class或jar文件,Java都经历的是下面这三个方法调用

  • loadClass 的作用是从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机制),在前面没有找到的情况下,执行findClass

  • findClass 的作用是根据基础URL指定的方式来加载类的字节码,就像上一节中说到的,可能会在本地文件系统、jar包或远程http服务器上读取字节码,然后交给defineClass

  • defineClass 的作用是处理前面传入的字节码,将其处理成真正的Java类

protected final Class<?> defineClass(String name, byte[] b, int off, int len)

// name 为类名 (可设置为 null)

// b 为字节码数组

// off 为数组的偏移值 (从第几位开始为字节码数据)

// len 为数组的长度
  • 所以可见,真正核心的部分其实是defineClass ,他决定了如何将一段字节流转变成一个Java类,Java默认的ClassLoader#defineClass 是一个native方法,逻辑在JVM的C语言代码中。

  • 注意一点,在defineClass 被调用的时候,类对象是不会被初始化的,只有这个对象显式地调用其构造函数,初始化代码才能被执行。而且,即使我们将初始化代码放在类的static块中,在defineClass 时也无法被直接调用到。所以,如果我们要使用defineClass 在目标机器上执行任意代码,需要想办法调用构造函数。

  • 如下示例,因为系统的ClassLoader#defineClass 是一个保护属性,所以我们无法直接在外部访问,不得不使用反射的形式来调用。在实际场景中,因为defineClass方法作用域是不开放的,所以攻击者很少能直接利用到它,但它却是我们常用的一个攻击链TemplatesImpl 的基石。

获取 ClassLoader, 以下是常用几种获取 ClassLoader 的方式

ClassLoader loader = Thread.currentThread().getContextClassLoader();

ClassLoader loader = ClassLoader.getSystemClassLoader();

ClassLoader loader = this.getClass().getClassLoader();

举例:

public class HelloDefineClass {

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

        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);        // 注意 getDeclaredMethod 只能获取当前类的所有方法, 而 defineClass 其实是在 AppClassLoader 的父类 java.lang.ClassLoader 里面, 所以需要通过 ClassLoader.class 来获取 Class 对象

        defineClass.setAccessible(true);

        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAGwoABgANCQAOAA8IABAKABEAEgcAEwcAFAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApTb3VyY2VGaWxlAQAKSGVsbG8uamF2YQwABwAIBwAVDAAWABcBAAtIZWxsbyBXb3JsZAcAGAwAGQAaAQAFSGVsbG8BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAABAAEABwAIAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoAAAAOAAMAAAACAAQABAAMAAUAAQALAAAAAgAM");

        Class hello = (Class)defineClass.invoke(ClassLoader.getSystemClassLoader(), "Hello", code, 0, code.length);

        hello.newInstance();

    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thunderclap_

点赞、关注加收藏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值