[GWCTF 2019]babyvm
[GWCTF 2019]babyvm
看题目的的名称猜测这是一道vm逆向题,相关资料如下
(44条消息) 系统学习vm虚拟机逆向_43v3rY0unG的博客-CSDN博客
用IDA打开后查看主函数
先分析sub_CD1()函数
这是vm的初始化操作,unk_202060存储的是操作码,并且下面定义的操作码各自对应着一个函数的功能
0xF1
0xF1对应的操作为mov,被操作数0xE1,0xE2,0xE3,0xE5为寄存器,此时的操作是将用户的输入存入寄存器R1,R2,R3,R4,而0xE4,0xE7则表示将寄存器R1,R2的值存入用户的输入中
0xF2
0xF2执行的操作指令为xor,将R1与R2寄存器的值进行异或后存入R1
0xF5
0xF5表示的是指令read,作用是读取用户的输入,此处存入dword_2022A8中
0xF4
0xF4表示空指令nop
0xF7
0xF7表示乘法运算mul,此处是将R1与R4中的值相乘然后存入R1中
0xF8
0xF8表示指令swap,此处将R1和R2中的值进行交换
0xF6
0xF6此处为执行一个自定义运算,R1 = R3 + 2 × R2 + 3 × R1
此时在接着分析sub_E0B()函数,发现会遍历每个字节码,若不是nop指令就进入sub_E6E()函数
发现该函数就是执行每一步的字节码的功能
将字节码翻译回操作指令
此时我们要将执行的指令还原,编写还原脚本如下:
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()
该函数将变化后的用户输入与已知数组进行比较,但是根据提示的输出,感觉不一定是正确答案,而且刚好上面得出的指令有两段,推测这不是真正的判断的函数。我们对qword_2022A8按x进行交叉引用,发现果然存在另一个比较函数
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!}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了