绕过Android隐藏的API限制

2024-02-04

从 Android Pie 开始,对某些隐藏类、方法和字段的访问受到限制 https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces。在 Pie 之前,只需使用反射即可轻松使用这些隐藏的非 SDK 组件。

但是现在,针对 API 28 (Pie) 或更高版本的应用程序在尝试访问以下组件时将遇到 ClassNotFoundException、NoSuchMethodError 或 NoSuchFieldExceptionActivity#createDialog()。对于大多数人来说这很好,但对于喜欢破解 API 的人来说,这可能会让事情变得困难。

我该如何解决这些限制?


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


安全设置

出于测试目的,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/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

绕过Android隐藏的API限制 的相关文章

  • 如何清除所有WebView存储的信息?

    我有一个 Android 浏览器 我可以选择清除缓存 存储 cookie 等 代码如下所示 webView clearCache true webView clearFormData webView clearHistory webView
  • 使用workmanager时Firestore脱机持久性错误

    我正在使用一个WorkManger定期从我的中检索信息Firestore当应用程序处于后台和前台时的数据库 此信息用于根据状态更新 UI 因此不同的状态会添加或删除 UI 的不同部分 第一次运行时效果很好 但是 一旦应用程序处于后台并且Wo
  • android中向sqlite中插入大量数据

    目前 我必须一次向我的 Android 中插入超过 100 亿条数据 然而 内存不足的问题会使程序崩溃 sqlite 插入测试非常简单 只需使用 for 循环生成 sql 插入命令并通过 开始 和 提交 进行包装 private Array
  • 卸载后 Web 应用程序不显示“添加到主屏幕”

    这是我第一次创建网络应用程序 我设法解决了这个问题 所以我得到了实际的 chrome 提示 将其添加到主屏幕 然后我从手机上卸载了该网络应用程序 因为我想将其展示给我的同事 但是 屏幕上不再出现提示 问题 这是有意为之的行为还是我的应用程序
  • 找不到 com.google.firebase:firebase-core:9.0.0 [重复]

    这个问题在这里已经有答案了 在遵循有些不一致的指示之后here https firebase google com docs admob android quick start name your project and here http
  • 无法获取log.d或输出Robolectrict + gradle

    有没有人能够将 System out 或 Log d 跟踪从 robolectric 测试输出到 gradle 控制台 我在用Robolectric Gradle 测试插件 https github com robolectric robo
  • Android 中 Kotlin 协程的正确使用方式

    我正在尝试使用异步更新适配器内的列表 我可以看到有太多的样板 这是使用 Kotlin 协程的正确方法吗 这个可以进一步优化吗 fun loadListOfMediaInAsync async CommonPool try Long runn
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • 如何使用 Cordova 获取当前安装的应用程序的版本?

    我已经找到了应用程序可用性插件 https github com ohh2ahh AppAvailability它主要检查用户是否在其设备上安装了某个应用程序 是否有可能获得应用程序的当前版本 开发者名称 重要 以及所有可能的信息 一般来说
  • 发布android后更改应用内购买项目的价格

    在 Google Play 上发布后 是否可以更改应用内购买商品的价格 我假设该应用程序也已发布 完整的在线文档位于http developer android com http developer android com也http sup
  • 原色(有时)变得透明

    我正在使用最新的 SDK 版本 API 21 和支持库 21 0 2 进行开发 并且在尝试实施新的材料设计指南时遇到了麻烦 材料设计说我需要有我的primary color and my accent color并将它们应用到我的应用程序上
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 如何使用 IF 检查 TextView 可见性

    我有一个 onCheckedChangeListener 来根据选择的单选按钮显示文本视图 我有 1 个疑问和 1 个难题 想知道是否有人可以帮助我 问题 您能否将单选组默认检查值设置为 否 单选按钮 以便一开始就不会检查任何内容 问题 如
  • 如何发布Android .aar源以使Android Studio自动找到它们?

    我正在将库发布到内部 Sonatype Nexus 存储库 Android Studio 有一个功能 可以自动查找通过 gradle 引用的库的正确源 我将 aar 的源代码作为单独的 jar 发布到 Nexus 但 Android Stu
  • Android Studio - Windows 7 上的 Android SDK 问题

    我对 Google i o 2013 上发布的最新开发工具 Android Studio 有疑问 我已经成功安装了该程序并且能够正常启动 我可以导入现有项目并对其进行编辑 但是 当我尝试单击 SDK 管理器图标或 AVD 管理器图标时 或者
  • Android向menuItem添加子菜单,addSubMenu()在哪里?

    我想根据我的参数以编程方式将 OptionsMenu 内的子菜单添加到 menuItem 中 我检查了android sdk中的 MenuItem 没有addSubMenu 方法 尽管你可以找到 hasSubMenu 和 getSubMen
  • Android 套接字和 asynctask

    我即将开始制作一个应该充当 tcp 聊天客户端的应用程序 我一直在阅读和阅读 我得出的结论是最好 如果不需要 将我的套接字和异步任务中的阅读器 问题是我不确定从哪里开始 因为我是 Android 新手 这至少对我来说是一项艰巨的任务 但据我
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • android sdk 的位置尚未在 Windows 操作系统的首选项中设置

    在 Eclipse 上 我转到 windows gt Android SDK 和 AVD Manager 然后弹出此消息 Android sdk 的位置尚未在首选项中设置 进入首选项 在侧边栏找到 Android 然后会出现一个 SDK 位
  • 如何将 google+ 登录集成到我的 Android 应用程序中?

    大家好 实际上我需要通过我的应用程序从 google 登录人们 现在我阅读了 google 上的文档 其中指出 要允许用户登录 请将 Google Sign In 集成到您的应用中 初始化 GoogleApiClient 对象时 请求 PL

随机推荐