关于 Android 突破非 SDK 接口限制的延伸
从 Android9 开始,系统开始针对非 SDK 接口做限制。
在国内做 Android 开发的都经历过,如果想要实现一些黑科技,性能优化,或者沙箱等功能,常常需要反射一些隐藏接口。随着安卓开发生态的逐渐规范化,以及系统的性能与安全性的提升,一方面不再允许直接调用非 SDK 接口避免安全与稳定性问题,另一方面也无需通过黑科技来提升应用的性能。
然而,国内的应用开发,尤其是多年的老产品,包含了大量的祖传代码。直接全方面修改需要很高的开发成本,甚至由于无百分百替代方案需要修改产品逻辑。除非是功能完全失效,否则做这类兼容对业务“有害无益”(即,消耗了资源但没有提升业务价值)。
而且,非 SDK 接口的限制通常会区分等级,随 TargetSdkVersion 的提升扩大限制范围。尤其是每一两年,应用市场或有关部门,都会要求活跃的应用必须提升 TargetSdkVersion 才能上架或升级,就导致做相应的适配成为一件必须关注的事情。
有一位技术大神 weishu,曾经在自己的博客中连载两篇分析如何突破限制,并开源了相关代码。
一种绕过 Android P 对非 SDK 接口限制的简单方法https://weishu.me/2018/06/07/free-reflection-above-android-p/
另一种绕过 Android P 以上非公开 API 限制的办法https://weishu.me/2019/03/16/another-free-reflection-above-android-p/
Github - FreeReflectionhttps://github.com/tiann/FreeReflection
通过查看代码可知,目前所使用的方案,是通过“元反射”去反射被限制的接口,欺骗系统,假装是系统自己的调用以突破限制(毕竟很多隐藏 API 只是不给三方应用调用,并不是功能失效)。
此外,博客和代码里还有修改内存的方案,改变内存变量值以突破限制。这个方案并没有被实际调用,可能是因为风险较高。目标变量的内存的地址是通过其他变量的相对位置来锁定的,系统升级或厂商定制后数据结构若发生改变,就可能导致未知错误。
当然,最坏的情况还是后续系统升级,判断是否限制的逻辑发生改变,还需要重新适配。
技术细节补充
博客里提到了 fn_caller_is_trusted 这个条件,但并没有给出这个变量的具体逻辑,这里补充下。
首先,fn_caller_is_trusted 是作为参数传进来的,GetMemberAction 方法调用方式 java_lang_Class.cc。
java_lang_Class.cc 中的流程,Class_getDeclaredMethodInternal -> ShouldBlockAccessToMember -> hidden_api.h GetMemberAction
IsCallerTrusted 是一个方法。通过调用栈解析(WalkStack),获取到当前方法的调用者 caller,并调用到 hidden_api.h 的 IsCallerTrusted。
回到 hidden_api.h,如果 caller 的 dex 是系统的 dex,那么就会放过,属于可信 caller。
所以,当使用“元反射”去反射目标接口时,Class 所属的 dex 必然就是系统的 dex,从而绕过限制。
版权声明: 本文为 InfoQ 作者【XCG00】的原创文章。
原文链接:【http://xie.infoq.cn/article/81c04887c4a6dfac4cf122263】。文章转载请联系作者。
评论