类加载
初始化:静态代码块
实例化:构造代码块,无参构造函数
类加载过程
先在方法区找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"); 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(); } }
|
