听说你想在Android P上使用hide api?

7,315 阅读3分钟

前言

从 Android 9(API 级别 28)开始,此平台对应用能使用的非 SDK 接口实施了限制。只要应用引用非 SDK 接口或尝试使用反射或 JNI 来获取其句柄,这些限制就适用。这些限制旨在帮助提升用户体验和开发者体验,为用户降低应用发生崩溃的风险,同时为开发者降低紧急发布的风险

一条消息瞬间席卷了整个开发圈子。会不会影响插件化?会不会影响热修复?好在,对这些没影响。然而,对一些非常hacker的手段,还是有着不小的影响,比如上一篇的DNS hook libcore的方案。那么,我们如何解决呢?

针对非 SDK 接口的限制

如果大家不了解这个限制,可以先去针对非 SDK 接口的限制这个文档中了解一下,这里简单的说一下。当我们访问受限的接口时,会出现如下情况。

那么,如何检查你的应用中是否有使用受限的接口呢。我们可以使用veridex工具进行查看。用法如下

### Linux x64
Download veridex-linux.zip, unzip the file and run with:
> ./appcompat.sh --dex-file=test.apk
### macOS
Download veridex-mac.zip, unzip the file and run with:
> ./appcompat.sh --dex-file=test.apk

经过检查,如果发现没有使用,那便是极好的,但是!!!如果使用了且无可替代怎么办?办他!

解除限制的原理

很早之前,360团队就出了两篇文章。 Android P 调用隐藏API限制原理 以及 突破Android P(Preview 1)对调用隐藏API限制的方法 。这两篇文章也是我们下面方案的原理来源。

方法一(不建议)

这个方法一对应的是360文章中的方法三。主要代码如下。

其中,fake_dlopen、fake_dlsym 使用的是Nougat_dlfunctions,主要是Android 7.0以上对dlopen、dlsym等函数做了限制。因此用这个库。而MSHookFunction,则是大名鼎鼎的cydiasubstrate

上面的代码只解决了反射方法的问题。我按照这种思路去解决字段问题的时候发现。

GetDeclaredField是inline的,无法切入。而CreateFromArtField又是hidden的,也不好切入。

因此,放弃了这种方法。

方法二(可用,但是有更好的)

这里对应的方法二,对应的是360文章中的方法二,也就是修改classloader的方式。代码如下。

没错,代码就是这么点。这样,我们就可以在ReflectionHelper中调用非公开API了。但是这里会依赖Nougat_dlfunctions这个库。

方法三(超级好)

既然是修改classloader,那么我们为什么不在java层修改呢。代码如下。

而这里用的相关反射只是light级别的,没有什么影响。反而代码量超小,也不依赖其他。

方法四(超级好+1)

这个方案来自 @区长 大神

方法四还是存在一点问题。如果以后把classloader加入到深灰或者黑名单,那就僵硬了。所以,我们不用反射,直接用unsafe去修改。代码这就不贴了。为了得到classloader的偏移量,我们写一个和Class结构一样的类,用这个类得到的classLoader的偏移量和Class是一样的。

方法五

田维术 VMRuntime.setHiddenApiExemptions 方法,链接在这里点我查看

觉得写的还行的朋友可以关注以下我的微信公众号,这里用于交流一些Android基础架构、疑难杂症、面试等等问题。