keac's Bolg.

Java ClassLoader

字数统计: 696阅读时长: 2 min
2022/05/23 Share

前言

Java依赖于JVM(Java虚拟机),在运行前需要编译为class二进制文件,程序运行的时候不会一口气全部加载class到内存,而是通过java的类加载机制来进行动态加载。

ClassLoader类

再JVM类加载器中,最顶层的是Bootstrap ClassLoader(引导加载器)、Extension ClassLoader(拓展类加载器)、App ClassLoader(系统类加载器)。

ClassLoader是一个抽象类,主要功能就是通过指定的类名称找到或生成对应的字节码返回一个java.lang.Class类的实例。开发者就可以通过继承ClassLoader类来实现自定义加载器。

1
2
3
4
5
6
getParent() //返回这个加载器的父加载器
loadClass() //加载指定名称的类
findClass() //查找指定名词的类
findLoadedClass() //查找已经被加载过的类
defineClass(String name,byte[] b,int off,int len) // 把字节数组b转换为Java类 方法被声明为final
resolveClass() // 链接指定的Java类

loadClass 方法

方法被调用时会首先使用findLoadedClass方法判断类是否已经加载,如果没有被加载优先使用父加载器进行加载,如果不存在父加载器会调用自身的findClass方法,所以我们可以通过重写来完成一些类加载的特殊要求。

利用defineClass方法可以把字节转换为java.lang.class类对象,就可以实现自定义的加载器。

loadClass只会对类进行加载,不会进行初始化,而Class.forName会默认对类进行初始化。

UrlClassLoader

UrlClassLoader提供了加载远程资源的能力,在利用漏洞或者写webshell的时候可以通过这个特性来实现远程类方法的调用。

1
2
URL url = new URL("https://xxx/cmd.jar");
URLClassLoader ucl = new URLClassLoader(new URL[]{url});

类加载隔离

创建类加载器的时候可以指定类加载器的父类加载器,ClassLoader是由隔离机制的,不同的ClassLoader可以加载相同的Class(必须是非继承关系),同级的ClassLoader加载必须使用反射。

跨类加载器调用方法时,A和B ClassLoader 可以加载相同的类名,但是两个类是不相同的对象,两者互相之间调用只能通过反射。

BCEL ClassLoader

一个用于分析、创建、操纵Java类文件的工具库。BCEL类加载器解析类名时会对ClassName中包含$$BCEL$$标识的类进行特殊处理,这个特性经常用于编写各种payload。

BCEL的com.sun.org.apache.bcel.internal.util.ClassLoader#loadClass加载一个类名中有$$BCEL$$类的时候会截取出后面的字符串,然后使用com.sun.org.apache.bcel.internal.classfile.Utility#decode把字符串解析为字节码

特性仅限于BCEL6.0以下,支持的范围为JDK1.5 - 1.7JDK8 - JDK8u241JDK9

image-20220524135144172

CATALOG
  1. 1. 前言
  2. 2. ClassLoader类
    1. 2.1. loadClass 方法
      1. 2.1.0.1. UrlClassLoader
  3. 2.2. 类加载隔离
    1. 2.2.1. BCEL ClassLoader