VMProtect的一次奇妙之旅 何潇潇@永信至诚 CONTENTS VMProtect是什么 VMProtect背后的原理 还原VMProtect的方法 演示还原 总结 VMProtect是什么? VMProtect是世界上最强大的二进制代码保护软件之一,是由俄 罗斯人开发的,至今没有人公开声称对其完全破解。 8/27/16 2:30PM 2 VMProtect是什么? 01 02 一个基于堆 栈机的intel指 令的模拟器 8/27/16 2:30PM 03 特定的解释引 擎,用于解释 执行上述的虚 通过编译,把intel 拟指令 指令编译成精心 设计的一组虚拟 指令(PCode) 从本质来讲,VMProtect是 2 8/27/16 2:30PM 3 相关术语 Intel指令寄存器(Register) 和 VM指令寄存器(VMReg) VMProtect一共有14个寄存 器,但是用16个格子(slot)存 放它们,有多的2个格子可 以理解成自由寄存器,最终 扩展成16个寄存器。 8/27/16 2:30PM 4 相关术语 Intel指令(Intel Instruction) 和 VM指令(VMRecord) Intel指令就是Intel的汇编指令, 比如 在VMProtect的世界里面,指令是由 VMRecord组成的,比如 add eax,ecx vm_push_imm32 xor eax,eax … vm_get_context_dword 0x1 slot_offset Intel指令编译生成对应的一组VMRecord, 比如 mov 8/27/16 2:30PM ecx,eax; vm_get_context_dword vEax vm_save_context_dword vEcx 5 相关术语 Intel函数基本块(BasicBlock) 和 VM基本块(VMBlock) BasicBlock是组成Intel函数控制 流图的基本单位,在VMProtect 里面,VMBlock和它一一对应的, 只不过VMBlock是VMRecord的 载体。而且基本块与基本块之间 的关系(也就是控制流图CFG), 也在VMBlock之间一一对应。 8/27/16 2:30PM 6 VMProtect背后的原理 8/27/16 2:30PM 7 VMProtect背后的原理 逻辑门运算 VMProtect是通过NOR(或非门)和ADD(加法门)来实现intel指令的等价运算。 NOR(a,b) = NOT(OR(a,b)) = AND(NOT(a),NOT(b)) 有了NOR的操作,就很容易表示其他的运算,例如: NOT(a) = NOR(a,a) AND(a,b) = NOR(NOT(a),NOT(b)) = NOR(NOR(a,a),NOR(b,b)) OR(a,b) = NOR(NOR(a,b),NOR(a,b)) XOR(a,b) = NOR(NOR(a,b),NOR(NOR(a,a),NOR(b,b))) SUB(a,b) = NOR(ADD(NOR(a,a),b),ADD(NOR(a,a),b)) 比如VMRecord来表示and eax,ecx 8/27/16 2:30PM 7 VMProtect背后的原理 映射 指令集可以理解成线性空间,寄存器就是空间的基,寄存器个数也就是空间 的维数。指令集中的指令,可以理解成算子,比如intel里面的add,xor,or等 在这里,intel指令集空间维度是9,VMProtect的是16,所以注定这2个空间不 同构。 从intel指令到VMProtect指令的变换f,是同态变换,也就是这种变换没有逆 变换,从理论上面证明了不存在完全还原方法。 8/27/16 2:30PM 8 VMProtect背后的原理 具体原因是,VMProtect的寄存器16个格子里面,任何时刻都有2个格子是 自由的(其实是3个,因为vEex是垃圾寄存器,也是自由的)。 VMProtect当一个 寄存器发生变化的时候,它不会把新的值保存在原来的那个格子里面,它会 从空闲格子里面取一个出来保存新值。比如vEax 开始存放在1号格子里面, 经过一系列运算vEax值发生变化,需要更新,这时会从空闲格子里面随机 取出一个比如(2号格子)用来存放vEax,原来的1号格子就会进入空闲池子里 了,正是这种特性,造成了Intel指令到VM指令之间不可能是一一对应的关 系,因为操作数也就是VMProtect用到的格子时刻都在随机变化,只有 VMProtect自己知道对应关系,除了它本身,第三者很难知道。 8/27/16 2:30PM 9 VMProtect背后的原理 还是and eax,ecx ,通过变换f,生成了上面的VMRecords 比如vEax开始保存在1号格子里面,经过and运算以后,保存最后结果的 时候,从空闲格子中随机取一个出来(比如2号),最终vEax从1号格子转 移到2号格子里面,而1号格子变成了空闲格子。 8/27/16 2:30PM 10 还原VMProtect的方法 8/27/16 2:30PM 10 还原VMProtect的方法 基于数据流的还原方法 是通过动态监控堆栈机的执行,获取其每一步的执行的指令,和操 作数.然后根据最终的结果进行溯源,找到其指令的内在联系. 优点 比较简单,而且效率比较高. 缺点 并没有跑遍所有的指令(non-all-path),相当粗糙,不精确. 8/27/16 2:30PM 11 还原VMProtect的方法 基于控制流的静态还原方法 1.Control Flow的还原 2.Intel指令还原 Intel指令与VMRecord的对应 操作符(opcode)还原 操作数(operand)还原 8/27/16 2:30PM 12 Control Flow的还原 8/27/16 2:30PM 13 Intel指令还原 Intel指令与VMRecord的对应 在一个VMBlock里面,哪些 VMRecords对应原始的Intel指 令,这是需要首先解决,因为虚 拟机的本质是堆栈机,也就是 说,当执行完一条Intel指令对应 的VMRecords后,堆栈机的堆栈 应该是平衡的。为此,这里给 VMRecord加上一个字段,表示 执行完后,相对于VMBlock入口 出的堆栈偏移。通过观察这个堆 栈的偏移的变化来确定。 8/27/16 2:30PM 14 Intel指令还原 操作符(opcode)还原 操作符的还原,就是模式识别。首先是要建 立识别库,也就是规则,这个需要相当的积累。 还是用前面的例子and eax,ecx,看到左边的 VMRecords,通过模式识别,很容易就能分析 出,这是一个and 或者是 test操作,操作数是寄 存器,操作数大小是dword,通过具体后面分析, 因为结果不是垃圾数据,确定是and操作。 8/27/16 2:30PM 15 Intel指令还原 操作数(operand)还原 只讨论寄存器操作数的还原,这是VMProtect里面最难 的部分,先前的介绍了解到,VMProtect有2个自由寄存器和 1个vEex垃圾寄存器,导致再重新写入1个寄存器的时候,不 是写在先前位置,而是从空闲里面找一个出来写入,这种情 况在很多时候会带来很大麻烦。 对于二元操作,比如add,xor,and,or等,可以表示成 result = lhs op rhs。这是一个典型的三地址模式,因为Intel 的格式,这种指令在Intel下面其实是两地址模式,result 和 lhs 重合了。对于二元操作的情况,只要分析出源操作符, 就能对应出目的操作数是Intel下面的哪个寄存器。 8/27/16 2:30PM 16
2016-《VMProtect 的一次奇妙之旅》
温馨提示:如果当前文档出现乱码或未能正常浏览,请先下载原文档进行浏览。
本文档由 张玉竹 于 2022-04-08 10:16:33上传分享