某短视频虚拟机分析和还原

查看 35|回复 1
作者:金罡   
前言
在windows流行的时候,虚拟机保护是多人不敢碰的东西现在依然也是如此,pc的性能比移动端性能要高出不少,虚拟化和变异的代码多到令人发指,因此在加密保护强度上要比移动端要强很多很多,为了移动端App更好的体验(ANR率)移动端加密强度短时间内不会达到pc上的强度,随着移动cpu性能越来越好相信加密强度会逐年加强。
早年兴趣使然分析研究过windows端VMProtect、Safengine Shielden、Themida、VProtect、Enigma Protector等等虚拟机,最近发现国内流行的短视频也有虚拟机加密同时也比较感兴趣,便开始了我的分析之旅。
分析任何虚拟机必须要扣汇编指令级细节。
准备
安卓诞生这么多年了至今没有像windows端olldbg、x64dbg那样友好的调试器,IDA PRO虽然自带了安卓调试器总是没有相像中的稳定。lldb作为移动端iOS和android开发的御用调试器,带源码调试在开发环境中还算比较友好,而汇编级调试只能输入命令行了,这是很多用惯了gui调试器的人接受不了的,但是个人发现lldb调试稳定性出奇的好,功能上比IDA Pro的安卓调试器强大太多了。
工具 && 参考文档
  • 静态分析工具
    IDA Pro
    IDA Pro中的变量和标签命名约定: 1. 无下线为精确的名字,已经非常了解代码的功能和含义,例如:"xxx"。2. "_"单下划线定义为代码的功能和含义比较模糊,例如:"_xxx"。3. 双下划线为分析的代码模糊不清,由于地址不好记忆但需要命名以区分,例如:"__xxx"。
  • 动态分析工具
    lldb
  • ARM参考文档
    《Arm Architecture Reference Manual》
    《ARM Cortex-A Series Programmer's Guide for ARMv8-A》
  • 其他工具
    CyberChef

    虚拟机分析
    libEncryptor.so一共包含了三套虚拟机,三套虚拟机各自独立并且代码一模一样,本文重点只分析vm2虚拟机


    vms_length.png (87.55 KB, 下载次数: 0)
    下载附件
    2024-6-26 17:01 上传

    虚拟机指令编解码参考借鉴了arm64的一部分规则,并实现了自己的一套规则,在后面的解码分析中会有很多和arm64解码相似的地方。
    另外虚拟机并没有像VMProtect那样将一条指令分割成多条"微指令"的方式,此虚拟机没有把当前真实的上下文放到虚拟机上下文去模拟执行,而是运行了一套自己单独的上下文。
    [ol]
  • vm1: 0xDA0
    在JNI_OnLoad中被调用,该虚拟机起始位置在0xDA0,主要作用解密是注册java native所需要的字符串和调用RegisterNatives进行注册。
  • vm2: 0x2AC4
    虚拟机起始位置在0x2AC4,是java注册的原生接口com.bytedance.frameworks.encryptor.EncryptorUtil.ttEncrypt(byte[] buff, int size),用来加密buff字节数组。
  • vm3: 0x444
    代码位置在0x444,用于生成aes-128 cbc算法的key和iv。
    [/ol]
    在函数中调用虚拟机时会传入一个指针数组类型参数变量,这是传入到虚拟机入口的唯一参数。
    void vm_entry(*int args)
    c伪代码来表示函数调用虚拟机入口
    void ttEncrypt(char* buff, int buff_size) {
        int dst_size = size +0x76;
        char* pDstBuff = malloc(size +0x76);
        vm_entry(buff, size, pDstBuff, &dst_size);
    }
    反汇编版本:


    1.ttEncrypt.png (256.13 KB, 下载次数: 0)
    下载附件
    2024-6-26 17:02 上传

    入口
    IDA Pro查看入口的cfg图,复杂程序看似很难其实一点都不简单,话说回来cfg看起来和ollvm的混淆平坦化非常相似,其实和ollvm混淆关系不大,只不过一部分的switch被拉平了,在了解调度逻辑后分析也不算复杂。
    在代码中依然能看到两个ollvm swtich var变量,其作用没有详细分析,但整个cfg图确定与ollvm关系不是很大,猜测开启ollvm后性能会大幅下降影响app启动速度了。


    vm2_entry_cfg.png (94.75 KB, 下载次数: 0)
    下载附件
    2024-6-26 17:04 上传

    在进入虚拟机运行时前,在入口需要准备虚拟机所需的内存和参数。对虚拟机内存布局情况必须了解如指掌,这样在动态和静态分析时才不会迷失方向。
  • 分配空间
    入口首先会分配堆栈空间,真实堆栈空间中包含了参数占用、虚拟机运行时的上下文(context)和虚拟机堆栈的所使用的空间,
    从上图代码中看出虚拟机堆栈起始位置位于sp+0x38,结束位置sp+0x4D8,大小4D8-0x38=4A0,虚拟机所有可用真实内存为0x4A0,其中上下文(context)使用0x150,剩余分配给虚拟机堆栈4A0-150=2C0。
    vm_entry调用vm2_run时的堆栈内存布局情况:

    [table]
    [tr]
    [td]SP[/td]
    [td]类型[/td]
    [td]变量名[/td]
    [td]注释[/td]
    [/tr]
    [tr]
    [td]0x0

    虚拟机, 堆栈

  • 几度夕阳红   

    左边 收听下的 目录是真方便,这解析到位
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部