类的加载过程
先在方法区找class信息,有的话直接调用,没有的话则使用类加载器加载到方法区(静态成员放在静态区,非静态成功放在非静态区),静态代码块在类加载时自动执行代码,非静态的不执行;先父类后子类,先静态后非静态;静态方法和非静态方法都是被动调用,即不调用就不执行。
public class LoadClassTest {
public static void main(String[] args) {
new Person();
//静态代码块
//构造代码块
//无参Person
new Person("a",22);
//静态代码块
//构造代码块
//有参Person
Person.staticAction();
//静态代码块
//静态方法
Person.id=1;
//静态代码块
Class c=Person.class;
//无结果
动态加载
Class.forName("Person");
//静态代码块
ClassLoader cl =ClassLoader.getSystemClassLoader();
Class.forName("com.example.fastjson122.demos.web.Person",true,cl);//初始化
//静态代码块
ClassLoader cl =ClassLoader.getSystemClassLoader();
Class.forName("com.example.fastjson122.demos.web.Person",false,cl);//不初始化
//无结果
c.newInstance();
//静态代码块
//构造代码块
//无参Person
Class<?>c=cl.loadClass("com.example.fastjson122.demos.web.Person");//不初始化的
c.newInstance();
//静态代码块
//构造代码块
//无参Person
}
}
类加载机制
1、类加载与反序列化
类加载的时候会执行代码
初始化:加载静态代码块
实例化:加载构造代码块、无参构造函数
2、动态类加载方法
Class.forname
初始化/不初始化
ClassLoader.loadClass不进行初始化
底层的原理,实现加载任意的类
ClassLoader(父类)->SecureClassLoader->URLClassLoader->AppClassLoader(继承关系)
(调用关系)loadClass->findClass(重写的方法)->defineClass(从字节码加载类)
public class LoadClassTest {
public LoadClassTest() {
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, MalformedURLException {
ClassLoader cl =ClassLoader.getSystemClassLoader();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///C:\\JAVA\\")});
URLClassLoader urlClassLoader=new URLClassLoader(new URL[]{new URL("http://localhost:8080/")});
URLClassLoader urlClassLoader=new URLClassLoader(new URL[]{new URL("jar:http://localhost:8080/Test2.jar/")});
URLClassLoader urlClassLoader=new URLClassLoader(new URL[]{new URL("jar:file://D:\\tmp\\classes\\Test2.jar/")});
Class<?> c = urlClassLoader.loadClass("Test2");
c.newInstance();
Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass",String.class,byte[].class,int.class,int.class);
defineClassMethod.setAccessible(true);
byte[] code= Files.readAllBytes(Paths.get("D:\\tmp\\classes\\Test2.class"));
Class c=(Class) defineClassMethod.invoke(cl,"Test",code,0,code.length);
c.newInstance();
}
}
一下两个类是反序列化中常用的两个类都调用了defineClass
漏洞利用
URLClassLoader 任意类加载:file/http/jar
ClassLoder.defineClass字节码加载任意类 私有(好用,常用)
Unsafe.defineClass 字节码加载 public 类不能直接生成 Spring里可以直接生成