引言
从Andriod P
开始,对应用能使用的非 SDK 接口实施了限制,具体可参考官方简介:https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces?hl=zh-cn
黑名单、灰名单和白名单
当您的应用尝试访问黑名单中的非 SDK 接口时可能会出现的预期异常:
内部API限制代码分析
Android P
限制APP对内部API的调用,而内部API只能通过反射或JNI间接调用,那么限制机制必然是在反射和JNI方法调用链中插入判断逻辑。
这里以Class.java
中的反射获取函数的getDeclaredMethod()
为例来展开说明,其他反射或JNI调用也是类似的逻辑。
代码参考自AOSP
中:Android-9.0.0_r1\bin\Work\libcore\ojluni\src\main\java\java\lang\Class.java
==》getMethod(String name, Class<?>[] parameterTypes, boolean recursivePublicMethods)
中第二个参数表示是否为public函数
,上面传的是false
, 继续看下面的代码:
==》因为recursivePublicMethods
传入的为false
,所以会调用getDeclaredMethodInternal
,这是一个native
函数
==》跳转到NDK的Class_getDeclaredMethodInternal
代码参考自AOSP
中:Android-9.0.0_r1\Android-9.0.0_r1\bin\Work\art\runtime\native\java_lang_Class.cc
==》跳转到ShouldBlockAccessToMember
==》关键函数hiddenapi::GetMemberAction
代码参考自AOSP
中:Android-9.0.0_r1\Android-9.0.0_r1\bin\Work\art\runtime\hidden_api.h
这里可以看出绕过隐藏API的方式有多种
可以从GetHiddenApiAccessFlags
入手,也可以从GetMemberActionImpl
入手
enum Action {
kAllow,
kAllowButWarn,
kAllowButWarnAndToast,
kDeny
};
==》关键函数1GetHiddenApiAccessFlags
==》关键函数2GetMemberActionImpl
绕过内部API限制
用cp
命令拷贝出libart.so
,没有真机,就使用模拟器中的libart.so
C:\Users\Administrator>adb shell
generic_x86:/ # cd /system/
2|generic_x86:/system # cd ./lib
127|generic_x86:/system/lib # cp ./libart.so /sdcard/
127|generic_x86:/ $ exit
C:\Users\Administrator>adb pull /sdcard/libart.so
/sdcard/libart.so: 1 file pulled. 50.6 MB/s (8064080 bytes in 0.152s)
使用IDA打开,从前面我们可以看出,关键函数是hiddenapi::GetMemberAction
,IDA搜索hiddenapi::GetMemberAction
跳转到函数体:
hook这两个函数就好了,记得要取真实的符号名字,右键Edit function
,就可以看到Name of function
其中detail::GetMemberActionImpl
有两个,分别对应符号名字为_ZN3art9hiddenapi6detail19GetMemberActionImplINS_8ArtFieldEEENS0_6ActionEPT_NS_20HiddenApiAccessFlags7ApiListES4_NS0_12AccessMethodE
_ZN3art9hiddenapi6detail19GetMemberActionImplINS_9ArtMethodEEENS0_6ActionEPT_NS_20HiddenApiAccessFlags7ApiListES4_NS0_12AccessMethodE
VA做的操作就是把这几个关键函数做了hook