正如评论中所指出的,除了 Linux 文件权限之外,现代 Android 还有许多额外的防御层。其中之一是 SELinux。
即使拥有提升的权限,围绕 SELinux 进行工作也很困难相当复杂 https://su.chainfire.eu/#selinux——它是专门为了防止这种情况而设计的。所有 Android SELinux 设置都存储在修改过的单个文件中sepolicy https://android.googlesource.com/platform/external/sepolicy/格式。该文件是只读系统映像的一部分,修补它基本上等同于对设备进行 root。几乎只有从事超级用户应用程序开发的人才是超级用户应用程序的开发人员,例如 SuperSu 或this one https://github.com/phhusson/Superuser.
我建议您利用已安装的 su 应用程序已经完成的任何操作,而不是尝试自己克服 SELinux。例如,SuperSu 在不受限制的 SELinux 上下文中运行传递给它的命令(请参阅上面 Chainfire 站点的链接),本质上就好像 SELinux 不存在一样。这允许您通过 su 运行专门的二进制文件来克服 SELinux,这会为您完成肮脏的工作。
遗憾的是,可用于此类纯本机二进制文件的公共高级 API 非常少。您可以使用 Linux 内核系统调用和一些 C 库函数……仅此而已。幸运的是,如果您想要的只是打开一堆受保护的文件,则无需在本机帮助程序二进制文件中移动大量逻辑。相反,您可以使用“开放服务器”库,例如this one https://github.com/Alexander--/fdshare:
Context context = ...
try (FileDescriptorFactory factory = FileDescriptorFactory.create(context);
ParcelFileDescriptor fd = factory.open("/dev/input", 2))
{
// the file descriptor is yours, as if you have gotten it by
// calling ParcelFileDescriptor#open
// You can use it from Java or pass to native code to read/write/ioctl on it
...
} catch (FactoryBrokenException oups) {
// most likely the root access being denied
...
} catch (IOException ioerr) {
...
}
免责声明:我是链接库的作者。
“开放服务器”的概念非常简单:
- 普通的 Android 应用程序会创建一个Linux 域套接字 http://developer.android.com/reference/android/net/LocalServerSocket.html
- 普通 Android 应用程序通过系统“su”启动二进制文件
- 二进制文件连接到套接字
- 二进制文件读取应用程序写入套接字的文件名并打开它们
- 二进制文件通过相同的套接字将所述文件的文件描述符发送到应用程序(该技术也称为“文件描述符传递” https://google.com/search?q=file+descriptor+passing)
只要安装的“su”应用程序成功克服 SELinux 并为通过它运行的命令提供不受限制的上下文,这个巧妙的技巧就会起作用。我所知道的所有现代人都是如此。
EDIT: 这个答案已经写了很久了。最新的 Android sepolicy 格式不再被视为“修改”,它们的更改已成功上游(幽默地导致创建完后还有向后不兼容的 sepolicy 格式)。上面链接的库总体上仍然可以正常工作,但它的功能受到现代 SEAndroid 策略的进一步限制,因此您可能对其感兴趣新迭代 https://github.com/chdir/fdutil。事实上,SELinux 策略对每个人强制执行额外的检查read
/write
除了标准 Unix 检查之外open
,使用共享内存和 Linux 管道来仔细解决该策略可能是更明智的做法,而不是将原始描述符传递给调用者。