zoukankan      html  css  js  c++  java
  • VMP分析笔记(cmp命令在VM中的表达)

    之前在6月份的时候,突然心血来潮去研究VM,当然那时候全网搜索找相关的文章,但是很多是对我来说是比较深奥的,最起码就是只能看懂一些。然后就写了一篇关于VM的爆破文章,如果你感兴趣的话,可以在本博客找到。
     
    然后经过几天思考,觉得VM还不是我玩的时候,又转向了算法的分析,大家可以去看看文章的发表日期就知道我最近做什么了,O(∩_∩)O哈哈~ 其实就是自娱自乐吧。。找虐 T~T
     

    VMP的破解

    http://www.52pojie.cn/thread-205189-1-1.html

    (出处: 吾爱破解论坛)

    看了这个帖子,自己重新理解了帖子的话,就是下面这句。

    vma-b就是

    temp= add(a, nor(b,b))

    nor (temp, temp)

    所以调用VM_Handle的顺序应该是

    Nor(X1,X2)à add(Y1,Y2)à nor(Z1,Z2)àseteip

    其中X1==X2 , Z1==Z2

    这个笔记可以看作是cmp指令在VM中的表达过程

    自己写了一个demo

    易语言代码如下

    .版本 2

    .子程序 _按钮1_被单击

    .局部变量 a, 整数型

    置入代码 ({ 235, 16, 86, 77, 80, 114, 111, 116, 101, 99, 116, 32, 98, 101, 103, 105, 110, 0 })

    a = 到整数 (编辑框1.内容)

    .如果真 (a 123)

    信息框 (success, 0, , )

    返回 ()

    .如果真结束

    信息框 (fail, 0, , )

    置入代码 ({ 235, 14, 86, 77, 80, 114, 111, 116, 101, 99, 116, 32, 101, 110, 100, 0 })

    然后分别找到Nor32 handler add32 handler 这个可以用FKvmp插件找到

    得出 00499BDE 0049B565 2个地址

    现在我要的数据是

    0049B565 0145 04 add dword ptr ss:[ebp+0x4],eax 这句的eax [ebp+4]

    还有就是 nor32 中的

    Not eax

    Not edx

    And eax,edx

    详细看脚本代码

    脚本代码

    loop:

    run

    cmp esi,00499BDE

    jnz nor32

    nor32:

    var a

    log "nor32"

    log eax

    log edx

    mov a,eax

    not a

    log a

    cmp esi,0049B565

    jnz test_start

    test_start:

    var tmp

    mov tmp,[ebp+4]

    log "add32"

    log eax

    log tmp

    jmp loop

    好了,运行脚本然后下00499BDE 0049B565 2个地址的断点,点击按钮 让程序自己跑起来,这时候脚本开始记录下我想要的数据。

    点击OD中的L 就可以看到所有输出的数据。

    我是输入123 得出以下数据

    00499BDE [PhantOm_iNFO] > Breakpoint [sti]

    00499BDE Breakpoint at VMadd_vm.00499BDE

    nor32

    eax: 0000007B

    edx: 0000007B

    a: FFFFFF84

    add32

    eax: 0000007B

    tmp: 0000007B

    0049B565 [PhantOm_iNFO] > Breakpoint [sti]

    0049B565 Breakpoint at VMadd_vm.0049B565

    nor32

    eax: FFFFFF84

    edx: 00000286

    a: 0000007B

    add32

    eax: FFFFFF84

    tmp: 0000007B

    00499BDE [PhantOm_iNFO] > Breakpoint [sti]

    00499BDE Breakpoint at VMadd_vm.00499BDE

    nor32

    eax: FFFFFFFF

    edx: FFFFFFFF

    a: 00000000

    add32

    eax: FFFFFFFF

    tmp: FFFFFFFF

    可以看到7BH=123D

    这时a=not 7B = FFFFFF84

    Add FFFFFF847B = FFFFFFFF

    Not FFFFFFFF=0

    然后我又自己思考了一下,为什么最后是等于0呢,因为上面已经说了,cmp命令相当于a-b 比如我这个程序对比输入的数据是否等于123 16进制7B 。只要将输入的数和7B相减等于0的话,说明输入对了。

    然而在VM中,先not 后再and not 最后结果等于0 最后还是等于0

    以上就是正确的流程,最后是等于0的 所以为什么吾爱的那个帖子,走到and eax,edx 0 就是这个原因

    错误的流程:

    00499BDE [PhantOm_iNFO] > Breakpoint [sti]

    00499BDE Breakpoint at VMadd_vm.00499BDE

    nor32

    eax: 000001C8

    edx: 000001C8

    not eax

    temp: FFFFFE37

    not edx

    temp1: FFFFFE37

    add32

    eax: 000001C8

    tmp: 000001C8

    0049B565 [PhantOm_iNFO] > Breakpoint [sti]

    0049B565 Breakpoint at VMadd_vm.0049B565

    nor32

    eax: FFFFFE37

    edx: 00000282

    not eax

    temp: 000001C8

    not edx

    temp1: FFFFFD7D

    add32

    eax: FFFFFE37

    tmp: 0000007B

    00499BDE [PhantOm_iNFO] > Breakpoint [sti]

    00499BDE Breakpoint at VMadd_vm.00499BDE

    nor32

    eax: FFFFFEB2

    edx: FFFFFEB2

    not eax

    temp: 0000014D

    not edx

    temp1: 0000014D

    add32

    eax: FFFFFEB2

    tmp: FFFFFEB2

    上面就是下面这句话的解释

    temp= add(a, nor(b,b))

    nor (temp, temp)

    总结:

    如果遇到2个数进行对比的话,可以找到add32 add dword ptr ss:[ebp+0x4],eax 关注eax[ebp+0x4]的值 可以找到是和哪个数据对比

    Demo and pdf download:

    https://yunpan.cn/c6i72JaATqvBR 访问密码 b0b7

    附录:

    在VMP中,减法是采用迂回的方式实现的:
    A-B:
    NOT(A)
    A=A+B
    NOT(A)
    而NOT运算又要使用NAND来完成
    A-B:
    NAND(A,A)
    A=A+B
    NAND(A,A)

    2.3.EFLAGS标志位检测+跳转
    这一节看完后,就可以畅通无阻的浏览VMP的伪指令了。
    2.3.1.判断两个数是否相同
    举例数据:
    把立即数0000和内存00427D51中的1个word数据比较,检测是否为0。
    整个过程分为两个阶段:
    第一阶段:执行减法运算
    A-B:
    NAND(A,A) ;这里的标志位是无用的
    A=A+B ;获得标志位A
    NAND(A,A) ;获得标志位B
    第二阶段:合并两个标志位
    A=AND(A,00000815)
    B=AND(B,FFFFF7EA)
    A=A+B
    第三阶段:检测ZF位+跳转
    构建跳转地址结构
    检测ZF位
    获得加密跳转地址
    解密跳转地址
    调用VM_JMP
    在开始这个部分前,把所有VM_MOV_EDISTACK_EBPSTACK伪指令中的AND AL,3C指令的下一条指令处下好断点,我们要记录下各个标志位的走向!000000286-->14(表示EFL存储到偏移量14的[EDI+EAX]位置)
    第一阶段:
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_PUSHw_IMMEDIATEb
    0013F9AC 0000
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;立即数IMM0000
    VM_PUSHdw_IMMEDIATEdw
    0013F9A8 7D51
    0013F9AC 00000042 B...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_PUSHw_MEMORYb
    0013F9AC 00000000
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;内存数MEM0000。很明显,我们看到两个数是相同的
    VM_PUSHdw_EBP
    0013F9A8 0013F9AC .
    0013F9AC 00000000 ....
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_COPYw_EBPSTACK
    0013F9A8 0000
    0013F9AC 00000000 ....
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;复制内存数MEM0000
    VM_NANDw
    0013F9A8 00000286 ..
    0013F9AC 000000FF ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NOT(MEM0000)=MEM00FF
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9AC 000000FF ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;000000286-->14(表示EFL存储到偏移量14的[EDI+EAX]位置)
    VM_ADDb_EBPSTACK
    0013F9A8 0286
    0013F9AC 00FF0000 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;00FF=IMM0000+MEM00FF
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9AC 00FF
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;标志位A 000000286-->04
    VM_PUSHdw_EBP
    0013F9A8 F9AE
    0013F9AC 00FF0013 ..
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_COPYw_EBPSTACK
    0013F9AC 00FF00FF ..
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_NANDw
    0013F9A8 0246
    0013F9AC 00000000 ....
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NOT(00FF)
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9AC 0000
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;标志位B 00000246-->3C
    VM_MOVw_EDISTACKb_EBPSTACKw
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;
    第一阶段结束。
    两个操作数都是0000,很明显这次判断将是两个数相同,减法后的ZF位置1。
    运算的结果都是无用的,关键在于它的标志位,继续看标志位ZF的检测+跳转
    第二阶段:
    VM_PUSHdw_EDISTACKdw
    0013F9AC 00000286 ..
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;标志位A 000000286<--04
    VM_PUSHdw_EDISTACKdw
    0013F9A8 00000286 ..
    0013F9AC 00000286 ..
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;再来一次标志位A
    VM_NANDdw
    0013F9A8 00000282 ..
    0013F9AC FFFFFD79 y
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(A,A)=NOT(A)=FFFFFD79
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9AC FFFFFD79 y
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_PUSHdw_IMMEDIATEw
    0013F9A8 FFFFF7EA
    0013F9AC FFFFFD79 y
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(X,X)=NOT(00000815)=FFFFF7EA 传递相反数,隐藏NOT(00000815)
    VM_NANDdw
    0013F9A8 00000202 ..
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(A,A),NAND(X,X))=标志位A 00000286 AND 00000815
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_PUSHdw_EDISTACKdw
    0013F9A8 00000246 F..
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;标志位B 00000246<--3C
    VM_PUSHdw_EDISTACKdw
    0013F9A4 00000246 F..
    0013F9A8 00000246 F..
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;再来一次标志位B
    VM_NANDdw
    0013F9A4 00000282 ..
    0013F9A8 FFFFFDB9
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(B,B)=NOT(B)=FFFFFDB9
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9A8 FFFFFDB9
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_PUSHdw_IMMEDIATEw
    0013F9A4 00000815 ..
    0013F9A8 FFFFFDB9
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(Y,Y)=NOT(FFFFF7EA)=00000815 传递相反数,隐藏NOT(FFFFF7EA)
    VM_NANDdw
    0013F9A4 00000206 ..
    0013F9A8 00000242 B..
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(B,B),NAND(Y,Y))=标志位B 00000246 AND FFFFF7EA
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9A8 00000242 B..
    0013F9AC 00000004 ...
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_ADDdw_EBPSTACK
    0013F9A8 00000202 ..
    0013F9AC 00000246 F..
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;两个AND后的标志位相加
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9AC 00000246 F..
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;00000246-->00 暂存结果
    第二阶段结束
    现在VMP已经把两个标志位合并成了一个,关于标志位合并的解析结束后再来看。继续看第三阶段:检测ZF+跳转,注意看好堆栈数据的构造,堆栈虚拟机的跳转判断有他独特的地方!同时它巧妙的运用了ZF位在EFLAGS中的位置。
    第三阶段:
    VM_PUSHdw_IMMEDIATEdw
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳转地址1
    VM_PUSHdw_IMMEDIATEdw
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳转地址2
    VM_PUSHdw_EBP
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳转地址指针
    VM_PUSHw_IMMEDIATEb
    0013F9A0 0004
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM

    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;传递4,看好堆栈的构造,下面的几个操作是独立的
    VM_PUSHdw_EDISTACKdw
    0013F99C 0246
    0013F9A0 00040000 ...
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;第二阶段结果00000246<--00
    VM_PUSHdw_EBP
    0013F998 F99E
    0013F99C 02460013 .F
    0013F9A0 00040000 ...
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_COPYdw_EBPSTACK
    0013F998 0246
    0013F99C 02460000 ..F
    0013F9A0 00040000 ...
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;复制标志位
    VM_NANDdw
    0013F998 0282
    0013F99C FDB90000 ..
    0013F9A0 0004FFFF .
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(A,A)=NOT(A)=NOT(00000246)=FFFFFDB9
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F99C FDB9
    0013F9A0 0004FFFF .
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_PUSHdw_IMMEDIATEb
    0013F998 FFBF
    0013F99C FDB9FFFF
    0013F9A0 0004FFFF .
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(B,B)=NOT(00000040)=FFFFFFBF 传递相反数,隐藏NOT(000000040)
    VM_NANDdw
    0013F998 0202
    0013F99C 00400000 ..@. ; OFFSET NOTEPAD.B
    0013F9A0 00040000 ...
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;NAND(NAND(B,B),NAND(B,B))=标志位 00000246 AND 00000040
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F99C 0040
    0013F9A0 00040000 ...
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;AND结果是00000040,说明ZF位是1,两个数相等;想想如果不相等,结果是00000000
    VM_SHRdw_EBPSTACKb
    0013F99C 00000202 ..
    0013F9A0 00000004 ...
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;右移4位刚好把00000040移动成00000004;如果不相等,右移后是00000000
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9A0 00000004 ...
    0013F9A4 0013F9A8 .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A
    VM_ADDdw_EBPSTACK
    0013F9A0 00000206 ..
    0013F9A4 0013F9AC .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;00000004+0013F9A8=0013F9AC;如果不相等,00000000+0013F9A8=0013F9A8
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9A4 0013F9AC .
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳转地址指针指向的就是判断后的跳转地址
    VM_COPYdw_EBPSTACK
    0013F9A4 4DBE4AD8 JM
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;跳转地址指针指向的跳转地址复制出来
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9A8 4DBE49D5 IM
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;把最终的跳转地址暂存到EDISTACK,4DBE4AD8-->18
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;扫尾工作,释放EBPSTACK
    VM_MOVdw_EDISTACKdw_EBPSTACKdw
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;扫尾工作,释放EBPSTACK
    VM_PUSHdw_EDISTACKdw
    0013F9AC 4DBE4AD8 JM
    0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;压入判断的跳转地址4DBE4AD8<--18
    第三阶段结束
    接下来VM将使用一次XOR运算解密4DBE4AD8数据(详见2.2.3.XOR举例),然后是VM_JMP指令调用的组合(详见2.1.3.举例),全过程结束。
    两个操作数都是0000,1个来自内存空间,一个来自ESI的编译数据,同时这段代码是在VM刚刚启动就进行的了,都是定量。但是VM还要进行检测,说明两个数据是不确定的,VM在运行过程中要知道它是不是0,可以把它猜测为VMP内部的一个信号。VM一开始就要知道到底应该走向哪个分支。到后面我们会进行测试,如果这个信号比较结果不为0,VM的走向是怎样的。
    下面我们来详解上面的操作过程,从第二阶段合并标志位来看
    第一阶段:执行减法运算
    IMM0000-MEM0000:
    NAND(IMM0000,IMM0000) ;这里的标志位是无用的
    00FF=IMM00FF+MEM0000 ;获得标志位A 000000286
    NAND(00FF,00FF) ;获得标志位B 000000246
    第二阶段:合并两个标志位
    00000004=AND(00000286,00000815)
    00000242=AND(00000246,FFFFF7EA)
    00000246=00000004+00000242
    把两个标志位分别AND后相加,AND操作时用于保留想要的标志位,加法把它合并起来。

     

     

    By 星空之上

    2016-8-14 15:02:55

  • 相关阅读:
    《应用Yii1.1和PHP5进行敏捷Web开发》学习笔记(转)
    YII 小模块功能
    Netbeans代码配色主题大搜集
    opensuse 启动巨慢 解决方法 90s多
    opensuse 安装 网易云音乐 rpm netease music
    linux qq rpm deb opensuse
    openSUSE 安装 alien
    第一行代码 Android 第2版
    Android Studio AVD 虚拟机 联网 失败
    docker error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.29/containers/json: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuratio
  • 原文地址:https://www.cnblogs.com/Sendige/p/9600968.html
Copyright © 2011-2022 走看看