0%

Zygisk - MagiskHide

新版的 Magisk 没有 MagiskHide 了,于是我把旧版 (v23.0) 的 MagiskHide 抄了过来.

hide_unmount

最简单的检测 magisk 就是查看 /proc/%d/mounts 文件。代码如下

1
2
3
4
5
6
7
8
9
10
11
12
char line[1024];
char path[PATH_MAX];
FILE* fp;

sprintf(path,"/proc/%d/mounts",getpid());
fp = fopen(path, "r");
if (fp) {
while (fgets(line, 1024, fp)) {
LOGD("%s",line);
}
fclose(fp);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
......
2022-07-30 17:45:31.015 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/libvkjson.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.015 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/libvm_control.dylib.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.015 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/libvsim_auth.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.015 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/libvulkan.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.015 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/libwebviewchromium_loader.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.015 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/libwilhelm.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.016 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/shared-file-region-aidl-cpp.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.016 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/vendor.fs.fsalsps@1.0.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.016 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/vendor.qti.hardware.display.config-V3-ndk_platform.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.016 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/vendor.qti.hardware.display.config-V4-ndk_platform.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.016 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/vendor.qti.hardware.secureprocessor.common@1.0-helper.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0
2022-07-30 17:45:31.016 13650-13650/com.shocker.zygiskdetect D/Shocker: /dev/Y1U/.magisk/block/system_root /system/lib64/vendor.xiaomi.hardware.campostproc@1.0.so erofs ro,seclabel,relatime,user_xattr,acl,cache_strategy=readaround 0 0

可以看到,有很多 /dev/Y1U/.magisk/block/system_root .

在 MagiskHide 里,这些信息都会被 magisk daemon 给 unmount 掉.

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
void hide_unmount(int pid) {
if (pid > 0 && switch_mnt_ns(pid))//切换的目标进程的namespace
return;

LOGD("hide: handling PID=[%d]\n", pid);

char val;
int fd = xopen(SELINUX_ENFORCE, O_RDONLY);
xxread(fd, &val, sizeof(val));
close(fd);
// Permissive
if (val == '0') {
chmod(SELINUX_ENFORCE, 0640);
chmod(SELINUX_POLICY, 0440);
}

vector<string> targets;

// Unmount dummy skeletons and /sbin links
targets.push_back(MAGISKTMP);
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext))
targets.emplace_back(mentry->mnt_dir);
return true;
});

for (auto &s : reversed(targets))
lazy_unmount(s.data());
targets.clear();

// Unmount all Magisk created mounts
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
if (strstr(mentry->mnt_fsname, BLOCKDIR))
targets.emplace_back(mentry->mnt_dir);
return true;
});

for (auto &s : reversed(targets))
lazy_unmount(s.data());
}
1
2
3
4
static void lazy_unmount(const char* mountpoint) {
if (umount2(mountpoint, MNT_DETACH) != -1)
LOGD("hide: Unmounted (%s)\n", mountpoint);
}

在 zygisk 里需要改进下.

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
void do_hide(int pid)
{
if (pid > 0 && switch_mnt_ns(pid))
return;

char buf[64];
readlink("/proc/self/exe", buf, sizeof(buf));
string MAGISKTMP = dirname(buf);

lazy_unmount(MAGISKTMP.data());

parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
if (TMPFS_MNT(system) || TMPFS_MNT(vendor) || TMPFS_MNT(product) || TMPFS_MNT(system_ext))
{
lazy_unmount(mentry->mnt_dir);
}
return true;
});

// Unmount all Magisk created mounts
parse_mnt("/proc/self/mounts", [&](mntent *mentry) {
if (strstr(mentry->mnt_fsname, BLOCKDIR))
{
lazy_unmount(mentry->mnt_dir);
}
return true;
});
return;
}
1
2
3
4
5
6
7
8
9
10
11
static void companion_handler(int i)
{
int pid;
read(i, &pid, sizeof(pid));

unshare(CLONE_NEWNS);
mount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr);
LOGD("do_hide start pid:%d\n",pid);
do_hide(pid);
return;
}

加载模块后,查看效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
......
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: /dev/block/dm-15 /storage/emulated/0/Android/data f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,checkpoint_merge,fsync_mode=nobarrier 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: /dev/block/dm-15 /storage/emulated/0/Android/obb f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,checkpoint_merge,fsync_mode=nobarrier 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: tmpfs /data/data tmpfs rw,seclabel,nosuid,nodev,noexec,relatime,mode=751 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: tmpfs /data/user tmpfs rw,seclabel,nosuid,nodev,noexec,relatime,mode=751 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: tmpfs /data/user_de tmpfs rw,seclabel,nosuid,nodev,noexec,relatime,mode=751 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: /dev/block/dm-15 /data/user_de/0/com.shocker.zygiskdetect f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,checkpoint_merge,fsync_mode=nobarrier 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: /dev/block/dm-15 /data/data/com.shocker.zygiskdetect f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,checkpoint_merge,fsync_mode=nobarrier 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: /dev/block/dm-15 /data/user_de/0/com.google.android.gms f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,checkpoint_merge,fsync_mode=nobarrier 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: /dev/block/dm-15 /data/data/com.google.android.gms f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,checkpoint_merge,fsync_mode=nobarrier 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: tmpfs /data/misc/profiles/cur tmpfs rw,seclabel,nosuid,nodev,noexec,relatime,mode=751 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: tmpfs /data/misc/profiles/ref tmpfs rw,seclabel,nosuid,nodev,noexec,relatime,mode=751 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: /dev/block/dm-15 /data/misc/profiles/cur/0/com.shocker.zygiskdetect f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,checkpoint_merge,fsync_mode=nobarrier 0 0
2022-07-30 19:03:32.597 6774-6774/com.shocker.zygiskdetect D/Shocker: /dev/block/dm-15 /data/misc/profiles/ref/com.shocker.zygiskdetect f2fs rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=32768,resuid=0,resgid=1065,inlinecrypt,alloc_mode=default,checkpoint_merge,fsync_mode=nobarrier 0 0

hide_sensitive_props

修改系统敏感属性,例如 ro.boot.vbmeta.device_state ro.boot.verifiedbootstate 等等.
其原理是找到 /dev/__properties__/properties_serial 在进程中的内存,然后在内存中解析和修改
也可以参考这篇文章.
Android Property 实现解析与黑魔法
部分代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool ContextsSerialized::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) {
char filename[PROP_FILENAME_MAX];// filename:/dev/__properties__/properties_serial
int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial", filename_);
if (len < 0 || len >= PROP_FILENAME_MAX) {
serial_prop_area_ = nullptr;
return false;
}

if (access_rw) {
serial_prop_area_ =
prop_area::map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);//mmap映射到内存
} else {
serial_prop_area_ = prop_area::map_prop_area(filename);//mmap映射到内存
}
return serial_prop_area_;// serial_prop_area_就是 /dev/__properties__/properties_serial 在内存的映射地址
}

移植的 resetprop 代码如下.

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
static const char *prop_key[] =
{"ro.boot.vbmeta.device_state", "ro.boot.verifiedbootstate", "ro.boot.flash.locked",
"ro.boot.veritymode", "ro.boot.warranty_bit", "ro.warranty_bit",
"ro.debuggable", "ro.secure", "ro.build.type", "ro.build.tags",
"ro.vendor.boot.warranty_bit", "ro.vendor.warranty_bit",
"vendor.boot.vbmeta.device_state","ro.secureboot.lockstate", nullptr};

static const char *prop_val[] =
{"locked", "green", "1",
"enforcing", "0", "0",
"0", "1", "user", "release-keys",
"0", "0",
"locked","locked", nullptr};


void hide_sensitive_props()
{
LOGD("hide: Hiding sensitive props\n");

for (int i = 0; prop_key[i]; ++i)
{
char buf[256];
getprop(prop_key[i], buf);
string value = buf;
if (!value.empty())
{
LOGD("set %s:%s", prop_key[i], prop_val[i]);
setprop(prop_key[i], prop_val[i]);
}
}
}

日志输出如下

1
2
3
4
5
6
7
8
2022-08-01 14:12:11.035 2948-2949/? D/Shocker: set ro.boot.vbmeta.device_state:locked
2022-08-01 14:12:11.035 2948-2949/? D/Shocker: set ro.boot.verifiedbootstate:green
2022-08-01 14:12:11.035 2948-2949/? D/Shocker: set ro.boot.flash.locked:1
2022-08-01 14:12:11.035 2948-2949/? D/Shocker: set ro.boot.veritymode:enforcing
2022-08-01 14:12:11.035 2948-2949/? D/Shocker: set ro.debuggable:0
2022-08-01 14:12:11.035 2948-2949/? D/Shocker: set ro.secure:1
2022-08-01 14:12:11.035 2948-2949/? D/Shocker: set ro.build.type:user
2022-08-01 14:12:11.035 2948-2949/? D/Shocker: set ro.build.tags:release-keys
1
2
adb shell getprop ro.boot.vbmeta.device_state
locked

最后

已测试招商银行 app, 不会检测出 root.

GitHub 地址:
https://github.com/PShocker/Zygisk-MagiskHide