SCTF REVERSE CplusExceptionEncrypt 赛后复现

知识点

C++异常处理机制,如何 patch 代码使得 IDA 可以分析异常处理代码

C++ 异常处理机制

C++ 的异常处理机制非常灵活,相比于原来使用 SEH 等可以自定义异常类型等。不同编译器对 C++ 异常处理的编译结果不同。使用如下测试代码进行编译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
int main()
{
try {
int a;
std::cin >> a;
if(a == 0)
{
throw("a==0");
}
}
catch (const char* msg)
{
std::cout << msg<<"error";
}
}

MSVC x86

对于 MSVC x86编译器,会变成类似 windows SEH 进行处理:

使用_CxxThrowException函数抛出异常,之后在 SEH 异常处理器中捕获异常并转到异常处理代码中。而使用 IDA 进行反编译时,是无法正常分析出反编译结果的:

需要对汇编代码进行一些修改。将 0x401042 地址处的 call 指令修改为 jmp 到catch块内(0x401063),使得强制发生跳转,即可使得 IDA 进行分析:

MSVC x64

MSVC x64 的情况较为复杂,其进行了更为严重的封装,暂时没找到什么好办法。

Clang x64

clang x64 编译结果和 MSVC x86 相似,都是在代码中就可以看到 try 块内和 catch 块内的代码:

对其进行处理也和 MSVC x86 一样,将 0x4015E8 处的 call 语句改成 jmp 到 catch 块内(0x4015F2)即可使 IDA 正常识别:

赛题复现

打开该文件后,发现伪代码中有 C++ 抛出异常的代码,却看不到任何的加密代码,猜测其使用C++异常处理将加密过程隐藏了。于是查看汇编,发现明显的C++异常处理特征,按照上述方法对代码进行 patch 处理。

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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *exception; // rbx
void *v4; // rax
struct_of_step1 *v5; // rbx
void *v6; // rax
void **v7; // rdx
struct_of_step2 *v8; // rbx
struct_of_step3 *v9; // rbx
last_struct *v10; // rbx
void *v11; // rax
int v12; // eax
enc_next_ready_struct *v13; // rbx
void **v14; // rdx
enc_next_struct *v15; // rbx
void *v17; // rbx
void *exception_ptr; // rax
uint32_t v19; // ebx
uint32_t v20; // eax
uint32_t v21; // esi
uint32_t v22; // edi
uint32_t v23; // eax
uint32_t v24; // eax
uint32_t v25; // eax
uint32_t v26; // eax
uint32_t v27; // ebx
uint32_t v28; // eax
uint32_t v29; // esi
uint32_t v30; // edi
uint32_t v31; // eax
uint32_t v32; // eax
uint32_t v33; // eax
uint32_t v34; // eax
uint32_t v35; // ebx
uint32_t v36; // eax
uint32_t v37; // esi
uint32_t v38; // edi
uint32_t v39; // eax
uint32_t v40; // eax
uint32_t v41; // eax
uint32_t v42; // eax
uint32_t v43; // ebx
uint32_t v44; // eax
uint32_t v45; // esi
uint32_t v46; // edi
uint32_t v47; // eax
uint32_t v48; // eax
uint32_t v49; // eax
uint32_t v50; // eax
void *v51; // rbx
void *v52; // rax
uint8_t *v53; // rdx
std::__cxx11::string init; // [rsp+20h] [rbp-60h] BYREF
enc_next_struct_0 temp_4; // [rsp+D0h] [rbp+50h]
enc_next_ready_struct_0 temp_3; // [rsp+F0h] [rbp+70h]
uint8_t key[16]; // [rsp+110h] [rbp+90h] BYREF
uint8_t ciphertext[16]; // [rsp+120h] [rbp+A0h] BYREF
unsigned __int8 out1[16]; // [rsp+130h] [rbp+B0h] BYREF
uint32_t dst[4]; // [rsp+140h] [rbp+C0h] BYREF
uint32_t inp[4]; // [rsp+150h] [rbp+D0h] BYREF
uint8_t cmp_arr[32]; // [rsp+160h] [rbp+E0h] BYREF
unsigned __int8 encdata[32]; // [rsp+180h] [rbp+100h] BYREF
char data[32]; // [rsp+1A0h] [rbp+120h] BYREF
char v65; // [rsp+1C7h] [rbp+147h] BYREF
uint32_t k3_0; // [rsp+1C8h] [rbp+148h]
uint32_t k2_0; // [rsp+1CCh] [rbp+14Ch]
uint32_t k1_0; // [rsp+1D0h] [rbp+150h]
uint32_t k0_0; // [rsp+1D4h] [rbp+154h]
int length; // [rsp+1D8h] [rbp+158h]
int control1; // [rsp+1DCh] [rbp+15Ch]
int j_0; // [rsp+1E0h] [rbp+160h]
int i_1; // [rsp+1E4h] [rbp+164h]
int i_0; // [rsp+1E8h] [rbp+168h]
int x; // [rsp+1ECh] [rbp+16Ch]
int k; // [rsp+1F0h] [rbp+170h]
int j; // [rsp+1F4h] [rbp+174h]
int m; // [rsp+1F8h] [rbp+178h]
int cnt; // [rsp+1FCh] [rbp+17Ch]
int i; // [rsp+200h] [rbp+180h]
uint32_t sum2; // [rsp+204h] [rbp+184h]
uint32_t sum1; // [rsp+208h] [rbp+188h]
uint32_t v3; // [rsp+20Ch] [rbp+18Ch]
uint32_t v2; // [rsp+210h] [rbp+190h]
uint32_t v1; // [rsp+214h] [rbp+194h]
uint32_t v0; // [rsp+218h] [rbp+198h]
int w; // [rsp+21Ch] [rbp+19Ch]

_main(argc, argv, envp);
control1 = 0;
memset(data, 0, sizeof(data));
memset(encdata, 0, sizeof(encdata));
memset(cmp_arr, 0, sizeof(cmp_arr));
memset(inp, 0, sizeof(inp));
printf("---------------------Welcome_to_SCTF_2021---------------------\n");
printf("Please input your flag: \n");
scanf("%s", data);
length = strlen(data);
if ( length != 32 )
{
printf("length error!\n");
return 0;
}
w = 0;
LABEL_4:
if ( w <= 1 )
{
if ( !w )
{
inp[0] = *(_DWORD *)data;
inp[1] = *(_DWORD *)&data[4];
inp[2] = *(_DWORD *)&data[8];
inp[3] = *(_DWORD *)&data[12];
}
if ( w == 1 )
{
inp[0] = *(_DWORD *)&data[16];
inp[1] = *(_DWORD *)&data[20];
inp[2] = *(_DWORD *)&data[24];
inp[3] = *(_DWORD *)&data[28];
}
v0 = inp[0];
v1 = inp[1];
v2 = inp[2];
v3 = inp[3];
sum1 = 0;
sum2 = 0;
memset(dst, 0, sizeof(dst));
memset(out1, 0, sizeof(out1));
exception = _cxa_allocate_exception(0x20ui64);
std::allocator<char>::allocator(&v65);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
exception,
"init_part",
&v65);
v4 = (void *)std::allocator<char>::~allocator(&v65);
v17 = v4;
if ( &`typeinfo for'std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>> != (void **)1 )
Unwind_Resume(v4);
exception_ptr = _cxa_get_exception_ptr(v4);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&init, exception_ptr);
_cxa_begin_catch(v17);
qmemcpy(key, "Welcome_to_sctf!", sizeof(key));
k0_0 = *(_DWORD *)key;
k1_0 = *(_DWORD *)&key[4];
k2_0 = *(_DWORD *)&key[8];
k3_0 = *(_DWORD *)&key[12];
cmp_arr[0] = -66;
cmp_arr[1] = 28;
cmp_arr[2] = -77;
cmp_arr[3] = -13;
cmp_arr[4] = -95;
cmp_arr[5] = -12;
cmp_arr[6] = -28;
cmp_arr[7] = 99;
cmp_arr[8] = 17;
cmp_arr[9] = -31;
cmp_arr[10] = 28;
cmp_arr[11] = 107;
cmp_arr[12] = 84;
cmp_arr[13] = 10;
cmp_arr[14] = -33;
cmp_arr[15] = 116;
cmp_arr[16] = -14;
cmp_arr[17] = -109;
cmp_arr[18] = 85;
cmp_arr[19] = -38;
cmp_arr[20] = 72;
cmp_arr[21] = -4;
cmp_arr[22] = -94;
cmp_arr[23] = 60;
cmp_arr[24] = -119;
qmemcpy(&cmp_arr[25], "c.", 2);
cmp_arr[27] = 127;
cmp_arr[28] = -115;
cmp_arr[29] = -92;
qmemcpy(&cmp_arr[30], "mN", 2);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&init);
_cxa_end_catch();
i = 0;
LABEL_10:
if ( i <= 1 )
{
cnt = 0;
srand(0x53435446u);
while ( 1 )
{
control1 = rand();
if ( control1 == 21000 )
break;
if ( control1 == 26001 )
{
v5 = (struct_of_step1 *)_cxa_allocate_exception(1ui64);
struct_of_step1::struct_of_step1(v5);
v7 = &`typeinfo for'struct_of_step1;
goto catch_40273d;
}
if ( control1 == 4265 )
{
v8 = (struct_of_step2 *)_cxa_allocate_exception(1ui64);
struct_of_step2::struct_of_step2(v8);
v7 = &`typeinfo for'struct_of_step2;
goto catch_40273d;
}
LABEL_19:
if ( ++cnt == 3 )
{
++i;
goto LABEL_10;
}
}
v9 = (struct_of_step3 *)_cxa_allocate_exception(1ui64);
struct_of_step3::struct_of_step3(v9);
v7 = &`typeinfo for'struct_of_step3;
catch_40273d:
if ( v7 == (void **)3 )
{
_cxa_begin_catch(v6);
v19 = operation1(sum1, i);
v20 = operation4(v1);
v21 = operation1(v20, k3_0);
v22 = operation1(v1, sum1);
v23 = operation2(v1);
v24 = operation1(v23, k2_0);
v25 = operation3(v24, v22);
v26 = operation3(v25, v21);
v0 += operation3(v26, v19);
v27 = operation1(sum2, i);
v28 = operation4(v3);
v29 = operation1(v28, k3_0);
v30 = operation1(v3, sum2);
v31 = operation2(v3);
v32 = operation1(v31, k2_0);
v33 = operation3(v32, v30);
v34 = operation3(v33, v29);
v2 += operation3(v34, v27);
_cxa_end_catch();
}
else if ( v7 == (void **)4 )
{
_cxa_begin_catch(v6);
v35 = operation1(sum1, i);
v36 = operation4(v0);
v37 = operation1(v36, k1_0);
v38 = operation1(v0, sum1);
v39 = operation2(v0);
v40 = operation1(v39, k0_0);
v41 = operation3(v40, v38);
v42 = operation3(v41, v37);
v1 += operation3(v42, v35);
v43 = operation1(sum2, i);
v44 = operation4(v2);
v45 = operation1(v44, k1_0);
v46 = operation1(v2, sum1);
v47 = operation2(v2);
v48 = operation1(v47, k0_0);
v49 = operation3(v48, v46);
v50 = operation3(v49, v45);
v3 += operation3(v50, v43);
_cxa_end_catch();
}
else
{
if ( v7 != (void **)2 )
goto LABEL_65;
_cxa_begin_catch(v6);
sum1 = operation1(sum1, delta);
sum2 = operation1(sum2, delta);
_cxa_end_catch();
}
goto LABEL_19;
}
v10 = (last_struct *)_cxa_allocate_exception(1ui64);
text_84(v10);
if ( &`typeinfo for'last_struct != (void **)6 )
Unwind_Resume(v11);
_cxa_begin_catch(v11);
dst[0] = v0 ^ HIBYTE(delta);
dst[1] = v1 ^ BYTE2(delta);
dst[2] = v2 ^ BYTE1(delta);
dst[3] = v3 ^ (unsigned __int8)delta;
_cxa_end_catch();
m = 0;
for ( j = 0; j <= 3; ++j )
{
for ( k = 0; k <= 3; ++k )
out1[m++] = *((_BYTE *)&dst[j] + k);
}
x = 0;
srand(0x53435446u);
while ( 1 )
{
if ( x == 2 )
{
if ( !w )
{
for ( i_0 = 0; i_0 <= 15; ++i_0 )
encdata[i_0] = ciphertext[i_0];
}
if ( w == 1 )
{
for ( i_1 = 0; i_1 <= 15; ++i_1 )
encdata[i_1 + 16] = ciphertext[i_1];
}
++w;
goto LABEL_4;
}
v12 = rand();
if ( v12 == 4265 )
{
v15 = (enc_next_struct *)_cxa_allocate_exception(0x18ui64);
enc_next_struct::enc_next_struct(v15, (uint8_t *)&init, out1, ciphertext);
v14 = &`typeinfo for'enc_next_struct;
}
else
{
if ( v12 != 26001 )
goto LABEL_33;
v13 = (enc_next_ready_struct *)_cxa_allocate_exception(0x10ui64);
enc_next_ready_struct::enc_next_ready_struct(v13, key, (uint8_t *)&init);
v14 = &`typeinfo for'enc_next_ready_struct;
}
v51 = v6;
if ( v14 == (void **)7 )
{
v52 = _cxa_get_exception_ptr(v6);
v53 = (uint8_t *)*((_QWORD *)v52 + 1);
temp_3.ourciphertext = *(uint8_t **)v52;
temp_3.ourroundkeys = v53;
_cxa_begin_catch(v51);
enc_next_ready(temp_3.ourciphertext, temp_3.ourroundkeys);
_cxa_end_catch();
}
else
{
if ( v14 != (void **)8 )
{
LABEL_65:
_cxa_begin_catch(v6);
_cxa_end_catch();
return 0;
}
temp_4 = *(enc_next_struct_0 *)_cxa_get_exception_ptr(v6);
_cxa_begin_catch(v51);
enc_next(temp_4.ourroundkeys, temp_4.ourplaintext, temp_4.ourciphertext);
_cxa_end_catch();
}
LABEL_33:
++x;
}
}
for ( j_0 = 0; j_0 <= 31; ++j_0 )
{
if ( encdata[j_0] != cmp_arr[j_0] )
{
printf("Sorry!Your flag is wrong!!!!\n");
exit(0);
}
}
printf("\ncongratulations!!!!your flag is \nSCTF{%s}", data);
return 0;
}

最终可以得到这样的一个 main 函数。根据其中的信息,可以得到对 flag 的加密过程由三部分组成。

首先是第一部分

这部分加密由一堆函数组成,通过对这些函数(其中也有大量的利用异常处理来隐藏代码)的分析,即可还原出函数的操作:

不难看出是魔改的 tea 加密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void tea_encrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3], sum1 = 0, sum2 = 0, i;
uint32_t delta = 0x73637466;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
uint32_t temp;
for (i = 0; i < 32; i++) {
sum1 += delta;
sum2 += delta;
v0 = ((v1 << 4) + k2) ^ (v1 + sum1) ^ ((v1 >> 5) + k3) ^ (sum1+i);
v2 = ((v3 << 4) + k2) ^ (v3 + sum2) ^ ((v3 >> 5) + k3) ^ (sum2+i);
v1 = ((v0 << 4) + k0) ^ (v0 + sum1) ^ ((v0 >> 5) + k1) ^ (sum1+i);
v3 = ((v2 << 4) + k0) ^ (v2 + sum2) ^ ((v2 >> 5) + k1) ^ (sum2+i);
}
v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3;
printf("sum: %x\n", sum1);
}

第二部分的加密是一个普通的异或加密:

第三部分根据其中用到的常数以及代码特征可以得到是魔改的 AES 加密,对轮秘钥生成和第一次AddRoundKeySubBytes做了修改。

解密脚本:

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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
#include <stdint.h>
#include <stdio.h>

#include "aes.h"
#include <stdlib.h>

/*
* round constants
*/
static uint8_t RC[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };

/*
* Sbox
*/
static uint8_t SBOX[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };

/*
* Inverse Sboxs
*/
static uint8_t INV_SBOX[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };

/**
* https://en.wikipedia.org/wiki/Finite_field_arithmetic
* Multiply two numbers in the GF(2^8) finite field defined
* by the polynomial x^8 + x^4 + x^3 + x + 1 = 0
* We do use mul2(int8_t a) but not mul(uint8_t a, uint8_t b)
* just in order to get a higher speed.
*/
static inline uint8_t mul2(uint8_t a)
{
return (a & 0x80) ? ((a << 1) ^ 0x1b) : (a << 1);
}

/**
* @purpose: ShiftRows
* @descrption:
* Row0: s0 s4 s8 s12 <<< 0 byte
* Row1: s1 s5 s9 s13 <<< 1 byte
* Row2: s2 s6 s10 s14 <<< 2 bytes
* Row3: s3 s7 s11 s15 <<< 3 bytes
*/
static void shift_rows(uint8_t* state)
{
uint8_t temp;
// row1
temp = *(state + 1);
*(state + 1) = *(state + 5);
*(state + 5) = *(state + 9);
*(state + 9) = *(state + 13);
*(state + 13) = temp;
// row2
temp = *(state + 2);
*(state + 2) = *(state + 10);
*(state + 10) = temp;
temp = *(state + 6);
*(state + 6) = *(state + 14);
*(state + 14) = temp;
// row3
temp = *(state + 15);
*(state + 15) = *(state + 11);
*(state + 11) = *(state + 7);
*(state + 7) = *(state + 3);
*(state + 3) = temp;
}

/**
* @purpose: Inverse ShiftRows
* @description
* Row0: s0 s4 s8 s12 >>> 0 byte
* Row1: s1 s5 s9 s13 >>> 1 byte
* Row2: s2 s6 s10 s14 >>> 2 bytes
* Row3: s3 s7 s11 s15 >>> 3 bytes
*/
static void inv_shift_rows(uint8_t* state)
{
uint8_t temp;
// row1
temp = *(state + 13);
*(state + 13) = *(state + 9);
*(state + 9) = *(state + 5);
*(state + 5) = *(state + 1);
*(state + 1) = temp;
// row2
temp = *(state + 14);
*(state + 14) = *(state + 6);
*(state + 6) = temp;
temp = *(state + 10);
*(state + 10) = *(state + 2);
*(state + 2) = temp;
// row3
temp = *(state + 3);
*(state + 3) = *(state + 7);
*(state + 7) = *(state + 11);
*(state + 11) = *(state + 15);
*(state + 15) = temp;
}

void aes_key_schedule_128(const uint8_t* key, uint8_t* roundkeys)
{

uint8_t temp[4];
uint8_t* last4bytes; // point to the last 4 bytes of one round
uint8_t* lastround;
uint8_t i;

for (i = 0; i < 16; ++i)
{
*roundkeys++ = *key++;
}

last4bytes = roundkeys - 4;
for (i = 0; i < AES_ROUNDS; ++i)
{
// k0-k3 for next round
temp[3] = SBOX[*last4bytes++];
temp[0] = SBOX[*last4bytes++];
temp[1] = SBOX[*last4bytes++];
temp[2] = SBOX[*last4bytes++];
temp[0] ^= RC[i];
lastround = roundkeys - 16;
*roundkeys++ = temp[0] ^ *lastround++;
*roundkeys++ = temp[1] ^ *lastround++;
*roundkeys++ = temp[2] ^ *lastround++;
*roundkeys++ = temp[3] ^ *lastround++;
// k4-k7 for next round
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
// k8-k11 for next round
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
// k12-k15 for next round
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
*roundkeys++ = *last4bytes++ ^ *lastround++;
}
}

void aes_encrypt_128(const uint8_t* roundkeys, const uint8_t* plaintext, uint8_t* ciphertext)
{

uint8_t tmp[16], t;
uint8_t i, j;

// first AddRoundKey
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(ciphertext + i) = *(plaintext + i) ^ *roundkeys++ ^ 0x66;
}

// 9 rounds
for (j = 1; j < AES_ROUNDS; ++j)
{

// SubBytes
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(tmp + i) = INV_SBOX[*(ciphertext + i)];
}
inv_shift_rows(tmp);
/*
* MixColumns
* [02 03 01 01] [s0 s4 s8 s12]
* [01 02 03 01] . [s1 s5 s9 s13]
* [01 01 02 03] [s2 s6 s10 s14]
* [03 01 01 02] [s3 s7 s11 s15]
*/
for (i = 0; i < AES_BLOCK_SIZE; i += 4)
{
t = tmp[i] ^ tmp[i + 1] ^ tmp[i + 2] ^ tmp[i + 3];
ciphertext[i] = mul2(tmp[i] ^ tmp[i + 1]) ^ tmp[i] ^ t;
ciphertext[i + 1] = mul2(tmp[i + 1] ^ tmp[i + 2]) ^ tmp[i + 1] ^ t;
ciphertext[i + 2] = mul2(tmp[i + 2] ^ tmp[i + 3]) ^ tmp[i + 2] ^ t;
ciphertext[i + 3] = mul2(tmp[i + 3] ^ tmp[i]) ^ tmp[i + 3] ^ t;
}

// AddRoundKey
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(ciphertext + i) ^= *roundkeys++;
}
}

// last round
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(ciphertext + i) = SBOX[*(ciphertext + i)];
}
shift_rows(ciphertext);
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(ciphertext + i) ^= *roundkeys++;
}
}

void aes_decrypt_128(const uint8_t* roundkeys, const uint8_t* ciphertext, uint8_t* plaintext)
{

uint8_t tmp[16];
uint8_t t, u, v;
uint8_t i, j;

roundkeys += 160;

// first round
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(plaintext + i) = *(ciphertext + i) ^ *(roundkeys + i);
}
roundkeys -= 16;
inv_shift_rows(plaintext);
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(plaintext + i) = INV_SBOX[*(plaintext + i)];
}

for (j = 1; j < AES_ROUNDS; ++j)
{

// Inverse AddRoundKey
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(tmp + i) = *(plaintext + i) ^ *(roundkeys + i);
}

/*
* Inverse MixColumns
* [0e 0b 0d 09] [s0 s4 s8 s12]
* [09 0e 0b 0d] . [s1 s5 s9 s13]
* [0d 09 0e 0b] [s2 s6 s10 s14]
* [0b 0d 09 0e] [s3 s7 s11 s15]
*/
for (i = 0; i < AES_BLOCK_SIZE; i += 4)
{
t = tmp[i] ^ tmp[i + 1] ^ tmp[i + 2] ^ tmp[i + 3];
plaintext[i] = t ^ tmp[i] ^ mul2(tmp[i] ^ tmp[i + 1]);
plaintext[i + 1] = t ^ tmp[i + 1] ^ mul2(tmp[i + 1] ^ tmp[i + 2]);
plaintext[i + 2] = t ^ tmp[i + 2] ^ mul2(tmp[i + 2] ^ tmp[i + 3]);
plaintext[i + 3] = t ^ tmp[i + 3] ^ mul2(tmp[i + 3] ^ tmp[i]);
u = mul2(mul2(tmp[i] ^ tmp[i + 2]));
v = mul2(mul2(tmp[i + 1] ^ tmp[i + 3]));
t = mul2(u ^ v);
plaintext[i] ^= t ^ u;
plaintext[i + 1] ^= t ^ v;
plaintext[i + 2] ^= t ^ u;
plaintext[i + 3] ^= t ^ v;
}

// Inverse ShiftRows
shift_rows(plaintext);

// Inverse SubBytes
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(plaintext + i) = SBOX[*(plaintext + i)];
}

roundkeys -= 16;
}

// last AddRoundKey
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
*(plaintext + i) ^= *(roundkeys + i) ^ 0x66;
}
}

void tea_encrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3], sum1 = 0, sum2 = 0, i; /* set up */
uint32_t delta = 0x73637466; /* a key schedule constant */
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; /* cache key */
uint32_t temp;
for (i = 0; i < 32; i++) { /* basic cycle start */
sum1 += delta;
sum2 += delta;
temp = ((v1 << 4) + k2) ^ (v1 + sum1) ^ ((v1 >> 5) + k3) ^ (sum1+i);
v0 += temp;
temp = ((v3 << 4) + k2) ^ (v3 + sum2) ^ ((v3 >> 5) + k3) ^ (sum2+i);
v2 += temp;


temp = ((v0 << 4) + k0) ^ (v0 + sum1) ^ ((v0 >> 5) + k1) ^ (sum1+i);
v1 += temp;

temp = ((v2 << 4) + k0) ^ (v2 + sum2) ^ ((v2 >> 5) + k1) ^ (sum2+i);
v3 += temp;

} /* end cycle */
v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3;
printf("sum: %x\n", sum1);

}
//解密函数
void tea_decrypt(uint32_t* v, uint32_t* k)
{
uint32_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3], sum1 = 0x6c6e8cc0, sum2 = 0x6c6e8cc0;// 0x6c6e90a0;
uint32_t delta = 0x73637466;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (int i = 31; i >= 0; i--)
{
v3 -= ((v2 << 4) + k0) ^ (v2 + sum2) ^ ((v2 >> 5) + k1) ^ (sum2+i);

v1 -= ((v0 << 4) + k0) ^ (v0 + sum1) ^ ((v0 >> 5) + k1) ^ (sum1+i);


v2 -= ((v3 << 4) + k2) ^ (v3 + sum2) ^ ((v3 >> 5) + k3) ^ (sum2+i);

v0 -= ((v1 << 4) + k2) ^ (v1 + sum1) ^ ((v1 >> 5) + k3) ^ (sum1+i);

sum2 -= delta;
sum1 -= delta;
}
v[0] = v0;
v[1] = v1;
v[2] = v2;
v[3] = v3;
// printf("v:%s", v);
}
int main()
{
unsigned char* dec1 = (unsigned char*)malloc(0x20);
unsigned char* dec = (unsigned char*)malloc(0x20);
unsigned char* roundKeys = (unsigned char*)malloc(0x200);
aes_key_schedule_128("Welcome_to_sctf!", roundKeys);
unsigned char enc1[] = { 0xBE, 0x1C, 0xB3, 0xF3, 0xA1, 0xF4, 0xE4, 0x63, 0x11, 0xE1,
0x1C, 0x6B, 0x54, 0x0A, 0xDF, 0x74 };
unsigned char enc2[] =
{ 0xF2, 0x93, 0x55, 0xDA,
0x48, 0xFC, 0xA2, 0x3C, 0x89, 0x63, 0x2E, 0x7F, 0x8D, 0xA4,
0x6D, 0x4E };



aes_decrypt_128(roundKeys, enc1, dec);
((uint32_t*)dec)[0] ^= 0x73;
((uint32_t*)dec)[1] ^= 0x63;
((uint32_t*)dec)[2] ^= 0x74;
((uint32_t*)dec)[3] ^= 0x66;

tea_decrypt((uint32_t*)(dec), "Welcome_to_sctf!");
puts("\nflag1:");
for (int i = 0; i < 16; i++)
{
printf("%c", dec[i]);
}

aes_decrypt_128(roundKeys, enc2, dec);
((uint32_t*)dec)[0] ^= 0x73;
((uint32_t*)dec)[1] ^= 0x63;
((uint32_t*)dec)[2] ^= 0x74;
((uint32_t*)dec)[3] ^= 0x66;

tea_decrypt((uint32_t*)(dec), "Welcome_to_sctf!");
puts("\nflag2:");
for (int i = 0; i < 16; i++)
{
printf("%c", dec[i]);
}

return 0;
}