VM 专场

之前一直遇到vm的题都没怎么去管,现在来学习学习。

总结一下,做vm的题主要要知道,那些是伪寄存器,那些是伪堆栈,一般都是以全局变量存在,哪些是vm函数,分别有什么功能,怎么调用的伪寄存器。而且vm的加密过程应该都不会弄太过于复杂的。

EzMachine

来自buu的一道经典vm。在看了SYJ师傅的文章后,豁然开朗。
分析主函数

看看程序中自己写的vm_function,和伪寄存器。

先还原程序流程

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

code=[0x01, 0x03, 0x03, 0x05, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x01, 0x11, 0x0C, 0x00, 0x01, 0x0D, 0x0A, 0x00, 0x01, 0x03, 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01, 0x00, 0x11, 0x0C, 0x00, 0x02, 0x0D, 0x2B, 0x00, 0x14, 0x00, 0x02, 0x01, 0x01, 0x61, 0x0C, 0x00, 0x01, 0x10, 0x1A, 0x00, 0x01, 0x01, 0x7A, 0x0C, 0x00, 0x01, 0x0F, 0x1A, 0x00, 0x01, 0x01, 0x47, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x00, 0x01, 0x0B, 0x24, 0x00, 0x01, 0x01, 0x41, 0x0C, 0x00, 0x01, 0x10, 0x24, 0x00, 0x01, 0x01, 0x5A, 0x0C, 0x00, 0x01, 0x0F, 0x24, 0x00, 0x01, 0x01, 0x4B, 0x0A, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x00, 0x01, 0x01, 0x01, 0x10, 0x09, 0x00, 0x01, 0x03, 0x01, 0x00, 0x03, 0x00, 0x00, 0x01, 0x01, 0x01, 0x06, 0x02, 0x01, 0x0B, 0x0B, 0x00, 0x02, 0x07, 0x00, 0x02, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x02, 0x05, 0x00, 0x02, 0x01, 0x00, 0x02, 0x0C, 0x00, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x0D, 0x00, 0x02, 0x05, 0x00, 0x02, 0x0F, 0x00, 0x02, 0x00, 0x00, 0x02, 0x09, 0x00, 0x02, 0x05, 0x00, 0x02, 0x0F, 0x00, 0x02, 0x03, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x05, 0x00, 0x02, 0x03, 0x00, 0x02, 0x03, 0x00, 0x02, 0x01, 0x00, 0x02, 0x07, 0x00, 0x02, 0x07, 0x00, 0x02, 0x0B, 0x00, 0x02, 0x02, 0x00, 0x02, 0x01, 0x00, 0x02, 0x02, 0x00, 0x02, 0x07, 0x00, 0x02, 0x02, 0x00, 0x02, 0x0C, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02, 0x01, 0x13, 0x01, 0x02, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x0E, 0x5B, 0x00, 0x01, 0x01, 0x22, 0x0C, 0x02, 0x01, 0x0D, 0x59, 0x00, 0x01, 0x01, 0x01, 0x06, 0x02, 0x01, 0x0B, 0x4E, 0x00, 0x01, 0x03, 0x00, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, 0x03, 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00]
reg_table={
0:'eax',
1:'ebx',
2:'ecx',
3:'edx',
}

instructions={
0: 'nop',
1: 'mov reg data',
2: 'push data',
3: 'push_reg',
4: 'pop_reg',
5: 'printf',
6: 'add_reg_reg1',
7: 'sub_reg_reg1',
8: 'mul',
9: 'div',
10: 'xor',
11: 'jmp',
12: 'cmp',
13: 'je',
14: 'jne',
15: 'jg',
16: 'jl',
17: 'strlen',
18: 'mem_init',
19: 'pop_reg1_to_reg',
20: 'load_input',
0xff: 'exit'}
for i in range(93):
if(instructions[code[i*3]]=='mov reg data'):
print(str(i+1)+':mov '+reg_table[code[i*3+1]]+' '+str(code[i*3+2]))
elif(instructions[code[i * 3]] == 'cmp'):
print(str(i + 1) + ':cmp ' + reg_table[code[i * 3 + 1]] + ' ' + reg_table[code[i * 3 + 2]])
elif(instructions[code[i * 3]] == 'add_reg_reg1'):
print(str(i + 1) + ':add ' + reg_table[code[i * 3 + 1]] + ' ' + reg_table[code[i * 3 + 2]])
elif (instructions[code[i * 3]] == 'sub_reg_reg1'):
print(str(i + 1) + ':sub ' + reg_table[code[i * 3 + 1]] + ' ' + reg_table[code[i * 3 + 2]])
elif(instructions[code[i * 3]] == 'push_reg'):
print(str(i + 1) + ':push '+ reg_table[code[i * 3 + 1]])
elif (instructions[code[i * 3]] == 'pop_reg'):
print(str(i + 1) + ':pop ' + reg_table[code[i * 3 + 1]])
else:
print(str(i+1)+':'+instructions[code[i*3]]+' '+str(code[i*3+1])+' '+str(code[i*3+2]))

再处理一下得到

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

1:mov edx 3
2:printf 0 0
3:strlen 0 0
4:mov ebx 17
5:cmp eax ebx
6:je 10 0
7:mov edx 1
8:printf 0 0
9:exit 0 0
10:mov ecx 0
11:mov eax 17
12:cmp eax ecx
13:je 43 0
14:load_input 0 2
15:mov ebx 97
16:cmp eax ebx
17:jl 26 0
18:mov ebx 122
19:cmp eax ebx
20:jg 26 0
21:mov ebx 71
22:xor 0 1
23:mov ebx 1
24:add eax ebx
25:jmp 36 0
26:mov ebx 65
27:cmp eax ebx
28:jl 36 0
29:mov ebx 90
30:cmp eax ebx
31:jg 36 0
32:mov ebx 75
33:xor 0 1
34:mov ebx 1
35:sub eax ebx
36:mov ebx 16
37:div 0 1
38push ebx
39push eax
40:mov ebx 1
41:add ecx ebx
42:jmp 11 0
43:push data 7 0
44:push data 13 0
45:push data 0 0
46:push data 5 0
47:push data 1 0
48:push data 12 0
49:push data 1 0
50:push data 0 0
51:push data 0 0
52:push data 13 0
53:push data 5 0
54:push data 15 0
55:push data 0 0
56:push data 9 0
57:push data 5 0
58:push data 15 0
59:push data 3 0
60:push data 0 0
61:push data 2 0
62:push data 5 0
63:push data 3 0
64:push data 3 0
65:push data 1 0
66:push data 7 0
67:push data 7 0
68:push data 11 0
69:push data 2 0
70:push data 1 0
71:push data 2 0
72:push data 7 0
73:push data 2 0
74:push data 12 0
75:push data 2 0
76:push data 2 0
77:mov ecx 1
78:stack_to_reg ebx ecx
79:pop eax
80:cmp eax ebx
81:jne 91 0
82:mov ebx 34
83:cmp ecx ebx
84:je 89 0
85:mov ebx 1
86:add ecx ebx
87:jmp 78 0
88:mov edx 0
89:printf 0 0
90:exit 0 0
91:mov edx 1
92:printf 0 0
93:exit 0 0

撸一下汇编,翻译如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

code=[0x7,0xd,0x0,0x5,0x1,0xc,0x1,0x0,0x0,0xd,0x5,0xf,0x0,0x9,0x5,0xf,0x3,0x0,0x2,0x5,0x3,0x3,0x1,0x7,0x7,0xb,0x2,0x1,0x2,0x7,0x2,0xc,0x2,0x2]
code1=[]
input=[0*17]

for i in input:
tmp1=i
tmp2=i
if(65<=i<=90):
i=i^75+1
if(97<=i<=122):
i=i^71-1
tmp1=tmp1%16
code1.append(tmp1)#先push余数
tmp2=tmp2//16
code1.append(tmp2)#后push商

if(code[::-1]==code1):
print('yes')

写出脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

flag=''
code=[0x7,0xd,0x0,0x5,0x1,0xc,0x1,0x0,0x0,0xd,0x5,0xf,0x0,0x9,0x5,0xf,0x3,0x0,0x2,0x5,0x3,0x3,0x1,0x7,0x7,0xb,0x2,0x1,0x2,0x7,0x2,0xc,0x2,0x2]
for i in range(0,34,2):
tmp=code[i]*16+code[i+1]
if(97<=((tmp-1)^71)<=122):
flag+=chr((tmp-1)^71)
continue
if(65<=((tmp+1)^75)<=90):
flag+=chr((tmp+1)^75)
continue
else:
flag+=chr(tmp)
tmp=0
print(flag[::-1])
#flag{Such_A_EZVM}

VM

hagame2021 week4的vm

这道题给我感觉说是vm,但是感觉不完全是,是了但不完全是,哈哈哈。

这个主要是switch-case语句来进行的加密,解法感觉就是动调得到加密规律吧,耐心慢慢的调,找到规律后就可以下断点F9了。

大概分析一下吧,先是main函数,里面的gets函数可以看出长度<=34

然后就是那个加密函数了,就是通过switch-case一直处理程序自己生成好的opcode,先浏览一遍输入的数据(循环了很多轮),然后对这个输入的字符串字符串倒序加密,先异或一轮然后,减一轮。

5个地址代表的含义

然后就是下断点看加密了。

脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

//hgame{abcdefgghijklmnopqrstuvwxyz}

#include<stdio.h>
int main()
{
char code[]={ 0xCF, 0xBF, 0x80, 0x3B, 0xF6, 0xAF, 0x7E, 0x02, 0x24, 0xED,
0x70, 0x3A, 0xF4, 0xEB, 0x7A, 0x4A, 0xE7, 0xF7, 0xA2, 0x67,
0x17, 0xF0, 0xC6, 0x76, 0x36, 0xE8, 0xAD, 0x82, 0x2E, 0xDB,
0xB7, 0x4F, 0xE6, 0x09};
int i,j;
char xor_num[]={0xfe,0x21,0x44,0x67,0x8a,0xad,0xd0,0xf3,0x16,0x39,0x5c,0x7f,0xa3,0xc5,0xe8,0x0b,0x2e,0x51,0x74,0x97,0xba,0xdd,0x0,0x23,0x46,0x69,0x8c,0xaf,0xd2,0xf5,0x18,0x3b,0x5e,0x81};
char sub[] = { 0x7A,0x1A,0xBA,0x5A,0xFA,0x9A,0x3A,0xDA,0x7A,0x1A,0xBA,0x5A,0xFB,0x9A,0x3A,0xDA,0x7A,0x1A,0xBA,0x5A,0xFA,0x9A,0x3A,0xDA,0x7A,0x1A,0xBA,0x5A,0xFA,0x9A,0x3A,0xDA,0x7A,0x1A };

for(i=0,j=33;i<34;i++,j--)
{
printf("%c",(code[i]+sub[j])^xor_num[j]);
}
}
//hgame{w0W!itS_CpP_wItH_little_vM!}

[GWCTF 2019]babyvm

一道比较正宗的vm,还设置了错误解。还是慢慢分析。

对每一个函数分析之后就可以写脚本来还原程序流程了

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

code=[ 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]
reg_table={
0xe1:'eax',
0xe2:'ebx',
0xe3:'ecx',
0xe5:'edx',
}

instructions={
0xF1: 'mov',
0xF2: 'xor',
0xF4: 'nop',
0xF5:'read_strlen',
0xF6: 'jishuan',
0xF7: 'mul',
0xF8: 'swap'}
i=0
for j in range(len(code)):
if(code[i]==0xF1):
print('mov ',end='')
if (code[i+1] == 0xe1):
print('eax ' + 'flag[' + str(code[i + 2]) + ']')
elif(code[i+1]==0xe2):
print('ebx ' + 'flag[' + str(code[i + 2]) + ']')
elif (code[i + 1] == 0xe3):
print('ecx ' + 'flag[' + str(code[i + 2]) + ']')
elif (code[i + 1] == 0xe4):
print('flag[' + str(code[i + 2]) + '] ' + 'eax')
elif(code[i+1]==0xe5):
print('edx ' + 'flag[' + str(code[i + 2]) + ']')
elif (code[i + 1] == 0xe7):
print('flag[' + str(code[i + 2]) + '] ' + 'ebx')
i+=6
elif(code[i]==0xF2):
print('xor eax ebx')
i+=1
elif (code[i] == 0xF4):
print('nop')
i += 1
elif (code[i] == 0xF5):
print('read_strlen')
i += 1
elif (code[i] == 0xF6):
print('jishuan eax=ecx + 2*ebx + 3*eax')
i += 1
elif (code[i] == 0xF7):
print('mul eax edx')
i += 1
elif (code[i] == 0xF8):
print('swap eax ebx')
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
126
127
128

//第一部分是假的,就是flag[i]^18
read_strlen
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
//下面才是真的
read_strlen
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]
jishuan eax=ecx + 2*ebx + 3*eax
mul eax edx
mov flag[6] eax
mov eax flag[7]
mov ebx flag[8]
mov ecx flag[9]
mov edx flag[12]
jishuan eax=ecx + 2*ebx + 3*eax
mul eax edx
mov flag[7] eax
mov eax flag[8]
mov ebx flag[9]
mov ecx flag[10]
mov edx flag[12]
jishuan eax=ecx + 2*ebx + 3*eax
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

然后分析后,大概加密过程就是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

int main()
{
char flag[20];
char code[]={ 0x69, 0x45, 0x2A, 0x37, 0x09, 0x17, 0xC5, 0x0B, 0x5C, 0x72,
0x33, 0x76, 0x33, 0x21, 0x74, 0x31, 0x5F, 0x33, 0x73, 0x72, };
int i ;
for(i=0;i<6;i++)
{
flag[i]=flag[i]^flag[i+1];
}

flag[6]=(flag[8] + 2*flag[7] + 3*flag[6]) * flag[12];
flag[7]=(flag[9] + 2*flag[8] + 3*flag[7]) * flag[12];
flag[8]=(flag[10] + 2*flag[9] + 3*flag[8]) * flag[12];

swap(flag[13] ,flag[19]);
swap(flag[14] ,flag[18]);
swap(flag[15] ,flag[17]);
}

写出解密脚本,需要说一下的是,官方wp的code[6],code[7],code[8]是和题目给的不一样的,所以如果没有其他hint的话,应该是爆破来解,因为那个计算函数会导致溢出,但是题目中的这3个数只有一个字节,我们也就爆破这一个字节就行。

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

# s='Fz{aM{aM|}fMt~suM !!'
# for i in s:
# tmp=ord(i)^18
# print(chr(tmp),end='')
#fake_flag:This_is_not_flag_233

# from z3 import *
#
# s = Solver()
# a, b, c = Reals('a b c')
# s.add((c+2*b+3*a)*0x33==0x6dc5)
# s.add((0x72+2*c+3*b)*0x33==0x5b0b)
# s.add((0x33+2*0x72+3*c)*0x33==0x705c)
#
#
# if s.check() == sat:
# m = s.model()
# print(m)
# exit()
# else:
# print("no_sat")

code=[0x69, 0x45, 0x2A, 0x37, 0x09, 0x17, 0xC5, 0x0B, 0x5C, 0x72,
0x33, 0x76, 0x33, 0x21, 0x74, 0x31, 0x5F, 0x33, 0x73, 0x72]
flag=code
for a in range(32,128):
for b in range(32,128):
for c in range(32,120):
m=((c+2*b+3*a)*0x33)&0xff
n=((0x72+2*c+3*b)*0x33)&0xff
q=((0x33+2*0x72+3*c)*0x33)&0xff
if(m==0xc5 and n==0x0B and q==0x5c):
print(a,b,c)
flag[6]=a
flag[7]=b
flag[8]=c
for i in range(5,-1,-1):
flag[i]=flag[i]^flag[i+1]
flag[13],flag[19]=flag[19],flag[13]
flag[14], flag[18]=flag[18],flag[14]
flag[15], flag[17]=flag[17],flag[15]
for i in flag:
print(chr(i),end='')
#Y0u_hav3_r3v3rs3_1t!