运行前先编译成class,类初始化的时候调用java.lang.ClassLoader加载字节码,ClassLoader调用JVM的native方法来定义一个java.lang.Class实例

  • 启动类加载器: 将/lib下目录下的类加载到虚拟机内存中,加载java的核心库,不继承java.lang.ClassLoader,不能被java程序调用,是使用c++编写的
  • 拓展类加载器:加载/lib/ext下的,拓展库,可以直接使用
  • 应用程序类加载器:一般情况下是系统默认的类加载器

层次结构大概如下

  1. Bootstrap ClassLoader
  2. Extension ClassLoader
  3. App ClassLoader

默认使用第三个,ClassLoader.getSystemClassLoader()返回的是第三个

获取类加载器的时候如果返回null,那么就是被Bootstrap加载的

核心方法

  • loadClass 加载指定类
  • findClass 查找指定类
  • findLoadedClass 查找JVM已经加载过的类
  • defineClass 定义一个类
  • resolveClass 链接指定的类

类加载方式

  • 显式 :java反射或ClassLoader(动态加载)
  • 隐式 : 类名.方法名(),或者new

Class.forName("xx")会初始化静态属性和方法,有恶意代码就会执行了
ClassLoader.loadClass不会初始化类方法

常看常新

package tmp;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class MyClassLoader extends ClassLoader{
public static String className = "tmp.EvilObject";
public static Path path = Paths.get("/Users/dionysus/code/IdeaProjects/Serial/src/main/java/tmp/EvilObject.class");
public static byte[] classBytes;

static {
try {
classBytes = Files.readAllBytes(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

protected Class<?> findClass(String name) throws ClassNotFoundException {
System.out.println(name);
if (className.equals(name)) {
return defineClass(className, classBytes, 0, classBytes.length);
}
return super.findClass(name);
}

public static void main(String[] args) throws Exception{
MyClassLoader myClassLoader = new MyClassLoader();
Class<?> aClass = myClassLoader.loadClass(className);
Object a = aClass.newInstance();

}
}

恶意类

package tmp;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Hashtable;

public class EvilObject extends UnicastRemoteObject implements ObjectFactory {
static {
try {
Runtime.getRuntime().exec("open -a Calculator");
} catch (IOException e) {
e.printStackTrace();
}
}

protected EvilObject() throws RemoteException {
}

// public EvilObject() throws Exception {
// System.out.println("EvilObject instantiated");
// Runtime rt = Runtime.getRuntime();
// String[] commands = {"open", "-a" , "Calculator"};
// Process pc = rt.exec(commands);
// pc.waitFor();
// }
public static void main(String[] args) throws Exception {
new EvilObject();
}

@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
return null;
}
}