类加载

初始化:静态代码块
实例化:构造代码块,无参构造函数

类加载过程

先在方法区找class信息,有则直接调用,没有则使用类加载器加载到方法区(静态区/非静态区)。
静态代码块在类加载时执行,非静态成员不执行
先父类后子类,先静态后非静态
静态方法和非静态方法都是被动调用(不调用就不执行)

动态加载类方法

  • Class.forname可以选择进行初始化或不初始化
  • ClassLoader.loadClass不进行初始化

继承关系:
ClassLoader -> SecureClassLoader -> URLClassLoader -> AppClassLoader
调用关系:
LoadClass -> findClass(重写的方法) -> defineClass(从字节码加载类)

java 9 及以上会报错但是也可弹计算器

URLClassLoader:

URLClassLoader任意类加载:file/http/jar

Test.java:

1
2
3
4
5
6
7
8
9
10
11
import java.io.IOException;

public class Test {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

file:
LoadClassTest.java:

1
2
3
4
5
6
7
8
9
10
import java.net.URL;
import java.net.URLClassLoader;

public class LoadClassTest {
public static void main(String[] args) throws Exception {
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///E:\\WebSecurity\\JavaSecurity\\unserialize\\out\\production\\unserialize\\Load\\")});
Class<?> test = urlClassLoader.loadClass("Load.Test"); //package Load
test.newInstance();
}
}

编译好Test.class并移动位置,将Test.java删除后仍可弹出计算器(我的删之前可以弹出,删了无法弹出布吉岛为什莫)

http:

1
2
3
4
5
6
7
8
9
10
import java.net.URL;
import java.net.URLClassLoader;

public class LoadClassTest {
public static void main(String[] args) throws Exception {
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("http://localhost:9999")});
Class<?> test = urlClassLoader.loadClass("Load.Test");
test.newInstance();
}
}
1
python -m http.server 9999

弹出计算器

jar

1
jar:file:///D:\\xxxx\\Test.jar!/

http更常用一点

ClassLoader

ClassLoader.defineClass 字节码加载任意类 私有

LoadClassTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;

public class LoadClassTest {
public static void main(String[] args) throws Exception {
ClassLoader cl = ClassLoader.getSystemClassLoader();
Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClassMethod.setAccessible(true);
byte[] code = Files.readAllBytes(Path.of("E:\\WebSecurity\\JavaSecurity\\unserialize\\out\\production\\unserialize\\Load\\Test.class"));
Class df = (Class)defineClassMethod.invoke(cl, code, 0, code.length);
df.newInstance();
}
}

unsafe

unsafe.defineClass 字节码加载 public类不能直接生成(Spring 里面可以直接生成)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class LoadClassTest {
public static void main(String[] args) throws Exception {
ClassLoader cl = ClassLoader.getSystemClassLoader();
byte[] code = Files.readAllBytes(Paths.get("E:\\WebSecurity\\JavaSecurity\\unserialize\\out\\production\\unserialize\\Load\\Test.class"));
Class unsafeClass = Unsafe.class;
Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
Class c2 = (Class)unsafe.defineClass("Load.Test",code, 0 , code.length,cl,null);
c2.newInstance();
}
}