Java安全必学习类加载机制

admin 2026-05-23 05:16:08 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文系统解析Java类加载机制,涵盖静态与动态加载的区别、类加载的七个阶段(重点分析加载、验证、准备、解析、初始化)及触发条件。详细阐述三类加载器(Bootstrap、Extension、Application)与双亲委派模型的安全作用,并指出动态加载中反射可控输入可能引发的RCE风险,为安全审计提供关键技术视角。 综合评分: 85 文章分类: 代码审计,漏洞分析,WEB安全,应用安全,安全开发


加载(Loading)【从哪里来?–> 怎么处理? –>到哪里去?】

在该阶段 JVM 将字节码从不同的数据源(Class文件、Jar文件、网络)转为二进制字节流加载到内存中,并生成为一个代表类的 java.lang.Class 对象

验证(Verification)【主要有什么规范?】

该阶段 JVM 对二进制字节流进行校验,只有符合 JVM 字节码规范的才能被 JVM 执行,主要包含以下几个部分:

  1. 1. 确保二进制字节流格式符合规范。s
  2. 2. 所有方法需遵守访问控制关键字限定。
  3. 3. 方法调用的参数个数和类型是否正确
  4. 4. 确保变量在使用之前被正确初始化
  5. 5. 检查变量是否被赋予恰当类型的值
  6. 6. … 该阶段是保证 JVM 安全的屏障。

准备(Preparation)

该阶段 JVM 对类变量/静态变量(static)分配内存并初始化(给定对应数据类型的默认初始值: 0、0L、null…) 例如:

public String var1 = "test";
public static String var2 = "test2";
public static final String var3 = "test3";

上述代码在准备阶段:

  1. 1. var1 不会分配内存
  2. 2. var2 会被分配内存初始值为null
  3. 3. var3是(static final)常量会被初始化为test3

解析(Resolution)【处理哪里的数据?完整怎样的转化?】

该阶段将常量池中的符号引用解析为直接引用,简单来说,将”名字”转换为”真实位置”。 例如,代码中编写 com.example.vuln,在编译时只是一个字符串(‘名字’),JVM 并不知道它来自于哪里。等程序运行时,JVM会根据该名字找到类在内存的位置,该结果即为直接引用。

  • • 举例:Class.forName(userInput) 当 userInput 可控,其作为符号引用,JVM在该阶段会解析并寻找加载对应的类。

  • • 没加载 → 触发类加载(Load → Link → Init)

  • • 已加载 → 直接拿已有的Class对象

初始化(Initialization)【做了什么?什么会触发?】

该阶段为类加载的最后一步,类变量将被赋予代码定义的值。换句话说,初始化阶段是执行类构造器方法,执行类里的 static 代码(也就是 <clinit>())。 比如:

class A {
&nbsp; &nbsp; static int x = 10;
&nbsp; &nbsp; static {
&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("init A");
&nbsp; &nbsp; }
}

初始化时做的就是:

x = 10
执行 static 代码块
  • • 初始化的触发需要满足以下某项:
  1. 1. 创建类的实例(new xxx())
  2. 2. 访问 static 变量/方法(非 final)
  3. 3. 反射(Class.forName())
  4. 4. 初始化子类(会先初始化父类)
  5. 5. 程序的入口(Main方法对应类) 那么,初始化是会执行类里的 static 代码,而这一步可能导致RCE。

类加载器【 加载器类型,对于不同标准怎么统一处理?加载地址 】

JVM 判断类是否相同,不仅看类名,还看是”谁加载的”。 ![[类加载器.png]] 类加载器决定从哪里加载类,通过 “双亲委派” 机制 例如:new Test() JVM 视角: 1.使用ClassLoader –> 找到 Test.class –> 加载 –> 运行 主要的类加载器为以下三种:

  1. 1. Bootstrap
  • • 加载: Java核心类(Java.lang.*)
  • • 特点: 通过 C++ 实现,不是 Java 对象。String.class.getClassLoader()返回null
  1. 2. Extension
  • • 加载: jre/lib/ext 中的拓展库
  1. 3. Application
  • • 加载: 用户编写的代码(classpath中)
  • • 特点:平常接触的多。 自定义类加载器属于第四种,类的加载问题可被控制。 由于 类加载默认是”从上往下找” 双亲委派: 加载 Test 类 –> 想问 Bootstrap … 避免核心类被覆盖的问题并且不同加载器可加载 “同名不同类”。

在漏洞分析过程中,需要关注类从哪里来,是否是自定义的类加载器,关键在于触发类加载的方式。

双亲委派【加载规则】

类加载先交给父加载器,只有父加载器加载不了才自己加载,从而保证类的唯一性和核心类的安全性。

Bootstrap ClassLoader
&nbsp; &nbsp; &nbsp; &nbsp; ↑
&nbsp; &nbsp; &nbsp; &nbsp; │
Extension ClassLoader
&nbsp; &nbsp; &nbsp; &nbsp; ↑
&nbsp; &nbsp; &nbsp; &nbsp; │
System/Application ClassLoader
&nbsp; &nbsp; &nbsp; &nbsp; ↑
&nbsp; &nbsp; &nbsp; &nbsp; │
Custom ClassLoader

这种层次关系被称作为双亲委派模型: 加载一个类 → 先给父加载器 → 一直往上问(直到 Bootstrap) → 都加载不了 → 才自己加载。 这种设计存在两个核心作用:

  1. 1. 防止核心类被覆盖
  • • 例如: java.lang.String
  1. 2. 避免重复加载

总结

加载阶段是从不同来源(文件、网络、jar包等)找到二进制字节流,将其转换为方法区中的运行时数据结构,并在堆中生成对应的 Class 对象作为访问入口。 在此过程中 JVM 提供了三种内置类加载器:Bootstrap ClassLoader(负责加载核心类库)、Extension ClassLoader(负责加载扩展类)、Application ClassLoader(负责加载用户 classpath 下的类),此外还支持自定义类加载器。为保证加载的安全性,设计了双亲委派机制,防止核心类被覆盖和重复加载。 验证阶段,验证 Class 对象是否符合 JVM 规范。 准备阶段,将定义的 static 变量进行内存分配并赋默认值(如 int 默认为 0,引用类型默认为 null)。 解析阶段,将常量池中的符号引用替换为直接引用(即内存中的实际地址),使 JVM 能够真正找到对应的类、方法和字段。 初始化阶段,执行类的初始化逻辑,触发条件包括:使用 new 创建对象、调用静态方法或访问静态字段、使用 Class.forName() 加载类、子类初始化时父类尚未初始化、以及 JVM 启动时的主类(含 main 方法的类)。

参考文章

一文彻底搞懂 Java 类加载机制 类加载过程详解 Java 类加载篇(一)ClassLoader 类加载机制总结


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Gh0xE9 me7eorite me7eorite《Java安全必学习类加载机制》

Java安全必学习类加载机制 网络安全文章

Java安全必学习类加载机制

文章总结: 本文系统解析Java类加载机制,涵盖静态与动态加载的区别、类加载的七个阶段(重点分析加载、验证、准备、解析、初始化)及触发条件。详细阐述三类加载器(
评论:0   参与:  0