*郑重声明:本文内容只为学习研究之用,如有人用于非法用途,产生的后果笔者不负任何责任。
上回说到我们考虑两种方法:
(1)通过反射,调用PackageManagerService中的设置权限的方法,直接传入权限和应用信息,对应用授权;
(2)直接修改uid:修改 /data/system/packages.list, /data/system/packages.xml等存储应用运行信息的文件
反射
参考了在上篇中引用的引用文献【1】的大佬的思路,这里也实现了大佬文章中的方法
该方法是反射得到IAppOpsService
对象,调用其setMode方法,设置权限。IAppOpsService
是Android自带的权限管理工具,通过setMode()
方法设置权限。
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
IAppOpsService service = IAppOpsService.Stub.asInterface(b);
service.setMode(…)
直接上代码:
1 | // IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); |
在外层套上main函数,然后打包成一个jar,放入设备。应用运行时,通过adb shell
命令执行该jar文件。
(1)main():
1 | public static void main(String[] args) { |
方法末尾加入反射代码即可。具体打包和执行过程,参考大佬文章不再赘述。
大佬的文章中采用了直接修改framework源码的方法,并且成功了,但是这种方法需要一定的ROM源码知识,我们选择了反射的方法调用IAppOpsService.setMode
,最终执行并没有成功。考虑权限设置是否有两套机制,又反射调了IPackageManager.grantRuntimePermission()
,即应用弹框请求权限时最终调用的方法。
在权限控制源码分析一文中我们可以看到,在ActivityThread.getPackageManager()
中:
1 | IBinder b = ServiceManager.getService("package"); |
这里的sPackageManager
就是IPackageManager
类型的对象,PackageManagerService
实现了IpackageManager
。
然后,调用grantRuntimePermission()
方法,传入包名,权限,uid即可。
代码参考:
1 | try { |
编译执行没有报错,但是最终对权限并无改变。
修改uid
先说结论:方法不可行。因为不管是在 /data/system/packages.list, /data/system/packages.xml文件中修改,还是通过hook修改传入的uid,都只是在上层打转,并没有改变Setings
对象中存放的权限情况。
还是说说具体实践过程吧,纯粹做个记录防止回头又掉进这个坑。
(1)hook
主要hook了几个获取uid的方法:UserHandle类的getUid、getIdentifier、getUserId,Process类的myUid。代码示例:
1 | XposedHelpers.findAndHookMethod(UserHandle.class, "getUid", int.class, int.class, new XC_MethodHook() { |
hook虽然成功了,修改了应用的uid, 但是对授权并没有什么用。
(2)修改存放应用权限的文件信息
/data/system目录中的packages.list和packages.xml两个文件分别存放了应用的uid、安装路径信息和授予的权限信息。
找到package
标签中name=包名
的项,在<perm>
字段增加权限:
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="0" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="0" />
保存文件。
点击运行应用,发现并未生效。重启设备,发现新增的字段没有了。手动在设备的”设置“中修改权限,发现此文件并未改变,还是只有系统默认授予的权限。
另外还有一个文件/data/system/users/0/runtime-permissions.xml
,保存了实时的权限信息,在“设置”中,修改授权情况会直接将权限信息写入此文件。
<pkg name="com.xxx">
<item name="android.permission.READ_SMS" granted="true" flags="0" />
<item name="android.permission.READ_CALENDAR" granted="true" flags="0" />
<item name="android.permission.READ_CALL_LOG" granted="true" flags="0" />
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="0" />
</pkg>
尝试手动在文件中添加以上内容,重启设备后又恢复之前的状态了,也没有生效。
读写runtime-permissions.xml源码分析
分析一下在哪里读了这个文件。
在Settings类中,可以看到
1 | private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml"; |
搜索RUNTIME_PERMISSIONS_FILE_NAME
,找到:
1 | 1372 private File getUserRuntimePermissionsFile(int userId) { |
返回该文件的File对象。搜索getUserRuntimePermissionsFile
方法,找到了readStateForUserSyncLPr()
读取该文件。调用此方法的位置只有一处,在readLPw
方法中。同样的readLPw
方法也读了packages.xml
文件。而readLPw
有且只有在PackageManagerService
的构造方法中调用了,说明开机时确实是读了runtime-permissions.xml
文件。
然后分析下在哪里写了文件。
runtime-permissions.xml
文件的编辑在Settings类中,PackageManagerService
构造方法中调用了updatePermissionsLPw()
方法,里面调用了Settings对象的grantPermissionsLPw
方法,此方法最终调用writPermissionsSync
,也就是说授予权限时会写入该文件:(具体过程在授权源码分析一文中)
1 | 4984 private void writePermissionsSync(int userId) { |
这样就将包的权限信息写入了runtime-permissions.xml
文件。
失败原因:
关键在runtime-permissions.xml
文件,在设备中的”设置“修改权限时,文件同步更新了,修改文件的话却没办法更新权限,涉及到某些存储权限信息的字段,还未找到。
至于通过hook修改uid,也只能在checkPermission时起到绕过作用,具体调用接口还是没有权限。还尝试了hook权限申请弹框的代码,也并没有什么用(涉及到framework层,难道说尝试修改ROM才是最终秘诀?)。
另外,测试使用的是小米,跟原生系统的权限控制不太一样。
小米应用权限设置页Activity:
ACTIVITY com.miui.securitycenter/com.miui.permcenter.permissions.PermissionsEditorActivity b347418 pid=6791
原生系统应用权限设置页:
ACTIVITY com.google.android.permissioncontroller/com.android.packageinstaller.permission.ui.ManagePermissionsActivity 23a5170 pid=4142
ACTIVITY com.google.android.permissioncontroller/com.android.packageinstaller.permission.ui.AppPermissionActivity 9e17de6 pid=4142
还尝试了把APP改成系统应用,以为就可以随便获取权限了。但是Android 7之后就不行了,系统应用要使用涉及隐私的接口,也需要弹框向用户申请权限。
在实践这个方法的时候,使用小米手机碰到了挂载文件系统问题,刷入了一些第三方包还把手机刷成砖,废了半天劲才挽救回来。。。。
总结一下:
不管是反射还是hook都要在framework层下手,要么研究怎么修改ROM,要么研究使用Magisk怎么在设备开机初始化之前修改配置。
经过十几天的抓耳挠腮,上蹿下跳,目前还处于“山重水复疑无路”阶段。不过,鲁迅说过:“排除掉错误的路线,剩下的就是对的路线。”(鲁迅:我没有,别瞎说。)多多尝试,就算没结果,也会有收获。