前言

参照https://javasec.org/以及p神的Java安全漫谈的路线进行学习,类似读书笔记那种吧。之前都是ctf遇到Java的题才学一点,像是反序列化这种,没系统化的学过Java Web安全,这次从头来好好学一遍。

Java平台版本

Java平台共分为三个主要版本Java SE(Java Platform, Standard Edition-Java平台标准版)、Java EE(Java Platform Enterprise Edition-Java平台企业版)、和Java ME(Java Platform, Micro Edition-Java平台微型版)。Java SE是JDK自带的标准API,是Java学习的基础。

ClassLoader(类加载机制)

Java是一个依赖于JVM(Java虚拟机)实现的跨平台的开发语言。Java程序在运行前需要先编译成class文件,Java类初始化的时候使用类加载器创建。

加载器分为两种:由 Java 虚拟机提供的引导类加载器,以及用户定义的类加载器。 每个用户定义的类加载器都是一个ClassLoader抽象类的子类的实例.

Java类初始化的时候会调用java.lang.ClassLoader加载类字节码,ClassLoader会调用JVM的native方法(defineClass0/1/2)来定义一个java.lang.Class实例(创建一个对象)。

JVM架构图:

ClassLoader

一切的Java类都必须经过JVM加载后才能运行,而ClassLoader的主要作用就是Java类文件.class 的加载。将 Class 的字节码形式转换成内存形式的 Class 对象。字节码可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流,字节码的本质就是一个字节数组 []byte,它有特定的复杂的内部格式。

.class文件结构示例

JVM类加载器内置了三个重要的类加载器,三者形成层次结构,从上到下依次为:

  1. Bootstrap ClassLoader(引导类加载器,内嵌在java虚拟机中由C++编写)主要加载核心类库,ClassLoader就是是由它来加载的,它并不是Java类,而其它加载器则都是Java类。
  2. Extension ClassLoader(扩展类加载器),负责加载 JVM 扩展类,比如 swing 系列、内置的 js 引擎、xml 解析器 等等,这些库名通常以 javax 开头,它们的 jar 包位于 JAVA_HOME/lib/ext/*.jar 中。Java9之后更名为platform classloader
  3. App ClassLoader(系统类加载器)AppClassLoader会加载 Classpath 环境变量里定义的路径中的 jar 包和目录,是默认的类加载器,如果类加载时我们不指定类加载器的情况下,默认会使用AppClassLoader加载类,ClassLoader.getSystemClassLoader()返回的系统类加载器也是AppClassLoader

jdk还内置了一个 URLClassLoader,用户只需要传递规范的网络路径给构造器,就可以使用 URLClassLoader 来加载远程/本地类库,取决于构造器中不同的地址形式。ExtensionClassLoader 和 AppClassLoader 都是 URLClassLoader 的子类,它们都是从本地文件系统里加载类库。

这三个类加载器实例的父子关系如上图,不过虽然ExtClassLoader是AppClassLoader父加载器,但却是由Bootstrap加载的AppClassLoader

如同上图当中的例子所示,某些时候我们获取一个类的类加载器时,可能会返回一个null值,如:java.io.File.class.getClassLoader()将返回一个null对象,因为java.io.File类在JVM初始化的时候会被Bootstrap ClassLoader(引导类加载器)加载(该类加载器实现于JVM层,采用C++编写),我们在尝试获取被Bootstrap ClassLoader类加载器所加载的类的ClassLoader时候都会返回null

还需注意的是上面所提到的父子加载器并不是类继承上的父子关系,是类加载器实例之间的关系。类继承关系如下图所示:

ClassLoader类有如下核心方法:

  1. loadClass(加载指定的Java类)
  2. findClass(查找指定的Java类)
  3. findLoadedClass(查找JVM已经加载过的类)
  4. defineClass(定义一个Java类)
  5. resolveClass(链接指定的Java类)

Java类动态加载方式

Java类加载方式分为显式隐式,显式即我们通常使用Java反射或者ClassLoader来动态加载一个类对象,而隐式指的是类名.方法名()new类实例。显式类加载方式也可以理解为类动态加载,我们可以自定义类加载器去加载任意的类。

常用的类动态加载方式:

// 反射加载TestHelloWorld示例
Class.forName("HelloTest");// ClassLoader加载TestHelloWorld示例
this.getClass().getClassLoader().loadClass("HelloTest");

Class.forName("类名")默认会初始化被加载类的静态属性和方法,如果不希望初始化类可以使用Class.forName("类名", 是否初始化类, 类加载器),而ClassLoader.loadClass默认不会初始化类方法。Class.forName() 方法可以获取原生类型的 Class,而ClassLoader.loadClass()则会报错。

如上图所示,必须等到Class.forName执行才完成对Tester类的初始化。

ClassLoader类加载流程

先了解一下JVM的三种主要类加载机制:

缓存机制:

保证所有加载过的Class都会被缓存。即当需要某个类时会先从缓存区中搜寻该Class,若没有则进行加载。(修改Class后,必须重启JVM)

JVM判断两个类对象相同的两个条件:

  1. 类的完整名必须一致
  2. 加载这个类的ClassLoader实例必须为同一个

父类委托 /双亲委派:

某个特定的类加载器在接到加载类的请求时,首先判断这个class是否以及加载成功,如果没有则将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

委托机制的意义 — 防止内存中出现多份同样的字节码。

全盘负责:

当一个类加载器负责加载某个Class时,该Class所依赖的和引用的Class也将由其负责载入,除非显式指定另一加载器。

ClassLoader加载Tester类重要流程如下:

  1. ClassLoader会调用public Class<?> loadClass(String name)方法加载Tester类。
  2. 调用findLoadedClass方法检查Tester类是否已经初始化,如果JVM已初始化过该类则直接返回类对象。
  3. 如果创建当前ClassLoader时传入了父类加载器(new ClassLoader(父类加载器))就使用父类加载器加载Tester类,否则使用JVM的Bootstrap ClassLoader加载。
  4. 如果上一步无法加载Tester类,那么调用自身的findClass方法尝试加载Tester类。
  5. 如果当前的ClassLoader没有重写了findClass方法,那么直接返回类加载失败异常。如果当前类重写了findClass方法并通过传入的Tester类名找到了对应的类字节码,那么应该调用defineClass方法去JVM中注册该类。
  6. 如果调用loadClass的时候传入的resolve参数为true,那么还需要调用resolveClass方法链接类,默认为false。
  7. 返回一个被JVM加载后的java.lang.Class类对象。

类加载隔离

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

BCEL ClassLoader

BCEL(Apache Commons BCEL™)是一个用于分析、创建和操纵Java类文件的工具库,Oracle
JDK引用了BCEL库,不过修改了原包名org.apache.bcel.util.ClassLoadercom.sun.org.apache.bcel.internal.util.ClassLoader,BCEL的类加载器在解析类名时会对ClassName中有$$BCEL$$标识的类做特殊处理,该特性经常被用于编写各类攻击Payload。

BCEL攻击原理

当BCEL的com.sun.org.apache.bcel.internal.util.ClassLoader#loadClass加载一个类名中带有$$BCEL$$的类时会截取出$$BCEL$$后面的字符串,然后使用com.sun.org.apache.bcel.internal.classfile.Utility#decode将字符串解析成类字节码(带有攻击代码的恶意类),最后会调用defineClass注册解码后的类,一旦该类被加载就会触发类中的恶意代码,正是因为BCEL有了这个特性,才得以被广泛的应用于各类攻击Payload中。

示例 - BCEL类名解码:

BCEL编解码

BCEL编码:

byte[]{类字节码byte数组}];// BCEL编码类字节码 String className = "$$BCEL$$" +
com.sun.org.apache.bcel.internal.classfile.Utility.encode(CLASS_BYTES,
true); ```编码后的类名:`$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$85S$dbn$d......`,BCEL会对类字节码进行编码,**BCEL解码:**```java int    index    = className.indexOf("$$BCEL$$"); String
realName = className.substring(index + 8);// BCEL解码类字节码 byte[] bytes =
com.sun.org.apache.bcel.internal.classfile.Utility.decode(realName,
true); ```如果被加载的类名中包含了`$$BCEL$$`关键字,BCEL就会使用特殊的方式进行解码并加载解码之后的类。## ClassLoader总结`ClassLoader`是JVM中一个非常重要的组成部分,`ClassLoader`可以为我们加载任意的java类(配合反射机制实现,使得Java这一静态语言具有一定的动态性),通过自定义`ClassLoader`更能够实现自定义类加载行为。码类字节码 byte[] bytes =
com.sun.org.apache.bcel.internal.classfile.Utility.decode(realName,
true); ```如果被加载的类名中包含了`$$BCEL$$`关键字,BCEL就会使用特殊的方式进行解码并加载解码之后的类。

ClassLoader总结

ClassLoader是JVM中一个非常重要的组成部分,ClassLoader可以为我们加载任意的java类(配合反射机制实现,使得Java这一静态语言具有一定的动态性),通过自定义ClassLoader更能够实现自定义类加载行为。

Javaweb安全——Java类加载机制相关推荐

  1. 两道面试题,带你解析Java类加载机制

    2019独角兽企业重金招聘Python工程师标准>>> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Grandpa {static ...

  2. Java类加载机制详解【java面试题】

    Java类加载机制详解[java面试题] (1)问题分析: Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数 ...

  3. 谈谈 Java 类加载机制

    点击上方"方志朋",选择"置顶或者星标" 你的关注意义重大! 来源:Rainstorm , github.com/c-rainstorm/blog/blob/m ...

  4. Java类加载机制:双亲委托模型

    Java类加载机制:双亲委托模型 前言(废话) 一如既往,这篇博客是我极为浅显的理解,仅仅是我记录我自己成长的一环而已.我以前听我老师说过,什么是进步,进步就是当你三个月后重新再看自己的代码,发现那就 ...

  5. 深入研究Java类加载机制

    深入研究Java类加载机制   类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载 ...

  6. Java类加载机制深度分析

    为什么80%的码农都做不了架构师?>>>    Java类加载机制 类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. ...

  7. Java高级篇——深入浅出Java类加载机制

    转载自 Java高级篇--深入浅出Java类加载机制 类加载器 简单讲,类加载器ClassLoader的功能就是负责将class文件加载到jvm内存. 类加载器分类 从虚拟机层面讲分为两大类型的类加载 ...

  8. Java类加载机制的理解

    算上大学,尽管接触Java已经有4年时间并对基本的API算得上熟练应用,但是依旧觉得自己对于Java的特性依然是一知半解.要成为优秀的Java开发人员,需要深入了解Java平台的工作方式,其中类加载机 ...

  9. java 加载类java_深入研究Java类加载机制

    深入研究Java类加载机制 类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比 ...

  10. java版如何使区块常加载,Java类加载机制 - suer27zhu的个人空间 - OSCHINA - 中文开源技术交流社区...

    首先上图 如图所示,Java类加载机制的六个阶段 Java代码编译完成后会生成对应的class文件,接着我们运行java命令的时候,其实是启动了JVM虚拟机执行class字节码文件的内容.大致分为六个 ...

最新文章

  1. 循环获取结构体中的健名与值的实现
  2. cmd打开java文件夹_Java用CMD打开指定文件和文件夹
  3. 将四个整数进行从小到大的顺序排列 java_07_Java基础语法_第7天(练习)_讲义(练习加强+在eclipse中实现)...
  4. ❤️六W字《计算机基础知识》(八)(建议收藏)❤️
  5. CTF:攻防世界web PART01
  6. Activiti6.0.0及以上版本集成Activiti Modeler
  7. 【Unity3D基础2-11】Unity3D网格和材质
  8. 栈的push,pop序列
  9. 【npm i 报错解决方法】npm ERR! code ERESOLVEnpm ERR!npm ERR! While resolving: by-web@1.2.2npm ERR!
  10. 淘宝店铺动销率对店铺有什么影响,怎样提高店铺动销率
  11. OSPF状态切换以及包内容的交互,以及如何根据LSDB还原单区域拓扑
  12. 【JavaLearn】 # (2)类和对象、变量、构造方法、普通方法、this关键字
  13. 【转】.NET引用Excel操作时无法关闭Excel.exe进程的解决方法
  14. PPT形状的多种玩法
  15. 【魏先生搞定Python系列】一文搞定Cufflinks画图
  16. hook createmutex openmutex 实现多开
  17. linux下查看磁盘空间
  18. 怎样看 计算机类b0809,计算机类(B0809、A0812、A0854)为什么是神?
  19. 基于springboot的毕业设计管理系统
  20. linux电池充电阀值控制

热门文章

  1. 【Java实现】南京地铁导航系统的简单实现(三)—— 图形化界面的设计
  2. Linux聊天服务器
  3. struts2通配符的问题的解决
  4. 【Linux应用】SAN(存储区域网络)技术
  5. 无法访问,您可能没有权限使用网络资源的解决
  6. 小马哥杂牌机高仿机刷机教程---史上最简单的卡刷方法。adb推送模式自动卡刷教程
  7. java $字符串替换_Java8字符串替换方法梳理
  8. 浅谈医院HIS系统审计
  9. 腾讯云window阿帕奇服务器开通ssl证书实现https访问
  10. 计算机显示发送报告,Word文档打不开提示发送错误报告的解决方法