以攻促防-Android安全开发
字数 997 2025-08-06 08:34:54

Android安全开发:AES加密与防护实践

1. 项目概述

本教学文档基于一个Android AES加密Demo项目,展示了从基础实现到安全防护的全过程。项目采用Java与C++混合开发:

  • Java层:提供接口调用
  • C++层:实现核心AES加密算法

2. 基础实现

2.1 Java层结构

2.1.1 Aes类(加密接口)

package com.bmstd.aesencryption.bm;

public class Aes {
    static {
        System.loadLibrary("native-lib");
    }
    
    public static native String encryption(String plainText);
    public static native String decryption(String encryptText);
}

2.1.2 MainActivity(调用示例)

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        String text = "bmstdAEStest";
        String textEnc = Aes.encryption(text);
        String textDec = Aes.decryption(textEnc);
        
        Log.d("bmstdAes", "text: " + text);
        Log.d("bmstdAes", "textAESEnc: " + textEnc);
        Log.d("bmstdAes", "textAESDec: " + textDec);
    }
}

2.2 Native层实现

2.2.1 JNI接口

extern "C" JNIEXPORT jstring JNICALL
Java_com_bmstd_aesencryption_bm_Aes_encryption(JNIEnv *env, jclass thiz, jstring plain_text) {
    const char *c_data = env->GetStringUTFChars(plain_text, 0);
    string encrypt_data = encryptByAES(c_data);
    return env->NewStringUTF(encrypt_data.c_str());
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_bmstd_aesencryption_bm_Aes_decryption(JNIEnv *env, jclass thiz, jstring encrypt_text) {
    const char *c_data = env->GetStringUTFChars(encrypt_text, 0);
    string decrypt_data = decryptByAES(c_data);
    return env->NewStringUTF(decrypt_data.c_str());
}

2.2.2 加密核心实现

const char* secretKey = "bmstd-aes-key666";
const char* iv = "bmstd-aes-iv1234";
int iMode = 1;

string encryptByAES(const char* data) {
    string data_str(data);
    size_t length = data_str.length();
    int block_num = length / BLOCK_SIZE + 1;
    
    // 明文处理
    char* szDataIn = new char[block_num * BLOCK_SIZE + 1];
    memset(szDataIn, 0x00, block_num * BLOCK_SIZE + 1);
    strcpy(szDataIn, data_str.c_str());
    
    // PKCS7Padding填充
    int k = length % BLOCK_SIZE;
    int j = length / BLOCK_SIZE;
    int padding = BLOCK_SIZE - k;
    for (int i = 0; i < padding; i++) {
        szDataIn[j * BLOCK_SIZE + k + i] = padding;
    }
    szDataIn[block_num * BLOCK_SIZE] = '\0';
    
    // 加密
    char* szDataOut = new char[block_num * BLOCK_SIZE + 1];
    memset(szDataOut, 0, block_num * BLOCK_SIZE + 1);
    
    AES aes;
    aes.MakeKey(secretKey, iv, 16, 16);
    aes.Encrypt(szDataIn, szDataOut, block_num * BLOCK_SIZE, iMode);
    
    string str = base64_encode((unsigned char*)szDataOut, block_num * BLOCK_SIZE);
    
    delete[] szDataIn;
    delete[] szDataOut;
    return str;
}

3. 安全风险分析

3.1 Java层风险

  1. 类名暴露功能:Aes类名直接表明加密功能
  2. 代码可读性高:未混淆的代码逻辑清晰
  3. 关键字符串暴露:如"bmstdAEStest"直接可见

3.2 Native层风险

  1. 硬编码密钥:secretKey和iv直接写在代码中
  2. 函数名暴露逻辑:encryptByAES等函数名直接表明功能
  3. 缺乏保护措施:无混淆、无花指令

4. 安全防护措施

4.1 Java层防护

4.1.1 类名混淆

  1. 修改build.gradle:
buildTypes {
    release {
        minifyEnabled true // 开启混淆
        zipAlignEnabled true // Zipalign优化
        shrinkResources true // 移除无用资源
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
  1. 配置proguard-rules.pro:
# 保留native方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

# 其他混淆规则...

4.1.2 生成垃圾代码

  1. 添加依赖:
buildscript {
    dependencies {
        classpath "cn.hx.plugin:android-junk-code:1.0.2"
    }
}
  1. 配置垃圾代码生成:
android.applicationVariants.all { variant ->
    switch (variant.name) {
        case "debug":
        case "release":
            androidJunkCode.configMap.put(variant.name, {
                packageBase = "com.bmstd.aesencryption" // 根包名
                packageCount = 30 // 生成包数量
                activityCountPerPackage = 3 // 每个包Activity数量
                otherCountPerPackage = 50 // 每个包其他类数量
                methodCountPerClass = 20 // 每个类方法数量
                resPrefix = "junk_" // 资源前缀
                drawableCount = 300 // drawable数量
                stringCount = 300 // string数量
            })
            break
    }
}

4.1.3 代码混淆

  1. 添加BlackObfuscator插件:
plugins {
    id 'top.niunaijun.blackobfuscator'
}
  1. 配置混淆:
blackObfuscator {
    enabled true
    depth 2
    obfClass = ["com.bmstd.aesencryption"]
    blackClass = ["com.bmstd.aesencryption.MainActivity"]
}

4.2 Native层防护

4.2.1 密钥保护

static const char* getKey() {
    const int len = 16;
    char* src = static_cast<char*>(malloc(len + 1));
    for (int i = 0; i < len; ++i) {
        switch (i) {
            case 0: src[i] = 'b'; break;
            case 1: src[i] = 'm'; break;
            // ... 其他字符
            case 15: src[i] = '6'; break;
        }
    }
    src[len] = '\0';
    return src;
}

4.2.2 代码混淆

  1. 使用宏定义混淆函数名:
#define decryptByAES ll11l1l1ll
#define encryptByAES ll11lll11l
#define MakeKey ll11lll1l1
  1. 混淆后的AES.h:
#define BLOCK_SIZE 16
#define decryptByAES ll11l1l1ll
#define encryptByAES ll11lll11l
#define MakeKey ll11lll1l1
#define Decrypt ll11l1l1l1
#define Encrypt ll11l1l11l
#define getKey lll1l1l1l1
#define getIV ll11l1llll
#define AES ll1ll1l1ll

4.2.3 花指令插入

  1. 花指令库junk.h:
#define _JUNK_FUN_0 { \
    if(junk_fun2())junk_fun1(); \
    if(junk_fun0()) junk_fun3(); \
    if(junk_fun1()) junk_fun2(); \
    if(junk_fun3()) junk_fun1(); \
    if(junk_fun1())junk_fun0(); \
    if(junk_fun2()) junk_fun3(); \
    if(junk_fun3()) junk_fun1(); \
    if(junk_fun1()) junk_fun0(); \
}
  1. 在关键函数中插入花指令:
static const char* getKey() {
    const int len = 16;
    char* src = static_cast<char*>(malloc(len + 1));
    for (int i = 0; i < len; ++i) {
        switch (i) {
            case 0: src[i] = 'b'; _JUNK_FUN_0 break;
            case 1: src[i] = 'm'; break;
            // ...
        }
    }
    src[len] = '\0';
    return src;
}

5. 防护效果对比

5.1 Java层防护效果

  1. 类名混淆:Aes → a, b, c等无意义短名
  2. 代码膨胀:增加大量无关包、类和方法
  3. 逻辑混淆:添加无意义条件判断和跳转

5.2 Native层防护效果

  1. 密钥隐藏:从明文变为运行时计算
  2. 函数名混淆:encryptByAES → ll11lll11l
  3. 逻辑干扰:花指令增加分析难度

6. 总结

本教学文档展示了Android安全开发的完整流程:

  1. 基础功能实现:完成AES加密的核心功能
  2. 安全风险分析:识别Java和Native层的脆弱点
  3. 防护措施实施
    • Java层:混淆、垃圾代码、代码保护
    • Native层:密钥保护、混淆、花指令

通过这些措施,原始简单明了的代码变得复杂难懂,显著提高了逆向分析的难度,实现了"以攻促防"的安全开发理念。

Android安全开发:AES加密与防护实践 1. 项目概述 本教学文档基于一个Android AES加密Demo项目,展示了从基础实现到安全防护的全过程。项目采用Java与C++混合开发: Java层 :提供接口调用 C++层 :实现核心AES加密算法 2. 基础实现 2.1 Java层结构 2.1.1 Aes类(加密接口) 2.1.2 MainActivity(调用示例) 2.2 Native层实现 2.2.1 JNI接口 2.2.2 加密核心实现 3. 安全风险分析 3.1 Java层风险 类名暴露功能 :Aes类名直接表明加密功能 代码可读性高 :未混淆的代码逻辑清晰 关键字符串暴露 :如"bmstdAEStest"直接可见 3.2 Native层风险 硬编码密钥 :secretKey和iv直接写在代码中 函数名暴露逻辑 :encryptByAES等函数名直接表明功能 缺乏保护措施 :无混淆、无花指令 4. 安全防护措施 4.1 Java层防护 4.1.1 类名混淆 修改build.gradle: 配置proguard-rules.pro: 4.1.2 生成垃圾代码 添加依赖: 配置垃圾代码生成: 4.1.3 代码混淆 添加BlackObfuscator插件: 配置混淆: 4.2 Native层防护 4.2.1 密钥保护 4.2.2 代码混淆 使用宏定义混淆函数名: 混淆后的AES.h: 4.2.3 花指令插入 花指令库junk.h: 在关键函数中插入花指令: 5. 防护效果对比 5.1 Java层防护效果 类名混淆 :Aes → a, b, c等无意义短名 代码膨胀 :增加大量无关包、类和方法 逻辑混淆 :添加无意义条件判断和跳转 5.2 Native层防护效果 密钥隐藏 :从明文变为运行时计算 函数名混淆 :encryptByAES → ll11lll11l 逻辑干扰 :花指令增加分析难度 6. 总结 本教学文档展示了Android安全开发的完整流程: 基础功能实现 :完成AES加密的核心功能 安全风险分析 :识别Java和Native层的脆弱点 防护措施实施 : Java层:混淆、垃圾代码、代码保护 Native层:密钥保护、混淆、花指令 通过这些措施,原始简单明了的代码变得复杂难懂,显著提高了逆向分析的难度,实现了"以攻促防"的安全开发理念。