apk加固工具探究系列——advmp
字数 1586 2025-08-22 12:22:24

ADVMP加固工具原理与实现详解

一、ADVMP概述

ADVMP是一款基于Dalvik虚拟机解释器原理实现的APK加固工具,其主要特点是通过将Java方法指令抽取并转换为native方法,使用自定义的解释器执行原始字节码。

1.1 项目结构

AdvmpTest/       - 测试用的项目
base/            - Java写的工具代码
control-centre/  - Java写的控制加固流程的代码
separator/       - Java写的抽离方法指令并生成C文件
template/jni/    - C写的解释器核心代码
ycformat/        - Java写的自定义文件格式代码

二、Dalvik虚拟机解释器原理

2.1 方法调用流程

  1. 通过RegisterNatives函数注册native方法
  2. 最终调用dvmSetNativeFunc将Method的nativeFunc指向dvmCallJNIMethod
  3. dvmCallMethodV函数处理参数:
    • ins指向第一个参数
    • 非静态方法将this指针放入ins
    • 根据参数类型依次放入后续参数

2.2 解释器执行流程

  1. 调用native方法:进入dvmCallJNIMethod
  2. 调用Java方法:进入dvmInterpret
    • 选择解释器(如Portable解释器)
    • 调用dvmInterpretPortable函数

2.3 Portable解释器实现

  1. 使用DEFINE_GOTO_TABLE定义handlerTable[kNumPackedOpcodes]数组
  2. 数组元素通过H宏定义,如H(OP_RETURN_VOID)展开为&&op_OP_RETURN_VOID
  3. HANDLE_OPCODE宏定义各指令处理逻辑
  4. FINISH(0)取第一条指令并执行
    • 移动PC
    • 获取操作码到inst
    • 根据inst跳转到对应label处理
    • 处理完成后调整PC处理下一条指令

三、ADVMP加固流程

3.1 加固步骤

  1. 插入System.loadLibrary指令加载advmp.so
  2. 抽取目标方法(如separatorTest)的指令到classes.yc文件
  3. 将原方法转换为native方法
  4. 生成对应的C代码(advmp_separator.cpp
  5. 合并到定义JNI_OnLoadavmp.cpp

3.2 关键文件格式

classes.yc文件

  • 自定义格式
  • 包含内容:
    • 抽取的方法指令
    • 访问标志
    • 参数个数
    • 其他方法元信息

advmp_separator.cpp

// 生成的native方法实现
void Java_com_example_test_separatorTest(JNIEnv* env, jobject obj) {
    BwdvmInterpretPortable(data_from_yc, ...);
}

// 注册方法
void registerFunctions() {
    JNINativeMethod methods[] = {
        {"separatorTest", "()V", (void*)Java_com_example_test_separatorTest}
    };
    // 注册代码...
}

3.3 JNI初始化

JNI_OnLoad函数流程:

  1. 调用registerFunctions注册native方法
  2. 释放并解析yc文件

3.4 解释器实现

BwdvmInterpretPortable函数:

  1. 类似dvmCallMethodV处理参数
  2. 类似dvmInterpretPortable解释执行字节码

四、实现细节分析

4.1 方法抽取与转换

  1. 识别目标方法(默认separatorTest
  2. 提取方法字节码指令
  3. 转换为自定义格式存储
  4. 将原方法改为native声明

4.2 解释器核心

  1. 指令表初始化
  2. PC寄存器管理
  3. 操作数提取(如INST_AINST_B
  4. 指令分派机制

4.3 性能考虑

  1. 解释执行相比直接执行会有性能损耗
  2. 指令解码开销
  3. 上下文切换成本

五、防御与对抗

5.1 加固优势

  1. 原始字节码不直接暴露
  2. 自定义解释器增加分析难度
  3. 动态加载关键逻辑

5.2 潜在弱点

  1. 解释器本身可能被逆向
  2. 内存中的字节码可能被dump
  3. 固定的指令处理模式

六、扩展开发

6.1 自定义指令集

  1. 修改yc文件格式
  2. 扩展解释器支持新指令
  3. 添加混淆指令

6.2 多方法加固

  1. 批量处理方法抽取
  2. 优化native方法注册
  3. 共享解释器实例

6.3 增强保护

  1. 添加反调试检测
  2. 解释器代码混淆
  3. 完整性校验机制

七、参考资料

  1. Dalvik虚拟机源码
  2. JNI编程指南
  3. 解释器设计模式
  4. 原生开发文档

通过以上分析,ADVMP提供了一种基于解释执行的APK保护方案,理解其原理有助于开发更强大的加固工具或分析加固后的应用。

ADVMP加固工具原理与实现详解 一、ADVMP概述 ADVMP是一款基于Dalvik虚拟机解释器原理实现的APK加固工具,其主要特点是通过将Java方法指令抽取并转换为native方法,使用自定义的解释器执行原始字节码。 1.1 项目结构 二、Dalvik虚拟机解释器原理 2.1 方法调用流程 通过 RegisterNatives 函数注册native方法 最终调用 dvmSetNativeFunc 将Method的 nativeFunc 指向 dvmCallJNIMethod dvmCallMethodV 函数处理参数: ins 指向第一个参数 非静态方法将this指针放入 ins 根据参数类型依次放入后续参数 2.2 解释器执行流程 调用native方法:进入 dvmCallJNIMethod 调用Java方法:进入 dvmInterpret 选择解释器(如Portable解释器) 调用 dvmInterpretPortable 函数 2.3 Portable解释器实现 使用 DEFINE_GOTO_TABLE 定义 handlerTable[kNumPackedOpcodes] 数组 数组元素通过 H 宏定义,如 H(OP_RETURN_VOID) 展开为 &&op_OP_RETURN_VOID HANDLE_OPCODE 宏定义各指令处理逻辑 FINISH(0) 取第一条指令并执行 移动PC 获取操作码到 inst 根据 inst 跳转到对应label处理 处理完成后调整PC处理下一条指令 三、ADVMP加固流程 3.1 加固步骤 插入 System.loadLibrary 指令加载 advmp.so 抽取目标方法(如 separatorTest )的指令到 classes.yc 文件 将原方法转换为native方法 生成对应的C代码( advmp_separator.cpp ) 合并到定义 JNI_OnLoad 的 avmp.cpp 中 3.2 关键文件格式 classes.yc文件 自定义格式 包含内容: 抽取的方法指令 访问标志 参数个数 其他方法元信息 advmp_ separator.cpp 3.3 JNI初始化 JNI_OnLoad 函数流程: 调用 registerFunctions 注册native方法 释放并解析 yc 文件 3.4 解释器实现 BwdvmInterpretPortable 函数: 类似 dvmCallMethodV 处理参数 类似 dvmInterpretPortable 解释执行字节码 四、实现细节分析 4.1 方法抽取与转换 识别目标方法(默认 separatorTest ) 提取方法字节码指令 转换为自定义格式存储 将原方法改为native声明 4.2 解释器核心 指令表初始化 PC寄存器管理 操作数提取(如 INST_A 、 INST_B ) 指令分派机制 4.3 性能考虑 解释执行相比直接执行会有性能损耗 指令解码开销 上下文切换成本 五、防御与对抗 5.1 加固优势 原始字节码不直接暴露 自定义解释器增加分析难度 动态加载关键逻辑 5.2 潜在弱点 解释器本身可能被逆向 内存中的字节码可能被dump 固定的指令处理模式 六、扩展开发 6.1 自定义指令集 修改 yc 文件格式 扩展解释器支持新指令 添加混淆指令 6.2 多方法加固 批量处理方法抽取 优化native方法注册 共享解释器实例 6.3 增强保护 添加反调试检测 解释器代码混淆 完整性校验机制 七、参考资料 Dalvik虚拟机源码 JNI编程指南 解释器设计模式 原生开发文档 通过以上分析,ADVMP提供了一种基于解释执行的APK保护方案,理解其原理有助于开发更强大的加固工具或分析加固后的应用。