另一种绕过 -Android-P 以上非公开 API 限制的办法,安卓多线程面试题
以系统类的身份去反射 有两个意思,1. 直接把我们自己变成系统类;2. 借助系统类去调用反射。我们一个个分析。
「直接把我们自己变成系统类」这个方式有童鞋可能觉得天方夜谭,APP 的类怎么可能成为系统类?但是,一切皆有可能!我们知道,对 APP 来说,所谓的系统类就是被 BootstrapClassLoader 加载的类,这个 ClassLoader 并非普通的 DexClassLoader,因此我们无法通过插入 dex path 的方式注入类。但是,Android 的 ART 在 Android O 上引入了 JVMTI,JVMTI 提供了将某一个类转换为 BootstrapClassLoader 中的类的方法!具体来说,我们写一个类暴露反射相关的接口,然后通过 JVMTI 提供的 AddToBootstrapClassLoaderSearch
将此类加入 BootstrapClassLoader 就实现目的了。不过,JVMTI 要在 release 版本的 APP 上运行依然需要 Hack,所以这种途径与其他的黑科技无本质区别。关于 JVMTI 可以参考我这个回答:
[Android Studio 3.5 提供的”Apply Changes“是什么原理??www.zhihu.com[图片上传失败...(image-87cb61-1590133002486)]](
)
第二种方法,「借助系统的类去反射」也就是说,如果系统有一个方法systemMethod
,这个systemMethod
去调用反射相反的方法,那么systemMethod
毋庸置疑会反射成功。但是,我们从哪去找到这么一个方法给我们用?事
实上,我们不仅能找到这样的方法,而且这个方法能帮助我们调用任意的函数,那就是****反射本身!****可能你已经绕晕了,我解释一下:
首先,我们通过反射 API 拿到
getDeclaredMethod
方法。getDeclaredMethod
是 public 的,不存在问题;这个通过反射拿到的方法我们称之为元反射方法。然后,我们通过刚刚反射拿到元反射方法去反射调用
getDeclardMethod
。这里我们就实现了以系统身份去反射的目的——反射相关的 API 都是系统类,因此我们的元反射方法也是被系统类加载的方法;所以我们的元反射方法调用的getDeclardMethod
会被认为是系统调用的,可以反射任意的方法。
伪代码如下:
Method metaGetDeclaredMethod =Class.class.getDeclaredMethod("getDeclardMethod"); // 公开 API,无问题 Method hiddenMethod = metaGetDeclaredMethod.invoke(hiddenClass,"hiddenMethod", "hiddenMethod 参数列表"); // 系统类通过反射使用隐藏 API,检查直接通过。hiddenMethod.invoke // 正确找到 Method 直接反射调用
到这里,我们已经能通过「元反射」的方式去任意获取隐藏方法或者隐藏 Field 了。但是,如果我们所有使用的隐藏方法都要这么干,那还有点小麻烦。在?[上文](
)?中,我们后来发现,隐藏 API 调用还有「豁免」条件,具体代码如下:
if (shouldWarn || action == kDeny) {if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) {action = kAllow;// Avoid re-examining the exemption list next time.// Note this results in no warning for the member, which seems like what one would expect.// Exemptions effectively adds new members to the whitelist.MaybeWhitelistMember(runtime, member);return kAllow;}// 略
}
只要 IsExempted
方法返回 true,就算这个方法在黑名单中,依然会被放行然后允许被调用。我们再观察一下IsExempted
方法:
bool MemberSignature::IsExempted(const std::vectorstd::string& exemptions) {for (const std::string& exemption : exemptions) {if (DoesPrefixMatch(exemption)) {return true;
评论