Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

android5 对继承自android.view.MenuInflater的类中的getRealOwner方法进行重写,并vmp加固后出现错误,E/art ( 4011): Failed to register non-native method com.andpos.myapplication.TestMenuInflater.getRealOwner()Ljava/lang/Object; as native #29

Closed
AdenTk opened this issue Jan 10, 2022 · 13 comments
Labels
bug Something isn't working

Comments

@AdenTk
Copy link

AdenTk commented Jan 10, 2022

我在测试应用中创建了一个类为TestMenuInflater,继承自android.view.MenuInflater,并重写了getRealOwner方法,在MainActivity中调用了该方法,使用加固工程对该方法进行vmp化,发现出现Failed to register non-native method的错误。
1、对系统源码进行分析,发现在Android5下的art/runtime/jni_internal.cc的RegisterNativeMethods会抛出该错误
2、在RegisterNativeMethods方法中出现mirror::ArtMethod* m = c->FindDirectMethod(name, sig);跟踪进去

for (Class* klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
   ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature);
  if (method != nullptr) {
      return method;
   }
}
return nullptr;

发现会再jclass中寻找FindDeclaredDirectMethod,如果找不到会从klass = klass->GetSuperClass()父类中寻找,即MenuInflater获取得到getRealOwner,但是该方法中未发现accessflag为native,所以会报non-native method错误。
3、以上类似的问题相信会有很多,问题都是继承自android sdk中的公共类,然后重写其中的DirectMethod,进行vmp化。
4、经测试在android8未发现该问题,并且他在注册动态jni函数的函数与android5不一样。
5、请问下,针对在android5上面这个问题该如何解决呢?

@AdenTk
Copy link
Author

AdenTk commented Jan 10, 2022

以下为TestMenuInflater代码

import android.content.Context;
import android.view.MenuInflater;

public class TestMenuInflater extends MenuInflater {
    public TestMenuInflater(Context context) {
        super(context);
    }

    Object getRealOwner(){
        return null;
    }
}

在MainActivity中的调用方式为

TestMenuInflater testMenuInflater = new TestMenuInflater(MainActivity.this);
testMenuInflater.getRealOwner();

@maoabc
Copy link
Owner

maoabc commented Jan 10, 2022

写了个简单测试,复现了。只在api 21和22上有这个问题,这两个版本查找方法时先查找当前类的direct method,当前类没找到会查找父类的direct method,都没找到才会再查找当前类的virtual method。正确的查找逻辑应该是先查找当前类的direct method和virtual method,当前类找不到才会找父类。

目前想到的解决方法,感觉可以先解析manifest找到最低api版本,如果低于23则对所有class分析,找出所有类似的关系,处理时跳过这些方法

@maoabc
Copy link
Owner

maoabc commented Jan 10, 2022

还有一种方式是,找到有这类问题的方法,原方法不进行native而是生成一个不重名的新native方法,原方法调用这个native方法。

@maoabc maoabc added the bug Something isn't working label Jan 10, 2022
@AdenTk AdenTk closed this as completed Jan 11, 2022
@AdenTk
Copy link
Author

AdenTk commented Jan 11, 2022

还有一种方式是,找到有这类问题的方法,原方法不进行native而是生成一个不重名的新native方法,原方法调用这个native方法。

嗯嗯。感觉这种方式会比较好,但是相应的也是一个体力活

@AdenTk AdenTk reopened this Jan 11, 2022
@maoabc
Copy link
Owner

maoabc commented Jan 11, 2022

处理dex要比较大的改动,同时还得把安卓5的sdk一起引入找出这类方法,后面抽时间试试

maoabc added a commit that referenced this issue Jan 12, 2022
增加android5(21/22)兼容. #29
@maoabc
Copy link
Owner

maoabc commented Jan 12, 2022

调整了dex处理, 目前能分析自身class里包含的这种问题的方法. 初步实现后面继续改, 后面需要把android 5的sdk用dx或者d8转换为dex,加入一起分析才能完全找出.

maoabc added a commit that referenced this issue Jan 14, 2022
@AdenTk
Copy link
Author

AdenTk commented Jan 17, 2022

还有一种情况,不是直接继承androidsdk的类,而是一个类有多层继承关系,到继承最顶部的超类为android sdk,并且各个类分布在不同的dex中,则需要联合判断。

例如:
类A继承类B
类B继承类C
类C继承类D
类D继承类android.view.MenuInflater
类A,类B在classes.dex
类C,类D在classes2.dex
加固的方法还是为getRealOwner方法,则需要联合多个dex进行分析,不然还是会出现non-native

本来我想帮忙修复的,到这一步,感觉就有点难了,得改整个代码,而不是添加代码的问题

@maoabc
Copy link
Owner

maoabc commented Jan 17, 2022

已经能处理了,完整加载所有类就行,再进一步分析加入android sdk

@AdenTk
Copy link
Author

AdenTk commented Jan 17, 2022

请问android sdk你是准备怎么取得,直接使用android sdk中的source code还是使用源码编译的framework.jar,我目前是直接从android sdk中的source code中的文件逐个获取类名,然后在android工程里去加载类,并从中记录非final的类,及其对应的direct方法。

@maoabc
Copy link
Owner

maoabc commented Jan 17, 2022

直接用class吧,r8或者d8就能处理

@maoabc
Copy link
Owner

maoabc commented Jan 17, 2022

最极端也可以不去判断,直接对所以virtual method生成一个不重名native方法。

@AdenTk
Copy link
Author

AdenTk commented Jan 17, 2022

最极端也可以不去判断,直接对所以virtual method生成一个不重名native方法。

但如果类里面有很多方法需要加密,会导致生成较多的方法

@AdenTk
Copy link
Author

AdenTk commented Jan 17, 2022

对了,我有试过一个类里面有10000个方法去测试你的vmp加固,会出现stack size 最大为8M的错误,仅仅加固了那个类里的一个方法而已,就会报错

@AdenTk AdenTk closed this as completed Jan 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants