SELinux 安全机制

SELinux 安全机制

SELinux (Security-Enhanced Linux) 是 Android 安全模型的核心组件,从 Android 4.3 开始引入,Android 5.0 后全面强制执行。理解 SELinux 对于逆向工程、Root 检测绕过、应用沙箱分析至关重要。


1. SELinux 基础概念

1.1 什么是 SELinux

SELinux 是一种强制访问控制 (MAC, Mandatory Access Control) 安全机制,与传统的自主访问控制 (DAC, Discretionary Access Control) 不同:

特性DAC (传统 Linux)MAC (SELinux)
控制主体文件所有者系统策略
权限继承子进程继承父进程权限每个进程独立策略
Root 权限Root 可以做任何事Root 也受策略限制
灵活性用户可修改权限策略由管理员定义

1.2 SELinux 运行模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
┌─────────────────────────────────────────────────────────────┐
│                    SELinux 运行模式                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │  Disabled   │  │  Permissive │  │  Enforcing  │         │
│  │  (禁用)     │  │  (宽容模式) │  │  (强制模式) │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│        ↓                ↓                ↓                  │
│   完全禁用         仅记录违规         记录+阻止违规          │
│   不检查策略       不阻止操作         阻止未授权操作          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

查看当前模式:

1
2
3
4
5
6
# 查看 SELinux 状态
getenforce
# 返回: Enforcing / Permissive / Disabled

# 查看详细状态
sestatus

切换模式(需要 Root):

1
2
3
4
5
# 临时切换到 Permissive 模式
setenforce 0

# 临时切换到 Enforcing 模式
setenforce 1

1.3 核心概念

概念说明示例
Subject (主体)执行操作的进程u:r:untrusted_app:s0
Object (客体)被访问的资源文件、Socket、设备
Context (上下文)安全标签u:object_r:app_data_file:s0
Policy (策略)访问控制规则allow untrusted_app app_data_file:file read;
Domain (域)进程运行的安全上下文untrusted_app, system_app
Type (类型)资源的安全标签app_data_file, system_file

2. Android SELinux 架构

2.1 架构概览

 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
┌─────────────────────────────────────────────────────────────────────┐
│                         Android SELinux 架构                         │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                     User Space (用户空间)                    │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │   │
│  │  │   App    │  │ System   │  │  Zygote  │  │   Init   │    │   │
│  │  │ Process  │  │ Server   │  │          │  │          │    │   │
│  │  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘    │   │
│  │       │             │             │             │           │   │
│  │       ↓             ↓             ↓             ↓           │   │
│  │  ┌─────────────────────────────────────────────────────┐   │   │
│  │  │              libselinux.so (SELinux 库)              │   │   │
│  │  └─────────────────────────┬───────────────────────────┘   │   │
│  └────────────────────────────┼───────────────────────────────┘   │
│                               │                                    │
│  ┌────────────────────────────┼───────────────────────────────┐   │
│  │                     Kernel Space (内核空间)                 │   │
│  │                            ↓                                │   │
│  │  ┌─────────────────────────────────────────────────────┐   │   │
│  │  │              SELinux Security Server                 │   │   │
│  │  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  │   │   │
│  │  │  │   Policy    │  │   Access    │  │   Audit     │  │   │   │
│  │  │  │   Database  │  │   Vector    │  │   Log       │  │   │   │
│  │  │  │             │  │   Cache     │  │             │  │   │   │
│  │  │  └─────────────┘  └─────────────┘  └─────────────┘  │   │   │
│  │  └─────────────────────────────────────────────────────┘   │   │
│  └────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                    SELinux Policy Files                      │   │
│  │  /system/etc/selinux/    /vendor/etc/selinux/               │   │
│  │  - plat_sepolicy.cil     - vendor_sepolicy.cil              │   │
│  │  - plat_file_contexts    - vendor_file_contexts             │   │
│  │  - plat_property_contexts                                    │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2.2 策略文件位置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Android 8.0+ (Treble 架构)
/system/etc/selinux/          # 平台策略
/vendor/etc/selinux/          # 厂商策略
/odm/etc/selinux/             # ODM 策略

# 主要文件
plat_sepolicy.cil             # 编译后的策略
plat_file_contexts            # 文件上下文映射
plat_property_contexts        # 系统属性上下文
plat_service_contexts         # 服务上下文
plat_seapp_contexts           # 应用上下文规则

2.3 Android 进程域分类

域 (Domain)说明典型进程
initInit 进程/init
kernel内核线程kthreadd
zygoteZygote 进程zygote, zygote64
system_server系统服务system_server
system_app系统应用预装系统 App
platform_app平台签名应用使用平台签名的 App
priv_app特权应用/system/priv-app/ 下的 App
untrusted_app普通应用第三方 App
isolated_app隔离进程isolatedProcess=true
shellShell 进程adb shell
suRoot 进程Magisk su
magiskMagisk 域Magisk 守护进程

3. 安全上下文与标签

3.1 上下文格式

SELinux 安全上下文格式:

1
user:role:type:sensitivity[:categories]

示例解析:

1
2
3
4
5
6
u:r:untrusted_app:s0:c512,c768
│ │ │              │  └─────────── 类别 (MLS/MCS)
│ │ │              └───────────── 敏感度级别
│ │ └──────────────────────────── 类型/域
│ └────────────────────────────── 角色
└──────────────────────────────── 用户

3.2 查看上下文

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 查看进程上下文
ps -Z
# 输出示例:
# u:r:untrusted_app:s0:c512,c768  u0_a123  12345  com.example.app

# 查看文件上下文
ls -Z /data/data/com.example.app/
# 输出示例:
# u:object_r:app_data_file:s0:c512,c768  files

# 查看当前进程上下文
cat /proc/self/attr/current
# 或
id -Z

# 查看 Socket 上下文
ss -Z

# 查看系统属性上下文
getprop -Z

3.3 上下文转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
┌─────────────────────────────────────────────────────────────┐
│                    进程上下文转换流程                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Zygote (u:r:zygote:s0)                                   │
│         │                                                   │
│         │ fork()                                            │
│         ↓                                                   │
│   App Process (初始: u:r:zygote:s0)                        │
│         │                                                   │
│         │ setcon() 域转换                                   │
│         ↓                                                   │
│   App Process (最终: u:r:untrusted_app:s0:c512,c768)       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

seapp_contexts 规则示例:

1
2
3
4
5
# /system/etc/selinux/plat_seapp_contexts
user=_app seinfo=platform domain=platform_app type=app_data_file
user=_app isPrivApp=true domain=priv_app type=privapp_data_file
user=_app domain=untrusted_app type=app_data_file
user=_isolated domain=isolated_app

4. SELinux 策略分析

4.1 策略规则语法

allow 规则:

1
allow source_type target_type:class permissions;

示例:

1
2
3
4
5
6
7
8
# 允许 untrusted_app 域读取 app_data_file 类型的文件
allow untrusted_app app_data_file:file { read open getattr };

# 允许 untrusted_app 连接到 app_api_service
allow untrusted_app app_api_service:service_manager find;

# 允许 untrusted_app 使用 Binder IPC
allow untrusted_app servicemanager:binder { call transfer };

4.2 其他规则类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# neverallow - 禁止规则(编译时检查)
neverallow untrusted_app system_file:file write;

# dontaudit - 不记录拒绝日志
dontaudit untrusted_app self:capability sys_ptrace;

# auditallow - 允许但记录日志
auditallow untrusted_app app_data_file:file write;

# type_transition - 类型转换
type_transition untrusted_app app_data_file:file app_tmp_file;

4.3 提取和分析策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 从设备提取策略
adb pull /sys/fs/selinux/policy ./policy.bin

# 使用 seinfo 分析策略(需要 setools)
seinfo policy.bin

# 查看所有类型
seinfo -t policy.bin

# 查看所有域
seinfo -a domain -x policy.bin

# 使用 sesearch 搜索规则
# 搜索 untrusted_app 的所有 allow 规则
sesearch -A -s untrusted_app policy.bin

# 搜索对特定类型的访问规则
sesearch -A -t app_data_file policy.bin

# 搜索特定权限
sesearch -A -p write -t system_file policy.bin

4.4 分析 file_contexts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 查看文件上下文映射
cat /system/etc/selinux/plat_file_contexts

# 常见映射示例
/data(/.*)?                 u:object_r:system_data_file:s0
/data/app(/.*)?             u:object_r:apk_data_file:s0
/data/data(/.*)?            u:object_r:app_data_file:s0
/data/local/tmp(/.*)?       u:object_r:shell_data_file:s0
/system(/.*)?               u:object_r:system_file:s0
/vendor(/.*)?               u:object_r:vendor_file:s0

5. 常用命令与工具

5.1 基础命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 查看 SELinux 状态
getenforce                    # 获取当前模式
sestatus                      # 详细状态信息

# 切换模式(需要 Root)
setenforce 0                  # Permissive
setenforce 1                  # Enforcing

# 上下文操作
id -Z                         # 当前进程上下文
ps -eZ                        # 所有进程上下文
ls -Z                         # 文件上下文

# 修改文件上下文(需要 Root)
chcon u:object_r:system_file:s0 /path/to/file
restorecon /path/to/file      # 恢复默认上下文

# 查看拒绝日志
dmesg | grep avc              # 内核日志中的 AVC 拒绝
logcat | grep avc             # logcat 中的 AVC 拒绝

5.2 分析工具

工具用途安装方式
setools策略分析工具集apt install setools
seinfo查看策略信息setools 包含
sesearch搜索策略规则setools 包含
audit2allow生成 allow 规则apt install policycoreutils
sepolicy-analyzeAndroid 策略分析AOSP 构建

5.3 AVC 拒绝日志分析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# AVC 拒绝日志格式
avc: denied { read } for pid=12345 comm="com.example.app" \
    name="secret.txt" dev="dm-0" ino=123456 \
    scontext=u:r:untrusted_app:s0:c512,c768 \
    tcontext=u:object_r:system_data_file:s0 \
    tclass=file permissive=0

# 字段说明
# denied { read }           - 被拒绝的操作
# pid=12345                 - 进程 ID
# comm="com.example.app"    - 进程名
# name="secret.txt"         - 目标文件名
# scontext=...              - 源上下文(进程)
# tcontext=...              - 目标上下文(文件)
# tclass=file               - 目标类别
# permissive=0              - 是否为 Permissive 模式

使用 audit2allow 生成规则:

1
2
3
4
5
6
# 从日志生成 allow 规则
adb shell dmesg | audit2allow -p policy.bin

# 输出示例
#============= untrusted_app ==============
allow untrusted_app system_data_file:file read;

6. 逆向工程中的 SELinux

6.1 SELinux 对逆向的影响

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
┌─────────────────────────────────────────────────────────────┐
│              SELinux 对逆向工程的限制                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐     SELinux      ┌─────────────┐          │
│  │   Frida     │ ───────────────→ │  App 进程   │          │
│  │   Server    │     ptrace       │             │          │
│  └─────────────┘     denied       └─────────────┘          │
│                                                             │
│  限制场景:                                                   │
│  1. ptrace 附加进程                                         │
│  2. 读写 /proc/pid/mem                                      │
│  3. 注入 .so 文件                                           │
│  4. 访问其他应用数据                                         │
│  5. 执行特权操作                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6.2 检测 SELinux 状态

Java 层检测:

 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
public class SELinuxChecker {

    // 方法1: 通过 System 属性
    public static String getSELinuxStatus() {
        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class, String.class);
            return (String) get.invoke(null, "ro.build.selinux", "unknown");
        } catch (Exception e) {
            return "unknown";
        }
    }

    // 方法2: 通过执行命令
    public static boolean isEnforcing() {
        try {
            Process process = Runtime.getRuntime().exec("getenforce");
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream()));
            String result = reader.readLine();
            return "Enforcing".equals(result);
        } catch (Exception e) {
            return true; // 默认假设是 Enforcing
        }
    }

    // 方法3: 读取 /sys/fs/selinux/enforce
    public static int getEnforceValue() {
        try {
            BufferedReader reader = new BufferedReader(
                new FileReader("/sys/fs/selinux/enforce"));
            String line = reader.readLine();
            reader.close();
            return Integer.parseInt(line.trim());
        } catch (Exception e) {
            return -1;
        }
    }
}

Native 层检测:

 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
#include <stdio.h>
#include <selinux/selinux.h>

// 获取 SELinux 模式
int get_selinux_mode() {
    // 返回值: 1 = Enforcing, 0 = Permissive, -1 = Error
    return security_getenforce();
}

// 获取当前进程上下文
char* get_current_context() {
    char *context = NULL;
    if (getcon(&context) == 0) {
        return context;
    }
    return NULL;
}

// 获取文件上下文
char* get_file_context(const char *path) {
    char *context = NULL;
    if (getfilecon(path, &context) == 0) {
        return context;
    }
    return NULL;
}

// 检查是否可以访问
int check_access(const char *scon, const char *tcon,
                 const char *tclass, const char *perm) {
    return selinux_check_access(scon, tcon, tclass, perm, NULL);
}

6.3 Frida 检测 SELinux

 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
// Frida 脚本: 检测 SELinux 状态
function checkSELinux() {
    console.log("[*] Checking SELinux status...");

    // 方法1: 读取 enforce 文件
    try {
        var enforce = File.readAllText("/sys/fs/selinux/enforce");
        console.log("[*] /sys/fs/selinux/enforce: " + enforce.trim());
    } catch (e) {
        console.log("[!] Cannot read enforce file: " + e);
    }

    // 方法2: 读取当前进程上下文
    try {
        var context = File.readAllText("/proc/self/attr/current");
        console.log("[*] Current context: " + context.trim());
    } catch (e) {
        console.log("[!] Cannot read context: " + e);
    }

    // 方法3: Hook getenforce
    var getenforce = Module.findExportByName("libc.so", "security_getenforce");
    if (getenforce) {
        Interceptor.attach(getenforce, {
            onLeave: function(retval) {
                console.log("[*] security_getenforce() = " + retval);
            }
        });
    }
}

// 检测 SELinux 上下文获取
function hookSELinuxContextAPIs() {
    // Hook getcon
    var getcon = Module.findExportByName("libselinux.so", "getcon");
    if (getcon) {
        Interceptor.attach(getcon, {
            onEnter: function(args) {
                this.contextPtr = args[0];
            },
            onLeave: function(retval) {
                if (retval.toInt32() === 0) {
                    var context = Memory.readPointer(this.contextPtr);
                    console.log("[*] getcon() = " + Memory.readCString(context));
                }
            }
        });
    }

    // Hook getfilecon
    var getfilecon = Module.findExportByName("libselinux.so", "getfilecon");
    if (getfilecon) {
        Interceptor.attach(getfilecon, {
            onEnter: function(args) {
                this.path = Memory.readCString(args[0]);
                this.contextPtr = args[1];
            },
            onLeave: function(retval) {
                if (retval.toInt32() >= 0) {
                    var context = Memory.readPointer(this.contextPtr);
                    console.log("[*] getfilecon(" + this.path + ") = " +
                                Memory.readCString(context));
                }
            }
        });
    }
}

7. SELinux 绕过技术

7.1 Magisk 的 SELinux 处理

Magisk 通过以下方式处理 SELinux:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌─────────────────────────────────────────────────────────────┐
│                  Magisk SELinux 处理流程                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 注入自定义 SELinux 规则                                  │
│     ┌─────────────────────────────────────────────────┐    │
│     │  magiskpolicy --live                             │    │
│     │  "allow magisk * * *"                            │    │
│     │  "allow su * * *"                                │    │
│     └─────────────────────────────────────────────────┘    │
│                                                             │
│  2. 创建 magisk 和 su 域                                    │
│     ┌─────────────────────────────────────────────────┐    │
│     │  type magisk domain                              │    │
│     │  type su domain                                  │    │
│     │  permissive magisk                               │    │
│     │  permissive su                                   │    │
│     └─────────────────────────────────────────────────┘    │
│                                                             │
│  3. 上下文转换                                               │
│     App (untrusted_app) → su → magisk                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

7.2 动态修改 SELinux 策略

1
2
3
4
5
6
7
8
9
# 使用 magiskpolicy 修改策略
magiskpolicy --live "allow untrusted_app system_file file read"
magiskpolicy --live "allow untrusted_app app_data_file file *"

# 添加 permissive 域
magiskpolicy --live "permissive untrusted_app"

# 类型转换规则
magiskpolicy --live "type_transition untrusted_app system_file:process su"

7.3 Frida SELinux 绕过

 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
// 绕过 SELinux 上下文检查
function bypassSELinuxCheck() {
    // Hook security_getenforce 返回 0 (Permissive)
    var security_getenforce = Module.findExportByName("libselinux.so",
                                                       "security_getenforce");
    if (security_getenforce) {
        Interceptor.replace(security_getenforce, new NativeCallback(function() {
            return 0; // 返回 Permissive
        }, 'int', []));
        console.log("[*] Hooked security_getenforce -> always return 0");
    }

    // Hook selinux_check_access 总是返回成功
    var selinux_check_access = Module.findExportByName("libselinux.so",
                                                        "selinux_check_access");
    if (selinux_check_access) {
        Interceptor.replace(selinux_check_access, new NativeCallback(function(
            scon, tcon, tclass, perm, auditdata) {
            return 0; // 返回允许访问
        }, 'int', ['pointer', 'pointer', 'pointer', 'pointer', 'pointer']));
        console.log("[*] Hooked selinux_check_access -> always return 0");
    }
}

// 修改进程上下文检测结果
function spoofContext() {
    var getcon = Module.findExportByName("libselinux.so", "getcon");
    if (getcon) {
        Interceptor.attach(getcon, {
            onLeave: function(retval) {
                if (retval.toInt32() === 0) {
                    // 可以修改返回的上下文
                    // 注意: 这只影响检测,不影响实际权限
                }
            }
        });
    }
}

7.4 内核级绕过

1
2
3
4
5
// 内核模块方式(需要内核源码编译)
// 修改 security/selinux/hooks.c 中的 selinux_enforcing 变量

// 或通过 /dev/kmem 直接修改内核内存(需要特殊权限)
// 这种方式在现代 Android 上通常不可行

8. 实战案例

💡 思路一句话: SELinux 是 Android 安全的基石 — 逆向分析中遇到的权限拒绝、文件访问失败、调试受限,很多都与 SELinux 策略相关,学会读 audit 日志是排查问题的关键。

8.1 案例: 分析应用的 SELinux 权限

💡 思路一句话: 用 adb shell ps -eZ 查看进程的安全上下文 → 用 sesearch 查询该上下文允许的操作 → 理解应用能访问哪些资源、不能访问哪些资源。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 1. 获取目标应用的进程 ID
adb shell pidof com.example.app
# 输出: 12345

# 2. 查看进程上下文
adb shell cat /proc/12345/attr/current
# 输出: u:r:untrusted_app:s0:c512,c768

# 3. 查看应用数据目录上下文
adb shell ls -Z /data/data/com.example.app/
# 输出: u:object_r:app_data_file:s0:c512,c768 files

# 4. 分析该域的权限
sesearch -A -s untrusted_app -t app_data_file policy.bin
# 输出: allow untrusted_app app_data_file:file { read write ... };

# 5. 检查是否有敏感权限
sesearch -A -s untrusted_app -t system_file policy.bin
# 输出: (通常为空或受限)

8.2 案例: Root 检测中的 SELinux 检查

💡 思路一句话: 很多 App 通过读取 SELinux 状态(getenforce)或检查安全上下文来判断是否 root — 绕过方法是 hook getenforce 返回 “Enforcing” 或修改 /sys/fs/selinux/enforce。

 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
// 常见的 SELinux Root 检测
public class RootDetector {

    public boolean detectByContext() {
        try {
            // 检查是否存在 su 或 magisk 上下文
            Process process = Runtime.getRuntime().exec("cat /proc/self/attr/current");
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream()));
            String context = reader.readLine();

            // 正常应用: u:r:untrusted_app:s0
            // Root 后可能: u:r:su:s0 或 u:r:magisk:s0
            if (context.contains(":su:") || context.contains(":magisk:")) {
                return true; // 检测到 Root
            }
        } catch (Exception e) {}
        return false;
    }

    public boolean detectByEnforcing() {
        try {
            // 检查 SELinux 是否被禁用
            Process process = Runtime.getRuntime().exec("getenforce");
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream()));
            String status = reader.readLine();

            // Permissive 或 Disabled 通常意味着被修改
            if (!"Enforcing".equals(status)) {
                return true;
            }
        } catch (Exception e) {}
        return false;
    }
}

绕过脚本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// Frida 绕过 SELinux Root 检测
Java.perform(function() {
    // Hook Runtime.exec
    var Runtime = Java.use("java.lang.Runtime");
    Runtime.exec.overload('java.lang.String').implementation = function(cmd) {
        if (cmd.indexOf("getenforce") !== -1) {
            console.log("[*] Intercepted getenforce command");
            // 返回假的 Enforcing 结果
            return this.exec("echo Enforcing");
        }
        if (cmd.indexOf("/proc/self/attr/current") !== -1) {
            console.log("[*] Intercepted context read");
            // 返回正常应用上下文
            return this.exec("echo u:r:untrusted_app:s0");
        }
        return this.exec(cmd);
    };
});

8.3 案例: 调试 SELinux 拒绝问题

💡 思路一句话: adb logcat | grep avc 过滤 SELinux 拒绝日志 → 用 audit2allow 生成允许规则 → 通过 Magisk 模块注入策略 → 验证问题解决。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 场景: Frida 注入失败,查看是否被 SELinux 阻止

# 1. 实时监控 AVC 拒绝日志
adb shell "dmesg -w | grep avc"

# 2. 尝试注入操作
frida -U com.example.app

# 3. 观察日志输出
# avc: denied { ptrace } for pid=1234 comm="frida-server" ...

# 4. 分析拒绝原因
# scontext=u:r:shell:s0 (Frida Server 运行在 shell 域)
# tcontext=u:r:untrusted_app:s0 (目标应用)
# tclass=process perm=ptrace

# 5. 解决方案
# 方案 A: 使用 Magisk 修改策略
magiskpolicy --live "allow shell untrusted_app process ptrace"

# 方案 B: 临时切换到 Permissive 模式
adb shell setenforce 0

总结

要点说明
核心概念SELinux 是强制访问控制,即使 Root 也受策略限制
上下文格式user:role:type:sensitivity
策略位置/system/etc/selinux/, /vendor/etc/selinux/
分析工具seinfo, sesearch, audit2allow
逆向影响限制 ptrace、进程注入、文件访问等操作
绕过方式Magisk 策略注入、Hook SELinux API、切换 Permissive

相关章节


相关内容

如果这篇文章对你有帮助,请我喝杯咖啡吧~
+5 支付宝支付宝
+5 微信微信