准备阶段
在Android中,当执行adb命令时,实际上是和adbd进行交互,所以当我们进行adb root权限实际上是配置手机中的adbd运行在root权限的情况下。
adbd中涉及判断adb root权限开启判断源文件文件路径system/core/adb/daemon/main.cpp
看到aosp10的源码这里,当我们执行adb root
时,实际上就是跑了这个函数。
通过判断
ro.secure
是否为0来判断是否该进行降权处理,如果确定需要降权则adbd的权限将会降为现有用户进行运行,为0则表示不需要降权。通过修改
ro.adb.secure=0
表示adb默认授权打开,不用弹出adb授权弹框
adb root用户权限配置
有两种方式
- 修改main.mk属性
路径build/make/core/main.mk
在源码编译时会通过该文件进行一些属性的设置。
比如说此处,会判断当前要编译的是user/userdebug类型,如果是user则把ADDITIONAL_DEFAULT_PROPERTIES += ro.adb.secure=1
以及ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1
需要进行降权处理和adb授权弹框打开。
所以如果要编译user版本,可以把ro.secure=1改为ro.secure=0不进项降权处理以root用户运行。ro.adb.secure=1改为0不进行adb授权弹框。
但是这种方式容易被检测出来:通过获取ro.secure/ro.adb.secure是否为0来判断手机是否为root。
- 修改adbd源码
文件路径system/core/adb/daemon/main.cpp
通过修改auth_required值为false把授权框关闭。接着点击进入这个地方。
看注释的意思判断系统是否处于secure模式,如果存在就不要以root用户的身份运行。
来到该函数发现,这就是刚才我们分析的第一个函数我们直接看到,这个位置
1 | if (ro_debuggable && adb_root) { |
ro_debuggable和adb_root都为1时则返回false,行,那我们都不去走上面的流程,在该函数的开头直接返回false即可。
该方式不难看出有一大优点——不用修改ro.adb.secure和ro.secure为1,则root检测如果检测这两个点,则我们是不是就把root给过了呢?
通过上面简述两种方式,我们不难做出选择,第二种最为合适,即使我们把系统编译成userdebug那么root检测这两个点对我们是无效的,因为我们根本就没改这两个点为0。
整合frida-server到系统当中
- 在
/frameworks/base/cmds
目录下(ps: 如果编译过xposed源码,会对/frameworks/base/cmds
目录感到熟悉,因为xposed的一部分关键native逻辑(即Xposed的github项目下的Xposed项目)也是需要放到该目录下的。)创建一个用于存放fridaserver的目录,给出我创建的路径/frameworks/base/cmds/juziss/fs_server
(此处只是文件夹路径),然后把下载好的fridaserver解压放到该目录里,然后修改fridaserver的名字,自行修改,比如我就改成juzissFs,改好之后创建Android.mk(该模块用于添加一些编译模块的规则)
以下给出mk的内容此时我们就把frida的模块给建立好了,但是!此时我们还没有把该模块加入到源码编译的编译链当中。 如果现在编译,则该模块是不会被编译进系统当中的。1
2
3
4
5
6
7
8
9
10LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := juzissFs // 指定模块名称
LOCAL_MODULE_CLASS := EXECUTABLES // 指定模块为可执行程序
LOCAL_SRC_FILES := juzissFs // 指定编译文件
include $(BUILD_PREBUILT) // 指定预编译模式
把源码加入到编译链当中
增加模块到源码编译链的路径为build/make/target/product/base_system.mk
随意在这堆模块当中插入我们的编译模块名即可。(模块名为Android.mk里的LOCAL_MODULE := juzissFs,即我这插入的就是juzissFs)
随后直接编译即可
验证
adb shell ps -Z |grep "adbd"
查看当前adbd是否运行在su下juzissFs --version
查看当前内置的版本是否为我们下载好的frida-server版本
完成以上两步即可验证成功。
设置frida-server为后台进程
在selinux开启的情况下启动frida-server方法
介绍两种
- init.xx.rc文件中的配置
在安卓系统当中配置native后台服务,主要是在init.xx.rc文件中添加服务配置信息。
比如adbd的后台服务配置文件/system/core/rootdir/init.usb.rc
这种方法配置主要是通过init
进程进行解析init.xx.rc文件来进行启动的。该方法启动有一条限制如果配置的后台服务需要用到root权限,如frida-server启动之后需要ptrace来attach进程,这种情况最好把selinux关闭。这样在init.xx.rc进行配置才能达到预期效果。
以下给出参考配置
1 | service juzissFs /system/bin/juzissFs -D |
juzissFs为进程名,/system/bin/juzissFs -D为启动命令(实际上就是执行juzissFs -D这个命令),class main指定进程分到的类, user root以root用户运行(即使不写该命令也会默认走root用户,也就是说该命令可有可无),seclabel u:r:init:s0 指定进程所运行的安全域。
- 进程中启动服务配置
选择合适的后台进程,调用system函数(syscall)进行服务启动。可选root的adbd或者root的init进程。
测试后台服务是否运行
针对上面两种分别给出测试方式
init.xx.rc中配置
在selinux开启的情况下,由于init进程被限制了很多功能,比如禁止ptrace其他进程,所以frida-server的好多功能会失效。虽然init进程运行的是root用户,但是selinux的域为init,所以很多特权功能被限制,所以如果不是很在乎selinux的情况下,关闭selinux之后在进行配置。进程中启动服务
进程中启动服务主要是需要找到权限高的进程作为母体。如init、adbd进程。由于init进程所运行的域为init而selinux的运行也在init域当中,这就会导致init域下的特权服务被限制,所以init进程不适合启动frida-server。如果在adbd以root权限运行,并且把运行的标签改成u:r:su:s0,则adbd作为母体启动服务之后,服务就存在超级权限,则运行frida-server自然也就可以使用特权功能,运行自然也没有问题,所以比较适合frida-server。
查看init进程和adbd进程运行的selinux域
adb shell ps -Z |grep adbd
adb shell ps -Z |grep init
adbd启动fridaserver
查找合适的启动入口
在adbd启动过程中,会根据传入的参数如果存在root_seclabel会将adbd进程的域由u:r:adbd:s0
修改为u:r:su:s0
域。该逻辑位于system/core/adb/daemon/main.cpp
中。
也就是前面提到adbd如何走root权限的地方,通过selinux_android_setcon
函数设置,从变量名也可以看的出来root_seclabel
root标签,修改当前进程的域为u:r:su:s0从而使得adbd获得root权限。
所以我们可以考虑在执行完selinux_android_setcon函数之后启动我们的fridaserver逻辑。