找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3421

积分

0

好友

466

主题
发表于 2026-2-15 19:24:56 | 查看: 26| 回复: 0

间接跳转是一种常见的高级代码混淆技术,广泛应用于保护软件逻辑、增加逆向分析难度。这类混淆通过动态计算跳转目标,使得静态分析工具(如IDA、Binary Ninja)难以构建准确的控制流图(CFG),从而导致反编译失败或结果混乱。本文将深入探讨如何利用模拟执行技术,特别是基于 Unidbg 框架,有效去除 ARM64 架构下的间接跳转,以恢复可读的程序逻辑。

间接跳转的原理与危害

间接跳转的核心在于使用寄存器而非固定地址进行跳转,例如经典的 jmp eax 指令。这种设计让反编译器无法在静态分析阶段确定跳转的目标,进而破坏了控制流分析。

一个典型的混淆样本如下:

unsigned char dizhi[] = { 0x1, 0x2, 0x3, 0x4, 0x5 };
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k)
{
    unsigned char s[256];
    rc4_init(s, key, Len_k);
    _asm {
        lea eax, label1
        add eax, 8
        sub eax, 7 
        push ebx
        mov ebx, OFFSET dizhi
        movzx ecx, byte ptr [ebx+2]
        pop ebx
        add eax, ecx
        jmp eax
    label1:
        _emit 0x90
        _emit 0x90
        _emit 0x90
        _emit 0x90
    }
}

在此代码中,jmp eax 的目标地址由一系列复杂的计算决定。静态分析工具因无法解析 dizhi 数据段的值,导致常量传播失败,最终丢失了完整的 CFG。

模拟执行:破解混淆的利器

面对此类混淆,手动计算跳转地址虽可行,但对于包含数千种变体的大型程序而言,效率极低。此时,自动化模拟执行成为首选方案。

模拟执行框架通过模拟 CPU 指令执行过程,动态地计算出真实的跳转目标。主流的工具有:

  • Unicorn:提供裸机级别的 CPU 和内存模拟,轻量但需手动处理系统调用。
  • Qiling:在 Unicorn 基础上集成了系统调用 API,可模拟一个微型操作系统。
  • Unidbg:专为 Android Native 层(SO 文件)设计,补齐了 Linker、JNI 等关键组件,非常适合分析安卓应用中的混淆逻辑。
  • Angr:专注于符号执行和路径探索,适用于复杂约束求解。

对于安卓 SO 文件的分析,Unidbg 因其对安卓生态的良好支持而脱颖而出。

Unidbg 基础实战:单个间接跳转的去除

我们以一个简单的 jmp eax 为例,演示如何使用 Unidbg 和 Unicorn 结合的方式去除混淆。

首先,我们需要初始化 Unidbg 模拟器:

public jingqi(){
    emulator=AndroidEmulatorBuilder.for64Bit()
        .addBackendFactory(new Unicorn2Factory(true))
        .setProcessName("com.primite.drillbeam")
        .build();
    Memory memory = emulator.getMemory();
    memory.setLibraryResolver(new AndroidResolver(23));
    vm = emulator.createDalvikVM(new File("D:\\下载\\ctf题目\\2025京麒杯\\drillbeam.apk"));
    vm.setJni(this);
    vm.setVerbose(true);
    NativeApi = vm.resolveClass("com.primite.drillbeam.Check");
    DalvikModule dm = vm.loadLibrary("re0", true);
    Module module = dm.getModule();
    dm.callJNI_OnLoad(emulator);
}

接下来,我们编写一个 Hook 函数来捕获 jmp eax 指令:

public void logIns() {
    emulator.getBackend().hook_add_new(new CodeHook() {
        @Override
        public void hook(Backend backend, long address, int size, Object user) {
            Capstone capstone = new Capstone(Capstone.CS_ARCH_ARM64, Capstone.CS_MODE_ARM);
            byte[] bytes = emulator.getBackend().mem_read(address, 4);
            Instruction[] disasm = capstone.disasm(bytes, 0);
            System.out.printf("%x:%s %s\n", address - module.base, disasm[0].getMnemonic(), disasm[0].getOpStr());
        }

        @Override
        public void onAttach(UnHook unHook) {}

        @Override
        public void detach() {}
    }, module.base, module.base + module.size, null);
}

当捕获到 jmp eax 时,我们读取 eax 寄存器的值,即为真实的跳转地址。随后,我们可以使用 Keystone 引擎将 jmp eax 动态 patch 成 jmp 0x411cce 这样的直接跳转指令。

应对复杂场景:京麒CTF2024的Drillbeam挑战

实际场景远比上述例子复杂。以“京麒CTF2024”的 drillbeam 题目为例,该题结合了 OLLVM 平坦化和基于 CMP/CSEL/BR 的间接跳转,其模式如下:

CMP             W8, W19
CSEL            W9, W26, W24, LT
LDR             X9, [X28,W9,UXTW#3]
ADD             X9, X9, X20
BR              X9

这种模式的难点在于,CSEL 指令会根据比较结果选择不同的值,这意味着 BR 指令有两个潜在的跳转目标。简单的单次模拟无法覆盖所有路径。

为此,我们设计了一套更复杂的处理流程:

  1. 识别模式:通过 Hook 指令流,匹配 CMP -> (可选的中间指令) -> CSEL/CINC -> BR 的模式。
  2. 收集状态:在执行过程中,将每条指令及其执行时的寄存器状态压入栈中。
  3. 双重模拟:第一次模拟得到一个跳转目标后,启动一个新的 Unicorn 模拟器实例。我们将第一次模拟时的内存快照和寄存器状态复制过去,并篡改 NZCV 标志寄存器,强制程序走向另一条分支,从而计算出第二个跳转目标。
  4. Patch 回写:获得两个目标地址后,将原指令序列 patch 为两条条件跳转指令,例如 BLT target1B target2,并用 NOP 填充剩余空间。

此方法虽然效率较低(需要多次模拟),但兼容性好,能够处理 LTEQNE 等多种条件。

总结与展望

通过结合 Unidbg 的环境模拟能力和 Unicorn 的精确指令执行,我们成功实现了对复杂间接跳转的自动化去除。尽管该方法存在执行路径覆盖不全、环境补全繁琐等不足,但它为分析高度混淆的二进制程序提供了强有力的武器。未来,可进一步探索与符号执行工具(如 Angr)的集成,以提高路径覆盖率和自动化程度。

参考资料

[1] 去间接跳转/模拟执行学习, 微信公众号:mp.weixin.qq.com/s/aDHkOsTZ7Yc3FuOs7MiGqA

版权声明:本文由 云栈社区 整理发布,版权归原作者所有。




上一篇:Web前端安全审计:JavaScript静态分析与动态调试实战
下一篇:从单元到模糊:掌握Go语言四种核心测试模式的实践指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-23 11:45 , Processed in 0.570292 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表