汪汪一只猫
由于 Java 后期版本的 sun.misc.Unsafe 中删除了 defineClass 方法,所以我们需要在内部 Unsafe 中调用该方法。由于默认情况下整个包是隐藏的,我们需要反射地调用所有内容。此代码从 java 17 开始工作try { Field f = Unsafe.class.getDeclaredField("theUnsafe"), f1 = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); f1.setAccessible(false); Unsafe unsafe = (Unsafe) f.get(null); int i;//override boolean byte offset. should result in 12 for java 17 for (i = 0; unsafe.getBoolean(f, i) == unsafe.getBoolean(f1, i); i++); Field f2 = Unsafe.class.getDeclaredField("theInternalUnsafe"); unsafe.putBoolean(f2, i, true);//write directly into override to bypass perms Object internalUnsafe = f2.get(null); Method defineClass = internalUnsafe.getClass().getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class); unsafe.putBoolean(defineClass, i, true); Class<?> newClass = (Class<?>) defineClass.invoke(internalUnsafe, className, byteCode, offset, length, Object.class.getClassLoader(), Object.class.getProtectionDomain());} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { throw new RuntimeException(e);}我将逐步解释这是在做什么使用反射直接访问 sun.misc.Unsafe 实例。获取 sun Unsafe 字段的另一个副本,将其设置为不可访问严格地遍历这两个实例中的字节,直到发现差异。这是 AccessibleObject 类中的变量“覆盖”,字段和方法用于确定它们是否可访问。从 sun Unsafe 类中获取 internalUnsafe 字段,使用 sun Unsafe 实例将其设置为可访问(虽然我们可以获取字段对象,但 java 不会让我们将内部或反射包中的任何内容设置为可直接访问)获取 internalUnsafe 实例,将其保存到 Object 指针,因为我们不能直接引用 internal.misc.Unsafe从 internalUnsafe 反射性地获取 defineClass 方法使用与太阳相同的偏移量将方法设置为可访问不安全用我们的参数调用它希望只要 Unsafe 保留在 jdk 中,它就可以继续工作。