ByteBuddy – 无法拦截超类的静态方法

huangapple go评论86阅读模式
英文:

ByteBuddy - unable to intercept static method from superclass

问题

我正在为 Android 开发命令行工具(类似于 am),尝试利用 ByteBuddy 的功能来桩化 android.security.KeyStore 中定义的静态方法 getApplicationContext

然而,当我在子类化 android.security.KeyStore 并使用 ByteBuddy 的 getDeclaredMethods 时,该方法似乎对 ByteBuddy 不可见,因此无法进行拦截。

当我使用反射 API 中的 getMethods 时,我能够列出该方法。

            Class AndroidKeyStore = Class.forName("android.security.KeyStore");
            Method[] keyStoreMethods =  new ByteBuddy()
                      .with(TypeValidation.DISABLED)
                      .subclass(AndroidKeyStore, ConstructorStrategy.Default.IMITATE_SUPER_CLASS)
                      .name("KeyStoreMasker")
                      .method(ElementMatchers.named("getApplicationContext"))
                      .intercept(SuperMethodCall.INSTANCE)
                      .make()
                      .load(getClass().getClassLoader(),
                            new AndroidClassLoadingStrategy
                            .Injecting(new File("/data/app/cmdutil")))
                      .getLoaded()
                      .getDeclaredMethods();
            for(i = 0; i < keyStoreMethods.length; i++) {
                System.out.println("method = " + keyStoreMethods[i].toString());
            }

当运行上述代码时,我预期在子类中应该有一个方法 - getApplicationContext。然而,子类中却没有任何方法。

如果将对 getDeclaredMethods 的调用替换为 getMethods,我能够列出超类的所有公共方法。

将拦截的方法替换为非静态方法(例如 "state"),我能够使用 ByteBuddy 的 getDeclaredMethods 函数列出该方法:

>在 keyStoreMethods 中声明的方法数量:2
>
>method = public android.security.KeyStore$State AndroidKeyStoreMasker.state()
>
>method = public android.security.KeyStore$State AndroidKeyStoreMasker.state(int)

因此,我的最终结论是 ByteBuddy(或我使用 ByteBuddy 的情况)在处理静态方法可见性方面存在一些问题。

android.security.KeyStore.java 的参考链接:
<https://android.googlesource.com/platform/frameworks/base/+/master/keystore/java/android/security/KeyStore.java>

非常感谢任何提供帮助的支持。

英文:

I'm working on command line tool for Android (think of am), trying to utilize the power of ByteBuddy to stub the static method getApplicationContext defined in android.security.KeyStore

However - the method seem to be invisible to ByteBuddy getDeclaredMethods when subclassing the android.security.KeyStore and hence it is unable to intercept it.

When using getMethods from the reflection API i'm able to list the method.

            Class AndroidKeyStore = Class.forName(&quot;android.security.KeyStore&quot;);
            Method[] keyStoreMethods =  new ByteBuddy()
                      .with(TypeValidation.DISABLED)
                      .subclass(AndroidKeyStore, ConstructorStrategy.Default.IMITATE_SUPER_CLASS)
                      .name(&quot;KeyStoreMasker&quot;)
                      .method(ElementMatchers.named(&quot;getApplicationContext&quot;))
                      .intercept(SuperMethodCall.INSTANCE)
                      .make()
                      .load(getClass().getClassLoader(),
                            new AndroidClassLoadingStrategy
                            .Injecting(new File(&quot;/data/app/cmdutil&quot;)))
                      .getLoaded()
                      .getDeclaredMethods();
            for(i = 0; i &lt; keyStoreMethods .length; i++) {
                System.out.println(&quot;method = &quot; + keyStoreMethods[i].toString());
            }

When running the above, I was expecting to have a single method - getApplicationContext in the subclass. However the subclass doesn't contain any methods.

Replacing the call to getDeclaredMethods by getMethods I'm able to list all public method of the superclass.

By replacing the intercepted method to a non-static one (for example "state"), i'm able to list the method using ByteBuddy's getDeclaredMethods function:

>Number of declared methods in keyStoreMethods: 2
>
>method = public android.security.KeyStore$State AndroidKeyStoreMasker.state()
>
>method = public android.security.KeyStore$State AndroidKeyStoreMasker.state(int)

So my final conclusion is that ByteBuddy (or my usage case with ByteBuddy) has some issue with static method visibility.

Reference to android.security.KeyStore.java:
<https://android.googlesource.com/platform/frameworks/base/+/master/keystore/java/android/security/KeyStore.java>

Any help would be much appreaciated.

答案1

得分: 2

创建subclass时,Byte Buddy只能拦截由子类直接声明的方法或超类的虚方法。这是JVM的工作原理,static方法会直接在接收器上分派。

Byte Buddy还能够重新定义和重新转换现有类,但这需要一个Java代理,在Android上不可用。因此,恐怕您需要找到一个非静态的挂钩点来实现您的目标。或者,您可以查看MemberSubstitution,您可以从您的代码中重定向这些调用。这也需要重新转换,但由于它发生在您的代码中,您可以使用Byte Buddy的构建插件。

英文:

When creating a subclass, Byte Buddy is only able to intercept methods directly declared by a subclass or virtual methods of super classes. This is how the JVM works, static methods are dispatched directly on the receiver.

Byte Buddy is capable of redefining and retransforming existing classes, too, but this requires a Java agent which is not available on Android. Therefore, I am afraid that you need to find a non-static hook point to accomplish what you are trying. Alternatively, have a look at the MemberSubstitution where you can redirect such calls from your code. This also requires a retransformation but since it happens in your code, you can use Byte Buddy's build plugin.

huangapple
  • 本文由 发表于 2020年5月3日 18:18:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/61572835.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定