Invoke private method by Java ASM

user12801918 :

I would like to invoke a private method without using Reflection: is it possible to hook a private native method by using ASM and invoke it?

Holger :

The challenge is not to generate a class invoking the private method via ASM or a similar bytecode generation tool. The challenge is to get the bytecode into the JVM without being rejected by the verifier.

For OpenJDK/HotSpot, there is sun.misc.Unsafe which has the method defineAnonymousClass(Class<?>, byte[], Object[]) which is used for generating accessor classes, like the runtime classes implementing functional interfaces and invoking the private synthetic methods holding a lambda expression’s body.

You could use this to load your bytecode, using the private method’s declaring class as first argument, to make the method accessible. On the other hand, the JRE’s own use case implies that you don’t even need to generate such bytecode yourself:

MethodHandles.Lookup l = MethodHandles.privateLookupIn(Class.class, MethodHandles.lookup());
MethodHandle target = l.findSpecial(Class.class, "getDeclaredFields0",
    MethodType.methodType(Field[].class, boolean.class), Class.class);
BiFunction<Class<?>,Boolean,Field[]> a = (BiFunction)LambdaMetafactory.metafactory(
    l, "apply", MethodType.methodType(BiFunction.class), target.type().generic(),
    target, target.type().changeParameterType(1, Boolean.class))
    .getTarget().invokeExact();

Then, you can call, e.g. a.apply(Class.class, false) which will invoke getDeclaredFields0 without Reflection.

privateLookupIn is a Java 9 method which will work if you’re in non-modular code or provide the necessary --add-opens option at JVM startup, to open java.base to your module. There will be a warning about the Reflection access and well, it is right about noting that such access “will be denied in a future release”. Anyway, How to hide warning "Illegal reflective access" in java 9 without JVM argument? might be interesting.

For Java 8, you’d need to hack into the Lookup class to get an appropriate lookup instance. This answer shows a solution, here is another approach.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=416525&siteId=1