VCTF ez_app wp & 安卓逆向分析
字数 1377 2025-11-26 12:17:37
VCTF ez_app 安卓逆向分析教学文档
概述
本文详细分析VCTF ez_app题目的安卓逆向过程,涵盖Native层代码分析、签名校验、动态加载解密等关键技术点。
知识点梳理
1. 安卓逆向基本流程
- Java层分析:首先分析Java代码,定位关键方法
- Native层分析:针对JNI方法进行深入分析
- 检测绕过:注意虚拟机检测、调试器检测、签名检测等防护措施
- 工具使用:熟练使用Apktool、Frida、IDA Pro等工具
2. JNI执行流程详解
2.1 加载流程
// 典型加载顺序
System.loadLibrary("xxx") → dlopen() → JNI_OnLoad()
2.2 JNI_OnLoad函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
// 主要功能:
// 1. 缓存JavaVM指针
// 2. 获取JNIEnv环境
// 3. 注册Native函数
// 4. 执行解密和初始化逻辑
}
2.3 Native函数注册方式
静态绑定
- 特征:函数名遵循
Java_包名_类名_方法名格式 - IDA识别:函数名较长且包含完整包名路径
- 执行流程:JVM自动定位对应JNI函数
示例:
__int64 Java_com_qwq_myapplication_MainActivity_checkFlag()
动态绑定
- 实现方式:在
JNI_OnLoad中调用RegisterNatives - 关键结构:
JNINativeMethod数组 - 逆向重点:找到注册表,建立Java方法与Native函数映射
示例:
env->RegisterNatives(clazz, methods, count);
2.4 JNIEnv常用操作
(*env)->NewStringUTF() // 创建字符串
(*env)->GetStringUTFChars() // 获取字符串内容
(*env)->CallObjectMethod() // 调用Java方法
题目具体分析
1. Java层分析
- 发现调用
native checkFlag()方法 - 存在
initNative()在onCreate中调用,先于checkFlag执行
2. Native层分析
2.1 关键函数定位
- 入口点:
JNI_OnLoad函数 - 核心逻辑:
sub_18BC函数(解密加载逻辑)
2.2 动态加载保护机制
解密流程:
- 从assets加载加密so文件("qwqer1")
- 使用密钥"p0l1st"进行魔改AES解密
- 写入临时文件并设置权限
- 通过
dlopen动态加载解密后的so - 查找
MainActivity.checkFlag函数地址
3. 绕过防护技术
3.1 签名校验绕过
- 问题:应用存在签名校验,直接修改APK会导致安装失败
- 解决方案:
- 本地patch so文件
- 修改文件后缀避免系统检测
- 在模拟器中重命名为apk安装
3.2 文件提取技术
IDA Patch步骤:
- 定位需要修改的指令
- 使用Edit → Patch program功能
- 确认patch成功应用
文件提取命令:
# 复制到SD卡
cp /data/data/com.qwq.myapplication/validator_decrypted_4621.so /sdcard/
# 拉取到本地
adb pull /sdcard/validator_decrypted_4621.so
4. 解密so分析
4.1 算法识别
- 加密算法:TEA算法变种
- 密钥:
0xa56babcd, 0x1f1234f1, 0x12345678, 0xfedcba98
4.2 TEA解密实现
#include <stdint.h>
#include <string.h>
#include <stdio.h>
void tea_decrypt(uint32_t v[2], const uint32_t k[4]) {
uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720;
const uint32_t delta = 0x9e3779b9;
for (int i = 0; i < 32; i++) {
v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
sum -= delta;
}
v[0] = v0; v[1] = v1;
}
void decrypt_string(uint32_t* blocks, int block_count, uint32_t key[4], char* output) {
uint32_t temp_blocks[16];
// 复制数据
for (int i = 0; i < block_count * 2; i++) {
temp_blocks[i] = blocks[i];
}
// 解密每个块
for (int i = 0; i < block_count; i++) {
tea_decrypt(&temp_blocks[i * 2], key);
}
// 输出结果
memcpy(output, temp_blocks, block_count * 8);
output[block_count * 8] = '\0';
}
逆向技巧总结
1. 分析路径建议
- 定位
JNI_OnLoad入口点 - 查找动态注册信息
- 根据Java调用关系定位实际入口
- 追踪Native层调用链
- 注意隐藏入口和字符串解密
2. 文件系统知识
/data/data/目录结构:
files/ # 应用内部数据
databases/ # SQLite数据库
shared_prefs/ # 配置文件
cache/ # 缓存文件
lib/ # 加载的.so库
code_cache/ # JIT/ART缓存
3. 对抗技术
- 反调试检测:注意ptrace等检测手段
- 代码混淆:控制流混淆(CFO)处理
- 加密算法:识别AES/RC4/XXTEA等常见算法
- 签名校验:魔改签名校验机制分析
总结
本题考察了安卓逆向的完整流程,重点在于:
- 理解JNI动态加载机制
- 掌握动态绑定函数的定位方法
- 熟悉文件解密和提取技术
- 具备绕过各种检测的能力
通过此题可以全面提升安卓Native层逆向分析能力,为更复杂的安卓应用逆向打下坚实基础。