[GWCTF 2019]babyvm

发布时间 2023-07-28 17:27:54作者: h40vv3n

[GWCTF 2019]babyvm

看题目的的名称猜测这是一道vm逆向题,相关资料如下

(44条消息) 系统学习vm虚拟机逆向_43v3rY0unG的博客-CSDN博客

用IDA打开后查看主函数

image-20230713200112997

先分析sub_CD1()函数

image-20230713201005739

这是vm的初始化操作,unk_202060存储的是操作码,并且下面定义的操作码各自对应着一个函数的功能

0xF1

0xF1对应的操作为mov,被操作数0xE10xE20xE30xE5为寄存器,此时的操作是将用户的输入存入寄存器R1,R2,R3,R4,而0xE40xE7则表示将寄存器R1,R2的值存入用户的输入中

image-20230713202647464

0xF2

0xF2执行的操作指令为xor,将R1与R2寄存器的值进行异或后存入R1

image-20230713203837992

0xF5

0xF5表示的是指令read,作用是读取用户的输入,此处存入dword_2022A8

image-20230713204919142

0xF4

0xF4表示空指令nop

image-20230713205028646

0xF7

0xF7表示乘法运算mul,此处是将R1与R4中的值相乘然后存入R1中

image-20230713205322229

0xF8

0xF8表示指令swap,此处将R1和R2中的值进行交换

image-20230713205826216

0xF6

0xF6此处为执行一个自定义运算,R1 = R3 + 2 × R2 + 3 × R1

image-20230713210049356

此时在接着分析sub_E0B()函数,发现会遍历每个字节码,若不是nop指令就进入sub_E6E()函数

image-20230713211001819

发现该函数就是执行每一步的字节码的功能

image-20230713211143406

将字节码翻译回操作指令

此时我们要将执行的指令还原,编写还原脚本如下:

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, 0xF4]

for i in range(len(opcode)):
    if opcode[i] == 0xF1:
        if opcode[i+1] == 0xE1:
            print('mov R1 '+'flag['+str(opcode[i+2])+']')
        elif opcode[i+1] == 0xE2:
            print('mov R2 '+'flag['+str(opcode[i+2])+']')
        elif opcode[i+1] == 0xE3:
            print('mov R3 '+'flag['+str(opcode[i+2])+']')
        elif opcode[i+1] == 0xE4:
            print('mov '+'flag['+str(opcode[i+2])+']'+' R1')
        elif opcode[i+1] == 0xE5:
            print('mov R4 '+'flag['+str(opcode[i+2])+']')
        elif opcode[i+1] == 0xE7:
            print('mov '+'flag['+str(opcode[i+2])+']'+' R2')
    elif opcode[i] == 0xF2:
        print('xor R1 R2')
    elif opcode[i] == 0xF5:
        print('read')
    elif opcode[i] == 0xF4:
        print('nop')
    elif opcode[i] == 0xF7:
        print('mul R1 R4')
    elif opcode[i] == 0xF8:
        print('swap R1 R2')
    elif opcode[i] == 0xF6:
        print('R1 = R3+2×R2+3×R1')
    

得到的操作指令如下:

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

逆向操作指令

此时我们看最后一个函数sub_F83()

image-20230713220339615

该函数将变化后的用户输入与已知数组进行比较,但是根据提示的输出,感觉不一定是正确答案,而且刚好上面得出的指令有两段,推测这不是真正的判断的函数。我们对qword_2022A8x进行交叉引用,发现果然存在另一个比较函数

image-20230713220745687

byte_202020为已知数组,因此此时可以写出解题脚本:

from z3 import *
list1 = [  0x69, 0x45, 0x2A, 0x37, 0x09, 0x17, 0xC5, 0x0B, 0x5C, 0x72, 
  0x33, 0x76, 0x33, 0x21, 0x74, 0x31, 0x5F, 0x33, 0x73, 0x72]

list1[15], list1[17] = list1[17], list1[15]
list1[14], list1[18] = list1[18], list1[14]
list1[13], list1[19] = list1[19], list1[13]

a6,a7,a8=BitVecs('a6 a7 a8', 8)
s = Solver()
s.add((3*a6+2*a7+a8)*list1[12] == list1[6])
s.add((3*a7+2*a8+list1[9])*list1[12] == list1[7])
s.add((3*a8+2*list1[9]+list1[10])*list1[12] == list1[8])
s.check()
print(s.model())
list1[6] = 118
list1[7] = 51
list1[8] = 95

for i in range(5,-1,-1):
    list1[i] = list1[i] ^ list1[i+1]

flag = ''
for i in range(len(list1)):
    flag += chr(list1[i])

print('flag{'+flag+'}')

得到此题的flag为:flag{Y0u_hav3_r3v3rs3_1t!}