绕过Android的隐藏API限制 [英] Bypass Android's hidden API restrictions

查看:952
本文介绍了绕过Android的隐藏API限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从Android Pie开始,访问某些隐藏类,方法和字段受到限制.在使用Pie之前,仅通过反射即可使用这些隐藏的非SDK组件非常容易.

Starting with Android Pie, access to certain hidden classes, methods and fields was restricted. Before Pie, it was pretty easy to use these hidden non-SDK components by simply using reflection.

但是,现在,尝试访问Activity#createDialog()之类的组件时,面向API 28(Pie)或更高版本的应用将遇到ClassNotFoundException,NoSuchMethodError或NoSuchFieldException.对于大多数人来说,这很好,但是作为喜欢使用该API的人,这可能会使事情变得困难.

Now, however, apps targeting API 28 (Pie) or later will be met with ClassNotFoundException, NoSuchMethodError or NoSuchFieldException when trying to access components such as Activity#createDialog(). For most people this is fine, but as someone who likes to hack around the API, it can make things difficult.

如何解决这些限制?

推荐答案

UPDATE 2

似乎有人已经破坏了Android 11的隐藏API黑名单.我还无法亲自测试它,它也不是纯Java解决方案,但这是源代码: https ://github.com/ChickenHook/RestrictionBypass .

以下是其工作方式的说明: https://androidreverse.wordpress.com/2020/05/02/android-api-restriction-bypass-for-all-android-versions/.

And here's a description of how it works: https://androidreverse.wordpress.com/2020/05/02/android-api-restriction-bypass-for-all-android-versions/.

Google已使用Android 11加强了API限制.以下使用JNI和Java的方法将不再适用于定位API 30或更高版本的应用程序.

Google has hardened the API restrictions with Android 11. The methods below using JNI and Java will no longer work in apps targeting API 30 or later.

实际上有几种方法可以做到这一点.

There are actually a few ways to do this.

出于测试目的,Google内置了一种在给定的Android设备上全局禁用隐藏API限制的方式.问题链接的标题为如何启用对非SDK接口的访问权限?的内容如下:

Google built in a way to disable the hidden API restrictions globally on a given Android device, for testing purposes. The section in the link in the question titled How can I enable access to non-SDK interfaces? says the following:

您可以使用以下adb命令来更改API实施策略,从而在开发设备上启用对非SDK接口的访问:

You can enable access to non-SDK interfaces on development devices by changing the API enforcement policy using the following adb commands:

adb shell settings put global hidden_api_policy_pre_p_apps  1
adb shell settings put global hidden_api_policy_p_apps 1

要将API实施策略重置为默认设置,请使用以下命令:

To reset the API enforcement policy to the default settings, use the following commands:

adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps

这些命令不需要root用户的设备.

These commands do not require a rooted device.

您可以将API强制策略中的整数设置为以下值之一:

You can set the integer in the API enforcement policy to one of the following values:

  • 0:禁用所有非SDK接口检测.使用此设置将禁用所有非SDK接口使用的日志消息,并阻止您使用StrictMode API测试应用.不建议使用此设置.
  • 1:启用对所有非SDK接口的访问,但会打印日志消息,并带有警告,警告所有非SDK接口使用情况.使用此设置还可以使您使用StrictMode API测试应用.
  • 2:禁止使用属于黑名单或灰名单且受目标API级别限制的非SDK接口.
  • 3:禁止使用属于黑名单的非SDK接口,但允许使用属于灰名单且受目标API级别限制的接口.

(在Q beta中,现在似乎只有一把钥匙:hidden_api_policy.)

(On the Q betas, there seems to be only one key now: hidden_api_policy.)

(在我的测试中,更改此设置后,您的应用需要完全重新启动-已终止进程-才能生效.)

(In my testing, after changing this setting, your app needs to be fully restarted—process killed–for it to take effect.)

您甚至可以使用Settings.Global.putInt(ContentResolver, String, Int)在应用程序内部更改此设置.但是,它要求应用程序拥有WRITE_SECURE_SETTINGS权限,该权限仅自动授予签名级或特权应用程序.可以通过亚行手动授予它.

You can even change this from inside an app with Settings.Global.putInt(ContentResolver, String, Int). However, it requires the app to hold the WRITE_SECURE_SETTINGS permission, which is only automatically granted to signature-level or privileged apps. It can be manually granted through ADB.

安全设置方法非常适合测试或用于个人应用程序,但是如果要将您的应用程序分发到您无法控制的设备上,则试图指导最终用户如何使用ADB可能是一场噩梦,甚至如果他们已经知道该怎么办,那就不方便了.

The secure settings method is good for testing or for personal apps, but if your app is meant to be distributed to devices you don't control, trying to instruct end users on how to use ADB can be a nightmare, and even if they already know what to do, it's inconvenient.

幸运的是,实际上,有一种方法可以使用本机代码中的一些巧妙技巧来禁用应用程序的API限制.

Luckily, there is actually a way to disable the API restrictions for your app, using some clever tricks in native code.

在您的JNI_OnLoad()方法中,您可以执行以下操作:

Inside your JNI_OnLoad() method, you can do the following:

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检查,而无需任何特殊权限.

This will disable the hidden API checks for you, without any special permissions.

来源

还有一个库可供您使用: https://github.com/tiann/FreeReflection/

There's also a library you can use that will do this for you: https://github.com/tiann/FreeReflection/

JNI并不适合所有人(包括我).它还需要您为不同的体系结构使用单独的应用程序版本.幸运的是,还有一个纯Java解决方案.

JNI isn't for everyone (including me). It also needs you to have separate versions of your app for different architectures. Luckily, there is also a pure-Java solution.

Android的隐藏API限制仅适用于未由平台签名签名且未在/system/etc/sysconfig/中手动列入白名单的第三方应用.这意味着该框架(显然)可以访问它想要的任何隐藏方法,而这正是该方法所利用的.

Android's hidden API restrictions only apply to third party apps that aren't signed by the platform signature and aren't manually whitelisted in /system/etc/sysconfig/. What this means is that the framework (obviously) can access any hidden methods it wants, which is what this method takes advantage of.

这里的解决方案是使用双反射(或元反射",正如经翻译的源称其).这是一个示例,它检索一个隐藏的方法(在Kotlin中):

The solution here is to use double-reflection (or "meta-reflection," as the translated source calls it). Here's an example, retrieving a hidden method (in 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,我们可以通过两次反射来做到这一点.

Now, this could stand as a good enough solution on its own, but it can be taken a step further. The class dalvik.system.VMRuntime has a method: setHiddenApiExemptions(vararg methods: String). Simply passing "L" to this method will exempt all hidden APIs, and we can do that with double-reflection.

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.

Put that code in your Application class' onCreate() method, for example, and then you'll be able to use hidden APIs like normal.

有关此示例的完整Java示例,请查看JNI部分中链接的FreeReflection库,或遵循下面的源代码.

For a full Java example of this, check out the FreeReflection library linked in the JNI section, or follow through the source below.

来源

这篇关于绕过Android的隐藏API限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆