zoukankan      html  css  js  c++  java
  • re | [GKCTF2020]EzMachine

    这是一个win32的VM逆向。

    这是第一次做VM逆向,简单的说一下思路:

    1.找出主要的虚拟机逻辑片段。

    2.找出指令集、堆栈、寄存器。

    3.找出要执行的虚拟指令。

    4.具体分析。

    这次的主函数加了花指令混淆,去除掉以后创建函数然后f5:

    同时找到了字符串和虚拟寄存器的地址:

    大概的流程摸清楚了,开始分析指令:

    指令分析:
    0 : 'nop',
    1 : 'mov i(寄存器编号), j',
    2 : 'push x',
    3 : 'push i(寄存器编号)',
    4 : 'pop i(寄存器编号)',
    5 : 'print',
    6 : 'add i(寄存器编号),j(寄存器编号?)'7 : 'sub',
    8 : 'mul',
    9 : 'div',
    10 : 'xor',
    11 : 'jmp',
    12 : 'subcmp',
    13 : 'je',
    14 : 'jne',
    15 : 'jg',
    16 : 'jl',
    17 : 'input',
    18 : 'clr?',
    19 : 'loadstack',
    20 : 'loadstring',
    0xff : 'quit',

    此处后半部分参考了这篇文章的分析过程(https://blog.csdn.net/weixin_43876357/article/details/108488762)

    下面把command给提出来:

    command:
    01 03 03 05 00 00 11 00 00 01 01 11 0C 00 01 0D
    0A 00 01 03 01 05 00 00 FF 00 00 01 02 00 01 00
    11 0C 00 02 0D 2B 00 14 00 02 01 01 61 0C 00 01
    10 1A 00 01 01 7A 0C 00 01 0F 1A 00 01 01 47 0A
    00 01 01 01 01 06 00 01 0B 24 00 01 01 41 0C 00
    01 10 24 00 01 01 5A 0C 00 01 0F 24 00 01 01 4B
    0A 00 01 01 01 01 07 00 01 01 01 10 09 00 01 03
    01 00 03 00 00 01 01 01 06 02 01 0B 0B 00 02 07
    00 02 0D 00 02 00 00 02 05 00 02 01 00 02 0C 00
    02 01 00 02 00 00 02 00 00 02 0D 00 02 05 00 02
    0F 00 02 00 00 02 09 00 02 05 00 02 0F 00 02 03
    00 02 00 00 02 02 00 02 05 00 02 03 00 02 03 00
    02 01 00 02 07 00 02 07 00 02 0B 00 02 02 00 02
    01 00 02 02 00 02 07 00 02 02 00 02 0C 00 02 02
    00 02 02 00 01 02 01 13 01 02 04 00 00 0C 00 01
    0E 5B 00 01 01 22 0C 02 01 0D 59 00 01 01 01 06
    02 01 0B 4E 00 01 03 00 05 00 00 FF 00 00 01 03
    01 05 00 00 FF 00 00 00

    然后写个脚本来还原伪汇编代码:

     1 cmd = [0x01,0x03,0x03,0x05,0x00,0x00,0x11,
     2 0x00,0x00,0x01,0x01,0x11,0x0C,0x00,0x01,0x0D,
     3 0x0A,0x00,0x01,0x03,0x01,0x05,0x00,0x00,0xFF,
     4 0x00,0x00,0x01,0x02,0x00,0x01,0x00,0x11,0x0C,
     5 0x00,0x02,0x0D,0x2B,0x00,0x14,0x00,0x02,0x01,
     6 0x01,0x61,0x0C,0x00,0x01,0x10,0x1A,0x00,0x01,
     7 0x01,0x7A,0x0C,0x00,0x01,0x0F,0x1A,0x00,0x01,
     8 0x01,0x47,0x0A,0x00,0x01,0x01,0x01,0x01,0x06,
     9 0x00,0x01,0x0B,0x24,0x00,0x01,0x01,0x41,0x0C,
    10 0x00,0x01,0x10,0x24,0x00,0x01,0x01,0x5A,0x0C,
    11 0x00,0x01,0x0F,0x24,0x00,0x01,0x01,0x4B,0x0A,
    12 0x00,0x01,0x01,0x01,0x01,0x07,0x00,0x01,0x01,
    13 0x01,0x10,0x09,0x00,0x01,0x03,0x01,0x00,0x03,
    14 0x00,0x00,0x01,0x01,0x01,0x06,0x02,0x01,0x0B,
    15 0x0B,0x00,0x02,0x07,0x00,0x02,0x0D,0x00,0x02,
    16 0x00,0x00,0x02,0x05,0x00,0x02,0x01,0x00,0x02,
    17 0x0C,0x00,0x02,0x01,0x00,0x02,0x00,0x00,0x02,
    18 0x00,0x00,0x02,0x0D,0x00,0x02,0x05,0x00,0x02,
    19 0x0F,0x00,0x02,0x00,0x00,0x02,0x09,0x00,0x02,
    20 0x05,0x00,0x02,0x0F,0x00,0x02,0x03,0x00,0x02,
    21 0x00,0x00,0x02,0x02,0x00,0x02,0x05,0x00,0x02,
    22 0x03,0x00,0x02,0x03,0x00,0x02,0x01,0x00,0x02,
    23 0x07,0x00,0x02,0x07,0x00,0x02,0x0B,0x00,0x02,
    24 0x02,0x00,0x02,0x01,0x00,0x02,0x02,0x00,0x02,
    25 0x07,0x00,0x02,0x02,0x00,0x02,0x0C,0x00,0x02,
    26 0x02,0x00,0x02,0x02,0x00,0x01,0x02,0x01,0x13,
    27 0x01,0x02,0x04,0x00,0x00,0x0C,0x00,0x01,0x0E,
    28 0x5B,0x00,0x01,0x01,0x22,0x0C,0x02,0x01,0x0D,
    29 0x59,0x00,0x01,0x01,0x01,0x06,0x02,0x01,0x0B,
    30 0x4E,0x00,0x01,0x03,0x00,0x05,0x00,0x00,0xFF,
    31 0x00,0x00,0x01,0x03,0x01,0x05,0x00,0x00,0xFF,
    32 0x00,0x00,0x00]
    33 
    34 opcode = {0 : 'nop',
    35 1 : 'mov i(寄存器编号), j',
    36 2 : 'push x',
    37 3 : 'push i(寄存器编号)',
    38 4 : 'pop i(寄存器编号)',
    39 5 : 'print',
    40 6 : 'add i(寄存器编号),j(寄存器编号?)',
    41 7 : 'sub',
    42 8 : 'mul',
    43 9 : 'div',
    44 10 : 'xor',
    45 11 : 'jmp',
    46 12 : 'subcmp',
    47 13 : 'je',
    48 14 : 'jne',
    49 15 : 'jg',
    50 16 : 'jl',
    51 17 : 'input',
    52 18 : 'clr?',
    53 19 : 'loadstack',
    54 20 : 'loadstring',
    55 0xff : 'quit',}
    56 
    57 i = 0 #3个byte为一条指令
    58 x = 0
    59 for ip in cmd:
    60     if x % 3 == 0:
    61         i += 1
    62         print(str(i) + ': ', end='') # 打印行号
    63         print(opcode[ip] + ' ', end='')
    64     elif x % 3 == 1:
    65         print(str(ip)+',', end='')
    66     else:
    67         print(str(ip))
    68     x += 1

    运行结果(因为我的标注所以有点难看、将就一下):

    1: mov i(寄存器编号), j 3,3
    2: print 0,0
    3: input 0,0
    4: mov i(寄存器编号), j 1,17
    5: subcmp 0,1
    6: je 10,0
    7: mov i(寄存器编号), j 3,1
    8: print 0,0
    9: quit 0,0
    10: mov i(寄存器编号), j 2,0
    11: mov i(寄存器编号), j 0,17
    12: subcmp 0,2
    13: je 43,0
    14: loadstring 0,2
    15: mov i(寄存器编号), j 1,97
    16: subcmp 0,1
    17: jl 26,0
    18: mov i(寄存器编号), j 1,122
    19: subcmp 0,1
    20: jg 26,0
    21: mov i(寄存器编号), j 1,71
    22: xor 0,1
    23: mov i(寄存器编号), j 1,1
    24: add i(寄存器编号),j(寄存器编号?) 0,1
    25: jmp 36,0
    26: mov i(寄存器编号), j 1,65
    27: subcmp 0,1
    28: jl 36,0
    29: mov i(寄存器编号), j 1,90
    30: subcmp 0,1
    31: jg 36,0
    32: mov i(寄存器编号), j 1,75
    33: xor 0,1
    34: mov i(寄存器编号), j 1,1
    35: sub 0,1
    36: mov i(寄存器编号), j 1,16
    37: div 0,1
    38: push i(寄存器编号) 1,0
    39: push i(寄存器编号) 0,0
    40: mov i(寄存器编号), j 1,1
    41: add i(寄存器编号),j(寄存器编号?) 2,1
    42: jmp 11,0
    43: push x 7,0
    44: push x 13,0
    45: push x 0,0
    46: push x 5,0
    47: push x 1,0
    48: push x 12,0
    49: push x 1,0
    50: push x 0,0
    51: push x 0,0
    52: push x 13,0
    53: push x 5,0
    54: push x 15,0
    55: push x 0,0
    56: push x 9,0
    57: push x 5,0
    58: push x 15,0
    59: push x 3,0
    60: push x 0,0
    61: push x 2,0
    62: push x 5,0
    63: push x 3,0
    64: push x 3,0
    65: push x 1,0
    66: push x 7,0
    67: push x 7,0
    68: push x 11,0
    69: push x 2,0
    70: push x 1,0
    71: push x 2,0
    72: push x 7,0
    73: push x 2,0
    74: push x 12,0
    75: push x 2,0
    76: push x 2,0
    77: mov i(寄存器编号), j 2,1
    78: loadstack 1,2
    79: pop i(寄存器编号) 0,0
    80: subcmp 0,1
    81: jne 91,0
    82: mov i(寄存器编号), j 1,34
    83: subcmp 2,1
    84: je 89,0
    85: mov i(寄存器编号), j 1,1
    86: add i(寄存器编号),j(寄存器编号?) 2,1
    87: jmp 78,0
    88: mov i(寄存器编号), j 3,0
    89: print 0,0
    90: quit 0,0
    91: mov i(寄存器编号), j 3,1
    92: print 0,0
    93: quit 0,0
    94: nop

    整体逻辑如下:

    1.先判断是不是17位

    2.大小写字母分别进行操作并压栈

    3.将结果压栈

    4.将结果pop出来比较

    具体的分析过程还是有参考上面的那篇文章。

    然后写一个脚本来还原flag:

     1 ans = [7,
     2 13,
     3 0,
     4 5,
     5 1,
     6 12,
     7 1,
     8 0,
     9 0,
    10 13,
    11 5,
    12 15,
    13 0,
    14 9,
    15 5,
    16 15,
    17 3,
    18 0,
    19 2,
    20 5,
    21 3,
    22 3,
    23 1,
    24 7,
    25 7,
    26 11,
    27 2,
    28 1,
    29 2,
    30 7,
    31 2,
    32 12,
    33 2,
    34 2,]
    35 ans.reverse()
    36 flag = ''
    37 for i in range(0, len(ans), 2):
    38     x = ans[i] + ans[i+1]*16
    39     tmp = (x-1) ^ 71
    40     if tmp >= ord('a') and tmp <= ord('z'):
    41         flag += chr(tmp)
    42         continue
    43     tmp = (x+1) ^ 75
    44     if tmp >= ord('A') and tmp <= ord('Z'):
    45         flag += chr(tmp)
    46         continue
    47     flag += chr(x)
    48     
    49 print(flag)

    跑一下就出来了。

    总的来说感觉这种题不是很复杂,但是需要足够细致耐心。

  • 相关阅读:
    SpringCloud Ribbon实现负载均衡,SpringCloud Ribbon自定义策略
    springCloud zookeeper整合,Java Zookeeper微服务注册中心整合
    SpringCloud Eureka安装和使用,SpringCloud使用Eureka作为服务注册中心
    Linux yum安装Consul服务中心,Centos7在线安装consul
    SpringCloud consul安装和使用,Windows Consul安装和使用,Java consul服务中心安装和使用
    哔哩哔哩视频下载到电脑,bilibili UWP下载的视频重命名,blibli视频下载到电脑
    elasticsearch kibana安装和配置
    elasticsearch安装和配置,elasticsearch启动报错:can not run elasticsearch as root
    cmd打开当前文件所在目录,cmd进入当前文件目录,cmd进入指定目录
    京东到家 首页 笔记
  • 原文地址:https://www.cnblogs.com/Mz1-rc/p/13773166.html
Copyright © 2011-2022 走看看