[GWCTF 2019]babyvm

系统学习vm虚拟机逆向

64位vm的题目

找到主函数

分析sub_CD1函数:

sub_B5F代表mov操作,其中 0xE1,0xE2...代表不同的寄存器。

 

sub_A64是一个异或操作xor。

sub_AC5是一个读取操作并判断他的长度是否等于21

 

sub_956是空操作nop。

 

sub_A08 两个数相乘操作mul

 

sub_8F0是一个交换操作swap

sub_99c线性运算

 

该函数是对6010A0操作码内容的执行,一直到0xf4结束

下面我们对操作码进行虚拟化指令分析 

opcode=[  0xF5, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4,
  0x20, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x01, 0x00, 0x00, 0x00,
  0xF2, 0xF1, 0xE4, 0x21, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x02,
  0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x22, 0x00, 0x00, 0x00,
  0xF1, 0xE1, 0x03, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x23,
  0x00, 0x00, 0x00, 0xF1, 0xE1, 0x04, 0x00, 0x00, 0x00, 0xF2,
  0xF1, 0xE4, 0x24, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x05, 0x00,
  0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x25, 0x00, 0x00, 0x00, 0xF1,
  0xE1, 0x06, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x26, 0x00,
  0x00, 0x00, 0xF1, 0xE1, 0x07, 0x00, 0x00, 0x00, 0xF2, 0xF1,
  0xE4, 0x27, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x08, 0x00, 0x00,
  0x00, 0xF2, 0xF1, 0xE4, 0x28, 0x00, 0x00, 0x00, 0xF1, 0xE1,
  0x09, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x29, 0x00, 0x00,
  0x00, 0xF1, 0xE1, 0x0A, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4,
  0x2A, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0B, 0x00, 0x00, 0x00,
  0xF2, 0xF1, 0xE4, 0x2B, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0C,
  0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2C, 0x00, 0x00, 0x00,
  0xF1, 0xE1, 0x0D, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2D,
  0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0E, 0x00, 0x00, 0x00, 0xF2,
  0xF1, 0xE4, 0x2E, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0F, 0x00,
  0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2F, 0x00, 0x00, 0x00, 0xF1,
  0xE1, 0x10, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x30, 0x00,
  0x00, 0x00, 0xF1, 0xE1, 0x11, 0x00, 0x00, 0x00, 0xF2, 0xF1,
  0xE4, 0x31, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x12, 0x00, 0x00,
  0x00, 0xF2, 0xF1, 0xE4, 0x32, 0x00, 0x00, 0x00, 0xF1, 0xE1,
  0x13, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x33, 0x00, 0x00,
  0x00, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xF1,
  0xE1, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x01, 0x00, 0x00,
  0x00, 0xF2, 0xF1, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE1,
  0x01, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x02, 0x00, 0x00, 0x00,
  0xF2, 0xF1, 0xE4, 0x01, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x02,
  0x00, 0x00, 0x00, 0xF1, 0xE2, 0x03, 0x00, 0x00, 0x00, 0xF2,
  0xF1, 0xE4, 0x02, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x03, 0x00,
  0x00, 0x00, 0xF1, 0xE2, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xF1,
  0xE4, 0x03, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x04, 0x00, 0x00,
  0x00, 0xF1, 0xE2, 0x05, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4,
  0x04, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x05, 0x00, 0x00, 0x00,
  0xF1, 0xE2, 0x06, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x05,
  0x00, 0x00, 0x00, 0xF1, 0xE1, 0x06, 0x00, 0x00, 0x00, 0xF1,
  0xE2, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x08, 0x00, 0x00,
  0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6, 0xF7, 0xF1,
  0xE4, 0x06, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x07, 0x00, 0x00,
  0x00, 0xF1, 0xE2, 0x08, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x09,
  0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6,
  0xF7, 0xF1, 0xE4, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x08,
  0x00, 0x00, 0x00, 0xF1, 0xE2, 0x09, 0x00, 0x00, 0x00, 0xF1,
  0xE3, 0x0A, 0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00,
  0x00, 0xF6, 0xF7, 0xF1, 0xE4, 0x08, 0x00, 0x00, 0x00, 0xF1,
  0xE1, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x13, 0x00, 0x00,
  0x00, 0xF8, 0xF1, 0xE4, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xE7,
  0x13, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0E, 0x00, 0x00, 0x00,
  0xF1, 0xE2, 0x12, 0x00, 0x00, 0x00, 0xF8, 0xF1, 0xE4, 0x0E,
  0x00, 0x00, 0x00, 0xF1, 0xE7, 0x12, 0x00, 0x00, 0x00, 0xF1,
  0xE1, 0x0F, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x11, 0x00, 0x00,
  0x00, 0xF8, 0xF1, 0xE4, 0x0F, 0x00, 0x00, 0x00, 0xF1, 0xE7,
  0x11, 0x00, 0x00, 0x00, 0xF]
reg = {0xe1:'eax',0xe2:'ebx',0xe3:'ecx',0xe5:'edx'}
operation = {0xf1:'mov',0xf2:'xor',0xf5:'read',0xf4:'nop',0xf7:'add',0xf8:'swap',0xf6:'mul'}
i = 0
for j in range(len(opcode)):
    if(opcode[i] == 0xF1 ):
        print('mov ',end='')
        if (opcode[i+1] == 0xe1):
            print('eax ' + 'flag[' + str(opcode[i + 2]) + ']')
        elif(opcode[i+1] == 0xe2):
            print('ebx '+'flag['+str(opcode[i+2])+']')
        elif(opcode[i+1] == 0xe3):
            print('ecx ','flag['+str(opcode[i+2])+']')
        elif(opcode[i+1] == 0xe4):
            print('flag['+str(opcode[i+2])+'] '+'eax')
        elif(opcode[i+1] == 0xe5):
            print('edx '+'flag['+str(opcode[i+2])+']')
        elif(opcode[i+1] == 0xe7):
            print('flag['+str(opcode[i+2])+'] '+'ebx')
        i+=6
    elif(opcode[i] == 0xf2):
        print('xor eax ecx')
        i+=1
    elif(opcode[i] == 0xf5):
        print('read')
        i+=1
    elif(opcode[i] == 0xf4):
        print('nop')
        i+=1
    elif(opcode[i] == 0xf7):
        print('eax=eax*ecx')
        i+=1
    elif(opcode[i] == 0xf8):
        print('swap eax ebx')
        i+=1
    elif(opcode[i] == 0xf6):
        print('mul eax=ecx+2*ebx+3*eax')
        i+=1
    else:
        i+=1

 得到,注意我们得到两段代码。

read
mov eax flag[0]
xor eax ecx
mov flag[32] eax
mov eax flag[1]
xor eax ecx
mov flag[33] eax
mov eax flag[2]
xor eax ecx
mov flag[34] eax
mov eax flag[3]
xor eax ecx
mov flag[35] eax
mov eax flag[4]
xor eax ecx
mov flag[36] eax
mov eax flag[5]
xor eax ecx
mov flag[37] eax
mov eax flag[6]
xor eax ecx
mov flag[38] eax
mov eax flag[7]
xor eax ecx
mov flag[39] eax
mov eax flag[8]
xor eax ecx
mov flag[40] eax
mov eax flag[9]
xor eax ecx
mov flag[41] eax
mov eax flag[10]
xor eax ecx
mov flag[42] eax
mov eax flag[11]
xor eax ecx
mov flag[43] eax
mov eax flag[12]
xor eax ecx
mov flag[44] eax
mov eax flag[13]
xor eax ecx
mov flag[45] eax
mov eax flag[14]
xor eax ecx
mov flag[46] eax
mov eax flag[15]
xor eax ecx
mov flag[47] eax
mov eax flag[16]
xor eax ecx
mov flag[48] eax
mov eax flag[17]
xor eax ecx
mov flag[49] eax
mov eax flag[18]
xor eax ecx
mov flag[50] eax
mov eax flag[19]
xor eax ecx
mov flag[51] eax
nop
read
mov eax flag[0]
mov ebx flag[1]
xor eax ecx
mov flag[0] eax
mov eax flag[1]
mov ebx flag[2]
xor eax ecx
mov flag[1] eax
mov eax flag[2]
mov ebx flag[3]
xor eax ecx
mov flag[2] eax
mov eax flag[3]
mov ebx flag[4]
xor eax ecx
mov flag[3] eax
mov eax flag[4]
mov ebx flag[5]
xor eax ecx
mov flag[4] eax
mov eax flag[5]
mov ebx flag[6]
xor eax ecx
mov flag[5] eax
mov eax flag[6]
mov ebx flag[7]
mov ecx  flag[8]
mov edx flag[12]
mul eax=ecx+2*ebx+3*eax
eax=eax*ecx
mov flag[6] eax
mov eax flag[7]
mov ebx flag[8]
mov ecx  flag[9]
mov edx flag[12]
mul eax=ecx+2*ebx+3*eax
eax=eax*ecx
mov flag[7] eax
mov eax flag[8]
mov ebx flag[9]
mov ecx  flag[10]
mov edx flag[12]
mul eax=ecx+2*ebx+3*eax
eax=eax*ecx
mov flag[8] eax
mov eax flag[13]
mov ebx flag[19]
swap eax ebx
mov flag[13] eax
mov flag[19] ebx
mov eax flag[14]
mov ebx flag[18]
swap eax ebx
mov flag[14] eax
mov flag[18] ebx
mov eax flag[15]
mov ebx flag[17]
swap eax ebx
mov flag[15] eax
mov flag[17] ebx

 我们用sub_F83的check函数会得到假的flag:

This_is_not_flag_233

查看qword_2022A8的交叉引用,找到真正的check函数,再结合第二段写脚本

from z3 import *
import re

flag = '69 45 2A 37 09 17 C5 0B 5C 72 33 76 33 21 74 31 5F 33 73 72'.split(' ')
flag = [int(_, 16) for _ in flag]

# 置换
flag[15], flag[17] = flag[17], flag[15]
flag[14], flag[18] = flag[18], flag[14]
flag[19], flag[13] = flag[13], flag[19]

# z3
a6, a7, a8 = BitVecs('a6 a7 a8', 8)
s = Solver()
s.add(flag[6] == (a8 + 2 * a7 + 3 * a6) * flag[12])
s.add(flag[7] == (flag[9]  + 2 * a8 + 3 * a7) * flag[12])
s.add(flag[8] == (flag[10] + 2 * flag[9] + 3 * a8) * flag[12])
if s.check() == sat:
    m = s.model()
    for i in m:
        index = int(re.search(r'\d+', str(i)).group())
        flag[index] = m[i].as_long()

# 异或
for i in range(5, -1, -1):
    flag[i] ^= flag[i + 1]

print(''.join([chr(_) for _ in flag]))

得到flag

flag{Y0u_hav3_r3v3rs3_1t!}

参考[GWCTF 2019]babyvm  

babyvm-vm逆向

[GW-CTF2019] babyvm

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值