android简单应用加固

0 阅读3分钟

什么是Android应用加固?

应用加固(App Hardening)是一种保护Android应用免受逆向工程、篡改和攻击的技术,主要包括:

  • 代码混淆(ProGuard/R8)
  • 反调试/反Hook检测
  • 完整性校验
  • 加壳/脱壳保护
  • so文件加密

1. 基础加固:代码混淆(必做)

配置 build.gradle (Module: app)

gradle

复制

android {
    buildTypes {
        release {
            minifyEnabled true      // 启用代码压缩
            shrinkResources true    // 移除无用资源
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

配置 proguard-rules.pro

proguard

复制

# 基础混淆规则
-optimizationpasses 5          # 优化次数
-dontusemixedcaseclassnames   # 不使用混合大小写
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

# 保留入口点
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application

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

# 保留注解
-keepattributes *Annotation*

# 混淆类名
-repackageclasses 'a'        # 将所有类移到'a'包下
-allowaccessmodification       # 允许修改访问修饰符

2. 中级加固:签名校验 + 完整性检查

在 MainActivity.java 或 Application 中添加自检代码

java

复制

public class SecurityUtils {
    
    // 签名校验(防止二次打包)
    public static boolean checkSignature(Context context) {
        try {
            String packageName = context.getPackageName();
            PackageManager pm = context.getPackageManager();
            
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                pm.getPackageInfo(packageName, 
                    PackageManager.GET_SIGNING_CERTIFICATES);
            }
            
            // 对比签名hash(你需要提前计算好正确签名的hash)
            String correctHash = "你的正确签名SHA-256值";
            // 实际获取当前签名并对比...
            
            return true; // 校验通过
        } catch (Exception e) {
            return false;
        }
    }
    
    // APK完整性校验(校验classes.dex CRC)
    public static boolean checkDexIntegrity(Context context) {
        try {
            String apkPath = context.getPackageCodePath();
            File apkFile = new File(apkPath);
            
            // 计算关键文件的CRC或MD5
            long crc = getFileCRC32(apkFile);
            long expectedCRC = 123456789L; // 预存的正确值
            
            return crc == expectedCRC;
        } catch (Exception e) {
            return false;
        }
    }
    
    // CRC32计算
    private static long getFileCRC32(File file) throws Exception {
        CRC32 crc32 = new CRC32();
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                crc32.update(buffer, 0, len);
            }
        }
        return crc32.getValue();
    }
}

在 Application.onCreate() 中调用

java

复制

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        
        // 安全检测
        if (!SecurityUtils.checkSignature(this)) {
            Toast.makeText(this, "应用签名异常,请从官方渠道下载", Toast.LENGTH_LONG).show();
            System.exit(0);
        }
        
        if (!SecurityUtils.checkDexIntegrity(this)) {
            Toast.makeText(this, "应用已被篡改", Toast.LENGTH_LONG).show();
            System.exit(0);
        }
        
        // 反调试检测
        if (isDebugged()) {
            System.exit(0);
        }
    }
    
    private boolean isDebugged() {
        return Debug.isDebuggerConnected() || Debug.waitingForDebugger();
    }
}

3. 高级加固:加壳保护(DEX加密)

基本原理

复制

原始APK: classes.dex (明文)
    ↓
加固后APK: 
  - classes.dex (壳程序,很小)
  - assets/encrypted.dex (加密后的原dex)
  - libs/libdecoder.so (解密so)

简单加壳实现思路

步骤1:加密原始DEX

java

复制

// 加密工具(独立程序)
public class DexEncryptor {
    public static void encrypt(String dexPath, String outPath, String key) {
        try {
            byte[] dexData = Files.readAllBytes(Paths.get(dexPath));
            // AES加密
            byte[] encrypted = aesEncrypt(dexData, key);
            Files.write(Paths.get(outPath), encrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

步骤2:壳程序(ProxyApplication)

java

复制

public class ProxyApplication extends Application {
    private Application realApp;
    
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        
        // 1. 解密assets中的加密dex
        byte[] encryptedDex = loadEncryptedDex();
        byte[] decryptedDex = decrypt(encryptedDex, "密钥");
        
        // 2. 写入临时文件
        File tempDex = new File(getCacheDir(), " decrypted.dex");
        FileUtils.writeByteArrayToFile(tempDex, decryptedDex);
        
        // 3. 使用DexClassLoader加载解密后的dex
        DexClassLoader dcl = new DexClassLoader(
            tempDex.getAbsolutePath(),
            getCacheDir().getAbsolutePath(),
            null,
            base.getClassLoader()
        );
        
        // 4. 替换ClassLoader(反射)
        replaceClassLoader(dcl);
        
        // 5. 加载原Application
        realApp = (Application) dcl.loadClass("com.example.RealApp").newInstance();
        realApp.attachBaseContext(base);
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
        realApp.onCreate();
    }
}

步骤3:AndroidManifest.xml 修改

xml

复制

<application
    android:name=".ProxyApplication"  <!-- 改为壳Application -->
    android:label="@string/app_name">
    <!-- 原Application配置移到meta-data -->
    <meta-data 
        android:name="REAL_APPLICATION" 
        android:value="com.example.MyRealApp" />
</application>

4. Native层加固(SO加密)

反调试检测(C代码)

c

复制

// anti_debug.c
#include <sys/ptrace.h>
#include <unistd.h>
#include <jni.h>

// Ptrace反调试
void anti_ptrace() {
    ptrace(PTRACE_TRACEME, 0, 0, 0);
}

// 检测调试器
int is_being_debugged() {
    // 检查TracerPid
    FILE* fp = fopen("/proc/self/status", "r");
    char line[256];
    while (fgets(line, sizeof(line), fp)) {
        if (strstr(line, "TracerPid:")) {
            int pid = atoi(line + 10);
            fclose(fp);
            return pid != 0;
        }
    }
    fclose(fp);
    return 0;
}

JNIEXPORT void JNICALL
Java_com_example_security_SecurityUtils_initSecurity(JNIEnv* env, jclass clazz) {
    anti_ptrace();
    
    if (is_being_debugged()) {
        // 检测到调试,退出或崩溃
        _exit(0);
    }
}

5. 使用第三方加固服务(推荐)

对于商业应用,建议使用成熟的加固方案:

表格

复制

服务商特点官网
腾讯乐固免费额度,兼容性好legu.qcloud.com
阿里聚安全与阿里云生态整合jaq.alibaba.com
360加固保老牌方案,企业版强jiagu.360.cn
网易云加固游戏应用优化nos.netease.com
百度移动安全深度保护方案mtc.baidu.com

使用腾讯乐固示例(Gradle插件)

gradle

复制

// build.gradle (Project)
buildscript {
    dependencies {
        classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.21'
    }
}

// build.gradle (Module)
apply plugin: 'AndResGuard'

andResGuard {
    mappingFile = null
    use7zip = true
    useSign = true
    keepRoot = false
    whiteList = [
        "R.drawable.icon",
        "R.string.app_name"
    ]
}

加固等级总结

表格

复制

级别方法难度防护效果
基础ProGuard混淆 + 移除Log防小白
中级签名校验 + 完整性检测⭐⭐防初级破解
高级DEX加壳 + SO加密⭐⭐⭐防中级逆向
商业第三方专业加固防高级攻击