0%

Magisk源码分析(三)

对 Magisk 源码做一个简单的分析,本人很菜,分析不到位的地方请各位大神指出来。本文以 Magisk v25.1 为例

Magisk service

在上一章中,介绍了 magiskinit 注入了 init.rc 并添加了 magisk 服务。这个文件会被 magisk daemon 删掉,需要注释这个代码

1
// rm_rf((MAGISKTMP + "/" ROOTOVL).data());

我们来看一看 magisk 都做了啥事.

post-fs-data

1
2
3
4
service 3dgv8Xp9rdRtMv /dev/BYdnLYi/magisk --post-fs-data
user root
seclabel u:r:magisk:s0
oneshot

Magisk\native\jni\core\magisk.cpp

1
2
3
4
5
6
7
8
int magisk_main(int argc, char *argv[]) {
......
} else if (argv[1] == "--post-fs-data"sv) {
close(connect_daemon(MainRequest::POST_FS_DATA, true));
return 0;
}
......
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int connect_daemon(int req, bool create) {
sockaddr_un sun{};
socklen_t len = setup_sockaddr(&sun, MAIN_SOCKET);
int fd = xsocket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (connect(fd, (sockaddr *) &sun, len)) {//若建立连接失败,则fork出magisk daemon,第一次执行这里一定是-1.
if (!create || getuid() != AID_ROOT) {
LOGE("No daemon is currently running!\n");
close(fd);
return -1;
}

char buf[64];
xreadlink("/proc/self/exe", buf, sizeof(buf));
if (str_starts(buf, "/system/bin/")) {
LOGE("Start daemon on /dev or /sbin\n");
close(fd);
return -1;
}

if (fork_dont_care() == 0) {//fork
close(fd);
daemon_entry();//建立连接失败时,用fork的子进程当作daemon进程.
}

while (connect(fd, (struct sockaddr *) &sun, len))
usleep(10000);
}
......
}

上面代码建立了 daemon 进程,接收 magisk 的 socket 消息。接下来直接到 daemon 进程的代码里分析
Magisk\native\jni\core\bootstages.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
void post_fs_data(int client) {
close(client);

mutex_guard lock(stage_lock);

if (getenv("REMOUNT_ROOT"))
xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);

if (!check_data())
goto unblock_init;

DAEMON_STATE = STATE_POST_FS_DATA;
setup_logfile(true);

LOGI("** post-fs-data mode running\n");

unlock_blocks();//猜测是解锁/dev/block下的设备,让它们可读可写
mount_mirrors();//挂载到magisk mirrors里,可以结合日志分析.
prune_su_access();//从sqlite数据库查出所有的已授权root的app,然后根据是否卸载app来决定移除授权,因为sqlite记录的是app uid.

if (access(SECURE_DIR, F_OK) != 0) { //#define SECURE_DIR "/data/adb"
if (SDK_INT < 24) {
// There is no FBE pre 7.0, we can directly create the folder without issues
xmkdir(SECURE_DIR, 0700);
} else {
// If the folder is not automatically created by Android,
// do NOT proceed further. Manual creation of the folder
// will have no encryption flag, which will cause bootloops on FBE devices.
LOGE(SECURE_DIR " is not present, abort\n");
goto early_abort;
}
}

if (!magisk_env()) {
LOGE("* Magisk environment incomplete, abort\n");
goto early_abort;
}

if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
safe_mode = true;//这里应该是判断安全模式,拒绝加载所有模块
// Disable all modules and denylist so next boot will be clean
disable_modules();
disable_deny();
} else {
exec_common_scripts("post-fs-data"); //执行/data/adb/post-fs-data.d目录下的脚本
db_settings dbs;
get_db_settings(dbs, ZYGISK_CONFIG);
zygisk_enabled = dbs[ZYGISK_CONFIG];
initialize_denylist();
handle_modules(); //执行模块的post-fs-data脚本
}

early_abort:
// We still do magic mount because root itself might need it
magic_mount();
DAEMON_STATE = STATE_POST_FS_DATA_DONE;

unblock_init:
close(xopen(UNBLOCKFILE, O_RDONLY | O_CREAT, 0));
}

慢慢来,先看 mount_mirrors .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
static void mount_mirrors() {
char buf1[4096];
char buf2[4096];

LOGI("* Mounting mirrors\n");

parse_mnt("/proc/mounts", [&](mntent *me) {
struct stat st{};
do {
mount_mirror(system)
mount_mirror(vendor)
mount_mirror(product)
mount_mirror(system_ext)
mount_mirror(data)
link_orig(cache)
link_orig(metadata)
link_orig(persist)
link_orig_dir("/mnt/vendor/persist", persist)
if (SDK_INT >= 24 && MNT_DIR_IS("/proc") && !strstr(me->mnt_opts, "hidepid=2")) {
xmount(nullptr, "/proc", nullptr, MS_REMOUNT, "hidepid=2,gid=3009");
break;
}
} while (false);
return true;
});
SETMIR(buf1, system); // buf1:/dev/JLeAqcN/.magisk/mirror/system
if (access(buf1, F_OK) != 0) {
xsymlink("./system_root/system", buf1);
LOGI("link: %s\n", buf1);
parse_mnt("/proc/mounts", [&](mntent *me) {
struct stat st;
if (MNT_DIR_IS("/") && me->mnt_type != "rootfs"sv && stat("/", &st) == 0) {
do_mount_mirror(system_root)
return false;
}
return true;
});
}
link_mirror(vendor)
link_mirror(product)
link_mirror(system_ext)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#define mount_mirror(part) \
if (MNT_DIR_IS("/" #part) \
&& !MNT_TYPE_IS("tmpfs") \
&& !MNT_TYPE_IS("overlay") \
&& lstat(me->mnt_dir, &st) == 0) { \
LOGI("me->mnt_dir:%s\n",me->mnt_dir); \ //me->mnt_dir:/system_ext
do_mount_mirror(part); \
break; \
}

#define do_mount_mirror(part) { \
SETMIR(buf1, part); \
SETBLK(buf2, part); \
unlink(buf2); \ //buf2 : /dev/6Mesvw/.magisk/block/system_ext
mknod(buf2, S_IFBLK | 0600, st.st_dev); \ //创建块设备文件,这个st对应/system_ext
xmkdir(buf1, 0755); \
int flags = 0; \
auto opts = split_ro(me->mnt_opts, ",");\
for (string_view s : opts) { \
if (s == "ro") { \
flags |= MS_RDONLY; \
break; \
} \
} \
xmount(buf2, buf1, me->mnt_type, flags, nullptr); \ //mount到magisk的mirror目录下
LOGI("mount: %s\n", buf1); \
}

记得给 xmount 添加上日志

1
2
3
4
5
6
7
8
9
10
11
12
13
int xmount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data) {
int ret = mount(source, target, filesystemtype, mountflags, data);
if (ret < 0) {
PLOGE("mount %s->%s", source, target);
}else
{
LOGD("mount success %s->%s", source, target);//添加日志,否则很多信息看不出来
}

return ret;
}

结合日志分析

1
2
3
4
5
6
7
1970-07-29 07:07:34.339 1078-1080/? I/Magisk: * Mounting mirrors
1970-07-29 07:07:34.340 1078-1080/? D/Magisk: mount success (null)->/proc
1970-07-29 07:07:34.340 1078-1080/? D/Magisk: mount success /dev/Abyd/.magisk/block/system_ext->/dev/Abyd/.magisk/mirror/system_ext
1970-07-29 07:07:34.340 1078-1080/? D/Magisk: mount success /dev/Abyd/.magisk/block/product->/dev/Abyd/.magisk/mirror/product
1970-07-29 07:07:34.340 1078-1080/? D/Magisk: mount success /dev/Abyd/.magisk/block/vendor->/dev/Abyd/.magisk/mirror/vendor
1970-07-29 07:07:34.340 1078-1080/? D/Magisk: mount success /dev/Abyd/.magisk/block/data->/dev/Abyd/.magisk/mirror/data
1970-07-29 07:07:34.340 1078-1080/? D/Magisk: mount success /dev/Abyd/.magisk/block/system_root->/dev/Abyd/.magisk/mirror/system_root

这个函数的作用是把系统的 system_ext 等目录挂载到 magisk mirror.
magisk 目录里 block 下的文件是通过 mknod 创建的.

初始化 Magisk env

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#define SECURE_DIR      "/data/adb"
#define MODULEROOT SECURE_DIR "/modules"
#define DATABIN SECURE_DIR "/magisk"

static bool magisk_env() {
char buf[4096];

LOGI("* Initializing Magisk environment\n");

preserve_stub_apk();
string pkg;
get_manager(0, &pkg);// pkg:com.topjohnwu.magisk

sprintf(buf, "%s/0/%s/install", APP_DATA_DIR,
pkg.empty() ? "xxx" /* Ensure non-exist path */ : pkg.data());
//buf:/data/user_de/0/com.topjohnwu.magisk/install
// Alternative binaries paths
const char *alt_bin[] = { "/cache/data_adb/magisk", "/data/magisk", buf };
for (auto alt : alt_bin) {
struct stat st{};
if (lstat(alt, &st) == 0) {
if (S_ISLNK(st.st_mode)) {
unlink(alt);
continue;
}
rm_rf(DATABIN);
cp_afc(alt, DATABIN);
rm_rf(alt);//这个alt应该是/data/user_de/0/com.topjohnwu.magisk/install,然后把该目录删除
break; //这一段循环其实是把/data/user_de/0/com.topjohnwu.magisk/install里的文件cp到/data/adb/magisk里
}
}
rm_rf("/cache/data_adb");

// Directories in /data/adb
xmkdir(DATABIN, 0755);//在/data/adb目录下创建下面几个目录
xmkdir(MODULEROOT, 0755);
xmkdir(SECURE_DIR "/post-fs-data.d", 0755);
xmkdir(SECURE_DIR "/service.d", 0755);

if (access(DATABIN "/busybox", X_OK))//这里的busybox是从/data/user_de/0/com.topjohnwu.magisk/install里cp过来的
return false;

sprintf(buf, "%s/" BBPATH "/busybox", MAGISKTMP.data());
mkdir(dirname(buf), 0755);
cp_afc(DATABIN "/busybox", buf); //把busybox复制到/dev/xxx/.magisk
exec_command_async(buf, "--install", "-s", dirname(buf)); //安装busybox

if (access(DATABIN "/magiskpolicy", X_OK) == 0) {
sprintf(buf, "%s/magiskpolicy", MAGISKTMP.data());
cp_afc(DATABIN "/magiskpolicy", buf);//把magiskpolicy复制到/dev/xxx/.magisk
}

return true;
}

这个函数是 magisk 环境的初始化,建立了 /data/adb/magisk 目录等.

加载,运行模块 post-fs-data 脚本

1
2
3
4
5
6
7
8
9
10
if (getprop("persist.sys.safemode", true) == "1" || check_key_combo()) {
......
} else {
exec_common_scripts("post-fs-data"); //执行/data/adb/post-fs-data.d目录下的脚本
db_settings dbs;
get_db_settings(dbs, ZYGISK_CONFIG);
zygisk_enabled = dbs[ZYGISK_CONFIG];
initialize_denylist();
handle_modules(); //执行模块的post-fs-data脚本
}
1
2
3
4
5
6
7
8
9
void handle_modules() {
prepare_modules();
collect_modules(false); //收集所有magisk模块
exec_module_scripts("post-fs-data");//运行模块的脚本

// Recollect modules (module scripts could remove itself)
module_list->clear();
collect_modules(true);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
static void collect_modules(bool open_zygisk) {
foreach_module([=](int dfd, dirent *entry, int modfd) {
if (faccessat(modfd, "remove", F_OK, 0) == 0) {
LOGI("%s: remove\n", entry->d_name);
auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh";
if (access(uninstaller.data(), F_OK) == 0)
exec_script(uninstaller.data());
frm_rf(xdup(modfd));
unlinkat(dfd, entry->d_name, AT_REMOVEDIR);
return;
}
unlinkat(modfd, "update", 0);
if (faccessat(modfd, "disable", F_OK, 0) == 0)
return;

module_info info;
if (zygisk_enabled) {
// Riru and its modules are not compatible with zygisk
if (entry->d_name == "riru-core"sv || faccessat(modfd, "riru", F_OK, 0) == 0) { //如果有riru,则return
LOGI("%s: ignore\n", entry->d_name);
return;
}
if (open_zygisk) {
#if defined(__arm__)
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
#elif defined(__aarch64__)
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
info.z64 = openat(modfd, "zygisk/arm64-v8a.so", O_RDONLY | O_CLOEXEC);
#elif defined(__i386__)
info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC);
#elif defined(__x86_64__)
info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC);
info.z64 = openat(modfd, "zygisk/x86_64.so", O_RDONLY | O_CLOEXEC);
#else
#error Unsupported ABI
#endif
unlinkat(modfd, "zygisk/unloaded", 0);
}
} else {
// Ignore zygisk modules when zygisk is not enabled
if (faccessat(modfd, "zygisk", F_OK, 0) == 0) {
LOGI("%s: ignore\n", entry->d_name);
return;
}
}
info.name = entry->d_name;
module_list->push_back(info); //把模块放进module_list里
});
if (zygisk_enabled) {
bool use_memfd = true;
auto convert_to_memfd = [&](int fd) -> int {
if (fd < 0)
return -1;
if (use_memfd) {
int memfd = syscall(__NR_memfd_create, "jit-cache", MFD_CLOEXEC);
if (memfd >= 0) {
xsendfile(memfd, fd, nullptr, INT_MAX);
close(fd);
return memfd;
} else {
// memfd_create failed, just use what we had
use_memfd = false;
}
}
return fd;
};
std::for_each(module_list->begin(), module_list->end(), [&](module_info &info) {
info.z32 = convert_to_memfd(info.z32);
#if defined(__LP64__)
info.z64 = convert_to_memfd(info.z64);
#endif
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void foreach_module(Func fn) {
auto dir = open_dir(MODULEROOT); // /data/adb/modules
if (!dir)
return;

int dfd = dirfd(dir.get());
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_type == DT_DIR && entry->d_name != ".core"sv) {
int modfd = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
fn(dfd, entry, modfd);
close(modfd);
}
}
}

代码太多,简单说吧,先把模块 /data/adb/modules 放到 module_list 里,然后执行模块的 post-fs-data 脚本.

magic_mount

mount /system
挂载 /system 目录,添加或替换模块内系统文件.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
void magic_mount() {//mount /system
node_entry::mirror_dir = MAGISKTMP + "/" MIRRDIR;
node_entry::module_mnt = MAGISKTMP + "/" MODULEMNT "/";

auto root = make_unique<root_node>("");
auto system = new root_node("system");
root->insert(system);

char buf[4096];
LOGI("* Loading modules\n");
for (const auto &m : *module_list) {//挂载所有模块的文件
const char *module = m.name.data();
char *b = buf + sprintf(buf, "%s/" MODULEMNT "/%s/", MAGISKTMP.data(), module);

// Read props
strcpy(b, "system.prop");
if (access(buf, F_OK) == 0) {
LOGI("%s: loading [system.prop]\n", module);
load_prop_file(buf, false);
}

// Check whether skip mounting
strcpy(b, "skip_mount");
if (access(buf, F_OK) == 0)
continue;

// Double check whether the system folder exists
strcpy(b, "system");
if (access(buf, F_OK) != 0)
continue;

LOGI("%s: loading mount files\n", module);//如果需要替换系统文件(/system)
b[-1] = '\0';
int fd = xopen(buf, O_RDONLY | O_CLOEXEC);
system->collect_files(module, fd);
close(fd);
}
if (MAGISKTMP != "/sbin") {
// Need to inject our binaries into /system/bin
inject_magisk_bins(system);
}

if (!system->is_empty()) {
// Handle special read-only partitions
for (const char *part : { "/vendor", "/product", "/system_ext" }) {//处理这3个特殊的只读分区
struct stat st;
if (lstat(part, &st) == 0 && S_ISDIR(st.st_mode)) {
if (auto old = system->extract(part + 1)) {
auto new_node = new root_node(old);
root->insert(new_node);
}
}
}
root->prepare();//准备工作
root->mount();//挂载,替换/system目录,可以结合下面的日志分析
}

// Mount on top of modules to enable zygisk
if (zygisk_enabled) {
string zygisk_bin = MAGISKTMP + "/" ZYGISKBIN;
mkdir(zygisk_bin.data(), 0);
mount_zygisk(32)
mount_zygisk(64)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: mount success tmpfs->/system/bin
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: mnt_tmp : /system/bin <- tmpfs
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: cp_link : /system/bin/[ <- /dev/JLeAqcN/.magisk/mirror/system/bin/[
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: mount success /dev/JLeAqcN/.magisk/mirror/system/bin/abb->/system/bin/abb
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: bind_mnt: /system/bin/abb <- /dev/JLeAqcN/.magisk/mirror/system/bin/abb
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: mount success /dev/JLeAqcN/.magisk/mirror/system/bin/abx->/system/bin/abx
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: bind_mnt: /system/bin/abx <- /dev/JLeAqcN/.magisk/mirror/system/bin/abx
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: mount success /dev/JLeAqcN/.magisk/mirror/system/bin/abx2xml->/system/bin/abx2xml
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: bind_mnt: /system/bin/abx2xml <- /dev/JLeAqcN/.magisk/mirror/system/bin/abx2xml
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: cp_link : /system/bin/acpi <- /dev/JLeAqcN/.magisk/mirror/system/bin/acpi
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: mount success /dev/JLeAqcN/.magisk/mirror/system/bin/am->/system/bin/am
1970-07-31 05:31:53.071 1024-1026/? D/Magisk: bind_mnt: /system/bin/am <- /dev/JLeAqcN/.magisk/mirror/system/bin/am
......

先到这里吧,这章属实是太长了.