2

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?

Jester
  • 56,577
  • 4
  • 81
  • 125
  • Hook the method using a `MethodAdapter` to inject your own private method. Have your private method `InvokeStatic` or `InvokeVirtual` the original method with the correct parameters (ALOAD, ILOAD, etc.. to load arguments on the stack) – Brandon Feb 18 '20 at 14:37
  • Could you post an example? –  Feb 18 '20 at 14:41
  • Not related to ASM. Have you considered [Method Handles](https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandles.html) or [Dynamic Proxy](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/InvocationHandler.html) ? – Abra Feb 18 '20 at 14:46
  • I need performance, so It's necessary to hook the method at low level –  Feb 18 '20 at 14:53
  • 1
    What is it supposed the mean, “to hook a private native method”? – Holger Feb 18 '20 at 15:02
  • I need to invoke the Class.getDeclaredFields0 method that is native and private without using Reflection for performance reason, so I asked if there is a way to do this by using ASM and bytecode transformation –  Feb 18 '20 at 15:07
  • https://pastebin.com/3ert55fG or similar will do it. You'll have to write the rest yourself.. If the method is Native, why do you even want to use ByteCode to hook it.. Another approach is to just hook at the callsite. Wherever calls the native method in Java, insert a call to your function there.. – Brandon Feb 18 '20 at 15:11
  • @Brandon is there a way to map my class method to the native method via JNI? –  Feb 18 '20 at 15:17
  • I want invoke that method without passing for Reflection but it is private –  Feb 18 '20 at 18:14

1 Answers1

2

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.

Community
  • 1
  • 1
Holger
  • 285,553
  • 42
  • 434
  • 765
  • I solved by this code you have supplied. I also tried with defineAnonymousClass(Class>, byte[], Object[]) with a java.lang.MemberSupplier class created by me and injected into Class.class, but once created this class I must use reflection to invoke methods –  Feb 19 '20 at 09:40