第十二章:Android安全机制全景

21 阅读13分钟

第十二章:Android安全机制全景

本章字数:约20000字 阅读时间:约65分钟 难度等级:★★★★★

声明:本文中的公司名称、包名、API地址、密钥等均已脱敏处理。文中的"梦想世界"、"dreamworld"等均为虚构名称,与任何真实公司无关。


引言

在前面的章节中,我们以攻击者的视角,成功突破了APP的安全防护。现在,让我们换一个角度,从防御者的视角来全面了解Android平台的安全机制。

理解这些安全机制,不仅能帮助我们更好地进行安全研究,也能指导我们设计更安全的应用。


12.1 Android安全架构概览

12.1.1 分层安全模型

┌─────────────────────────────────────────────────────────────────┐
│                    Android安全架构                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    应用层安全                            │    │
│  │  ─────────────────────────────────────────────────────  │    │
│  │  • 应用签名验证                                          │    │
│  │  • 权限系统                                              │    │
│  │  • 应用沙箱                                              │    │
│  │  • 代码混淆                                              │    │
│  └─────────────────────────────────────────────────────────┘    │
│                            │                                     │
│                            ▼                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                   框架层安全                             │    │
│  │  ─────────────────────────────────────────────────────  │    │
│  │  • Binder IPC安全                                        │    │
│  │  • 系统服务权限检查                                       │    │
│  │  • Intent过滤                                            │    │
│  │  • ContentProvider权限                                   │    │
│  └─────────────────────────────────────────────────────────┘    │
│                            │                                     │
│                            ▼                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                   Native层安全                           │    │
│  │  ─────────────────────────────────────────────────────  │    │
│  │  • SELinux强制访问控制                                   │    │
│  │  • Seccomp系统调用过滤                                   │    │
│  │  • ASLR地址随机化                                        │    │
│  │  • Stack Canary栈保护                                    │    │
│  └─────────────────────────────────────────────────────────┘    │
│                            │                                     │
│                            ▼                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                   内核层安全                             │    │
│  │  ─────────────────────────────────────────────────────  │    │
│  │  • Linux内核安全模块                                     │    │
│  │  • 进程隔离                                              │    │
│  │  • 文件系统权限                                          │    │
│  │  • 加密文件系统                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                            │                                     │
│                            ▼                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                   硬件层安全                             │    │
│  │  ─────────────────────────────────────────────────────  │    │
│  │  • TrustZone可信执行环境                                 │    │
│  │  • 硬件密钥存储                                          │    │
│  │  • 安全启动链                                            │    │
│  │  • 硬件随机数生成器                                       │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.1.2 安全设计原则

Android安全架构遵循以下核心原则:

1. 最小权限原则

  • 应用默认没有任何权限
  • 需要明确声明和用户授权
  • 权限按需申请

2. 纵深防御原则

  • 多层安全机制
  • 单点突破不会导致全面失守
  • 每层都有独立的安全检查

3. 隔离原则

  • 应用之间相互隔离
  • 用户数据与系统数据隔离
  • 敏感操作在可信环境执行

12.2 应用签名机制

12.2.1 签名方案演进

┌─────────────────────────────────────────────────────────────────┐
│                    APK签名方案演进                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  版本        引入时间      特点                                  │
│  ─────────────────────────────────────────────────────────────  │
│  v1 (JAR)   Android 1.0   基于JAR签名                           │
│                           只签名ZIP条目                          │
│                           可被篡改(添加文件)                    │
│                                                                  │
│  v2         Android 7.0   签名整个APK                           │
│                           防止任何修改                           │
│                           安装验证更快                           │
│                                                                  │
│  v3         Android 9.0   支持密钥轮换                          │
│                           向后兼容                               │
│                           更灵活的证书管理                        │
│                                                                  │
│  v4         Android 11    增量安装支持                          │
│                           流式验证                               │
│                           更快的安装速度                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.2.2 签名验证流程

/**
 * APK签名验证示意(简化版)
 */
public class ApkSignatureVerifier {
    
    /**
     * 验证APK签名
     */
    public boolean verifyApkSignature(File apkFile) {
        try {
            // 1. 尝试v4签名验证(Android 11+)
            if (hasV4Signature(apkFile)) {
                return verifyV4Signature(apkFile);
            }
            
            // 2. 尝试v3签名验证(Android 9+)
            if (hasV3Signature(apkFile)) {
                return verifyV3Signature(apkFile);
            }
            
            // 3. 尝试v2签名验证(Android 7+)
            if (hasV2Signature(apkFile)) {
                return verifyV2Signature(apkFile);
            }
            
            // 4. 回退到v1签名验证
            return verifyV1Signature(apkFile);
            
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * v2签名验证
     * 签名块位于ZIP Central Directory之前
     */
    private boolean verifyV2Signature(File apkFile) {
        // 1. 定位APK签名块
        // APK签名块位于ZIP Central Directory之前
        // 格式: [Contents of ZIP entries] [APK Signing Block] [Central Directory] [EOCD]
        
        // 2. 解析签名块
        // 签名块包含多个ID-Value对
        // ID 0x7109871a = v2签名
        
        // 3. 验证每个签名者
        // - 验证签名算法
        // - 验证摘要
        // - 验证证书链
        
        // 4. 验证APK内容完整性
        // 将APK分成1MB的块,计算每块的摘要
        // 验证摘要树
        
        return true;
    }
}

12.2.3 签名的安全意义

1. 身份验证

  • 确认APK来源
  • 防止冒充官方应用
  • 建立开发者信任

2. 完整性保护

  • 检测APK是否被篡改
  • 防止恶意代码注入
  • 保护用户安全

3. 权限继承

  • 相同签名的应用可共享权限
  • 支持应用升级
  • 实现应用间信任

12.3 权限系统

12.3.1 权限分类

┌─────────────────────────────────────────────────────────────────┐
│                      权限分类                                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  保护级别          说明                    示例                  │
│  ─────────────────────────────────────────────────────────────  │
│  normal           低风险权限              INTERNET               │
│                   安装时自动授予          VIBRATE                │
│                   无需用户确认            SET_WALLPAPER          │
│                                                                  │
│  dangerous        高风险权限              READ_CONTACTS          │
│                   需要用户明确授权        CAMERA                 │
│                   运行时请求              LOCATION               │
│                                                                  │
│  signature        签名权限                BIND_DEVICE_ADMIN      │
│                   仅相同签名应用可获得    MANAGE_DOCUMENTS       │
│                   系统应用专用                                   │
│                                                                  │
│  signatureOrSystem 签名或系统权限        ACCESS_ALL_DOWNLOADS   │
│                   (已废弃)               INSTALL_PACKAGES       │
│                                                                  │
│  privileged       特权权限                DELETE_PACKAGES        │
│                   仅系统特权应用          REBOOT                 │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.3.2 运行时权限

/**
 * 运行时权限请求示例
 */
public class PermissionHelper {
    
    private static final int REQUEST_CODE_PERMISSIONS = 100;
    
    /**
     * 检查并请求权限
     */
    public void checkAndRequestPermissions(Activity activity, String[] permissions) {
        List<String> permissionsToRequest = new ArrayList<>();
        
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) 
                    != PackageManager.PERMISSION_GRANTED) {
                permissionsToRequest.add(permission);
            }
        }
        
        if (!permissionsToRequest.isEmpty()) {
            // 检查是否需要显示权限说明
            for (String permission : permissionsToRequest) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                    // 显示权限说明对话框
                    showPermissionRationale(activity, permission);
                    return;
                }
            }
            
            // 请求权限
            ActivityCompat.requestPermissions(
                activity,
                permissionsToRequest.toArray(new String[0]),
                REQUEST_CODE_PERMISSIONS
            );
        }
    }
    
    /**
     * 处理权限请求结果
     */
    public void onRequestPermissionsResult(int requestCode, String[] permissions, 
                                          int[] grantResults) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            for (int i = 0; i < permissions.length; i++) {
                if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    // 权限已授予
                    onPermissionGranted(permissions[i]);
                } else {
                    // 权限被拒绝
                    onPermissionDenied(permissions[i]);
                }
            }
        }
    }
}

12.3.3 权限组

┌─────────────────────────────────────────────────────────────────┐
│                      危险权限组                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  权限组              包含的权限                                  │
│  ─────────────────────────────────────────────────────────────  │
│  CALENDAR           READ_CALENDAR, WRITE_CALENDAR               │
│                                                                  │
│  CAMERA             CAMERA                                       │
│                                                                  │
│  CONTACTS           READ_CONTACTS, WRITE_CONTACTS,              │
│                     GET_ACCOUNTS                                 │
│                                                                  │
│  LOCATION           ACCESS_FINE_LOCATION,                       │
│                     ACCESS_COARSE_LOCATION,                     │
│                     ACCESS_BACKGROUND_LOCATION                  │
│                                                                  │
│  MICROPHONE         RECORD_AUDIO                                │
│                                                                  │
│  PHONE              READ_PHONE_STATE, CALL_PHONE,               │
│                     READ_CALL_LOG, WRITE_CALL_LOG,              │
│                     ADD_VOICEMAIL, USE_SIP,                     │
│                     PROCESS_OUTGOING_CALLS                      │
│                                                                  │
│  SENSORS            BODY_SENSORS                                │
│                                                                  │
│  SMS                SEND_SMS, RECEIVE_SMS, READ_SMS,            │
│                     RECEIVE_WAP_PUSH, RECEIVE_MMS               │
│                                                                  │
│  STORAGE            READ_EXTERNAL_STORAGE,                      │
│                     WRITE_EXTERNAL_STORAGE                      │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.4 应用沙箱

12.4.1 沙箱机制原理

┌─────────────────────────────────────────────────────────────────┐
│                    应用沙箱架构                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐           │
│    │   App A     │  │   App B     │  │   App C     │           │
│    │  UID: 10001 │  │  UID: 10002 │  │  UID: 10003 │           │
│    └──────┬──────┘  └──────┬──────┘  └──────┬──────┘           │
│           │                │                │                    │
│           ▼                ▼                ▼                    │
│    ┌─────────────┐  ┌─────────────┐  ┌─────────────┐           │
│    │ /data/data/ │  │ /data/data/ │  │ /data/data/ │           │
│    │ com.app.a/  │  │ com.app.b/  │  │ com.app.c/  │           │
│    │ (700权限)   │  │ (700权限)   │  │ (700权限)   │           │
│    └─────────────┘  └─────────────┘  └─────────────┘           │
│                                                                  │
│    ════════════════════════════════════════════════════════     │
│                         SELinux策略                              │
│    ════════════════════════════════════════════════════════     │
│                                                                  │
│    ┌─────────────────────────────────────────────────────┐      │
│    │                    Linux内核                         │      │
│    │              进程隔离 / 文件系统权限                  │      │
│    └─────────────────────────────────────────────────────┘      │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

每个应用:
• 拥有唯一的Linux UID
• 运行在独立的进程中
• 拥有私有的数据目录
• 受SELinux策略约束

12.4.2 UID/GID分配

┌─────────────────────────────────────────────────────────────────┐
│                    UID分配规则                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  UID范围              用途                                       │
│  ─────────────────────────────────────────────────────────────  │
│  0                   root用户                                   │
│  1000                system用户                                 │
│  1001-1999           系统预定义用户                              │
│                      (radio, bluetooth, wifi等)                 │
│  2000                shell用户                                  │
│  10000-19999         普通应用                                   │
│  50000-59999         隔离进程                                   │
│  99000-99999         共享UID应用                                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.4.3 数据隔离

/**
 * 应用数据目录结构
 */
public class AppDataDirectories {
    
    // 内部存储(私有)
    // /data/data/<package_name>/
    // 或 /data/user/<user_id>/<package_name>/
    
    /**
     * 私有文件目录
     * 权限: 700 (仅应用自身可访问)
     */
    public File getFilesDir(Context context) {
        return context.getFilesDir();
        // /data/data/<package>/files/
    }
    
    /**
     * 私有缓存目录
     */
    public File getCacheDir(Context context) {
        return context.getCacheDir();
        // /data/data/<package>/cache/
    }
    
    /**
     * SharedPreferences目录
     */
    public File getSharedPrefsDir(Context context) {
        return new File(context.getDataDir(), "shared_prefs");
        // /data/data/<package>/shared_prefs/
    }
    
    /**
     * 数据库目录
     */
    public File getDatabasePath(Context context, String name) {
        return context.getDatabasePath(name);
        // /data/data/<package>/databases/<name>
    }
    
    /**
     * Native库目录
     */
    public String getNativeLibraryDir(Context context) {
        return context.getApplicationInfo().nativeLibraryDir;
        // /data/app/<package>/lib/<abi>/
    }
    
    // 外部存储(Android 10+作用域存储)
    
    /**
     * 应用专属外部存储
     */
    public File getExternalFilesDir(Context context, String type) {
        return context.getExternalFilesDir(type);
        // /storage/emulated/0/Android/data/<package>/files/<type>/
    }
}

12.5 SELinux强制访问控制

12.5.1 SELinux基础

┌─────────────────────────────────────────────────────────────────┐
│                    SELinux工作原理                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  传统Linux权限 (DAC - 自主访问控制):                             │
│  ─────────────────────────────────────────────────────────────  │
│  • 基于用户/组/其他的rwx权限                                     │
│  • root用户可以绑过所有检查                                      │
│  • 一旦获得root,系统完全暴露                                    │
│                                                                  │
│  SELinux (MAC - 强制访问控制):                                   │
│  ─────────────────────────────────────────────────────────────  │
│  • 基于安全上下文的策略                                          │
│  • 即使root也受策略约束                                          │
│  • 最小权限原则                                                  │
│                                                                  │
│  安全上下文格式:                                                 │
│  user:role:type:level                                           │
│  例如: u:r:untrusted_app:s0:c512,c768                           │
│                                                                  │
│  策略规则示例:                                                   │
│  allow untrusted_app app_data_file:file { read write };         │
│  (允许untrusted_app类型读写app_data_file类型的文件)              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.5.2 Android SELinux域

┌─────────────────────────────────────────────────────────────────┐
│                    主要SELinux域                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  域                    说明                                      │
│  ─────────────────────────────────────────────────────────────  │
│  init                 init进程                                  │
│  kernel               内核线程                                  │
│  system_server        系统服务进程                              │
│  zygote               Zygote进程                                │
│  untrusted_app        普通第三方应用                            │
│  platform_app         平台签名应用                              │
│  system_app           系统应用                                  │
│  priv_app             特权应用                                  │
│  isolated_app         隔离进程应用                              │
│  shell                adb shell                                 │
│  su                   root进程                                  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.5.3 SELinux对逆向的影响

SELinux限制了以下操作:

1. 进程注入
   • 无法ptrace其他应用进程
   • 无法修改其他应用内存
   
2. 文件访问
   • 无法读取其他应用私有数据
   • 无法修改系统文件
   
3. 网络操作
   • 某些端口受限
   • 某些协议受限
   
4. 设备访问
   • 无法直接访问硬件设备
   • 需要通过系统服务

绕过方法(需要root):
• setenforce 0  (切换到permissive模式)
• 修改SELinux策略
• 使用Magisk等工具

12.6 代码保护技术

12.6.1 代码混淆

┌─────────────────────────────────────────────────────────────────┐
│                    代码混淆技术                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  混淆类型          效果                    工具                  │
│  ─────────────────────────────────────────────────────────────  │
│  名称混淆          类/方法/字段名          ProGuard              │
│                   变为无意义字符           R8                    │
│                                                                  │
│  控制流混淆        插入虚假分支            DexGuard              │
│                   打乱执行顺序            Allatori              │
│                                                                  │
│  字符串加密        运行时解密字符串        DexGuard              │
│                   防止静态分析            自定义实现             │
│                                                                  │
│  反射调用          隐藏真实调用            自定义实现             │
│                   增加分析难度                                   │
│                                                                  │
│  Native化          关键代码转为Native      DexProtector          │
│                   提高逆向难度            自定义实现             │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.6.2 ProGuard/R8配置示例

# proguard-rules.pro

# 保留应用入口
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider

# 保留JNI方法
-keepclasseswithmembernames class * {
    native <methods>;
}

# 保留序列化类
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# 保留枚举
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 混淆字典(使用难以阅读的字符)
-obfuscationdictionary dictionary.txt
-classobfuscationdictionary dictionary.txt
-packageobfuscationdictionary dictionary.txt

# 优化选项
-optimizationpasses 5
-allowaccessmodification
-repackageclasses ''

12.6.3 字符串加密实现

/**
 * 字符串加密工具
 */
public class StringEncryptor {
    
    private static final byte[] KEY = {0x12, 0x34, 0x56, 0x78, 
                                       0x9A, 0xBC, 0xDE, 0xF0};
    
    /**
     * 加密字符串(编译时使用)
     */
    public static String encrypt(String plainText) {
        byte[] data = plainText.getBytes(StandardCharsets.UTF_8);
        byte[] encrypted = new byte[data.length];
        
        for (int i = 0; i < data.length; i++) {
            encrypted[i] = (byte) (data[i] ^ KEY[i % KEY.length]);
        }
        
        return Base64.getEncoder().encodeToString(encrypted);
    }
    
    /**
     * 解密字符串(运行时使用)
     */
    public static String decrypt(String encryptedText) {
        byte[] encrypted = Base64.getDecoder().decode(encryptedText);
        byte[] decrypted = new byte[encrypted.length];
        
        for (int i = 0; i < encrypted.length; i++) {
            decrypted[i] = (byte) (encrypted[i] ^ KEY[i % KEY.length]);
        }
        
        return new String(decrypted, StandardCharsets.UTF_8);
    }
}

// 使用示例
// 原始代码:
// String apiUrl = "https://api.example.com/v1/data";

// 加密后:
// String apiUrl = StringEncryptor.decrypt("Wm9uZXMgYXBpLmV4YW1wbGUuY29tL3YxL2RhdGE=");

12.7 运行时保护

12.7.1 反调试技术

/**
 * 反调试检测
 */
public class AntiDebug {
    
    /**
     * 检测是否被调试
     */
    public static boolean isBeingDebugged() {
        // 方法1: 检查调试标志
        if (android.os.Debug.isDebuggerConnected()) {
            return true;
        }
        
        // 方法2: 检查TracerPid
        if (getTracerPid() != 0) {
            return true;
        }
        
        // 方法3: 检查调试端口
        if (isDebugPortOpen()) {
            return true;
        }
        
        return false;
    }
    
    /**
     * 获取TracerPid
     */
    private static int getTracerPid() {
        try {
            BufferedReader reader = new BufferedReader(
                new FileReader("/proc/self/status"));
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("TracerPid:")) {
                    return Integer.parseInt(line.substring(10).trim());
                }
            }
            reader.close();
        } catch (Exception e) {
            // ignore
        }
        return 0;
    }
    
    /**
     * 检查调试端口
     */
    private static boolean isDebugPortOpen() {
        try {
            // 检查常见调试端口
            int[] debugPorts = {23946, 27042, 27043}; // Frida, IDA等
            for (int port : debugPorts) {
                try (java.net.Socket socket = new java.net.Socket()) {
                    socket.connect(new java.net.InetSocketAddress("127.0.0.1", port), 100);
                    return true;
                } catch (Exception e) {
                    // 端口未开放
                }
            }
        } catch (Exception e) {
            // ignore
        }
        return false;
    }
    
    /**
     * Native层反调试
     */
    public static native boolean nativeAntiDebug();
}

12.7.2 Native层反调试

// anti_debug.c

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <pthread.h>

// 检测ptrace
int detect_ptrace() {
    // 尝试ptrace自己,如果已被调试则会失败
    if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) == -1) {
        return 1;
    }
    // 解除ptrace
    ptrace(PTRACE_DETACH, 0, NULL, NULL);
    return 0;
}

// 检测/proc/self/status中的TracerPid
int detect_tracer_pid() {
    FILE *fp = fopen("/proc/self/status", "r");
    if (fp == NULL) return 0;
    
    char line[256];
    while (fgets(line, sizeof(line), fp)) {
        if (strncmp(line, "TracerPid:", 10) == 0) {
            int pid = atoi(line + 10);
            fclose(fp);
            return pid != 0;
        }
    }
    fclose(fp);
    return 0;
}

// 检测Frida
int detect_frida() {
    // 检测Frida特征文件
    const char *frida_files[] = {
        "/data/local/tmp/frida-server",
        "/data/local/tmp/re.frida.server",
        NULL
    };
    
    for (int i = 0; frida_files[i] != NULL; i++) {
        if (access(frida_files[i], F_OK) == 0) {
            return 1;
        }
    }
    
    // 检测Frida端口
    // ...
    
    return 0;
}

// 反调试线程
void *anti_debug_thread(void *arg) {
    while (1) {
        if (detect_ptrace() || detect_tracer_pid() || detect_frida()) {
            // 检测到调试,退出进程
            exit(0);
        }
        sleep(1);
    }
    return NULL;
}

// 启动反调试
JNIEXPORT jboolean JNICALL
Java_com_example_AntiDebug_nativeAntiDebug(JNIEnv *env, jclass clazz) {
    // 启动反调试线程
    pthread_t thread;
    pthread_create(&thread, NULL, anti_debug_thread, NULL);
    
    // 立即检测一次
    return detect_ptrace() || detect_tracer_pid() || detect_frida();
}

12.7.3 完整性校验

/**
 * 应用完整性校验
 */
public class IntegrityChecker {
    
    private final Context context;
    
    public IntegrityChecker(Context context) {
        this.context = context;
    }
    
    /**
     * 检查APK签名
     */
    public boolean verifySignature() {
        try {
            PackageInfo packageInfo = context.getPackageManager()
                .getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
            
            for (Signature signature : packageInfo.signatures) {
                // 计算签名哈希
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                byte[] hash = md.digest(signature.toByteArray());
                String signatureHash = bytesToHex(hash);
                
                // 与预期签名比较
                if (!signatureHash.equals(EXPECTED_SIGNATURE_HASH)) {
                    return false;
                }
            }
            return true;
            
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 检查安装来源
     */
    public boolean verifyInstaller() {
        String installer = context.getPackageManager()
            .getInstallerPackageName(context.getPackageName());
        
        // 检查是否从官方商店安装
        return "com.android.vending".equals(installer) ||  // Google Play
               "com.huawei.appmarket".equals(installer) || // 华为应用市场
               "com.xiaomi.market".equals(installer);      // 小米应用商店
    }
    
    /**
     * 检查是否被重打包
     */
    public boolean checkRepackaging() {
        try {
            // 检查classes.dex的哈希
            String apkPath = context.getPackageCodePath();
            String dexHash = calculateDexHash(apkPath);
            
            return dexHash.equals(EXPECTED_DEX_HASH);
            
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 检查运行环境
     */
    public boolean checkEnvironment() {
        // 检查是否在模拟器中运行
        if (isEmulator()) {
            return false;
        }
        
        // 检查是否root
        if (isRooted()) {
            return false;
        }
        
        // 检查是否有Xposed框架
        if (hasXposed()) {
            return false;
        }
        
        return true;
    }
    
    /**
     * 检测模拟器
     */
    private boolean isEmulator() {
        return Build.FINGERPRINT.contains("generic") ||
               Build.MODEL.contains("Emulator") ||
               Build.MODEL.contains("Android SDK") ||
               Build.MANUFACTURER.contains("Genymotion") ||
               Build.HARDWARE.contains("goldfish") ||
               Build.HARDWARE.contains("ranchu");
    }
    
    /**
     * 检测root
     */
    private boolean isRooted() {
        // 检查su文件
        String[] paths = {
            "/system/bin/su",
            "/system/xbin/su",
            "/sbin/su",
            "/data/local/xbin/su",
            "/data/local/bin/su",
            "/data/local/su"
        };
        
        for (String path : paths) {
            if (new File(path).exists()) {
                return true;
            }
        }
        
        // 检查Magisk
        if (new File("/sbin/.magisk").exists()) {
            return true;
        }
        
        return false;
    }
    
    /**
     * 检测Xposed
     */
    private boolean hasXposed() {
        try {
            // 检查Xposed类
            Class.forName("de.robv.android.xposed.XposedBridge");
            return true;
        } catch (ClassNotFoundException e) {
            // 未找到Xposed
        }
        
        // 检查堆栈中是否有Xposed
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement element : stackTrace) {
            if (element.getClassName().contains("xposed")) {
                return true;
            }
        }
        
        return false;
    }
    
    private static final String EXPECTED_SIGNATURE_HASH = "...";
    private static final String EXPECTED_DEX_HASH = "...";
    
    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    
    private String calculateDexHash(String apkPath) throws Exception {
        // 实现DEX哈希计算
        return "";
    }
}

12.8 网络安全

12.8.1 证书固定

/**
 * 证书固定实现
 */
public class CertificatePinning {
    
    /**
     * 创建带证书固定的OkHttpClient
     */
    public static OkHttpClient createPinnedClient() {
        // 证书固定配置
        CertificatePinner certificatePinner = new CertificatePinner.Builder()
            // 固定主域名证书
            .add("api.dreamworld.com", 
                 "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
            // 固定备用证书
            .add("api.dreamworld.com", 
                 "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")
            // 固定根证书
            .add("*.dreamworld.com", 
                 "sha256/CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=")
            .build();
        
        return new OkHttpClient.Builder()
            .certificatePinner(certificatePinner)
            .build();
    }
    
    /**
     * 使用Network Security Config(推荐)
     */
    // res/xml/network_security_config.xml
    /*
    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <domain-config cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">api.dreamworld.com</domain>
            <pin-set expiration="2026-01-01">
                <pin digest="SHA-256">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</pin>
                <pin digest="SHA-256">BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=</pin>
            </pin-set>
        </domain-config>
    </network-security-config>
    */
}

12.8.2 代理检测

/**
 * 代理检测
 */
public class ProxyDetector {
    
    /**
     * 检测系统代理
     */
    public static boolean hasSystemProxy() {
        String proxyHost = System.getProperty("http.proxyHost");
        String proxyPort = System.getProperty("http.proxyPort");
        
        return proxyHost != null && !proxyHost.isEmpty();
    }
    
    /**
     * 检测WiFi代理
     */
    public static boolean hasWifiProxy(Context context) {
        try {
            WifiManager wifiManager = (WifiManager) context
                .getApplicationContext()
                .getSystemService(Context.WIFI_SERVICE);
            
            WifiInfo wifiInfo = wifiManager.getConnectionInfo();
            // 检查代理设置...
            
        } catch (Exception e) {
            // ignore
        }
        return false;
    }
    
    /**
     * 检测VPN
     */
    public static boolean hasVpn(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Network activeNetwork = cm.getActiveNetwork();
            if (activeNetwork != null) {
                NetworkCapabilities caps = cm.getNetworkCapabilities(activeNetwork);
                if (caps != null) {
                    return caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
                }
            }
        }
        
        return false;
    }
    
    /**
     * 绕过代理直连
     */
    public static OkHttpClient createNoProxyClient() {
        return new OkHttpClient.Builder()
            .proxy(Proxy.NO_PROXY)
            .build();
    }
}

12.9 本章小结

本章我们从防御者的视角,全面分析了Android平台的安全机制:

12.9.1 技术要点回顾

┌─────────────────────────────────────────────────────────────────┐
│                      本章技术要点                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. 安全架构                                                     │
│     • 分层安全模型                                               │
│     • 纵深防御原则                                               │
│     • 最小权限原则                                               │
│                                                                  │
│  2. 应用签名                                                     │
│     • v1/v2/v3/v4签名方案                                        │
│     • 签名验证流程                                               │
│     • 签名的安全意义                                             │
│                                                                  │
│  3. 权限系统                                                     │
│     • 权限分类与保护级别                                         │
│     • 运行时权限                                                 │
│     • 权限组机制                                                 │
│                                                                  │
│  4. 应用沙箱                                                     │
│     • UID/GID隔离                                                │
│     • 数据目录隔离                                               │
│     • 进程隔离                                                   │
│                                                                  │
│  5. SELinux                                                      │
│     • 强制访问控制                                               │
│     • 安全上下文                                                 │
│     • 策略规则                                                   │
│                                                                  │
│  6. 代码保护                                                     │
│     • 代码混淆                                                   │
│     • 字符串加密                                                 │
│     • Native化                                                   │
│                                                                  │
│  7. 运行时保护                                                   │
│     • 反调试技术                                                 │
│     • 完整性校验                                                 │
│     • 环境检测                                                   │
│                                                                  │
│  8. 网络安全                                                     │
│     • 证书固定                                                   │
│     • 代理检测                                                   │
│     • 传输加密                                                   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.9.2 攻防对照表

┌─────────────────────────────────────────────────────────────────┐
│                      攻防对照                                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  防护措施              攻击方法              难度                │
│  ─────────────────────────────────────────────────────────────  │
│  代码混淆              反混淆工具            ★★☆☆☆             │
│  字符串加密            动态分析/Hook         ★★★☆☆             │
│  证书固定              Frida绕过             ★★★☆☆             │
│  反调试                反反调试              ★★★★☆             │
│  完整性校验            重打包绕过            ★★★★☆             │
│  Native保护            Unidbg模拟            ★★★★★             │
│  SELinux               需要root              ★★★★★             │
│  硬件安全              几乎无法绕过          ★★★★★             │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

12.9.3 安全建议

对于开发者

  1. 使用多层防护,不依赖单一机制
  2. 关键逻辑放在Native层
  3. 使用证书固定防止中间人攻击
  4. 实现运行时完整性校验
  5. 定期更新安全策略

对于安全研究员

  1. 了解各层安全机制的原理
  2. 掌握绕过技术的边界
  3. 遵守法律法规和道德准则
  4. 负责任地披露漏洞

12.9.4 下一章预告

在下一章《Native层安全深度剖析》中,我们将深入探讨:

  • ELF文件格式
  • SO加载机制
  • Native层保护技术
  • 反汇编与逆向分析
  • Unidbg高级技巧

本章完