root是linux中的管理员账号,拥有极高权限,出于安全考虑在Android设备上一般不提供给用户使用。在已root的设备上,许多安全措施都形同虚设,从用户的角度讲这可能导致安全威胁和恶意软件的攻击从而造成隐私泄露甚至财产安全受到威胁;从服务提供商的角度来说,在有root权限的设备上运行自己的程序无法保证自己的服务以预期方式运行,也存在数据泄露和财产安全的威胁。magisk又称面具,是目前国内外提权者钟爱并大量使用的root权限获取及管理工具,功能极为强大,所以对magisk的针对检测就成为了root检测中重要的一块。本文接下来将从android启动过程,magisk的原理和magisk的检测三个层次展开叙述。
说到Android启动就不得不拿出这张经典的老图:
可以看到在Boot ROM上电启动之后会先加载Boot Loader,然后加载kernel和启动init进程,解析init.rc脚本之后启动zygote进程开始框架的初始化。本文的重点就是Native层的启动。
boot.img是由Boot Loader加载的镜像文件,其中除了头文件之外包含kernel和ramdisk,如下图所示。ramdisk是一个打包的.cpio.lz4的压缩归档文件,其中包含着最初的目录结构和init二进制文件,这就是一阶段的init。二阶段的init在system.img中。
在两个阶段的init中主要执行了以下工作:
① first stage(kernel domain,即boot中的init):
初始化环境变量;
创建及挂载最基本的文件系统,如tmpfs、sysfs、selinuxfs;
初始化init的标准流 open_devnull_stdio( );
初始化log系统和log等级;
挂载system、cache、data等系统分区;
初始化SELinux,加载sepolicy;
切换domain,re-exec init;
② second stage(init domain,即system中的init):
一些判断与变量设置,如建立 /dev/.booting 文件(标示kernel boot完成);
初始化property系统,处理kernel启动参数,设置boot属性(即"ro.boot.*");
继续SELinux的初始化,注册处理器;
重新设置first stage挂载的目录的上下文;
初始化并启动Epoll,注册信号处理例程和属性服务;
解析和执行init.rc脚本;
进入循环;
在init的两个阶段中,我们主要关注的是一阶段里的分区挂载、加载SEpolicy和二阶段的解析执行init.rc脚本这几件事。
下面具体来看一下init.rc脚本的结构。init.rc脚本中主要有三种section,分别是import、action和service,形式如下图:
//第一种:引入其他rc文件
import xxxx.rc
//第二种:定义action
on <trigger>
<command>
<command>
......
//第三种:定义service
service <name> <pathname> [<argument>]*
<option>
<option>
......
其中import是用来引入其他rc文件,不再赘述。
action可以理解为一种触发器,在<trigger>时机触发,按顺序执行下列<command>。
service是系统的服务,<pathname>是服务对应的二进制文件路径,<argument>是服务的启动参数,<option>为服务的修饰符。
在启动时,init进程会循环解析执行init.rc脚本直到循环。
① magisk对boot的修改:
magisk在使用时需要使用者预先解锁BL锁(bootloader锁,又称BL锁,是一种启动时用于校验bootloader完整性的机制)并按照magisk的使用流程对boot.img进行修改(在magisk工具中称为“修补”)和刷写,那么让我们来看看magisk到底在这里做了什么。
首先对比magisk修改前后的boot.img,可以看到magisk并没有修改kernel的部分,而把主要的修改放在了ramdisk部分。首先magisk对init文件进行了替换(对于替换后二代init下称magiskinit),将原先的init放入了新建的/.backup目录下,同时还新增了/overlay.d目录并在其中放入了magisk的二进制文件,下面来具体分析其作用。
② magiskinit的工作:
详细分析magisk修改的init文件可以看出magiskinit主要进行了三个工作:
在系统挂载时挂载自己的可执行文件:
在启动时magisk会挂载rootmirror目录,然后利用bind mount将其与根目录绑定,从而将magiskinit中的magisk文件挂载到系统的可执行目录中(如/bin)。
修改SELinux:
SELinux是Linux中为限制root进程权限设计的一种权限管控机制,为每个进程和文件/文件夹赋予对应的安全上下文,只有符合SEpolicy的进程和文件组合才能允许进程对文件的访问请求。在magiskinit中会修改SEpolicy,并将其加载。
magisk对SEpolicy的修改在于添加了magisk的相关域,使得magisk及其授权的root进程可以不受管控的对文件系统进行访问。
启动magiskd守护进程:
在init.rc中magisk添加了自己的脚本,核心是启动自己的守护进程magiskd来进行root管理等工作。
① 针对包名及文件的检测:
可以直接对包名及包文件进行检测。但由于magisk提供包名隐藏的能力可以将自己重装为随机包名,所以可以检测magisk的模块安装路径或者检测magisk挂载的可执行文件,如有则已安装magisk并提权。
② 针对挂载信息的检测:
可以针对magiskinit的挂载进行检测,查看mounts文件来检查是否有magisk私有文件被挂载,如有则已安装magisk并提权。
③ 针对安全上下文的检测:
由于magisk修改的sepolicy添加了新的安全上下文,所以可以检测是否存在具有magisk新增的标签的文件或进程,如果找到则已安装magisk并提权。
④ 针对守护进程的检测:
magiskinit新增的rc脚本会启动magiskd进程,所以如果遍历进程找到了magisk的守护进程则已安装magisk并提权。
magisk 作为一款强大的 root 工具,会带来一定的安全和隐私风险。在实际应用中,为了防止提权者利用magisk 进行攻击或进行非法行为,我们需要不断提升检测能力与攻防能力,认真对待 magisk 的安全风险,采取必要的防范措施来保障用户的安全与隐私。