Java反序列化基础篇-类加载器
字数 1745 2025-08-12 12:08:18

Java类加载机制与反序列化基础教学文档

1. 类加载器概述

类加载器(ClassLoader)是Java虚拟机(JVM)的重要组成部分,负责将Class文件加载到JVM中,使其能够被程序使用。

1.1 类加载器的主要功能

  • 加载Class文件
  • 将抽象类实例化(如Student student = new Student();

1.2 类加载器层次结构

Java中有四种主要的类加载器:

  1. 引导类加载器(BootstrapClassLoader)

    • 底层由C++编写,是JVM的一部分
    • 不继承java.lang.ClassLoader类
    • 没有父加载器
    • 负责加载核心Java库(JVM本身)
    • 加载路径:/jre/lib/rt.jar
    • 只加载包名为java、javax、sun等开头的类
  2. 扩展类加载器(ExtensionsClassLoader)

    • sun.misc.Launcher$ExtClassLoader实现
    • 加载路径:/jre/lib/extjava.ext.dirs指定的目录
    • 用于加载Java扩展库
  3. 应用程序类加载器(AppClassLoader)

    • sun.misc.Launcher$AppClassLoader实现
    • 通过java.class.path或Classpath环境变量加载类
    • 通常用于加载应用程序类
    • 可通过ClassLoader.getSystemClassLoader()获取

2. 双亲委派机制

双亲委派机制是Java类加载的安全机制,确保核心类库的安全性。

2.1 双亲委派工作原理

类加载器在被调用时(new class),按以下顺序查找类:

BOOT(引导类加载器) → EXC(扩展类加载器) → APP(应用程序类加载器)

2.2 双亲委派示例

错误示例

package java.lang;

public class String {
    public String toString(){
        return "hello";
    }
    public static void main(String[] args) {
        String s = new String();
        s.toString();
    }
}
  • 会报错,因为与BOOT加载器中的String冲突

正确示例

package src.DynamicClassLoader;

public class Student {
    public String toString(){
        return "Hello";
    }
    public static void main(String[] args) {
        Student student = new Student();
        System.out.println(student.getClass().getClassLoader());
        System.out.println(student.toString());
    }
}
  • 可以正常加载,因为BOOT和EXC加载器中都没有Student类

3. 代码块加载顺序

Java中有四种主要代码块:

  1. 静态代码块:static{}
  2. 构造代码块:{}
  3. 无参构造器:ClassName()
  4. 有参构造器:ClassName(String name)

3.1 不同场景下的加载顺序

场景一:实例化对象

Person person = new Person();

加载顺序

  1. 静态代码块
  2. 构造代码块
  3. 构造器(根据实例化方式调用无参或有参构造器)

场景二:调用静态方法

Person.staticAction();

加载顺序

  1. 静态代码块
  2. 静态方法

场景三:对静态成员变量赋值

Person.staticVar = 1;

加载顺序

  1. 静态代码块

场景四:使用class获取类

Class c = Person.class;

结果

  • 不会加载类,无输出

场景五:使用forName获取类

三种形式:

  1. Class.forName("src.DynamicClassLoader.Person")
    • 会调用静态代码块
  2. Class.forName("src.DynamicClassLoader.Person", true, ClassLoader.getSystemClassLoader())
    • 会调用静态代码块
  3. Class.forName("src.DynamicClassLoader.Person", false, ClassLoader.getSystemClassLoader())
    • 不会调用静态代码块

场景六:使用ClassLoader.loadClass()

ClassLoader.getSystemClassLoader().loadClass("com.xiinnn.i.test.Person");

结果

  • 不会进行类的初始化,无输出
  • 如果后续使用newInstance()初始化,则与场景一相同

4. 类加载在反序列化中的应用

在Java反序列化中,理解类加载机制至关重要:

  1. 动态加载类:攻击者可能利用类加载机制加载恶意类
  2. 绕过安全限制:理解双亲委派机制有助于理解某些安全限制的绕过方式
  3. 代码执行:通过控制类加载过程可能实现任意代码执行

4.1 关键点

  • 类加载器决定了类的可见性和安全性
  • 双亲委派机制是Java安全模型的重要组成部分
  • 不同加载方式(如forName与loadClass)的行为差异可能被利用
  • 静态代码块在类初始化时执行,是反序列化攻击的常见切入点

5. 防御措施

  1. 严格限制反序列化的类白名单
  2. 使用SecurityManager限制类加载
  3. 及时更新Java运行环境
  4. 避免使用不安全的反序列化方法

理解这些类加载机制对于Java安全开发和反序列化漏洞分析至关重要。

Java类加载机制与反序列化基础教学文档 1. 类加载器概述 类加载器(ClassLoader)是Java虚拟机(JVM)的重要组成部分,负责将Class文件加载到JVM中,使其能够被程序使用。 1.1 类加载器的主要功能 加载Class文件 将抽象类实例化(如 Student student = new Student(); ) 1.2 类加载器层次结构 Java中有四种主要的类加载器: 引导类加载器(BootstrapClassLoader) 底层由C++编写,是JVM的一部分 不继承java.lang.ClassLoader类 没有父加载器 负责加载核心Java库(JVM本身) 加载路径: /jre/lib/rt.jar 只加载包名为java、javax、sun等开头的类 扩展类加载器(ExtensionsClassLoader) 由 sun.misc.Launcher$ExtClassLoader 实现 加载路径: /jre/lib/ext 或 java.ext.dirs 指定的目录 用于加载Java扩展库 应用程序类加载器(AppClassLoader) 由 sun.misc.Launcher$AppClassLoader 实现 通过 java.class.path 或Classpath环境变量加载类 通常用于加载应用程序类 可通过 ClassLoader.getSystemClassLoader() 获取 2. 双亲委派机制 双亲委派机制是Java类加载的安全机制,确保核心类库的安全性。 2.1 双亲委派工作原理 类加载器在被调用时(new class),按以下顺序查找类: 2.2 双亲委派示例 错误示例 : 会报错,因为与BOOT加载器中的String冲突 正确示例 : 可以正常加载,因为BOOT和EXC加载器中都没有Student类 3. 代码块加载顺序 Java中有四种主要代码块: 静态代码块: static{} 构造代码块: {} 无参构造器: ClassName() 有参构造器: ClassName(String name) 3.1 不同场景下的加载顺序 场景一:实例化对象 加载顺序 : 静态代码块 构造代码块 构造器(根据实例化方式调用无参或有参构造器) 场景二:调用静态方法 加载顺序 : 静态代码块 静态方法 场景三:对静态成员变量赋值 加载顺序 : 静态代码块 场景四:使用class获取类 结果 : 不会加载类,无输出 场景五:使用forName获取类 三种形式: Class.forName("src.DynamicClassLoader.Person") 会调用静态代码块 Class.forName("src.DynamicClassLoader.Person", true, ClassLoader.getSystemClassLoader()) 会调用静态代码块 Class.forName("src.DynamicClassLoader.Person", false, ClassLoader.getSystemClassLoader()) 不会调用静态代码块 场景六:使用ClassLoader.loadClass() 结果 : 不会进行类的初始化,无输出 如果后续使用 newInstance() 初始化,则与场景一相同 4. 类加载在反序列化中的应用 在Java反序列化中,理解类加载机制至关重要: 动态加载类 :攻击者可能利用类加载机制加载恶意类 绕过安全限制 :理解双亲委派机制有助于理解某些安全限制的绕过方式 代码执行 :通过控制类加载过程可能实现任意代码执行 4.1 关键点 类加载器决定了类的可见性和安全性 双亲委派机制是Java安全模型的重要组成部分 不同加载方式(如forName与loadClass)的行为差异可能被利用 静态代码块在类初始化时执行,是反序列化攻击的常见切入点 5. 防御措施 严格限制反序列化的类白名单 使用SecurityManager限制类加载 及时更新Java运行环境 避免使用不安全的反序列化方法 理解这些类加载机制对于Java安全开发和反序列化漏洞分析至关重要。