【问题标题】:Invoke private method by Java ASM通过 Java ASM 调用私有方法
【发布时间】:2020-06-02 14:44:35
【问题描述】:

我想在不使用反射的情况下调用私有方法:是否可以使用 ASM 挂钩私有本机方法并调用它?

【问题讨论】:

  • 使用MethodAdapter 挂钩方法以注入您自己的私有方法。让您的私有方法 InvokeStaticInvokeVirtual 具有正确参数(ALOAD、ILOAD 等)的原始方法,以便在堆栈上加载参数
  • 你能举个例子吗?
  • 与 ASM 无关。你考虑过Method HandlesDynamic Proxy 吗?
  • 我需要性能,所以需要底层hook方法
  • “挂钩私有本地方法”是什么意思?

标签: java methods invoke java-bytecode-asm


【解决方案1】:

挑战不是通过 ASM 或类似的字节码生成工具生成调用private 方法的类。挑战是在不被验证者拒绝的情况下将字节码放入 JVM。

对于 OpenJDK/HotSpot,sun.misc.Unsafe 具有方法 defineAnonymousClass(Class<?>, byte[], Object[]),用于生成访问器类,例如实现功能接口的运行时类和调用包含 lambda 表达式主体的 private 合成方法。

您可以使用它来加载您的字节码,使用 private 方法的声明类作为第一个参数,以使该方法可访问。另一方面,JRE 自己的用例意味着您甚至不需要自己生成这样的字节码:

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();

然后,您可以调用,例如a.apply(Class.class, false) 将在没有反射的情况下调用 getDeclaredFields0

privateLookupIn 是一种 Java 9 方法,如果您使用非模块化代码或在 JVM 启动时提供必要的 --add-opens 选项以打开您的模块的 java.base,则该方法将起作用。会有一个关于反射访问的警告,好吧,注意到这种访问“将在未来的版本中被拒绝”是正确的。不管怎样,How to hide warning "Illegal reflective access" in java 9 without JVM argument? 可能会很有趣。

对于 Java 8,您需要侵入 Lookup 类以获取适当的查找实例。 This answer 表示解决方案,here 是另一种方法。

【讨论】:

  • 我通过您提供的代码解决了问题。我还尝试使用 defineAnonymousClass(Class>, byte[], Object[]) 和我创建并注入 Class.class 的 java.lang.MemberSupplier 类,但是一旦创建了这个类,我必须使用反射来调用方法
猜你喜欢
  • 2013-01-23
  • 1970-01-01
  • 2013-03-13
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
  • 2016-09-09
  • 1970-01-01
  • 2014-08-06
相关资源
最近更新 更多