关于Code Virtualizer pcode解密的一种方法

来源:互联网 发布:你对大数据的理解 编辑:程序博客网 时间:2024/05/21 10:13

 

原文链接:http://bbs.pediy.com/showthread.php?t=137265

 【详细过程】
   1.VM的解密算法
    一般情况下Code Virtualizer的解密有三个运算:add,sub,xor,有如下计算;
      loads/b/w/d
      operand eax/ax/al ebx/bx/bl         //与key进行计算
      operand eax/ax/al imm32/imm16/imm8  
      operand eax/ax/al imm32/imm16/imm8
      operand ebx/bx/bl eax/ax/al         //更新key
    其中esi指向pcode的数据,ebx为解码key,也就是进入虚拟机前压入堆栈的值:
      push xxxxxxxx      //解码key,正常等于esi
      jmp  VMStart
   2.方法
    让VM代码在emulator中执行,记录寄存器和堆栈状态,并HOOK相应的操作,应该可以得到pcode的id
   3.x86 emulator
    应该有好多,本次采用的是PyEmu,并结合IDA和IDAPython
   4.明文pcode的获取
   设置emulator初始环境,设置EIP,指向虚拟机取指令处,为了使emulator顺利执行,安装异常处理函数,当发现异常时记录异常状态,重设EIP,指向下一指令(有问题??),并在更新key处监视eax/ax/al的值,这就是明文pcode,对python不熟悉(缩进实在无语,有可能是我的编辑器有问题),这个emulator BUG多多,不可能完整跑下来,修改了几处,以dump_wmimmc.sys为例,简单测试了取指令:

代码:
import syssys.path.append(r'D:\reverse\IDA\python\pyemu')sys.path.append(r'D:\reverse\IDA\python\pyemu\lib')from PyEmu import *emu = IDAPyEmu()#debug=0,1,2,>2emu.debug(0)vlizer_start = SegByName(".reloc")vlizer_end   = SegEnd( vlizer_start ) #load vlizer sectionfor i in range(vlizer_start,vlizer_end,4):   emu.set_memory(i,Dword(i))print "[*] Finished loading vlizer section into memory,Start at %x,End at %x,size:%x"%(vlizer_start,vlizer_end,vlizer_end-vlizer_start)flag=1instack=0#eip=fetchcodeemu.set_register("eip",0x10013bd6)#ebx=keyemu.set_register("ebx",0x10018cca)#esi=ebx+deltaemu.set_register("esi",0x10018cca)#edi=vmctx+deltaemu.set_register("edi",0x10013880)while True:    eip=emu.get_register("eip")    mnemonic=GetMnem(eip)    op1=GetOpnd(eip,0)    op2=GetOpnd(eip,1)    #push eax,ax    if mnemonic=="push":       if GetOpType(eip,0)==1 and GetOperandValue(eip,0)==0:          instack=1    #pop eax,ax    elif mnemonic=="pop":       if GetOpType(eip,0)==1 and GetOperandValue(eip,0)==0:          instack=0    #push eax,ax    #pop eax,ax    elif mnemonic=="mov":       if op1=="[esp]":          if GetOpType(eip,1)==1 and GetOperandValue(eip,1)==0:             instack=1       elif op2=="[esp]":          if GetOpType(eip,0)==1 and GetOperandValue(eip,0)==0:             instack=0    elif mnemonic=="add" or mnemonic=="sub" or mnemonic=="xor":       if  GetOpType(eip,0)==1 and (GetOperandValue(eip,0)==0 or GetOperandValue(eip,0)==0x10):          #operand eax/ax/al ebx/bx/bl          if GetOpType(eip,1)==1 and (GetOperandValue(eip,1)==3 or GetOperandValue(eip,1)==0x13) and flag:             print "%s %s,%s"%(mnemonic,op1,op2)             flag=0          #operand eax/ax/al imm32/imm16/imm8          else:             if not instack:                if GetOpType(eip,1)==1:                   print "%s %s,%x"%(mnemonic,op1,emu.get_register(op2))                elif GetOpType(eip,1)==5:                   print "%s %s,%x"%(mnemonic,op1,GetOperandValue(eip,1))    #operand ebx/bx/bl eax/ax/al    if (GetOpType(eip,0)==1 and (GetOperandValue(eip,0)==3 or GetOperandValue(eip,0)==0x13)) and (GetOpType(eip,1)==1 and (GetOperandValue(eip,1)==0 or GetOperandValue(eip,1)==0x10)):      print "%s %s,%s"%(mnemonic,op1,op2)      print "handleindex:%x"%emu.get_register("eax")      break    emu.execute()
 输出:
    sub al,e9
    add al,bl
    add al,e9
    xor al,d2
    sub al,f1
    add bl,al
    handleindex:2d
 最后清理后的取指令为:
    loadsb
    add al,bl
    xor al,d2
    sub al,f1
    add bl,al
    movzx eax,al
    jmp dword ptr [edi+eax*4]
  测试可行,起个抛砖引玉的作用。