网鼎杯 2020 青龙组 singal

[网鼎杯 2020 青龙组]singal

一道简单的vm逆向

打开main函数

image-20220810234443081

从unk_403040里面读取数据到v4,再将v4输入到vm_operad里面,也就是虚拟机

分析这个虚拟机可得知,v4是操作码,将v4处理后得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int opcode[] = {10, 4, 16, 8, 3, 5, 1, 4,
32, 8, 5, 3, 1, 3, 2, 8,
11, 1, 12, 8, 4, 4, 1, 5,
3, 8, 3, 33, 1, 11, 8, 11,
1, 4, 9, 8, 3, 32, 1, 2,
81, 8, 4, 36, 1, 12, 8, 11,
1, 5, 2, 8, 2, 37, 1, 2, 54,
8, 4, 65, 1, 2, 32, 8, 5, 1,
1, 5, 3, 8, 2, 37, 1, 4,
9, 8, 3, 32, 1, 2, 65, 8,
12, 1,
7, 34, 7, 63, 7, 52, 7, 50,
7, 114, 7, 51, 7, 24, 7, 167,255, 255, 255,
7, 49, 7, 241,255, 255, 255, 7, 40, 7, 132, 255, 255, 255,
7, 193, 255, 255, 255, 7, 30, 7, 12 }

然后进一步分析handler

image-20220810235333597

操作码7是程序的对比判断,7后面接的数字是操作数,因为index+=2

因此得出加密后的flag就是7后面的操作数

1
int flag[] = {34, 63, 52, 50, 114, 51, 24, 167, 49, 241, 40, 132, 193, 30, 122};

于是就可以进行编写脚本了,注意区分操作数和操作码

当然也可以先正向跑一遍来获取整个操作的顺序,因为这道题的操作码执行顺序与输入无关

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
#include<iostream>

using namespace std;

int main()
{
int opcode[] = {10, 4, 16, 8, 3, 5, 1, 4,
32, 8, 5, 3, 1, 3, 2, 8,
11, 1, 12, 8, 4, 4, 1, 5,
3, 8, 3, 33, 1, 11, 8, 11,
1, 4, 9, 8, 3, 32, 1, 2,
81, 8, 4, 36, 1, 12, 8, 11,
1, 5, 2, 8, 2, 37, 1, 2, 54,
8, 4, 65, 1, 2, 32, 8, 5, 1,
1, 5, 3, 8, 2, 37, 1, 4,
9, 8, 3, 32, 1, 2, 65, 8,
12, 1,
7, 34, 7, 63, 7, 52, 7, 50,
7, 114, 7, 51, 7, 24, 7, 167,255, 255, 255,
7, 49, 7, 241,255, 255, 255, 7, 40, 7, 132, 255, 255, 255,
7, 193, 255, 255, 255, 7, 30, 7, 12 };

char order[100] = {1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 81, 82, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114};
unsigned char v4[] = {34, 63, 52, 50, 114, 51, 24, 167, 49, 241, 40, 132, 193, 30, 122};
unsigned char flag[100] = {}; // [esp+13h] [ebp-E5h]
int v5; // [esp+DBh] [ebp-1Dh]
int m; // [esp+DCh] [ebp-1Ch]
int z; // [esp+E0h] [ebp-18h]
int x; // [esp+E8h] [ebp-10h]
int i; // [esp+ECh] [ebp-Ch]
x = 15;
z = 15;
m = 15;
for(int k=strlen(order) - 1;k>=0;k--)//从后往前
{
i = order[k];
switch ( opcode[i] )
{
case 1:
--x;
--z;
v5 = v4[z];
break;
case 2:
flag[x] = v5 - opcode[i + 1];
break;
case 3:
flag[x] = v5 + opcode[i + 1];
break;
case 4:
flag[x] = v5 ^ opcode[i + 1];
break;
case 5:
flag[x] = v5 / opcode[i + 1];
break;
case 6:
break;
case 8:
v5 = flag[--m];
break;
case 11:
flag[x] = v5 + 1;
break;
case 12:
flag[x] = v5 - 1;
break;
}
}
printf("%s",flag);
return 0;
}

1
flag{757515121f3d478}