Internal implementation principle of Magisk

insert image description here

After Android10, the Android system restricts the modification of the System partition. The result is that even if you compile the Android system yourself, even if you have high root privileges, you still cannot mount the System partition and modify its content. There are various posts that say it can be used mount -o rw,remount /, but this doesn't solve the real problem of the developer. This means that the traditional universal root has limitations. In order to solve this problem, the author of Magisk confirmed this problem Top John Wuin a tweet , and confirmed that the cause of the problem is that Google introduced it after Android 10 EXT4 共享块, and this shared block and other partitions The difference is that there is no concept of free space at all, so there is no way to hang it as readable and writable. In order to solve this problem, the Magisk team found that the file path when the file is read can be redirected to achieve the purpose of modification, which seems to be similar to our Hook, and this is called Top John WuSystemless (no System partition) and this concept The extended root solution is also called systemless root. .

Magisk file structure

The Magisk system includes the upper-level control software, the lower-level executable binary files, and some related configuration or data files. It will be easier for us to understand Magisk's functional composition and architectural thinking from the bottom to the top.

First, Magisk will mount a tmpfs directory to store some temporary data. Below Android11, this directory is sbin. Starting from Android 11, the /sbin folder may not exist, so Magisk will randomly create a folder under /dev and use it as the Root folder of Magisk.

The reason for placing it under sbin or dev is: the /sbin or /dev directory is unreadable without su permission, so third-party apps cannot detect it.

magisk --pathWe can print the directory currently used by Magisk by using the adb shell :

Find the magisk directory

blueline:/ # magisk --path
/dev/bNpnxq

File List

Next, let's take a look at what files are in this directory and how to interpret them;

blueline:/dev/bNpnxq # ls -al
total 720
drwx------  3 root    root       200 2022-12-24 21:41 .
drwxr-xr-x 24 root    root      6200 2022-12-25 01:40 ..
drwxr-xr-x  8 root    root       180 2022-12-24 21:41 .magisk
lrwxrwxrwx  1 root    root        10 1970-02-17 10:04 magisk -> ./magisk64
-rwxr-xr-x  1 root    root    154452 1970-02-17 10:04 magisk32
-rwxr-xr-x  1 root    root    247168 1970-02-17 10:04 magisk64
-rwxr-xr-x  1 u0_a206 u0_a206 328240 2022-12-24 21:41 magiskpolicy
lrwxrwxrwx  1 root    root         8 1970-02-17 10:04 resetprop -> ./magisk
lrwxrwxrwx  1 root    root         8 1970-02-17 10:04 su -> ./magisk
lrwxrwxrwx  1 root    root        14 1970-02-17 10:04 supolicy -> ./magiskpolicy

It can be seen that except magiskpolicy, others belong to the root user group.

The comments below are very clear, just look at the code directly.

# 想要获取 Magisk 正在使用的当前Base文件夹,请使用命令 `magisk --path`。
# 像 magisk、magiskinit 这样的二进制文件和所有指向小程序的符号链接都直接存储在这个路径中。 
# 这意味着当这是 /sbin 时,这些二进制文件将直接位于 PATH 中。
MAGISKBASE=$(magisk --path)

# Magisk 内部文件
MAGISKTMP=$MAGISKBASE/.magisk

# Magisk 的 BusyBox 目录。 
# 在此文件夹中存储 busybox 二进制文件和指向其所有小程序的符号链接。 
# 此目录的任何用法已弃用,请直接调用 /data/adb/magisk/busybox 并使用 BusyBox 的 ASH 独立模式。
# 将来会删除此路径的创建。
$MAGISKTMP/busybox

# /data/adb/modules 将mount在这里。 原始文件夹未被使用(由于 nosuid 挂载标志)。
$MAGISKTMP/modules

# 当前的 Magisk 安装配置
$MAGISKTMP/config

# 分区镜像
# 应用在访问系统文件的时候会优先访问该目录下的文件,以达到狸猫换太子的目的
# 例如 system,system_ext,vendor,data......
$MAGISKTMP/mirror

# Magisk 内部创建block设备来挂载镜像,和mirror对应,对应关系可通过ls -al列出
$MAGISKTMP/block

# Root 目录补丁文件
# 位于 system-as-root 设备上,/ 不可写。
# 所有预初始化补丁文件都放在这里并mount
$MAGISKTMP/rootdir

The following is /dev/bNpnxq/.magisk/mirrorthe list of files listed, corresponding to the device node of the block

blueline:/dev/bNpnxq/.magisk/block # ls -al
total 0
d--------- 2 root root      160 2022-12-24 21:41 .
drwxr-xr-x 8 root root      180 2022-12-24 21:41 ..
brw------- 1 root root 253,   8 2022-12-24 21:41 data
brw------- 1 root root 259,   4 1970-02-17 10:04 metadata
brw------- 1 root root 253,   7 2022-12-24 21:41 product
brw------- 1 root root 253,   5 2022-12-24 21:41 system_ext
brw------- 1 root root 253,   4 2022-12-24 21:41 system_root
brw------- 1 root root 253,   6 2022-12-24 21:41 vendor
blueline:/dev/bNpnxq/.magisk/block # cd ../mirror/
blueline:
####################################
/dev/bNpnxq/.magisk/mirror # ls -al
total 24
d---------  7 root   root    220 2022-12-24 21:41 .
drwxr-xr-x  8 root   root    180 2022-12-24 21:41 ..
drwxrwx--x 50 system system 4096 2022-12-24 21:41 data
lrwxrwxrwx  1 root   root      9 2022-12-24 21:41 metadata -> /metadata
lrwxrwxrwx  1 root   root     19 2022-12-24 21:41 persist -> /mnt/vendor/persist
drwxr-xr-x 14 root   root   4096 2009-01-01 08:00 product
lrwxrwxrwx  1 root   root     17 1970-02-17 10:04 sepolicy.rules -> ./metadata/magisk
lrwxrwxrwx  1 root   root     20 2022-12-24 21:41 system -> ./system_root/system
drwxr-xr-x  9 root   root   4096 2009-01-01 08:00 system_ext
drwxr-xr-x 26 root   root   4096 2009-01-01 08:00 system_root
drwxr-xr-x 20 root   shell  4096 2009-01-01 08:00 vendor

Configuration and modules (/data/adb directory)

Don't be confused by the directory name. Although adb is actually an application directory of Magisk, some data and configuration files of Magisk are stored in this directory, and the installed modules are also stored here. The reason why using this directory has its advantages of:

  • This directory exists for any factory-made device, and third-party apps cannot detect Magisk based on it.
  • The default permission of this directory is 700, and the owner is root, so third-party apps cannot enter and read and write.
  • The security context of this directory is u:object_r:adb_data_file:s0, which few processes have.
  • This directory is in Device Encrypted (DE) storage, so it can be used when the FBE (File-Based Encryption) device is in Direct Boot mode or after unlocking the lock screen.

This directory contains the following files (it is easier to understand with the Magisk startup process):

SECURE_DIR=/data/adb

# 存储一些 post-fs-data 后需要执行的脚本的文件夹
$SECURE_DIR/post-fs-data.d

# 存放通用 late_start 服务脚本的文件夹
$SECURE_DIR/service.d

# Magisk 模块目录
$SECURE_DIR/modules

# 待升级的 Magisk 模块
# 因为模块文件在挂载时修改是不安全的
# 通过 Magisk 应用程序安装的模块将存储在这里,并在下次重启时合并到 $SECURE_DIR/modules
$SECURE_DIR/modules_update

# 数据库存储应用设置和root授权日志
MAGISKDB=$SECURE_DIR/magisk.db

# 所有与 magisk 相关的二进制文件,包括 busybox、scripts和 magisk 二进制文件。 用于支持模块安装、addon.d、Magisk应用程序等。
DATABIN=$SECURE_DIR/magisk

Magisk startup process

Magisk startup is divided into the following steps: Pre-Init, post-fs-data, late_start, Resetprop, these startup processes we can correspond to the Android system startup, let me explain in detail below:

Pre-Init stage

Replace init with magiskinit and execute:

  • Mount the desired partition first. On a traditional system-as-root device, switch root to /system; on a 2SI device (using systemless), redirect the init file to magiskinit and execute it (the principle is that we will redirect the original init when patch boot step) to mount the desired partition.
  • Inject magisk service in init.rc
  • For devices using monolithic (overall) security policies, read the security policy from /sepolicy; for other devices, use FIFO to hijack selinuxfs nodes, set LD_PRELOAD to hook security_load_policy, and assist in hijacking 2SI devices, and start the daemon until init tries to read sepolicy.
  • Patch sepolicy rules. If using the "hijacking" method, load the patched sepolicy into the kernel, then release the init hijacking and exit the daemon.
  • Execute the original init to perform the subsequent startup process

post-fs-data stage

post-fs-dataThe process is triggered after /data is decrypted and mounted. First, the daemon process will be started magiskd, and post-fs-datathe script will be executed. At this time, the module file will be mounted.

late_start stage

Later in the boot process, the late_start class is triggered to start Magisk "service" mode. Service scripts will be executed in this mode.

At this point, Magisk is fully started, and the above is the App. It is only responsible for some configuration modifications and status display, and calls the previously started services and programs to execute. This is probably the process.

Modify properties (Resetprop)

Normally, only init can modify system properties, and non-root processes can only read and cannot modify. When there is root, you can send a request through the property_service provided by init (for example, adb can use the setprop command) to achieve modification, but you cannot modify and delete read-only properties (properties starting with ro., such as ro.build. product), unless the system source code is modified.

resetprop allows direct modification of the property area (prop_area) by extracting and patching the source code related to the system property in AOSP, and no longer needs to modify the system property through property_service (in fact, this function is similar to the principle of the open source mprop on Github). However, it is precisely because property_service is bypassed that the following precautions are required:

  • Fix for triggering events : Since property_service is bypassed, the on property:foo=bar action event registered in the *.rc script will not be triggered when the property changes (this is called a property trigger in the init language). But Mgisk has taken this into consideration, so by default resetprop will be the same as setprop when setting a property, and it will trigger an event (by first deleting the property and then setting the property through property_service). If you don't want to trigger action events, you can use the -n parameter to disable it.

  • The implementation also retains modifications after restart : persistent properties (properties starting with persist., such as persist.sys.usb.config) are stored in both prop_area and /data/property. By default, when deleting a persistent property, it will not be removed from the persistent storage, which means that the persistent property will be restored on the next restart; getprop will not read the persistent property from the persistent storage. But for resetprop, you can use the -p parameter , so that when deleting, the property will be removed from prop_area and /data/property at the same time, and when reading, it will also be read from prop_area and persistent storage.

SELinux policy

Magisk ensures that Magisk operations can be performed safely by patching the original sepolicy. The new magisk domain is highly privileged, and magiskd and all root shells will run in this domain. magisk_file is a new file type that allows access per domain (unrestricted file context), and the following magisk file uses the context magisk_file.

blueline:/data/adb # ls -Zl
total 52
drwxr-xr-x 3 root root u:object_r:magisk_file:s0     3488 2022-12-24 21:41 magisk
-rw------- 1 root root u:object_r:adb_data_file:s0  40960 2022-12-27 02:22 magisk.db
drwxr-xr-x 2 root root u:object_r:system_file:s0     3488 2022-12-24 21:41 modules
drwxr-xr-x 2 root root u:object_r:adb_data_file:s0   3488 2022-12-24 21:41 post-fs-data.d
drwxr-xr-x 2 root root u:object_r:adb_data_file:s0   3488 2022-12-24 21:41 service.d

Prior to Android 8.0, all su-enabled client domains could connect directly to magiskd and connect with the daemon to gain remote root shell access. Magisk also needs to release some ioctls for the root shell to work properly.

However, in Android 8.0 and later, in order to avoid the relaxation of rules in the Android sandbox, Magisk implements a new SELinux model. magisk binaries are marked with the magisk_exec file type, and processes executing magisk binaries (including the su command) while running in the domain of su client are transitioned to magisk_client (by using a type_transition rule).

The rules strictly limit the processes in the magisk domain to be allowed to belong to the magisk_exec file type. Direct socket connections to magiskd are no longer allowed; the only way to access the daemon is through a magisk_client process. Doing so ensures the integrity of the sandbox, keeping Magisk-specific rules separate from other rules. Magisk64 as follows:

blueline:/dev/bNpnxq # ls -lZ
total 720
lrwxrwxrwx 1 root    root    u:object_r:system_file:s0                            10 1970-02-17 10:04 magisk -> ./magisk64
-rwxr-xr-x 1 root    root    u:object_r:system_file:s0                        154452 1970-02-17 10:04 magisk32
-rwxr-xr-x 1 root    root    u:object_r:magisk_exec:s0                        247168 1970-02-17 10:04 magisk64
-rwxr-xr-x 1 u0_a206 u0_a206 u:object_r:app_data_file:s0:c206,c256,c512,c768  328240 2022-12-24 21:41 magiskpolicy
lrwxrwxrwx 1 root    root    u:object_r:system_file:s0                             8 1970-02-17 10:04 resetprop -> ./magisk
lrwxrwxrwx 1 root    root    u:object_r:system_file:s0                             8 1970-02-17 10:04 su -> ./magisk
lrwxrwxrwx 1 root    root    u:object_r:system_file:s0                            14 1970-02-17 10:04 supolicy -> ./magiskpolicy

More detailed rules can magiskpolicy/rules.cppbe found in .

Guess you like

Origin blog.csdn.net/zhonglunshun/article/details/128791807