以攻促防-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层风险
- 类名暴露功能:Aes类名直接表明加密功能
- 代码可读性高:未混淆的代码逻辑清晰
- 关键字符串暴露:如"bmstdAEStest"直接可见
3.2 Native层风险
- 硬编码密钥:secretKey和iv直接写在代码中
- 函数名暴露逻辑:encryptByAES等函数名直接表明功能
- 缺乏保护措施:无混淆、无花指令
4. 安全防护措施
4.1 Java层防护
4.1.1 类名混淆
- 修改build.gradle:
buildTypes {
release {
minifyEnabled true // 开启混淆
zipAlignEnabled true // Zipalign优化
shrinkResources true // 移除无用资源
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
- 配置proguard-rules.pro:
# 保留native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 其他混淆规则...
4.1.2 生成垃圾代码
- 添加依赖:
buildscript {
dependencies {
classpath "cn.hx.plugin:android-junk-code:1.0.2"
}
}
- 配置垃圾代码生成:
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 代码混淆
- 添加BlackObfuscator插件:
plugins {
id 'top.niunaijun.blackobfuscator'
}
- 配置混淆:
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 代码混淆
- 使用宏定义混淆函数名:
#define decryptByAES ll11l1l1ll
#define encryptByAES ll11lll11l
#define MakeKey ll11lll1l1
- 混淆后的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 花指令插入
- 花指令库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(); \
}
- 在关键函数中插入花指令:
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层防护效果
- 类名混淆:Aes → a, b, c等无意义短名
- 代码膨胀:增加大量无关包、类和方法
- 逻辑混淆:添加无意义条件判断和跳转
5.2 Native层防护效果
- 密钥隐藏:从明文变为运行时计算
- 函数名混淆:encryptByAES → ll11lll11l
- 逻辑干扰:花指令增加分析难度
6. 总结
本教学文档展示了Android安全开发的完整流程:
- 基础功能实现:完成AES加密的核心功能
- 安全风险分析:识别Java和Native层的脆弱点
- 防护措施实施:
- Java层:混淆、垃圾代码、代码保护
- Native层:密钥保护、混淆、花指令
通过这些措施,原始简单明了的代码变得复杂难懂,显著提高了逆向分析的难度,实现了"以攻促防"的安全开发理念。