nszdhd1's blog.

Magisk检测

2020/03/09

Magisk 原理

Xposed 和 Magisk原理图

image-20200220161119719

Xposed 原理

详细讲解:https://blog.csdn.net/ascii2/article/details/47974217

Xposed修改了app_process程序,在执行第一个java程序(com.Android.internal.os.ZygoteInit)之前进行截获,改变执行流程,进入到XposedBridge.jar,通过INI方法hookMethodNative指向Native方法xposedCallHandler,xposedCallHandler在转入handleHookedMethod这个Java方法执行用户规定的Hook Func

xposed 检测方法

1. 检测包名

检测是否安装de.robv.android.xposed.installer

2.调用栈

抛出一个异常并捕获,将堆栈信息打印出来:

image-20200220164108776

可以看到每个App是先执行的XposedBridge.jar的main方法,之后再调用的Zygote的main方法。通过检测堆栈中是否包含Xposed等字样即可知道是否安装了Xposed

3. xposed相关文件

Xposed的组件需要被加载,必然在内存空间留下痕迹,通过遍历/proc//maps内容,观察是否加载/system/framework/XposedBridge.jar

4. 检测并且关闭HOOK

de.robv.android.xposed.XposedBridge中有一个disableHooks字段用于标记对于当前应用是否要进行hook。通过获取这个字段的值就可以知道是否在我们App上启用hook了,甚至可以通过将其设置为true停掉Xposed。

1
2
3
4
5
6
7
Field disableHooksFiled = ClassLoader.getSystemClassLoader()
.loadClass("de.robv.android.xposed.XposedBridge")
.getDeclaredField("disableHooks");
disableHooksFiled.setAccessible(true);
Object enable = disableHooksFiled.get(null); // 当前状态
disableHooksFiled.set(null, true); // 设置为关闭

5. 来自支付宝的xposed HOOK检测

原文地址:https://segmentfault.com/a/1190000009976827

反射获得一个类de.robv.android.xposed.XposedHelpers 的对象,检测obXposedHelper成员fieldCache,methodCache,constructorCache是否有支付宝包的关键字。

Magisk 原理

网上分析magisk的资料很少,都只说:

Magisk则另辟蹊径,通过挂载一个与系统文件相隔离的文件系统来加载自定义内容,为系统分区打开了一个通往平行世界的入口,所有改动在那个世界(Magisk分区)里发生,在必要的时候却又可以被认为是(从系统分区的角度而言)没有发生过。

就这种程度的原理想检测magisk是不可能的。

因为知道magisk是靠修改boot.img来实现的,找到修改的shell脚本,介绍如下:

image-20200220172723250

通过阅读脚本,可知:

修改boot.img成功后,会将修改后的镜像添加到系统中去,主要为initialize()、main()函数。

initialize主要做一些检查、加载的工作,根据代码可知,magisk的工作目录在/data/adb/magisk

image-20200221110120916

main函数主要是安装magisk

image-20200221112244735

对main函数中的每个函数进行粗略的分析,mount_partitions主要是获取root权限,然后挂载一些自己的东西到系统

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
mount_partitions() {
# Check A/B slot
SLOT=`grep_cmdline androidboot.slot_suffix`
if [ -z $SLOT ]; then
SLOT=`grep_cmdline androidboot.slot`
[ -z $SLOT ] || SLOT=_${SLOT}
fi
[ -z $SLOT ] || ui_print "- Current boot slot: $SLOT"

# Mount ro partitions
mount_ro_ensure system
if [ -f /system/init.rc ]; then
SYSTEM_ROOT=true
[ -L /system_root ] && rm -f /system_root
mkdir /system_root 2>/dev/null
mount --move /system /system_root
mount -o bind /system_root/system /system
else
grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts \
&& SYSTEM_ROOT=true || SYSTEM_ROOT=false
fi
[ -L /system/vendor ] && mount_ro_ensure vendor
$SYSTEM_ROOT && ui_print "- Device is system-as-root"

# Mount persist partition in recovery
if ! $BOOTMODE && [ ! -z $PERSISTDIR ]; then
# Try to mount persist
PERSISTDIR=/persist
mount_name persist /persist
if ! is_mounted /persist; then
# Fallback to cache
mount_name cache /cache
is_mounted /cache && PERSISTDIR=/cache || PERSISTDIR=
fi
fi
}

find_manager_apk顾名思义,它提供了apk可能存在的几个路径:

1
2
3
4
5
6
7
8
9
10
11
12
find_manager_apk() {
[ -z $APK ] && APK=/data/adb/magisk.apk
[ -f $APK ] || APK=/data/magisk/magisk.apk
[ -f $APK ] || APK=/data/app/com.topjohnwu.magisk*/*.apk
if [ ! -f $APK ]; then
DBAPK=`magisk --sqlite "SELECT value FROM strings WHERE key='requester'" 2>/dev/null | cut -d= -f2`
[ -z $DBAPK ] && DBAPK=`strings /data/adb/magisk.db | grep 5requester | cut -c11-`
[ -z $DBAPK ] || APK=/data/user_de/*/$DBAPK/dyn/*.apk
[ -f $APK ] || [ -z $DBAPK ] || APK=/data/app/$DBAPK*/*.apk
fi
[ -f $APK ] || ui_print "! Unable to detect Magisk Manager APK for BootSigner"
}

install_magisk函数中的run_migrations,主要是将修boot.img.gz文件保存起来:

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
run_migrations() {
local LOCSHA1
local TARGET
# Legacy app installation
local BACKUP=/data/adb/magisk/stock_boot*.gz
if [ -f $BACKUP ]; then
cp $BACKUP /data
rm -f $BACKUP
fi

# Legacy backup
for gz in /data/stock_boot*.gz; do
[ -f $gz ] || break
LOCSHA1=`basename $gz | sed -e 's/stock_boot_//' -e 's/.img.gz//'`
[ -z $LOCSHA1 ] && break
mkdir /data/magisk_backup_${LOCSHA1} 2>/dev/null
mv $gz /data/magisk_backup_${LOCSHA1}/boot.img.gz
done

# Stock backups
LOCSHA1=$SHA1
for name in boot dtb dtbo; do
BACKUP=/data/adb/magisk/stock_${name}.img
[ -f $BACKUP ] || continue
if [ $name = 'boot' ]; then
LOCSHA1=`$MAGISKBIN/magiskboot sha1 $BACKUP`
mkdir /data/magisk_backup_${LOCSHA1} 2>/dev/null
fi
TARGET=/data/magisk_backup_${LOCSHA1}/${name}.img
cp $BACKUP $TARGET
rm -f $BACKUP
gzip -9f $TARGET
done
}

Magisk 检测方法

1. 检测是否安装Magisk manager

检查是否安装包名为 com.topjohnwu.magisk

2. Magisk 相关的文件

  1. 是否存在magisk的工作目录:/data/adb/magisk

  2. app安装相关目录:
    /data/app/com.topjohnwu.magisk、/data/user_de/0/com.topjohnwu.magisk、
    /config/sdcardfs/com.topjohnwu.magisk、/data/data/com.topjohnwu.magisk、
    /data/media/0/Android/data/com.topjohnwu.magisk、/mnt/runtime/default/emulated/0/Android/data/com.topjohnwu.magisk、
    /config/sdcardfs/com.topjohnwu.magisk

  3. magisk运行产生的目录和文件:

/data/magisk_backup_[md5]、/sbin/magisk、/cache/magisk.log、/mnt/vendor/persist/magisk

  1. 所有安装的magisk模块:/data/adb/modules
3. 系统信息

通过遍历/proc/mounts/proc/self/mounts中内容,观察是否有/sbin/magisk路径下的文件被挂载进系统

问题

  1. 目前magisk的检测方法,仅仅只是检测到手机上有magisk,并不能获得该用户在攻击自己app的证据

检测代码示例

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
app普通权限下 

std::vector<std::string> p;

//都失败:
p.push_back("/data/adb/magisk");
p.push_back("/data/app/com.topjohnwu.magisk");
p.push_back("/config/sdcardfs/com.topjohnwu.magisk");
p.push_back("/data/media/0/Android/data/com.topjohnwu.magisk");
p.push_back("/mnt/runtime/default/emulated/0/Android/data/com.topjohnwu.magisk");
p.push_back("/config/sdcardfs/com.topjohnwu.magisk");
p.push_back("/cache/magisk.log");
p.push_back("/mnt/vendor/persist/magisk");
p.push_back("/data/adb/modules");
p.push_back("/config/sdcardfs/com.topjohnwu.magisk/appid");
p.push_back("/data/adb/magisk/chromeos/kernel.keyblock");
p.push_back("/data/system/graphicsstats/1582156800000/com.topjohnwu.magisk");
p.push_back("/data/system_ce/0/shortcut_service/bitmaps/com.topjohnwu.magisk");
p.push_back("/mnt/runtime/default/emulated/0/Android/data/com.topjohnwu.magisk");
p.push_back("/mnt/runtime/write/emulated/0/Android/data/com.topjohnwu.magisk");

// access成功 ,open 失败 , stat失败:

p.push_back("/data/misc/profiles/ref/com.topjohnwu.magisk");
p.push_back("/data/misc/profiles/cur/0/com.topjohnwu.magisk");

// access成功 stat成功,open 失败:
p.push_back("/data/user_de/0/com.topjohnwu.magisk");
p.push_back("/data/data/com.topjohnwu.magisk");

//都成功:
p.push_back("/sbin/magiskpolicy");
p.push_back("/sbin/magiskinit");
p.push_back("/sbin/magiskhide");
p.push_back("/sbin/magisk");

int openfd = open("/proc/self/mounts",0,O_RDWR);
LOGE("open fd: %d",openfd);
char buff[1024] = {0};

while (read(openfd,buff,1024)){
LOGE("%s",buff);
}


close(openfd);
CATALOG
  1. 1. Magisk 原理
    1. 1.1. Xposed 和 Magisk原理图
    2. 1.2. Xposed 原理
    3. 1.3. xposed 检测方法
      1. 1.3.0.1. 1. 检测包名
      2. 1.3.0.2. 2.调用栈
      3. 1.3.0.3. 3. xposed相关文件
      4. 1.3.0.4. 4. 检测并且关闭HOOK
      5. 1.3.0.5. 5. 来自支付宝的xposed HOOK检测
  2. 1.4. Magisk 原理
  3. 1.5. Magisk 检测方法
    1. 1.5.0.1. 1. 检测是否安装Magisk manager
  • 1.6. 2. Magisk 相关的文件
    1. 1.6.0.1. 3. 系统信息
  • 1.7. 问题
  • 1.8. 检测代码示例