類的加載過程
先在方法區找class信息,有的話直接調用,沒有的話則使用類加載器加載到方法區(靜態成員放在靜態區,非靜態成功放在非靜態區),靜態代碼塊在類加載時自動執行代碼,非靜態的不執行;先父類后子類,先靜態后非靜態;靜態方法和非靜態方法都是被動調用,即不調用就不執行。
public class LoadClassTest {public static void main(String[] args) {new Person();//靜態代碼塊//構造代碼塊//無參Personnew Person("a",22);//靜態代碼塊//構造代碼塊//有參PersonPerson.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();//靜態代碼塊//構造代碼塊//無參PersonClass<?>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里可以直接生成