目录
  1. 1. 一、加固的核心目标
  2. 2. 二、DEX 加密与动态加载
  3. 3. 三、SO 保护
  4. 4. 四、完整性校验流程
  5. 5. 面试常考问题
【逆向安全技术-防护篇】应用加固原理

一、加固的核心目标

应用加固的核心思路是将原始的 DEX(Dalvik Executable)和 SO 文件加密后嵌入壳程序,等应用启动时由壳程序在内存中解密并动态加载执行。这样,即使攻击者获取了 APK,看到的也只是加密后的乱码数据,无法直接通过 jadx 或 baksmali 反编译。

商业加固(如 360 加固、梆梆、爱加密)的原理大体分为三个阶段:打包阶段——将原 DEX 加密后存放在 assets 或 lib 目录下,替换 Application 类为壳的入口类;启动阶段——壳 Application 在 attachBaseContext() 中加载解密 SO 库,从 assets 读取加密 DEX 到内存;执行阶段——解密并通过 DexClassLoaderInMemoryDexClassLoader 动态加载,反射调用原 Application 并移交控制权。

二、DEX 加密与动态加载

DEX 加密是最基础的加固手段。壳程序将多个 DEX 文件整体加密后存储,运行时在 Native 层解密。为对抗内存 dump,高级加固还会采用分段解密策略:在方法执行时才解密对应的代码区域,执行完后立即恢复加密状态,使攻击者无法通过单次 dump 获得完整的明文 DEX。

三、SO 保护

加固方案中的 SO 库负责加解密逻辑、反调试和完整性校验。对 SO 的保护手段包括:代码段加密(在 .init_array 中运行时解密)、符号表剥离(strip)、控制流平坦化(OLLVM -mllvm -fla)、字符串加密(编译器插件在编译期替换)。部分加固还会将核心代码以加密形式存放于 .rodata 段的自定义位置,运行时才映射为可执行内存并跳转。

四、完整性校验流程

加固 APK 在启动时会执行多轮完整性检查:校验 APK 签名(防止二次打包替换壳包)、校验自身 DEX 和 SO 的 CRC/哈希值(防止静态修改)、检测环境特征(Root、模拟器、hook 框架注入)。这些检查分散在 Native 层多处,形成互相验证的检查网络。

// Native 层 CRC 校验示例
bool verify_text_section() {
// 从 /proc/self/maps 找到当前 SO 的基址
void* base = get_module_base("libprotect.so");
Elf64_Ehdr* ehdr = (Elf64_Ehdr*)base;
Elf64_Shdr* shdr = (Elf64_Shdr*)((char*)base + ehdr->e_shoff);
for (int i = 0; i < ehdr->e_shnum; i++) {
if (strcmp(section_name(base, &shdr[i]), ".text") == 0) {
uint32_t crc = crc32((uint8_t*)base + shdr[i].sh_offset, shdr[i].sh_size);
return crc == EXPECTED_CRC;
}
}
return false;
}

面试常考问题

Q1: 加固为什么不能 100% 防止逆向?
A: 因为应用最终必须在 CPU 上执行,无论怎么加密,解密后的代码必然出现在内存中。攻击者可以在解密完成后的时间窗口内进行内存 dump(如通过 Frida 的 Memory.scan 或自定义 Kernel 模块),从而获取明文代码。加固的目标是提高逆向的时间成本和经济成本,而非绝对防御。AOSP 中 DexClassLoader 的实现路径为 /libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java

Q2: 分段解密与整体解密相比有什么优势?
A: 整体解密会在某个时刻让所有明文 DEX 同时存在于内存中,攻击者只需抓住一个时间点 dump 即可获取全部代码。分段解密只在方法执行前解密目标区域、执行后立即重新加密,使得内存中同时只有极少量的明文代码,大幅提升了 dump 的难度。

Q3: 绕过加固的常见思路有哪些?
A: 首先通过壳识别工具(如 ApkScan)确定加固厂商。然后选择策略:在解密完成后 Frida hook dump DEX(监控 DexFile::OpenCommondex_file.cc 中的相关函数);或者 hook 壳的签名校验、环境检测函数使其永远返回合法值;也可以从 /proc/pid/maps 和 /proc/pid/mem 直接读取进程内存。AOSP 中 DEX 加载的核心在 /art/runtime/dex_file.cc/art/runtime/class_linker.cc

打赏
  • 微信
  • 支付宝

评论