应用安全

应用安全

下面我将详细列举 Android 平台上的 Root 检测方法及其对抗方案。

Root 检测与对抗全景图

Root 检测的核心思路是寻找设备被 Root 后留下的 “痕迹”。对抗的核心思路则是 “隐藏痕迹” 或 “欺骗检测API”。

一、常规路径与文件检测

这是最基础、最常见的检测方法,检查通常只有 Root 后才会存在的特殊文件、路径和二进制工具。

检测方法检测目标示例对抗方法

检查 Superuser APK

/system/app/Superuser.apk/system/app/SuperSU.apk

重命名/隐藏APK:使用 Magisk Hide 或类似功能隐藏管理应用。

检查 SU 二进制文件

/system/bin/su/system/xbin/su/sbin/su/vendor/bin/su

移除默认SU路径:Magisk 将其 magisk 二进制文件放在随机化的路径下,并通过 su 符号链接调用。隐藏符号链接是关键。

检查其他Root工具

busybox, sqlite3 等常用工具

避免安装:不要安装不必要的、可能暴露环境的工具。

检查测试密钥

ro.build.tags=test-keys

修改Build属性:使用 MagiskHide Props Config 模块,将指纹 (fingerprint) 和标签 (tags) 模拟为官方发布密钥 (release-keys)。

对抗代码示例 (Hook java.io.File.exists()):

javascript

Java.perform(function() {

var suspiciousPaths = [

"/system/bin/su", "/system/xbin/su", "/sbin/su",

"/system/app/Superuser.apk", "/system/app/SuperSU"

];

var File = Java.use("java.io.File");

File.exists.implementation = function() {

var path = this.getAbsolutePath();

for (var i = 0; i < suspiciousPaths.length; i++) {

if (path.startsWith(suspiciousPaths[i])) {

console.log("[Bypass] Blocking access to: " + path);

return false; // 告诉调用者文件不存在

}

}

return this.exists(); // 正常调用原方法

};

});

二、环境属性检测

检查系统的各种属性,寻找与官方系统不一致的“非正常”值。

检测方法检测目标示例对抗方法

检查 ro.debuggable

getprop ro.debuggable != 0

动态修改属性值:使用 Magisk Hide 或通过 Hook 在应用读取时临时返回 0。

检查 ro.secure

getprop ro.secure != 1

同上,动态修改返回值。

检查 ro.build.type

getprop ro.build.type != user

修改为 user。

检查特定Magisk属性

ro.boot.vbmeta.device_statero.boot.veritymode

使用 Magisk 本身:Magisk 会主动隐藏这些痕迹。

对抗代码示例 (Hook android.os.SystemProperties.get()):

javascript

Java.perform(function() {

var SystemProperties = Java.use("android.os.SystemProperties");

SystemProperties.get.overload('java.lang.String').implementation = function(key) {

if (key === "ro.debuggable") {

return "0";

} else if (key === "ro.secure") {

return "1";

} else if (key === "ro.build.type") {

return "user";

} else if (key === "ro.build.tags") {

return "release-keys";

}

return this.get(key); // 其他属性正常返回

};

// 另一个重载方法也需要Hook

SystemProperties.get.overload('java.lang.String', 'java.lang.String').implementation = function(key, def) {

var origResult = this.get(key, def);

if (key === "ro.debuggable") {

return "0";

}

// ... 其他属性同上

return origResult;

};

});

三、运行命令检测

尝试执行 which su 或 pm list packages 等命令,查看输出结果。

检测方法检测目标示例对抗方法

which su

检查命令返回值或输出

隐藏 su 命令:Magisk 通过修改 PATH 环境变量或挂钩子 (hook) 系统调用来实现。

pm list packages

检查包列表中是否存在 magisk、supersu 等

隐藏管理包名:使用 Magisk Hide 功能隐藏特定的应用程序。

对抗代码示例 (Hook java.lang.Runtime.exec()):

javascript

Java.perform(function() {

var Runtime = Java.use("java.lang.Runtime");

var execOverloads = ['java.lang.String', '[Ljava.lang.String;'];

for (var i = 0; i < execOverloads.length; i++) {

Runtime.exec.overload(execOverloads[i]).implementation = function() {

var cmd = arguments[0];

if (typeof cmd === 'string') {

if (cmd.includes("which su") || cmd.includes("/system/bin/which su")) {

console.log("[Bypass] Blocking command: " + cmd);

// 可以返回一个空的Process对象或抛异常,但更安全的是返回一个“未找到”的模拟输出

// 这里需要更复杂的实现来模拟一个空的InputStream

return null; // 简单示例,实际处理更复杂

}

}

return this.exec.apply(this, arguments);

};

}

});

四、Native层检测

在 C/C++ 层进行更底层、更隐蔽的检测。

检测方法检测目标示例对抗方法

直接使用 access() 系统调用

access("/system/bin/su", F_OK)

Hook Native 函数:使用 Frida 或 Xposed (Whale) 来 Hook libc 中的 access、fopen、stat 等函数。

检查进程列表

读取 /proc/self/mounts 查找 magisk 路径

隐藏Magisk路径:Magisk 会使用 mount 命名空间来隔离其修改,使其对目标应用不可见。

检测加载的库

检查 maps 中是否加载了 libsu.so 等

隐藏库:避免使用会注入so库的Root管理App,或Hook读取 /proc/self/maps 的函数。

对抗代码示例 (Hook Native access()):

javascript

// Frida JS 代码

var libc = Module.findBaseName('libc.so');

var accessAddr = Module.findExportByName(libc, 'access');

Interceptor.attach(accessAddr, {

onEnter: function(args) {

this.path = args[0].readCString();

if (this.path && this.path.includes("su")) {

console.log("[Bypass] Blocking access to: " + this.path);

// 让 access 调用返回 -1 (表示文件不存在),并设置 errno 为 ENOENT

this.errno = 0x20000002; // 根据系统定义,通常为 2

}

},

onLeave: function(retval) {

if (this.errno) {

retval.replace(-1); // 返回 -1

// 在某些架构上,还需要通过 __errno location 来设置 errno

}

}

});

五、综合与高阶检测

检测方法检测目标示例对抗方法

SafetyNet API

Google 官方的完整性检验 API。

Magisk 的核心功能:Magisk 的 Universal SafetyNet Fix 模块通过模拟硬件 attestation 来通过验证。

执行结果差异性

对比 stat("/system/bin/su") 和 stat("/system/bin/ls") 的权限、用户组等。

完善的隐藏方案:需要完整的Root解决方案(如Magisk)在系统层面进行全局隐藏,而不是局部Hook。

内核特征检测

检测 syscall 表是否被修改(挂钩子)。

KernelSU:另一种Root方案,修改内核但力求隐藏得更好。对抗难度极大。

总结与最佳实践

对于普通用户/测试人员:

首选 Magisk:它是目前隐藏能力最强、更新最活跃的Root方案。

开启 Magisk Hide:在设置中启用,并勾选需要隐藏Root的目标应用(如银行App、游戏等)。

安装模块:安装 Universal SafetyNet Fix 和 MagiskHide Props Config 等模块来通过更严格的检测。

隐藏 Magisk 应用:在 Magisk 设置中,有一个选项可以将其自身应用包名随机化。

对于安全研究人员(需要对抗更强检测):

组合使用工具:Magisk + Frida。

定制化Hook:分析目标App的检测逻辑,使用上述 Frida 脚本示例,编写针对性的Hook代码。

环境隔离:使用基于内核的隔离方案(如 KernelSU),或者直接在定制ROM中实现隐藏。

动态分析:如果Hook失败,可能是因为检测在Native层或使用了反调试。需要逆向App的so库,找到检测函数并下断点分析,然后制定更底层的Hook方案。

记住:这是一场持续的攻防战。新的检测方法不断出现,而隐藏技术也在不断进化。没有一劳永逸的方案,关键在于理解原理,灵活运用各种工具。

过检工具

firda脚本绕过

https://github.com/AshenOneYe/FridaAntiRootDetection

Shamiko模块绕过

https://github.com/LSPosed/LSPosed.github.io/releases/tag/shamiko-344

狐狸面具绕过(推荐这种方法,一劳永逸)

对抗

const-string ([vp]\d+), “*.su”

替换

const-string $1, "/no_su"

最终效果

修改前:

smali

const-string v0, "/system/xbin/su" # 加载一个真实存在的Root路径

# file.exists() -> true (检测到Root)

修改后:

smali

const-string v0, "/no su" # 加载一个绝对不存在的假路径

# file.exists() -> false (未检测到Root)

通过将检测Root的关键字符串(su的路径)替换为一个无意义的、不存在的字符串,应用程序的Root检查逻辑就会被绕过,认为设备没有Root权限,从而允许应用继续正常运行。

相关文章

2025 iPhone 17「iCloud備份正在估計剩餘時間」解決方法大揭秘!
超英电影烂片太多?推荐10部顶级超级英雄电影,爽感和深度拉满!
剑网三:温泉山庄玩法详解及全成就
mobile 365365051

剑网三:温泉山庄玩法详解及全成就

📅 01-04 👁️ 8498