DASCTF 2022.07 E4sy_Mix 复现

前言

这个题说难似乎也不是很难,但就是十分的麻烦,将虚拟机VMXTEA魔改进行了结合,同时写对应脚本也比较费时间…总感觉这个题出出来是用来拖Re的解题时间的(可能对于一些佬来说不是)

加密

我们将程序拖入到IDA中可以清晰地看到其加密逻辑,程序分别进行了三个阶段,将我们的输入进行处理 ——> XTEA加密 ——> VM

1.png

因此对于逆向而言我们需要的是先去解密对应的VM虚拟机部分,我们将so文件也拖入进IDA进行反编译

4.png

3.png

通过上面的分析我们将每一个func函数进行翻译转换写出对应的脚本:

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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
opcode = [0]*160
opcode[0] = 1
opcode[1] = 0
opcode[2] = 0
opcode[3] = 1
opcode[4] = 1
opcode[5] = 1
opcode[6] = 3
opcode[7] = 2
opcode[8] = 0
opcode[9] = 3
opcode[10] = 3
opcode[11] = 0
opcode[12] = 3
opcode[13] = 4
opcode[14] = 0
opcode[15] = 1
opcode[16] = 5
opcode[17] = 2
opcode[18] = 1
opcode[19] = 6
opcode[20] = 30
opcode[21] = 12
opcode[22] = 3
opcode[23] = 5
opcode[24] = 13
opcode[25] = 4
opcode[26] = 6
opcode[27] = 8
opcode[28] = 3
opcode[29] = 4
opcode[30] = 4
opcode[31] = 2
opcode[32] = 3
opcode[33] = 3
opcode[34] = 3
opcode[35] = 0
opcode[36] = 3
opcode[37] = 4
opcode[38] = 0
opcode[39] = 1
opcode[40] = 5
opcode[41] = 10
opcode[42] = 1
opcode[43] = 6
opcode[44] = 22
opcode[45] = 12
opcode[46] = 3
opcode[47] = 5
opcode[48] = 13
opcode[49] = 4
opcode[50] = 6
opcode[51] = 8
opcode[52] = 3
opcode[53] = 4
opcode[54] = 4
opcode[55] = 2
opcode[56] = 3
opcode[57] = 3
opcode[58] = 3
opcode[59] = 0
opcode[60] = 3
opcode[61] = 4
opcode[62] = 0
opcode[63] = 1
opcode[64] = 5
opcode[65] = 18
opcode[66] = 1
opcode[67] = 6
opcode[68] = 14
opcode[69] = 12
opcode[70] = 3
opcode[71] = 5
opcode[72] = 13
opcode[73] = 4
opcode[74] = 6
opcode[75] = 8
opcode[76] = 3
opcode[77] = 4
opcode[78] = 4
opcode[79] = 2
opcode[80] = 3
opcode[81] = 3
opcode[82] = 3
opcode[83] = 0
opcode[84] = 3
opcode[85] = 4
opcode[86] = 0
opcode[87] = 1
opcode[88] = 5
opcode[89] = 24
opcode[90] = 1
opcode[91] = 6
opcode[92] = 8
opcode[93] = 12
opcode[94] = 3
opcode[95] = 5
opcode[96] = 13
opcode[97] = 4
opcode[98] = 6
opcode[99] = 8
opcode[100] = 3
opcode[101] = 4
opcode[102] = 4
opcode[103] = 2
opcode[104] = 3
opcode[105] = 2
opcode[106] = 0
opcode[107] = 2
opcode[108] = 5
opcode[109] = 0
opcode[110] = 1
opcode[111] = 1
opcode[112] = 3
opcode[113] = 8
opcode[114] = 9
opcode[115] = 0
opcode[116] = 3
opcode[117] = 11
opcode[118] = 3
opcode[119] = 0
opcode[120] = 1
opcode[121] = 0
opcode[122] = 0
opcode[123] = 1
opcode[124] = 1
opcode[125] = 1
opcode[126] = 1
opcode[127] = 2
opcode[128] = 50
opcode[129] = 3
opcode[130] = 3
opcode[131] = 0
opcode[132] = 3
opcode[133] = 4
opcode[134] = 2
opcode[135] = 9
opcode[136] = 3
opcode[137] = 4
opcode[138] = 11
opcode[139] = 159
opcode[140] = 0
opcode[141] = 5
opcode[142] = 0
opcode[143] = 1
opcode[144] = 5
opcode[145] = 2
opcode[146] = 1
opcode[147] = 1
opcode[148] = 3
opcode[149] = 8
opcode[150] = 9
opcode[151] = 0
opcode[152] = 3
opcode[153] = 11
opcode[154] = 126
opcode[155] = 0
opcode[156] = 0xE
opcode[157] = 0
opcode[158] = 0
opcode[159] = 0

for i in range(0,len(opcode),3):
if opcode[i] == 1:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] = {opcode[i+2]};")
if opcode[i] == 2:
print("label_%d:" %(i))
print(f"des[des[{opcode[i+1]}] + 10] = des[{opcode[i+2]}];")
if opcode[i] == 3:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] = des[des[{opcode[i+2]}]+10];")
if opcode[i] == 4:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] ^= des[{opcode[i+2]}];")
if opcode[i] == 5:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] += des[{opcode[i+2]}];")
if opcode[i] == 6:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] = des[{opcode[i+1]}] - des[{opcode[i+2]}];")
if opcode[i] == 7:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] &= des[{opcode[i+2]}];")
if opcode[i] == 8:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] |= des[{opcode[i+2]}];")
if opcode[i] == 9:
print("label_%d:" %(i))
print(f"d = des[{opcode[i+1]}] == des[{opcode[i+2]}];")
if opcode[i] == 10:
print("label_%d:" %(i))
print(f"if(d == 1) goto label_{opcode[i+1]};")
if opcode[i] == 11:
print("label_%d:" %(i))
print(f"if(d == 0) goto label_{opcode[i+1]};")
if opcode[i] == 12:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] <<= des[{opcode[i+2]}] & 0x1f;")
if opcode[i] == 13:
print("label_%d:" %(i))
print(f"des[{opcode[i+1]}] >>= des[{opcode[i+2]}] & 0x1f;")
if opcode[i] == 14:
print("label_%d:" %(i))
print('printf("success");')
if opcode[i] == 0:
print("label_%d:" %(i))
print('printf("wrong");')

我们通过添加label_X:可以让我们转换出来的代码交给VS等编译器进行编译,进而方便我们观察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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// easy_mix.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <cstring>
using namespace std;
int main()
{
bool d;
unsigned int des[100] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x556B4A7A, 0xD043F107, 0x3DD67E0E, 0xB065623F, 0x32870017, 0xACDA02A2,
0xD185BCEE, 0x015DA6EF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x215432AD, 0xC0848707, 0xD35AEA02, 0xB6707A11,
0xAD521CB0, 0x40DFFB26, 0xC59D8EE9, 0x7FF69654, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000
};
label_0:
des[0] = 0;
label_3:
des[1] = 1;
label_6:
des[2] = des[0 + 10];
label_9:
des[3] = des[0 + 10];
label_12:
des[4] = des[0 + 10];
label_15:
des[5] = 2;
label_18:
des[6] = 30;
label_21:
des[3] <<= des[5] & 0x1f;
label_24:
des[4] >>= des[6] & 0x1f;
label_27:
des[3] |= des[4];
label_30:
des[2] ^= des[3];
label_33:
des[3] = des[0 + 10];
label_36:
des[4] = des[0 + 10];
label_39:
des[5] = 10;
label_42:
des[6] = 22;
label_45:
des[3] <<= des[5] & 0x1f;
label_48:
des[4] >>= des[6] & 0x1f;
label_51:
des[3] |= des[4];
label_54:
des[2] ^= des[3];
label_57:
des[3] = des[0 + 10];
label_60:
des[4] = des[0 + 10];
label_63:
des[5] = 18;
label_66:
des[6] = 14;
label_69:
des[3] <<= des[5] & 0x1f;
label_72:
des[4] >>= des[6] & 0x1f;
label_75:
des[3] |= des[4];
label_78:
des[2] ^= des[3];
label_81:
des[3] = des[0 + 10];
label_84:
des[4] = des[0 + 10];
label_87:
des[5] = 24;
label_90:
des[6] = 8;
label_93:
des[3] <<= des[5] & 0x1f;
label_96:
des[4] >>= des[6] & 0x1f;
label_99:
des[3] |= des[4];
label_102:
des[2] ^= des[3];
label_105:
des[des[0] + 10] = des[2];
label_108:
des[0] += des[1];
label_111:
des[3] = 8;
label_114:
d = des[0] == des[3];
label_117:
if (d == 0) goto label_3;
label_120 :
des[0] = 0;
label_123:
des[1] = 1;
label_126:
des[2] = 50;
label_129:
des[3] = des[0 + 10];
label_132:
des[4] = des[2 + 10];
label_135:
d = des[3] == des[4];
label_138:
if (d == 0) goto label_159;
label_141 :
des[0] += des[1];
label_144:
des[2] += des[1];
label_147:
des[3] = 8;
label_150:
d = des[0] == des[3];
label_153:
if (d == 0) goto label_126;
label_156:
printf("Success!");
label_159:
printf("Wrong!");
}

进行转换后我们可以写出对应的加密过程,可以看到是一个SM4加密的一部分,用其来进行判断我们XTEA加密后的数据,对此我们可以利用z3进行约束求解:

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
from z3 import *
s = Solver()
des = [BitVec(f'des[{i}]',64) for i in range(8)]
enc = [0]*8
enc[0] = 0x215432AD
enc[1] = 0xC0848707
enc[2] = 0xD35AEA02
enc[3] = 0xB6707A11
enc[4] = 0xAD521CB0
enc[5] = 0x40DFFB26
enc[6] = 0xC59D8EE9
enc[7] = 0x7FF69654

for i in range(8):
x = des[i]
des[i] ^= (x << 2) & 0xffffffff | (x >> 30)
des[i] ^= (x << 10) & 0xffffffff | (x >> 22)
des[i] ^= (x << 18) & 0xffffffff | (x >> 14)
des[i] ^= (x << 24) & 0xffffffff | (x >> 8)
s.add(des[i] == enc[i])

if s.check() == sat:
model = s.model()
res = []
for j in range(len(model)):
for decls in model:
if decls.name() == ('des[%d]' % j):
res.append(int('%s' % model[decls]))
for i in range(8):
print(hex(res[i]),end=',')
else:
print("NO")

解密完成后我们便可以得到XTEA加密后的数据部分:

1
0x1cd14c3b,0x8ae1267c,0x91edd1f5,0xbf9c950,0xe060adf9,0xf88722cd,0x3b741595,0x54bb88b5

接下来我们观察对应的XTEA加密部分,可以看出程序魔改了对应的delta,我们也不难写出对应的解密脚本

2.png

最后我们将XTEA于字符串转换解密可以写出如下脚本:

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
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <iostream>
using namespace std;

#define uint32_t unsigned int

void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x21524B01, sum = 0 - delta * num_rounds;
for (i = 0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
sum += delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0;
v[1] = v1;
}
int main() {
uint32_t key[] = {0x21728857, 0xb5077292, 0xe737dc2b, 0x4cc17426};
uint32_t enc[] = {0x1cd14c3b,0x8ae1267c,0x91edd1f5,0xbf9c950,0xe060adf9,0xf88722cd,0x3b741595,0x54bb88b5,0};
decipher(32,enc,key);
decipher(32,enc+2,key);
decipher(32,enc+4,key);
decipher(32,enc+6,key);
for(int i =0;i<32;i++){
((unsigned char*)enc)[i] = (((unsigned char*)enc)[i] << 4) & 0xff | (((unsigned char *)enc)[i] >> 4) & 0xff;
}
cout<<(unsigned char*)enc<<endl;
}
//9592937429baca2948ffdb1442e39eb6
//DASCTF{9592937429baca2948ffdb1442e39eb6}

因此我们可以得到flag

1
DASCTF{9592937429baca2948ffdb1442e39eb6}

DASCTF 2022.07 E4sy_Mix 复现
https://equinox-shame.github.io/2022/07/29/DASCTF 2022.07 E4sy_Mix 复现/
作者
梓曰
发布于
2022年7月29日
许可协议