如果使用供应商密钥签名的数据应用程序能够 运行 'su'

Should a data application signed with the vendor key be able to run 'su'

背景: 我正在开发一个远程操作的标牌设备。我需要一个可以

的应用程序

我有一个没有根目录的 Android 设备。我也有一些文件,我被告知是平台密钥。

我开发了一个试图启动 su 进程的应用程序。

Process p = Runtime.getRuntime().exec("su");

在我使用平台密钥签署应用程序之前,它抛出了一个 IOException,消息是 Permission Denied

我使用这些平台密钥签署了应用程序,但我仍然收到 Permission Denied 异常。

这是三个相互矛盾的说法。以下哪一项陈述(如果有)是正确的?

语句 1:这应该有效。该应用程序即使存储在 /data/app 中,也应该能够 运行 su。要么我的密钥有误,要么我需要将其他一些条目添加到清单中才能使其正常工作。

声明 2:这不应该起作用。尽管它是用平台密钥签名的,但该应用程序在 /data/app 中,因此它是数据应用程序,而不是系统应用程序。数据应用程序不能 运行 su 在无根设备上。如果此应用程序安装到 /system/app,那么它将能够 运行 su。 (而且我无法将其放入 /system/app,因为它没有根目录,所以我被卡住了)。

声明 3:这永远行不通。如果设备未获得 root 权限,那么即使它是已签名的系统应用程序,也无法 运行 su

我会选择声明 3。这永远不会在无根的 Android 设备上工作。至少,最近的 Android OS 版本不是(我不知道这是否适用于非常旧的 Android 设备)。

"su" 是一个应用程序——磁盘上必须有一个 "su" 二进制文件才能执行它,而 Android 默认情况下不提供 "su" 出于安全目的的二进制文件。当您使用第三方 rootkit 时,它们会安装自己的 "su" 二进制文件,为用户提供一种将自己提升为 root 权限的机制。

如果您的应用程序使用特殊密钥签名并从启动时就被授予提升的权限,为什么您仍然需要执行 "su"?

Android 如果您没有将某种根方法闪存到设备,例如 Magisk 或 SuperSU,那么 su 甚至不应该有二进制文件。

即使它确实有一个 su 二进制文件,出于两个原因之一,我也不希望它工作。假设您的设备预装了 su 二进制文件,谁在管理它?如果它是非托管的,它应该拒绝所有请求。如果您刷新根方法,则由该管理器决定您的应用程序是否可以访问 su,无论您是否具有签名级权限(毕竟根管理器使用不同的签名) .

为什么您甚至需要访问 su 作为签名应用程序?无论如何,您都可以完全访问该设备。如果你需要 运行 一个命令,那么无论你 运行 做什么,只要它是从你的平台签名包中完成的,你都应该没有问题。但由于您拥有完全访问权限,本机 APIs 应该可以让您做任何您需要的事情。

至于当您尝试在进程中执行 su 时的 IOException returned,那只是一个奇怪的 Android 怪癖。如果没有安装 su 二进制文件,它有时会 return command not found 有时会 permission denied,具体取决于设备。

我想表达的意思是,除非您的应用程序是根管理器,否则您可以成为 system_server 的一部分并且仍然可以像其他人一样访问 su .对于我同意的说法,我认为#3,虽然我不完全同意它,因为机会 su 根本不存在,或者它是一个无用的二进制文件。

我已经解释了为什么 #1 不应该是真的,但是 #2 是不正确的。如果您查看 platform manifest,每个需要特权应用程序的权限也可以授予签名应用程序。因此,即使您确实将您的应用程序移动到 /system/priv-app//system/app/ 不会使其具有特权),也不会有什么不同。基本上,如果您的应用程序是由平台签名签名的,那么它安装在何处并不重要。

编辑:

您可以通过 运行ning reboot 作为命令轻松重启,因为您对系统具有签名级别的访问权限,但使用正确的 API 为此。如果你使用 API,你会得到关机动画,但你也让系统正常关闭,停止服务并发送 ACTION_REBOOT 广播给任何可能正在监听它的应用程序。

要使用 API,首先将以下权限添加到您的 AndroidManifest:

<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />

现在,在需要调用重启操作的地方,使用以下代码:

IStatusBarService bar = IStatusBarService.Stub.asInterface(ServiceManager.getService(Context.STATUS_BAR_SERVICE));
bar.reboot(false); //using true here will reboot to Safe Mode

此方法为隐藏方法,如果使用AndroidStudio编辑编译会报错。可以使用反射,也可以使用Android Hidden API直接访问。

这是系统 UI 在电源菜单中实现它的方式:https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java

这是实现 IStatusBar 服务的class:https://github.com/aosp-mirror/platform_frameworks_base/blob/master/services/core/java/com/android/server/statusbar/StatusBarManagerService.java#L969