• [GKCTF2020]EzMachine


    参考资料:

    https://blog.csdn.net/weixin_43876357/article/details/108488762

    https://www.cnblogs.com/EveningBreeze/p/13773930.html

    一直想动笔写ezmachine这个,去网上看wp的时候发现是vm,还从来没写过,然后尝试着分析,便很快放弃,代码量还好,就是老跳转,把自己跳傻了,今天在来挑战的试试看。

    由于在写这道题之前就看过wp,知道这是一个模仿机器指令的程序,所以先想办法推出程序流程。

     

     

    在浏览汇编的时候突然看到一些标红的代码段,并且在里面发现了混淆指令,把401594这里nop掉就行了

     看到函数,由于之前我用x32dbg动调的时候,看到了这一部分的汇编代码,我知道这是主要的跳转函数

     先看第一个dd offset sub_4011B0,之前动调经常看到这个全局变量,并且我推测这个全局变量是eip,所以这个指令可能就是eip+1

     看第二个dd offset sub_401000,这里把byte_4449a1的值给了eax与ecx,eip+3,a2的值存在off_4427fc与eax的一个偏移里面

    看第三个dd offset sub_401070,把byte_4449a1的值给cl,在把这个值给到dword__445bac+esi,esi看起来像个index,并且每次调用都会加1

     看第四个dd offset sub_401030,从off_4427fc中选一个数组里的元素出来,在放入另一个数组中,并且esi加1

     看第五个dd offset sub_4010A0,把dword_445BAC数组里的最后一个放入off_4427FC数组里的元素,并且dword_445BC8-1

    第六个dd offset sub_4010E0,一个switch语句,估计是打印结果的

    .text:004010E0                 mov     eax, dword_445BCC
    .text:004010E5                 mov     ecx, dword_445BA8
    .text:004010EB                 cmp     eax, 4          ; switch 5 cases
    .text:004010EE                 ja      loc_401187      ; jumptable 004010F4 default case
    .text:004010F4                 jmp     ds:off_401198[eax*4] ; switch jump
    .text:004010FB ; ---------------------------------------------------------------------------
    .text:004010FB
    .text:004010FB loc_4010FB:                             ; CODE XREF: sub_4010E0+14↑j
    .text:004010FB                                         ; DATA XREF: .text:off_401198↓o
    .text:004010FB                 mov     eax, ds:dword_4427D8 ; jumptable 004010F4 case 0
    .text:00401100                 mov     [ecx], eax
    .text:00401102                 mov     ax, ds:word_4427DC
    .text:00401108                 push    ecx
    .text:00401109                 mov     [ecx+4], ax
    .text:0040110D                 call    sub_407C00
    .text:00401112                 add     esp, 4
    .text:00401115                 add     dword_445BD8, 3
    .text:0040111C                 retn
    .text:0040111D ; ---------------------------------------------------------------------------
    .text:0040111D
    .text:0040111D loc_40111D:                             ; CODE XREF: sub_4010E0+14↑j
    .text:0040111D                                         ; DATA XREF: .text:off_401198↓o
    .text:0040111D                 mov     eax, ds:dword_4427E0 ; jumptable 004010F4 case 1
    .text:00401122                 mov     [ecx], eax
    .text:00401124                 mov     ax, ds:word_4427E4
    .text:0040112A                 push    ecx
    .text:0040112B                 mov     [ecx+4], ax
    .text:0040112F                 call    sub_407C00
    .text:00401134                 add     esp, 4
    .text:00401137                 add     dword_445BD8, 3
    .text:0040113E                 retn
    .text:0040113F ; ---------------------------------------------------------------------------
    .text:0040113F
    .text:0040113F loc_40113F:                             ; CODE XREF: sub_4010E0+14↑j
    .text:0040113F                                         ; DATA XREF: .text:off_401198↓o
    .text:0040113F                 movq    xmm0, ds:qword_4427E8 ; jumptable 004010F4 case 3
    .text:00401147                 movq    qword ptr [ecx], xmm0
    .text:0040114B                 mov     ax, ds:word_4427F0
    .text:00401151                 mov     [ecx+8], ax
    .text:00401155                 mov     al, ds:byte_4427F2
    .text:0040115A                 push    ecx
    .text:0040115B                 mov     [ecx+0Ah], al
    .text:0040115E                 call    sub_407C00
    .text:00401163                 add     esp, 4
    .text:00401166                 add     dword_445BD8, 3
    .text:0040116D                 retn
    .text:0040116E ; ---------------------------------------------------------------------------
    .text:0040116E
    .text:0040116E loc_40116E:                             ; CODE XREF: sub_4010E0+14↑j
    .text:0040116E                                         ; DATA XREF: .text:off_401198↓o
    .text:0040116E                 mov     eax, ds:dword_4427F4 ; jumptable 004010F4 case 4
    .text:00401173                 mov     [ecx], eax
    .text:00401175                 mov     ax, ds:word_4427F8
    .text:0040117B                 mov     [ecx+4], ax
    .text:0040117F                 mov     al, ds:byte_4427FA
    .text:00401184                 mov     [ecx+6], al
    .text:00401187
    .text:00401187 loc_401187:                             ; CODE XREF: sub_4010E0+E↑j
    .text:00401187                                         ; sub_4010E0+14↑j
    .text:00401187                                         ; DATA XREF: ...
    .text:00401187                 push    ecx             ; jumptable 004010F4 default case
    .text:00401188                 call    sub_407C00
    .text:0040118D                 add     dword_445BD8, 3
    .text:00401194                 add     esp, 4
    .text:00401197                 retn
    .text:00401197 sub_4010E0      endp
    .text:00401197
    .text:00401197 ; ---------------------------------------------------------------------------
    .text:00401198 off_401198      dd offset loc_4010FB    ; DATA XREF: sub_4010E0+14↑r
    .text:00401198                 dd offset loc_40111D    ; jump table for switch statement
    .text:00401198                 dd offset loc_401187
    .text:00401198                 dd offset loc_40113F
    .text:00401198                 dd offset loc_40116E
    .text:004011AC                 align 10h

     第七个dd offset sub_4011D0 ,两个值相加

     第8个dd offset sub_401200,两个数相减

     第9个dd offset sub_401230,两个数相乘

     第10个dd offset sub_401270,两个数相除,dword_445bdc存放商,dword_445bc4存放余数

     第11个dd offset sub_4012B0,两个数做异或

     第12个dd offset sub_4012E0,不太清楚

    第13个 dd offset sub_401300,两个数相减,并存放到dword_445bcc

     第14个dd offset sub_401340,这个也没看懂干嘛

     第15个dd offset sub_401370,感觉都跟上面一个样

     第16个dd offset sub_4013A0-17几乎都是跟上面一样

    第18个dd offset sub_401400,计算字符串的长度

     第19个dd offset sub_401430,没看懂

     第20个dd offset sub_401470,一个值加上dword_445bd0在加上dword_445bac偏移给另一个值

    第21个dd offset sub_4014B0,跟上面的差不都

     

     第22个dd offset sub_4011C0,不知道干啥

     把opcode和数据全部导出来,并写下脚本,把程序流程打印出来

    #字节码
    code =[
      0x01, 0x03, 0x03, 0x05, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 
      0x01, 0x11, 0x0C, 0x00, 0x01, 0x0D, 0x0A, 0x00, 0x01, 0x03, 
      0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, 0x02, 0x00, 
      0x01, 0x00, 0x11, 0x0C, 0x00, 0x02, 0x0D, 0x2B, 0x00, 0x14, 
      0x00, 0x02, 0x01, 0x01, 0x61, 0x0C, 0x00, 0x01, 0x10, 0x1A, 
      0x00, 0x01, 0x01, 0x7A, 0x0C, 0x00, 0x01, 0x0F, 0x1A, 0x00, 
      0x01, 0x01, 0x47, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 
      0x00, 0x01, 0x0B, 0x24, 0x00, 0x01, 0x01, 0x41, 0x0C, 0x00, 
      0x01, 0x10, 0x24, 0x00, 0x01, 0x01, 0x5A, 0x0C, 0x00, 0x01, 
      0x0F, 0x24, 0x00, 0x01, 0x01, 0x4B, 0x0A, 0x00, 0x01, 0x01, 
      0x01, 0x01, 0x07, 0x00, 0x01, 0x01, 0x01, 0x10, 0x09, 0x00, 
      0x01, 0x03, 0x01, 0x00, 0x03, 0x00, 0x00, 0x01, 0x01, 0x01, 
      0x06, 0x02, 0x01, 0x0B, 0x0B, 0x00, 0x02, 0x07, 0x00, 0x02, 
      0x0D, 0x00, 0x02, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x01, 
      0x00, 0x02, 0x0C, 0x00, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00, 
      0x02, 0x00, 0x00, 0x02, 0x0D, 0x00, 0x02, 0x05, 0x00, 0x02, 
      0x0F, 0x00, 0x02, 0x00, 0x00, 0x02, 0x09, 0x00, 0x02, 0x05, 
      0x00, 0x02, 0x0F, 0x00, 0x02, 0x03, 0x00, 0x02, 0x00, 0x00, 
      0x02, 0x02, 0x00, 0x02, 0x05, 0x00, 0x02, 0x03, 0x00, 0x02, 
      0x03, 0x00, 0x02, 0x01, 0x00, 0x02, 0x07, 0x00, 0x02, 0x07, 
      0x00, 0x02, 0x0B, 0x00, 0x02, 0x02, 0x00, 0x02, 0x01, 0x00, 
      0x02, 0x02, 0x00, 0x02, 0x07, 0x00, 0x02, 0x02, 0x00, 0x02, 
      0x0C, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02, 
      0x01, 0x13, 0x01, 0x02, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x01, 
      0x0E, 0x5B, 0x00, 0x01, 0x01, 0x22, 0x0C, 0x02, 0x01, 0x0D, 
      0x59, 0x00, 0x01, 0x01, 0x01, 0x06, 0x02, 0x01, 0x0B, 0x4E, 
      0x00, 0x01, 0x03, 0x00, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 
      0x01, 0x03, 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00
    ]
    #指令集
    opcodekey = {0:'pcadd',1:'mov',2:'push',3:'?',4:'pop',5:'caseprint',6:'add',7:'sub1',8:'mul',9:'div',10:'xor',11:'jmp',12:'subcmp',13:'jedx4',14:'jnedx4',15:'jedx4orlow',16:'jedx4orhight',17:'input',18:'?2',19:'LoadStack',20:'LoadString',0xFF:'end'}
     
    #B为字节码的下标
    B=0
    #C为每一行的序号
    C=1
    print(str(C)+": ",end="")
    #字节码三个一组,每三个的第一个是指令,后两个为操作数
    #i为字节码的遍历
    for i in code:
       #print(hex(i)+" ",end="")
        if B==0:
            #print(i)
            op=opcodekey[i]
            #opcodekey【每三个的第一个字节码】所对应的指令
            print(op,end=' ')
        else:
            print(i,end=" ")
        B=B+1
        #每三个转下一行,也就是下一个汇编
        if B==3:
            B=0
            C=C+1
            print()
            print(str(C)+": ",end="")

    得到如下程序流程

    1: mov 3 3
    2: caseprint 0 0
    3: input 0 0
    4: mov 1 17
    5: subcmp 0 1
    6: jedx4 10 0
    7: mov 3 1
    8: caseprint 0 0
    9: end 0 0
    10: mov 2 0
    11: mov 0 17
    12: subcmp 0 2
    13: jedx4 43 0
    14: LoadString 0 2
    15: mov 1 97
    16: subcmp 0 1
    17: jedx4orhight 26 0
    18: mov 1 122
    19: subcmp 0 1
    20: jedx4orlow 26 0
    21: mov 1 71
    22: xor 0 1
    23: mov 1 1
    24: add 0 1
    25: jmp 36 0
    26: mov 1 65
    27: subcmp 0 1
    28: jedx4orhight 36 0
    29: mov 1 90
    30: subcmp 0 1
    31: jedx4orlow 36 0
    32: mov 1 75
    33: xor 0 1
    34: mov 1 1
    35: sub1 0 1
    36: mov 1 16
    37: div 0 1
    38: ? 1 0
    39: ? 0 0
    40: mov 1 1
    41: add 2 1
    42: jmp 11 0
    43: push 7 0
    44: push 13 0
    45: push 0 0
    46: push 5 0
    47: push 1 0
    48: push 12 0
    49: push 1 0
    50: push 0 0
    51: push 0 0
    52: push 13 0
    53: push 5 0
    54: push 15 0
    55: push 0 0
    56: push 9 0
    57: push 5 0
    58: push 15 0
    59: push 3 0
    60: push 0 0
    61: push 2 0
    62: push 5 0
    63: push 3 0
    64: push 3 0
    65: push 1 0
    66: push 7 0
    67: push 7 0
    68: push 11 0
    69: push 2 0
    70: push 1 0
    71: push 2 0
    72: push 7 0
    73: push 2 0
    74: push 12 0
    75: push 2 0
    76: push 2 0
    77: mov 2 1
    78: LoadStack 1 2
    79: pop 0 0
    80: subcmp 0 1
    81: jnedx4 91 0
    82: mov 1 34
    83: subcmp 2 1
    84: jedx4 89 0
    85: mov 1 1
    86: add 2 1
    87: jmp 78 0
    88: mov 3 0
    89: caseprint 0 0
    90: end 0 0
    91: mov 3 1
    92: caseprint 0 0
    93: end 0 0
    94: pcadd

    在分析源程序

     整个程序的逻辑大概是这样的:(开了两个栈)
    首先判断你输入的是不是17位,不是直接跳转报错,是的话进行判断。
    如果是小写字母,那就xor71+1,最后除以16,将商和余数压栈。(即十位和个位)
    如果是大写字母,那就xor75-1,最后除以16,将商和余数压栈。(即十位和个位)
    其余的直接除16压栈。
    然后压入对照数据,最后弹栈比较。

    最终脚本

    array = [0x7,0xd,0x0,0x5,0x1,0xc,0x1,0x0,0x0,0xd,0x5,0xf,0x0,0x9,0x5,0xf,0x3,0x0,0x2,0x5,0x3,0x3,0x1,0x7,0x7,0xb,0x2,0x1,0x2,0x7,0x2,0xc,0x2,0x2,]
    #注意是压栈,先进后出,所以要[::-1]
    array = array[::-1] 
    #先输出的是个位然后是十位,两个一组
    for i in range(0, len(array), 2): 
        c = array[i] + array[i+1]*16 
        tmp = (c-1) ^ 71 
        #如果是小写字母
        if tmp >= ord('a') and tmp <= ord('z'): 
            print(chr(tmp), end = "") 
            continue 
        tmp = (c+1) ^ 75 
        #如果是大写字母
        if tmp >= ord('A') and tmp <= ord('Z'): 
            print(chr(tmp), end = "") 
            continue
        #都不是 
        print(chr(c), end = "") 

    学到的知识

    vm就是虚拟的机器指令

    cdq指令,把eax的符号位给edx的每一位

  • 相关阅读:
    升级到Net6后SignalR组件输出大量的Trace诊断日志
    mysql 权限设置
    mysql处理json数据
    mysql展示列的详细信息并可导出excel
    JPA使用笔记
    令牌桶算法实现限流
    left join(二) 方木
    left join(一) 方木
    时间处理及interval函数运用 方木
    concat()函数 方木
  • 原文地址:https://www.cnblogs.com/pppyyyzzz/p/13850626.html
Copyright © 2020-2023  润新知