前言
Unsafe类是一个位于sun.misc包下的类,它提供了一些相对底层方法,能够让我们接触到一些更接近操作系统底层的资源,如系统的内存资源、cpu指令等。而通过这些方法,我们能够完成一些普通方法无法实现的功能,例如直接使用偏移地址操作对象、数组等等。但是在使用这些方法提供的便利的同时,也存在一些潜在的安全因素,例如对内存的错误操作可能会引起内存泄漏,严重时甚至可能引起jvm崩溃。因此在使用Unsafe前,我们必须要了解它的工作原理与各方法的应用场景,并且在此基础上仍需要非常谨慎的操作,下面我们正式开始对Unsafe的学习。
Unsafe功能
Unsafe的功能大致如下:

查看Unsfe源码,可以看到该类被final关键字修饰,代表不能被其他类继承

构造方法被private修饰,就表明不能通过new的方式创建Unsafe类的实例,下面的getUnsafe()方法可以返回Unsafe的实例。

查看下isSystemDomainLoader()方法,可以看到如果var0为Bootstrap类加载器,那么就会等于”null”,也就是返回true

编写测试方法

Unsafe调用
方式一
该类的成员变量theUnsafe定义为它的实例化,因此可以利用反射获取该变量的值

编写测试代码
1 2 3 4 5 6 7 8 9
   | public class Test {     public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {         Class<?> aClass = Class.forName("sun.misc.Unsafe");         Field theUnsafe = aClass.getDeclaredField("theUnsafe");         theUnsafe.setAccessible(true);         Unsafe o = (Unsafe)theUnsafe.get(null);         System.out.println(o);     } }
  | 
 
运行结果

方式二
因为Unsafe类里面存在getUnsafe方法,该方法的返回值是Unsafe的实例对象,所以可以通过反射调用该方法。
编写测试方法
1 2 3 4 5 6 7 8 9
   | public class Test1 {     public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {         Class<?> aClass = Class.forName("sun.misc.Unsafe");         Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();         declaredConstructor.setAccessible(true);         Unsafe o = (Unsafe)declaredConstructor.newInstance();         System.out.println(o);     } }
  | 
 
运行结果

Class相关操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   |  public native long staticFieldOffset(Field f);
  public native Object staticFieldBase(Field f);
  public native boolean shouldBeInitialized(Class<?> c);
  public native void ensureClassInitialized(Class<?> c);
  public native Class<?> defineClass(String name, byte[] b, int off, int len,                                    ClassLoader loader,                                    ProtectionDomain protectionDomain);
 
  public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);
 
 
  | 
 
学习下Unsafe.defineClass()的运用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   | package org.agent;
  import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.NotFoundException; import sun.misc.Unsafe;
  import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.security.CodeSource; import java.security.ProtectionDomain; import java.security.cert.Certificate;
  public class Test2 {     public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException, CannotCompileException, IOException, NotFoundException, NotFoundException, CannotCompileException, IOException, InvocationTargetException {         String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";         String Classname ="org.agent.Commandtest";         ClassPool classPool= ClassPool.getDefault();         classPool.appendClassPath(AbstractTranslet);         CtClass payload=classPool.makeClass("org.agent.Commandtest");         payload.setSuperclass(classPool.get(AbstractTranslet));         payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");
          byte[] bytes=payload.toBytecode();                  ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();                  ProtectionDomain protectionDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), null, systemClassLoader, null);         Class<?> aClass = Class.forName("sun.misc.Unsafe");         Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();         declaredConstructor.setAccessible(true);         Unsafe unsafe = (Unsafe)declaredConstructor.newInstance();         Class<?> aClass1 = unsafe.defineClass(Classname, bytes, 0, bytes.length, systemClassLoader, protectionDomain);         Object o = aClass1.newInstance();
 
      } }
 
   | 
 
在JDK 11版本以后就移除了该方法。但还可以利用defineAnonymousClass方法。
参考
https://www.cnblogs.com/nice0e3/p/14102892.html