关掉magiskhide_[讨论] Magisk隐藏root的实现

本文探讨了Magisk隐藏root的实现,通过分析Magisk源码,解释了如何利用setns函数切换到目标进程的mnt-namespace,以及卸载特定文件系统来隐藏root。讨论了隐藏su文件的逻辑,并分享了相关测试结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Magisk源码地址:https://github.com/topjohnwu/Magisk,隐藏root功能包含了隐藏某些系统属性,隐藏magisk包名等。本菜抛砖引玉,希望大家讨论其中隐藏su文件的逻辑,以及检测这种情况的方法。代码位于工程的 Magisk/native/jni/magiskhide目录下,这里直接把功能实现核心代码抽离出来,以下是主要部分:

int main(int argc, char** argv) {

DEBUG_PRINT("hideroot start\n");

if (argc 

DEBUG_PRINT("usage: ./hideroot {pid}\n");

return 1;

}

pid_t target_pid = atoi(argv[1]);

DEBUG_PRINT("target pid is %d\n", target_pid);

// 1. 暂停目标进程

kill(target_pid, SIGSTOP);

// 2. 关联到目标进程的mnt-namespace

DEBUG_PRINT("hideroot switch_mnt_ns\n");

if (switch_mnt_ns(target_pid)) {

DEBUG_PRINT("");

return 1;

}

// 3. 卸载相关文件系统

DEBUG_PRINT("hideroot read mounts\n");

char buffer[256];

char* line = NULL;

struct vector mount_list;

snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", target_pid);

DEBUG_PRINT("hideroot init mount_list\n");

vec_init(&mount_list);

DEBUG_PRINT("hideroot read file\n");

file_to_vector(buffer, &mount_list);

DEBUG_PRINT("hideroot unmount dummy skeletons and /sbin links\n");

// Unmount dummy skeletons and /sbin links

vec_for_each(&mount_list, line) {

if (strstr(line, "tmpfs /system/") || strstr(line, "tmpfs /vendor/") || strstr(line, "tmpfs /sbin")) {

sscanf(line, "%*s %4096s", buffer);

lazy_unmount(buffer);

}

free(line);

}

vec_destroy(&mount_list);

// Re-read mount infos

snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", target_pid);

vec_init(&mount_list);

file_to_vector(buffer, &mount_list);

DEBUG_PRINT("hideroot unmount everything under /system, /vendor\n");

// Unmount everything under /system, /vendor, and loop mounts

vec_for_each(&mount_list, line) {

if (strstr(line, "/dev/block/loop") || strstr(line, " /system/") || strstr(line, " /vendor/")) {

sscanf(line, "%*s %4096s", buffer);

lazy_unmount(buffer);

}

free(line);

}

vec_destroy(&mount_list);

exit:

// 4. 目标进程继续运行

kill(target_pid, SIGCONT);

sleep(100);

return 0;

}

switch_mnt_ns的实现如下:

int switch_mnt_ns(int pid) {

char mnt[32];

snprintf(mnt, sizeof(mnt), "/proc/%d/ns/mnt", pid);

if(access(mnt, R_OK) == -1) {

DEBUG_PRINT("[switch_mnt_ns] %s can't access!", mnt);

return 1;

}

int fd, ret;

fd = open(mnt, O_RDONLY);

if (fd 

DEBUG_PRINT("[switch_mnt_ns] open %s failed!", mnt);

return 1;

}

// setns的详细解释见 http://man7.org/linux/man-pages/man2/setns.2.html

ret = setns(fd, 0);

close(fd);

return ret;

}

原理很简单,通过setns关联到目标进程,unmount掉一些文件系统。附件demo的测试输出:

unmount前后,目标进程/proc/self/mounts文件内容的变化:

然后测试了下namespace相关的输出,shell 和root的mnt-namespace 是同一个:

所以在shell或者root中某一个终端隐藏su后,在其他终端也不能直接访问su了。

另外,查看过的所有进程的net-namespace都是同一个:

关于哪些进程使用同一个namespace的逻辑,本菜也不清楚从内核源码的哪部分看,有大佬了解这块的欢迎拍砖。

上传的附件:

hideroot.zip

(7.06kb,202次下载)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值