gwctf-2019-babyvm详细分析

本文最后更新于:2 年前

与 vm 代码保护的初次交锋

代码分析

main函数 情况

img

vminit 函数

img

虚拟机启动函数

img

0xf4 是 结束标志 retn

opcode

img

真好看, 这样的opcode , 可惜是假的

最后的比较

img

vm指令分析

下面函数名称都是自己起的

mov 指令

img

每次执行, 将 eip 移动6 位, 对应 0xf1

xor_encerypto

img

eip 移动 1 位, 对应 0xf2

vm_eip_add

img

将 eip 向前移动一位, 并且是 retn 标志 , 对应 0xf4

vm_mul

img

r0 = r0 * r3

eip 移动一位, 对应 0xf7

vm_swap

img

r0,r1 = r1,r0

将 r1, r0 做交换, eip 移动一位, 对应 0xf8

vm_define_mul

img

r0 = r2 + (r1*2) + (r3 * 3)

eip 移动一位, 对应 0xf6

指令分析

fake code 分析

img

这样看, 直接可以看出 执行流程

  1. 读取输入 到堆栈上

  2. 0xf1 0xe1 -> 0xf2 -> 0xf1 0xe4

    读取堆栈上的字符,按照索引 读取, xor 加密, 和 r1 进行, 在放到堆栈中, base: 0x20

  3. 结束

解题

1
2
3
4
5
6
s = 'Fz{aM{aM|}fMt~suM !!'
flag = ''
for i in s:
flag += chr(ord(i) ^ 18) # 18 在 vm init 函数里面

print(flag)

img

吓得我直接看了 wp

https://github.com/gwht/2019GWCTF/tree/master/wp/reverse/babyvm

并且表示疑惑, 你的 代码都没有调用这个指令, 谁能想到呢, 我吐了。

第二次opcode 分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
opcode_true = [ 
0xF5, # 输入数据

0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00,
0xF1, 0xE2, 0x01, 0x00, 0x00, 0x00,
0xF2,
0xF1, 0xE4, 0x00, 0x00, 0x00, 0x00,
# s[0] = s[0] ^ s[1]
0xF1, 0xE1, 0x01, 0x00, 0x00, 0x00,
0xF1, 0xE2, 0x02, 0x00, 0x00, 0x00,
0xF2,
0xF1, 0xE4, 0x01, 0x00, 0x00, 0x00,
# s[1] = s[1] ^ s[2]
0xF1, 0xE1, 0x02, 0x00, 0x00, 0x00,
0xF1, 0xE2, 0x03, 0x00, 0x00, 0x00,
0xF2,
0xF1, 0xE4, 0x02, 0x00, 0x00, 0x00,
# s[2] = s[2] ^ s[3]
0xF1, 0xE1, 0x03, 0x00, 0x00, 0x00,
0xF1, 0xE2, 0x04, 0x00, 0x00, 0x00,
0xF2,
0xF1, 0xE4, 0x03, 0x00, 0x00, 0x00,
# s[3] = s[3] ^ s[4]
0xF1, 0xE1, 0x04, 0x00, 0x00, 0x00,
0xF1, 0xE2, 0x05, 0x00, 0x00, 0x00,
0xF2,
0xF1, 0xE4, 0x04, 0x00, 0x00, 0x00,
# s[4] = s[4] ^ s[5]
0xF1, 0xE1, 0x05, 0x00, 0x00, 0x00,
0xF1, 0xE2, 0x06, 0x00, 0x00, 0x00,
0xF2,
0xF1, 0xE4, 0x05, 0x00, 0x00, 0x00,
# s[5] = s[5] ^ s[6]
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,
# s[6] = (2* s[7] + s[8] + 3* s[6]) * s[12]
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,
# s[7] = (2* s[8] + s[9] + 3* s[7]) * s[12]
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,
# s[8] = (2* s[9] + s[10] + 3* s[8]) * s[12]
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,
# s[0x13],s[0xd] = s[0xd],s[0x13]
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,
# s[0xe],s[0x12] = s[0x12],s[0xe]
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,
# s[0xf],s[0x11] = s[0x11],s[0xf]
0xF4
]

思路:

前六位 xor 求解

z3 解出 6, 7 , 8,

后面 六位进行交换

这里偷懒,没写脚本, 直接抄的 wp 里的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
enc = [0x69, 0x45, 0x2a, 0x37, 0x9, 0x17, 0x6dc5, 0x5b0b, 0x705c, 0x72, 0x33, 0x76, 0x33, 0x21, 0x74, 0x31, 0x5f, 0x33, 0x73, 0x72]


#a=Int('a')
#b=Int('b')
#c=Int('c')
#solve((3*a+2*b+c)*0x33==0x6dc5,(3*b+2*c+0x72)*0x33==0x5b0b,(3*c+2*0x72+0x33)*0x33==0x705c)
#[c = 95, b = 51, a = 118]
flag = enc

flag[6] = 118
flag[7] = 51
flag[8] = 95

for i in range(6):
flag[6-i-1] ^= flag[6-i]

def exchange(i,j):
temp = flag[i]
flag[i] = flag[j]
flag[j] = temp

exchange(13,19)
exchange(14,18)
exchange(15,17)

string = ""
for i in flag:
string += chr(i)
print(string)

getflag!!!

Y0u_hav3_r3v3rs3_1t!

总结

第一次独立 做出 vm , 从 中午10点多, 一直到下午 6 点才结束, 可以看出,我是真的很菜, 我会慢慢赶上来的,真的。

开始享受, 程序 从黑盒变成白盒的感觉, 希望自己能够坚持下去吧。

2021.4.25


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!