Skip to content

Instantly share code, notes, and snippets.

@XiaoPangxie732
Created August 18, 2024 12:45
Show Gist options
  • Save XiaoPangxie732/fac9f360ed8e7bed9fb45d306d704233 to your computer and use it in GitHub Desktop.
Save XiaoPangxie732/fac9f360ed8e7bed9fb45d306d704233 to your computer and use it in GitHub Desktop.
Get IMPL_LOOKUP using FFI via JNI
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
public class ImplLookupGetter {
public static final MethodHandles.Lookup IMPL_LOOKUP;
public static final int JNI_VERSION_21 = 0x00150000;
private static final Linker LINKER = Linker.nativeLinker();
private static final AddressLayout pp = ValueLayout.ADDRESS.withTargetLayout(ValueLayout.ADDRESS);// void**
private static final AddressLayout JavaVM = ValueLayout.ADDRESS.withTargetLayout(MemoryLayout.sequenceLayout(8, ValueLayout.ADDRESS));
private static final VarHandle GET_FUNCTION_AT = ValueLayout.ADDRESS.withTargetLayout(
MemoryLayout.sequenceLayout(235, ValueLayout.ADDRESS)
).varHandle(
MemoryLayout.PathElement.dereferenceElement(),
MemoryLayout.PathElement.sequenceElement()
);
private static final MethodHandle P_PP = LINKER.downcallHandle(FunctionDescriptor.of(
ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS
));
private static final MethodHandle V_PP = LINKER.downcallHandle(FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS, ValueLayout.ADDRESS
));
private static final MethodHandle P_PPPP = LINKER.downcallHandle(FunctionDescriptor.of(
ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS
));
private static final MethodHandle V_PPPP = LINKER.downcallHandle(FunctionDescriptor.ofVoid(
ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS
));
private static void handleResult(int result) {
if (result != 0) throw new RuntimeException("JNI error occurred. Error code: " + result);
}
private static MemorySegment getFunctionAt(MemorySegment env, int index) {
return (MemorySegment) GET_FUNCTION_AT.get(env, 0, index);
}
/** jclass FindClass(JNIEnv *env, const char *name); */
private static MemorySegment FindClass(MemorySegment env, MemorySegment name) throws Throwable {
return (MemorySegment) P_PP.invokeExact(getFunctionAt(env, 6), env, name);
}
/** jobject NewGlobalRef(JNIEnv *env, jobject obj); */
private static MemorySegment NewGlobalRef(MemorySegment env, MemorySegment obj) throws Throwable {
return (MemorySegment) P_PP.invokeExact(getFunctionAt(env, 21), env, obj);
}
/** void DeleteGlobalRef(JNIEnv *env, jobject globalRef); */
private static void DeleteGlobalRef(MemorySegment env, MemorySegment globalRef) throws Throwable {
V_PP.invokeExact(getFunctionAt(env, 22), env, globalRef);
}
/** jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig); */
private static MemorySegment GetMethodID(MemorySegment env, MemorySegment clazz, MemorySegment name, MemorySegment sig) throws Throwable {
return (MemorySegment) P_PPPP.invokeExact(getFunctionAt(env, 33), env, clazz, name, sig);
}
/** void CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args); */
private static void CallVoidMethodA(MemorySegment env, MemorySegment obj, MemorySegment methodID, MemorySegment args) throws Throwable {
V_PPPP.invokeExact(getFunctionAt(env, 63), env, obj, methodID, args);
}
/** jobject GetModule(JNIEnv *env, jclass clazz); */
private static MemorySegment GetModule(MemorySegment env, MemorySegment clazz) throws Throwable {
return (MemorySegment) P_PP.invokeExact(getFunctionAt(env, 233), env, clazz);
}
/** jstring NewStringUTF(JNIEnv *env, const char *bytes); */
private static MemorySegment NewStringUTF(MemorySegment env, MemorySegment bytes) throws Throwable {
return (MemorySegment) P_PP.invokeExact(getFunctionAt(env, 167), env, bytes);
}
static {
try (Arena arena = Arena.ofConfined()) {
MethodHandle JNI_GetCreatedJavaVMs = LINKER.downcallHandle(
// jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs);
SymbolLookup.libraryLookup(System.mapLibraryName("jvm"), arena).find("JNI_GetCreatedJavaVMs").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.ADDRESS)
);
var ppVM = arena.allocate(ValueLayout.ADDRESS);// JavaVM **
handleResult((int) JNI_GetCreatedJavaVMs.invokeExact(ppVM, 1, MemorySegment.NULL));
MemorySegment vm = ppVM.get(pp, 0);// JavaVM*
MethodHandle GetEnv = LINKER.downcallHandle(
// jint GetEnv(JavaVM *vm, void **p_env, jint version);
vm.get(JavaVM, 0).getAtIndex(ValueLayout.ADDRESS, 6),
FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT)
);
var pEnv = arena.allocate(ValueLayout.ADDRESS);// JNIEnv **
handleResult((int) GetEnv.invokeExact(vm, pEnv, JNI_VERSION_21));
var env = pEnv.get(pp, 0);// JNIEnv *
var moduleClass = NewGlobalRef(env, FindClass(env, arena.allocateFrom("java/lang/Module")));
var module = NewGlobalRef(env, GetModule(env, moduleClass));
var implAddOpens = GetMethodID(env, moduleClass, arena.allocateFrom("implAddOpens"), arena.allocateFrom("(Ljava/lang/String;)V"));
MemorySegment arg0 = NewGlobalRef(env, NewStringUTF(env, arena.allocateFrom("java.lang.invoke")));
MemorySegment args = arena.allocate(ValueLayout.ADDRESS, 1);// 1 arg
args.setAtIndex(ValueLayout.ADDRESS, 0, arg0);
CallVoidMethodA(env, module, implAddOpens, args);
DeleteGlobalRef(env, arg0);
DeleteGlobalRef(env, module);
DeleteGlobalRef(env, moduleClass);
Field implLookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
implLookupField.setAccessible(true);
IMPL_LOOKUP = (MethodHandles.Lookup) implLookupField.get(null);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
System.out.println(IMPL_LOOKUP);
}
}
@sylv256
Copy link

sylv256 commented Oct 12, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment