实际上有几种方法可以做到这一点。
安全设置
出于测试目的,Google 构建了一种在给定 Android 设备上全局禁用隐藏 API 限制的方法。标题为问题的链接中的部分如何启用对非 SDK 接口的访问?说如下:
您可以通过使用以下 adb 命令更改 API 强制策略来启用对开发设备上非 SDK 接口的访问:
adb shell settings put global hidden_api_policy_pre_p_apps 1
adb shell settings put global hidden_api_policy_p_apps 1
要将 API 强制策略重置为默认设置,请使用以下命令:
adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps
这些命令不需要 root 设备。
您可以将 API 强制策略中的整数设置为以下值之一:
- 0:禁用所有非SDK接口的检测。使用此设置会禁用非 SDK 接口使用的所有日志消息,并阻止您使用 StrictMode API 测试应用程序。不推荐此设置。
- 1:允许访问所有非 SDK 接口,但打印日志消息,并对任何非 SDK 接口使用情况发出警告。使用此设置还允许您使用 StrictMode API 测试您的应用程序。
- 2:禁止使用属于黑名单或灰名单且受您的目标 API 级别限制的非 SDK 接口。
- 3:禁止使用属于黑名单的非SDK接口,但允许使用属于灰名单且受您的目标API级别限制的接口。
(在 Q beta 上,现在似乎只有一个键:hidden_api_policy
.)
(在我的测试中,更改此设置后,您的应用程序需要完全重新启动(进程被终止)才能生效。)
您甚至可以从应用程序内部更改此设置Settings.Global.putInt(ContentResolver, String, Int)
。但是,它要求应用程序持有WRITE_SECURE_SETTINGS
权限,仅自动授予签名级别或特权应用程序。可以通过 ADB 手动授予。
JNI
所有 API,包括 API 30 及更高版本
之前的方法仅适用于面向 API 29 及更低版本的应用程序。对于面向 API 30 及更高版本的应用程序,请使用此库:https://github.com/ChickenHook/RestrictionBypass https://github.com/ChickenHook/RestrictionBypass.
我不完全理解这是如何工作的,但它似乎滥用了 JNI 内部 Java 线程的创建来设置当前应用程序的隐藏 API 豁免策略以允许访问所有隐藏 API。
以下是其工作原理的完整描述:https://androidreverse.wordpress.com/2020/05/02/android-api-restriction-bypass-for-all-android-versions/ https://androidreverse.wordpress.com/2020/05/02/android-api-restriction-bypass-for-all-android-versions/.
使用方法很简单。确保您已将 JitPack 添加到您的存储库中(在项目级别build.gradle
):
allprojects {
repositories {
[..]
maven { url "https://jitpack.io" }
}
}
然后实现该库:
implementation 'com.github.ChickenHook:RestrictionBypass:2.2'
它会自动为您解除 API 限制。
API 29 及更早版本
安全设置方法非常适合测试或个人应用程序,但如果您的应用程序旨在分发到您无法控制的设备上,则尝试指导最终用户如何使用 ADB 可能是一场噩梦,即使他们已经知道要做什么,很不方便。
幸运的是,实际上有一种方法可以在本机代码中使用一些巧妙的技巧来禁用应用程序的 API 限制。
在你的里面JNI_OnLoad()
方法,您可以执行以下操作:
static art::Runtime* runtime = nullptr;
extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) {
...
runtime = reinterpret_cast<art::JavaVMExt*>(vm)->GetRuntime();
runtime->SetHiddenApiEnforcementPolicy(art::hiddenapi::EnforcementPolicy::kNoChecks);
...
}
这将为您禁用隐藏的 API 检查,无需任何特殊权限。
Source https://blog.quarkslab.com/android-runtime-restrictions-bypass.html
您还可以使用一个库来为您执行此操作:https://github.com/tiann/FreeReflection/ https://github.com/tiann/FreeReflection/
纯 Java/Kotlin
JNI 并不适合所有人(包括我)。它还需要您为不同的架构提供单独的应用程序版本。幸运的是,还有纯 Java 解决方案。
所有 API,包括 API 30 及更高版本
LSPosed(流行的 Xposed 框架的替代品)背后的团队提出了一个纯 Java 解决方案,用于绕过针对 API 28 或更高版本的应用程序的隐藏 API 限制。
该库位于他们的 GitHub 上:https://github.com/LSPosed/AndroidHiddenApiBypass https://github.com/LSPosed/AndroidHiddenApiBypass.
解释是中文的,但大意似乎是这样的。该库使用 Java 的 Unsafe API 作为反射的替代方案。然后,它的工作方式与 API 29 及更早版本的方法非常相似,允许用户设置隐藏的 API 豁免。
要使用它,只需实现该库:
implementation 'org.lsposed.hiddenapibypass:hiddenapibypass:2.0'
然后在应用程序启动时设置隐藏的 API 豁免:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
HiddenApiBypass.addHiddenApiExemptions("L");
}
API 29 及更早版本
Android隐藏API限制仅适用于未经平台签名且未手动列入白名单的第三方应用程序/system/etc/sysconfig/
。这意味着框架(显然)可以访问它想要的任何隐藏方法,这就是该方法所利用的。
这里的解决方案是使用双重反射(或翻译源称之为“元反射”)。下面是一个检索隐藏方法的示例(在 Kotlin 中):
val getDeclaredMethod = Class::class.java.getDeclaredMethod("getDeclaredMethod", String::class.java, arrayOf<Class<*>>()::class.java)
val someHiddenMethod = getDeclaredMethod.invoke(SomeClass::class.java, "someHiddenMethod", Param1::class.java, Param2::class.java)
val result = someHiddenMethod.invoke(someClassInstance, param1, param2)
现在,这本身就是一个足够好的解决方案,但还可以更进一步。班上dalvik.system.VMRuntime
有一个方法:setHiddenApiExemptions(vararg methods: String)
。简单的路过"L"
此方法将免除所有隐藏的 API,我们可以通过双重反射来做到这一点。
val forName = Class::class.java.getDeclaredMethod("forName", String::class.java)
val getDeclaredMethod = Class::class.java.getDeclaredMethod("getDeclaredMethod", String::class.java, arrayOf<Class<*>>()::class.java)
val vmRuntimeClass = forName.invoke(null, "dalvik.system.VMRuntime") as Class<*>
val getRuntime = getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null) as Method
val setHiddenApiExemptions = getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", arrayOf(arrayOf<String>()::class.java)) as Method
val vmRuntime = getRuntime.invoke(null)
setHiddenApiExemptions.invoke(vmRuntime, arrayOf("L"))
将该代码放入您的应用程序类中'onCreate()
例如,您将能够像平常一样使用隐藏的 API。
有关完整的 Java 示例,请查看 JNI 部分中链接的 FreeReflection 库,或按照下面的源代码进行操作。
Source http://weishu.me/2019/03/16/another-free-reflection-above-android-p/