baby_vm

学习一下简单vm题目的解法和一般原理,这是一个困扰我很久的问题

angr尝试

 题目就是baby_vm,一个简单的虚拟机,看到main函数逻辑简单,直接先用angr跑一下

跑出来一个假的flag,这里我猜测的原因应该是angr因为并没有真正的去运行程序,而是对程序的模拟,所以会陷入这个题目准备好的路径中,导致出现假的flag。

静态分析

 ida分析一波

image-20220314181702471

第一个函数

image-20220314181750305

 这里就是虚拟机的精髓了,所谓的vm实质上是用高级的编程语言,比如C,C++等语言,去模拟汇编语言的形式,比如这里:

1
2
3
4
*a1 = 0;                                      // r1
*(a1 + 4) = 0x12; // r2
*(a1 + 8) = 0; // r3
*(a1 + 12) = 0;

 这里首先是设置了四个相当于寄存器的东西,每一个都是4字节,然后地址相邻。

(a1+16)里存放着操作码数组的地址,什么是操作码,就是这个程序会根据这个数组里的数字来判断执行什么程序。

 接下来就是几个函数,一般情况下,这里对应这模拟的不同的汇编指令:

sub_b5f

image-20220314191025430

 是一个switch结构,前面知道了a1就是第一个寄存器,这里看到是一些赋值语句,所以可以判断出,这个函数模拟的是mov指令的功能,是实现一个寄存器和内存之间的通信。

sub_a64

image-20220314191221330

 两个寄存器进行异或,这里模仿的是xor指令。

sub_a45

image-20220314191317512

 这里是获取一段输入,然后将操作码往后移。

sub_956

image-20220314191423199

 这里就是一个操作码向后移,没有什么实际作用,可以理解为nop

sub_a08

image-20220314191537839

 实现了两个寄存器之间进行乘法的运算,相当于是mul r1, r4

sub_8f0

image-20220314191629043

 实现了两个寄存之间的交换,相当于是swap

sub_99c

image-20220314191719405

 实现了一个简单的运算操作,应该是用来加密flag的

第二个函数

image-20220314191803942

 判单操作码是不是0xf4, 如果不是执行sub_e6e函数

sub_e6e

image-20220314191902094

 一个循环,就是对操作码进行的一个判断,判断的右值就是几个特定的数值

  • a1+24
  • a1+40
  • a1+56
  • a1+72
  • a1+88
  • a1+104
  • a1+120

 看到第一个函数,可以发现这些数值对应这几个特定的数字。这里实现的功能就是:确定一个i值,然后下面通过这个i的值来确定执行什么函数。看到下面的函数引用其实都是a1+16的整数倍,正好可以对应第一个函数进行判断。

第三个函数

image-20220314192719520

一个判断函数,但是这里的祝贺语后面有问好,估计是个假的,先不管。

清晰程序流程

 用脚本将字节码模拟的汇编操作打印出来,方便分析。

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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]

i = 0
for i 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 ebx')
i += 1
elif opcode[i] == 0xF5:
print('get_input')
i += 1
elif opcode[i] == 0xF4:
print('nop')
i += 1
elif opcode[i] == 0xF7:
print('mul eax edx')
i += 1
elif opcode[i] == 0xF8:
print('swap eax ebx')
i += 1
elif opcode[i] == 0xF6:
print('mov eax=3*eax+2*ebx+ecx')
i += 1
else:
i += 1

得到给出的汇编

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
get_input
mov eax flag[0]
xor eax ebx
mov flag[32] eax
mov eax flag[1]
xor eax ebx
mov flag[33] eax
mov eax flag[2]
xor eax ebx
mov flag[34] eax
mov eax flag[3]
xor eax ebx
mov flag[35] eax
mov eax flag[4]
xor eax ebx
mov flag[36] eax
mov eax flag[5]
xor eax ebx
mov flag[37] eax
mov eax flag[6]
xor eax ebx
mov flag[38] eax
mov eax flag[7]
xor eax ebx
mov flag[39] eax
mov eax flag[8]
xor eax ebx
mov flag[40] eax
mov eax flag[9]
xor eax ebx
mov flag[41] eax
mov eax flag[10]
xor eax ebx
mov flag[42] eax
mov eax flag[11]
xor eax ebx
mov flag[43] eax
mov eax flag[12]
xor eax ebx
mov flag[44] eax
mov eax flag[13]
xor eax ebx
mov flag[45] eax
mov eax flag[14]
xor eax ebx
mov flag[46] eax
mov eax flag[15]
xor eax ebx
mov flag[47] eax
mov eax flag[16]
xor eax ebx
mov flag[48] eax
mov eax flag[17]
xor eax ebx
mov flag[49] eax
mov eax flag[18]
xor eax ebx
mov flag[50] eax
mov eax flag[19]
xor eax ebx
mov flag[51] eax
nop

get_input
mov eax flag[0]
mov ebx flag[1]
xor eax ebx
mov flag[0] eax
mov eax flag[1]
mov ebx flag[2]
xor eax ebx
mov flag[1] eax
mov eax flag[2]
mov ebx flag[3]
xor eax ebx
mov flag[2] eax
mov eax flag[3]
mov ebx flag[4]
xor eax ebx
mov flag[3] eax
mov eax flag[4]
mov ebx flag[5]
xor eax ebx
mov flag[4] eax
mov eax flag[5]
mov ebx flag[6]
xor eax ebx
mov flag[5] eax
mov eax flag[6]
mov ebx flag[7]
mov ecx flag[8]
mov edx flag[12]
mov eax=3*eax+2*ebx+ecx
mul eax edx
mov flag[6] eax
mov eax flag[7]
mov ebx flag[8]
mov ecx flag[9]
mov edx flag[12]
mov eax=3*eax+2*ebx+ecx
mul eax edx
mov flag[7] eax
mov eax flag[8]
mov ebx flag[9]
mov ecx flag[10]
mov edx flag[12]
mov eax=3*eax+2*ebx+ecx
mul eax edx
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
nop

不难发现,这里有两个get_input的汇编源码,看第一段,就是一些异或和异或,得到的答案就是angr跑出来的那个假的flag,分析下面的汇编:

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
get_input
mov eax flag[0]
mov ebx flag[1]
xor eax ebx
mov flag[0] eax

mov eax flag[1]
mov ebx flag[2]
xor eax ebx
mov flag[1] eax

mov eax flag[2]
mov ebx flag[3]
xor eax ebx
mov flag[2] eax

mov eax flag[3]
mov ebx flag[4]
xor eax ebx
mov flag[3] eax

mov eax flag[4]
mov ebx flag[5]
xor eax ebx
mov flag[4] eax

mov eax flag[5]
mov ebx flag[6]
xor eax ebx
mov flag[5] eax

mov eax flag[6]
mov ebx flag[7]
mov ecx flag[8]
mov edx flag[12]
mov eax=3*eax+2*ebx+ecx
mul eax edx
mov flag[6] eax

mov eax flag[7]
mov ebx flag[8]
mov ecx flag[9]
mov edx flag[12]
mov eax=3*eax+2*ebx+ecx
mul eax edx
mov flag[7] eax

mov eax flag[8]
mov ebx flag[9]
mov ecx flag[10]
mov edx flag[12]
mov eax=3*eax+2*ebx+ecx
mul eax edx
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

nop

前5位

进行一个和后一位的异或处理,突破口是flag[6]

678位

是一个运算和一个乘法,678位的数据需要进行暴力破一下,没有给出逆向思路。

最后几位

一些简单的交换

逆向脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
check[13], check[19] = check[19], check[13]
check[14], check[18] = check[18], check[14]
check[15], check[17] = check[17], check[15]

for i in range(128):
if check[8] == ((i*3 + check[9]*2 + check[10])*check[12])&0xff:
check[8] = i
for j in range(128):
if check[7] == ((j * 3 + check[8] * 2 + check[9]) * check[12]) & 0xff:
check[7] = j
for k in range(128):
if check[6] == ((k * 3 + check[7] * 2 + check[8]) * check[12]) & 0xff:
check[6] = k

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

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

 最后得到flag。