Java动态加载字节码

Chiexf Lv4

0x00 什么是字节码

0x01 URLClassLoader

  • CalcTest.java
1
2
3
4
5
6
7
8
9
public class CalcTest {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

file://协议

1
2
3
4
5
6
7
public class LoadClassTest {
public static void main(String[] args) throws Exception {
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///F:\\tmp\\classes\\")});
Class<?> c = urlClassLoader.loadClass("CalcTest");
c.newInstance();
}
}

http://协议

在**.class**文件对应的文件目录下起一个HTTP服务

1
python -m http.server 9999

尝试访问

1
2
3
4
5
6
7
public class LoadClassTest {
public static void main(String[] args) throws Exception {
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("http://localhost:9999/")});
Class<?> c = urlClassLoader.loadClass("CalcTest");
c.newInstance();
}
}

jar://协议

0x02 ClassLoader.defineClass

  • 字节码加载动态类
  • private
1
2
3
4
5
6
7
8
9
10
public class LoadClassTest {
public static void main(String[] args) throws Exception {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
defineClassMethod.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("F:\\tmp\\classes\\CalcTest.class"));
Class c = (Class) defineClassMethod.invoke(systemClassLoader, "CalcTest", code, 0, code.length);
c.newInstance();
}
}

0x03 Unsafe.defineClass

  • 字节码加载动态类
  • public,但是类不能直接生成
  • Spring里面可以直接生成
1
2
3
4
5
6
7
8
9
10
11
public class LoadClassTest {
public static void main(String[] args) throws Exception {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
Class<Unsafe> unsafeClass = Unsafe.class;
Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Class<?> c = unsafe.defineClass("CalcTest", code, 0, code.length, systemClassLoader, null);
c.newInstance();
}
}

0x04 Template