ClassLoader类加载机制
一切的Java类都需要经过JVM加载后才能运行,而ClassLoader
的主要作用就是Java类文件的加载。
JVM类加载器:
- Bootstrap ClassLoader(启动类加载器):负责加载jdk核心类库:rt.jar、resources.jar、charsets.jar
- Extension ClassLoader(扩展类加载器):负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
- App ClassLoader(系统类加载器):负责加载应用程序
classpath
目录下的所有jar和class文件。
AppClassLoader
是默认的类加载器,如果类加载时我们不指定类加载器的情况下,默认会使用AppClassLoader
加载类,ClassLoader.getSystemClassLoader()
返回的系统类加载器也是AppClassLoader
。
某些时候我们获取一个类的类加载器时候可能会返回一个null
值,如:java.io.File.class.getClassLoader()
将返回一个null
对象,因为java.io.File
类在JVM初始化的时候会被Bootstrap ClassLoader(启动类加载器Natives)
加载(该类加载器实现于JVM层,采用C++编写),我们在尝试获取被Bootstrap ClassLoader
类加载器所加载的类的ClassLoader
时候都会返回null
。
ClassLoader
类有如下核心方法:
loadClass
(加载指定的Java类)findClass
(查找指定的Java类)findLoadedClass
(查找JVM已经加载过的类)defineClass
(定义一个Java类)resolveClass
(链接指定的Java类)
Java动态类加载方式
显式:通过Java反射或者ClassLoader来动态加载一个类对象
-
自定义ClassLoader
Java.lang.ClassLoader是所有的类加载器的父类;
类加载器的继承机制:
URLClassLoader
继承了ClassLoader
,URLClassLoader
提供了加载远程资源的能力,在写漏洞利用的payload
或者webshell
的时候我们可以使用这个特性来加载远程的jar来实现远程的类方法调用。什么是Java的字节码
Java一直以来都称为是,一次编写到处运行。是因为运行在不同的平台的JMV能够载入和执行同一种与平台无关的字节码。 源代码中的各种变量,关键字和运算符号的语义最终都会编译成多条字节码命令。而字节码命令所能提供的语义描述能力是要明显强于Java本身的,所以有其他一些同样基于JVM的语言能提供许多Java所不支持的语言特性。
利用URLClassLoader加载远程class文件
URLClassLoader 实际上是我们平时默认使用的 AppClassLoader 的父类。那么讨论URLClassLoader实际上就是解释默认类加载的过程。
正常情况下,Java会根据配置项 sun.boot.class.path 和 java.class.path 中列举到的基础路径(这 些路径是经过处理后的 java.net.URL 类)来寻找.class文件来加载,而这个基础路径有分为三种情况:
- URL未以斜杠 / 结尾,则认为是一个JAR文件,使用 JarLoader 来寻找类,即为在Jar包中寻找.class文件
- URL以斜杠 / 结尾,且协议名是 file ,则使用 FileLoader 来寻找类,即为在本地文件系统中寻找.class文件
- URL以斜杠 / 结尾,且协议名不是 file ,则使用最基础的 Loader 来寻找类
我们正常开发的时候通常遇到的是前两者,那什么时候才会出现使用 Loader 寻找类的情况呢?当然是
非 file 协议的情况下,最常见的就是 http 协议。
Java的URLClassLoader支持哪一些协议-file,ftp,gopher,http,https,jar,mailto,netdoc
测试一下Java能否借助URLClassLoader发起Http请求去请求对应服务器上的class字节码,python拉起一个http服务(该服务对应的文件路径就是拉起http服务的路径)。
如图所示:作为攻击者,如果我们能够控制目标Java ClassLoader的基础路径为一个http服务器,则可以利
用远程加载的方式执行任意代码了。