Created
August 18, 2024 12:45
-
-
Save XiaoPangxie732/fac9f360ed8e7bed9fb45d306d704233 to your computer and use it in GitHub Desktop.
Get IMPL_LOOKUP using FFI via JNI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
cleaner version of https://gist.github.com/burningtnt/c188e65f048c2cf096db095e5858b5af