XCTF Final FlagChecker

前端代码提取

Tauri程序,字符串定位到index.html,然后找交叉调用到这边,直接用一把梭解压脚本发现解压失败,应该是数据被加密了。

alt text

查找该部分的交叉调用,在他被调用代码下面部分下断,动调,发现数据被自解密了,此时再用脚本提取解压即可得到相关的前端代码。

alt text

alt text

alt text

提取代码:

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
import idc
import brotli
import os
import pathlib
import shutil
import json

start = 0x140664738
end = 0x1406647F8

def extract(start_ea,end_ea,output_dir="assets"):
shutil.rmtree(output_dir,ignore_errors=True)
for offset in range(start,end,0x20):
asset_name_ea = idc.get_qword(offset)
asset_length = idc.get_qword(offset +0x8)
asset_name = idc.get_strlit_contents(asset_name_ea,asset_length,0).decode()[1:]
asset_data_ea = idc.get_qword(offset+0x10)
asset_data_length = idc.get_qword(offset+0x18)
try:
asset_data = brotli.decompress(idc.get_bytes(asset_data_ea,asset_data_length))
except:
print(1)
output_dir=pathlib.Path(output_dir)
asset_path: pathlib.Path = output_dir / asset_name
if not asset_path.parent.exists():
os.makedirs(asset_path.parent)
with open(asset_path,"wb") as f:
f.write(asset_data)
if asset_path.name.startswith("app") and asset_path.name.endswith(".js.map"):
content = json.loads(asset_data)['sourcesContent']
for i in range(len(content)):
with open(f"{asset_path}-content{i}.js","w",encoding='utf-8') as f:
f.write(content[i])

extract(start, end,r'C:\Users\Liv\Desktop\extrate_assets')

前端代码分析

这边存在一个base64数组,这边使用一个funny函数进行解密,funney函数是一个rc4代码。

alt text

alt text

使用python代码解密,得到以下字串,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
()=>_=_+_
()=>_=-_+_
()=>____=____^____
()=>____++
()=>_=____
()=>____=_
()=>_=_*_
()=>{__=_;_=_%__}
()=>_=_^_
()=>__=_
()=>_= ___.__[_]
()=>{__=_;_=_==__}
()=>{__=_;_=_&&__}
()=>___()
()=>_=_____(_)
()=>{__=_;_=_______(__,_)}
()=>{_=[]}
()=>{__=_;_=[...__,_]}
()=>{__=_;________=_;_=__;_=________}
()=>{_=_________(_)}
()=>{_=__________(_)}
()=>{_=___________(_)}
()=>{_=_&0xFF}
()=>{__=_;________=_;_=________;_=________[__];}
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
import base64

data = ['ZH1M76gWRUBE', 'ZH1M76gWNzQw3g==', 'ZH1M76h0RTQm3t9bDwuDagPi', 'ZH1M76h0RTQwqg==', 'ZH1M76gWRTRE3g==',
'ZH1M76h0RTQm3g==', 'ZH1M76gWRUFE', 'ZH1M74x0RVZEut85D3CDaiE=', 'ZH1M76gWRTVE',
'ZH1M76h0JzQ=', 'ZH1M76gWOjRE3q5bDw6DaA==', 'ZH1M74x0RVZEut85D2jhagPA',
'ZH1M74x0RVZEut85D3P6agPA', 'ZH1M76h0RUMy', 'ZH1M76gWRTRE3t8sD3w=',
'ZH1M74x0RVZEut85DwqDagPiVGHENopkPX8=', 'ZH1M74x0JzBG/A==',
'ZH1M74x0RVZEut85C3vyGwPiJxbGFA==',
'ZH1M74x0RVZEut9bDwqDagPiNhagNptkSzkrzX7vk8KLWCrDDQ==',
'ZH1M74x0JzRE3t9bDwqDanTiIjQ=', 'ZH1M74x0JzRE3t9bDwqDagOVVGDm',
'ZH1M74x0JzRE3t9bDwqDagPiIxayFA==', 'ZH1M74x0JzQ9sfhCFig=',
'ZH1M74x0RVZEut9bDwqDagPiNhagNptkS10rr37vk6aLOirDL4fDSOIaBO0yFO7E']

KEY = b"rujst-flag-checker"

def rc4(key: bytes, data: bytes) -> bytes:
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) & 0xFF
S[i], S[j] = S[j], S[i]
i = j = 0
out = bytearray()
for byte in data:
i = (i + 1) & 0xFF
j = (j + S[i]) & 0xFF
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) & 0xFF]
out.append(byte ^ K)
return bytes(out)

def base64_dec(s: str) -> bytes:
s = s.strip()
padding = (-len(s)) % 4
s += "=" * padding
return base64.b64decode(s, validate=False)

for idx, item in enumerate(data, 1):
b = base64_dec(item)
plain = rc4(KEY, b)
print(plain.decode())

其余代码是实现了一个vm虚拟机,其中各种指令都用下划线替代,checkme函数下面是几千行的看不懂的代码,尝试直接去IDA搜下划线相关字串找到native代码。

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
export const doit = function() {
window['_________'] = _0x3015ec => {
return invoke('____', {
'data': _0x3015ec
});
}
,
window['__________'] = _0x58db83 => {
return invoke('_____', {
'data': _0x58db83
});
}
,
window['___________'] = _0x2c10e9 => {
return invoke('______', {
'data': _0x2c10e9
});
}
,
window['_'] = 0x1,
window['__'] = 0x0,
window['________'] = 0x0,
window['____________'] = 0x0,
window['___'] = {
'__': []
},
window['____'] = 0x0,
window['______'] = window['___']['__']['push']['bind'](window['___']['__']);
let _0xf101ae = ['ZH1M76gWRUBE', 'ZH1M76gWNzQw3g==', 'ZH1M76h0RTQm3t9bDwuDagPi', 'ZH1M76h0RTQwqg==', 'ZH1M76gWRTRE3g==', 'ZH1M76h0RTQm3g==', 'ZH1M76gWRUFE', 'ZH1M74x0RVZEut85D3CDaiE=', 'ZH1M76gWRTVE', 'ZH1M76h0JzQ=', 'ZH1M76gWOjRE3q5bDw6DaA==', 'ZH1M74x0RVZEut85D2jhagPA', 'ZH1M74x0RVZEut85D3P6agPA', 'ZH1M76h0RUMy', 'ZH1M76gWRTRE3t8sD3w=', 'ZH1M74x0RVZEut85DwqDagPiVGHENopkPX8=', 'ZH1M74x0JzBG/A==', 'ZH1M74x0RVZEut85C3vyGwPiJxbGFA==', 'ZH1M74x0RVZEut9bDwqDagPiNhagNptkSzkrzX7vk8KLWCrDDQ==', 'ZH1M74x0JzRE3t9bDwqDanTiIjQ=', 'ZH1M74x0JzRE3t9bDwqDagOVVGDm', 'ZH1M74x0JzRE3t9bDwqDagPiIxayFA==', 'ZH1M74x0JzQ9sfhCFig=', 'ZH1M74x0RVZEut9bDwqDagPiNhagNptkS10rr37vk6aLOirDL4fDSOIaBO0yFO7E'];
window['_______'] = (_0x10095d, _0x5e3803) => {
return invoke('___', {
'addr': _0x10095d,
'data': _0x5e3803
});
}
,
window['_____'] = _0x4f759c => {
return invoke('__', {
'addr': _0x4f759c
});
}
,
_0xf101ae = _0xf101ae['map'](_0x210576 => eval(funny('rujst-flag-checker', _0x210576))),
Object['defineProperty'](window, '_', {
'get': () => ___['__']['pop'](),
'set': _0xf909c8 => ___['__']['push'](_0xf909c8)
});
for (const _0x4c804f of ['String', 'console', 'BigInt', 'window']) {
let _0x163081 = eval(_0x4c804f);
const _0x1d900a = Object['getOwnPropertyDescriptors']('String' == _0x4c804f ? _0x163081['prototype'] : _0x163081);
for (const _0x12d7ba in _0x1d900a) {
if (_0x12d7ba[0x0] == '_')
continue;
if (_0x12d7ba == 'valueOf' || _0x12d7ba == 'toString')
continue;
let _0x529138 = _0x1d900a[_0x12d7ba]['value'];
if (typeof _0x529138 !== 'function')
continue;
if (_0x4c804f == 'window' && !_0x12d7ba['startsWith']('SVG') && !_0x12d7ba['startsWith']('HTML'))
continue;
if (null != _0x529138)
try {
const _0x57ba50 = (0x4123123 * _0x4c804f['length'] + _0x12d7ba['length'] + 0x1231) % 0x18;
Object['defineProperty'](Object['prototype'], _0x12d7ba, {
'get': () => (_0xf101ae[_0x57ba50]?.(),
_0x529138)
}),
Object['defineProperty'](_0x163081, _0x12d7ba, {
'get': () => (_0xf101ae[_0x57ba50]?.(),
_0x529138)
});
} catch {}
}
}
};

async function checkme(ipt) {
const flag = [...ipt].map(a => a.charCodeAt(0))
___.__.push(flag)
...
...
...

Native层分析

发现搜索”___”不好搜,尝试直接搜立即数”5F5F5F5F”,搜到相关的代码,sub_14029BA40。

alt text

该函数实现了一个vm虚拟机的指令分发,其中存在三种加密,rc4、xxtea、aes,均被魔改。

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
char __fastcall sub_14029BA40(__int64 a1, __int64 a2)
{
__int64 v3; // rax
__int64 v4; // rdx
__int64 v5; // r8
__int64 v6; // rdi
__int64 v7; // rdx
__int64 v8; // rbx
__int64 v9; // r8
__int64 v10; // r9
char result; // al
__int64 v12; // rbx
__int64 v13; // rax
__int64 v14; // rcx
_QWORD *v15; // rcx
_QWORD *v16; // rsi
_QWORD *v17; // rcx
_QWORD *v18; // rsi
_QWORD *v19; // rcx
_QWORD *v20; // rsi
_QWORD *v21; // rcx
_QWORD *v22; // rsi
_BYTE Dst[520]; // [rsp+38h] [rbp-48h] BYREF
__int64 v24[50]; // [rsp+240h] [rbp+1C0h] BYREF
__int64 Src[50]; // [rsp+3D0h] [rbp+350h] BYREF
__m256i v26; // [rsp+560h] [rbp+4E0h] BYREF
__int128 v27; // [rsp+580h] [rbp+500h] BYREF
__int64 v28; // [rsp+590h] [rbp+510h]
__m256i v29; // [rsp+5A0h] [rbp+520h] BYREF
__int64 v30; // [rsp+5C0h] [rbp+540h]
__int64 v31; // [rsp+5C8h] [rbp+548h] BYREF
__m256i v32; // [rsp+5D0h] [rbp+550h]
__int128 v33; // [rsp+5F0h] [rbp+570h] BYREF
__int64 v34; // [rsp+600h] [rbp+580h]
__int64 v35; // [rsp+608h] [rbp+588h]
__int64 v36; // [rsp+610h] [rbp+590h]
char v37; // [rsp+623h] [rbp+5A3h]
char v38; // [rsp+624h] [rbp+5A4h]
char v39; // [rsp+625h] [rbp+5A5h]
char v40; // [rsp+626h] [rbp+5A6h]
char v41; // [rsp+627h] [rbp+5A7h]
__int64 v42; // [rsp+628h] [rbp+5A8h]

v42 = -2;
v3 = *(_QWORD *)(a2 + 464);
switch ( *(_QWORD *)(a2 + 472) )
{
case 2LL:
if ( *(_WORD *)v3 != 24415 )
goto LABEL_17;
memcpy(Dst, (const void *)a2, sizeof(Dst));
memcpy(v24, (const void *)(a2 + 520), sizeof(v24));
v28 = *(_QWORD *)(a2 + 936);
v27 = *(_OWORD *)(a2 + 920);
Src[6] = 0;
Src[0] = (__int64)&unk_140688138;
Src[1] = 2;
Src[2] = (__int64)&aAddrdata[18];
Src[3] = 4;
Src[4] = (__int64)Dst;
Src[5] = (__int64)&v27;
v40 = 1;
sub_14016D890((__int64)&v29, Src);
if ( v29.m256i_i8[0] == 6 )
{
v40 = 1;
v6 = sub_14010F3D0(v29.m256i_i64[1], v4, v5);
v8 = v7;
memcpy(Src, (const void *)(a2 + 520), sizeof(Src));
v32.m256i_i64[0] = v6;
v32.m256i_i64[1] = v8;
LOBYTE(v31) = 6;
v40 = 0;
sub_1401EF630(Src);
}
else
{
v32 = v29;
memcpy(Src, (const void *)(a2 + 520), 0x168u);
*(_OWORD *)v26.m256i_i8 = *(_OWORD *)(a2 + 880);
v26.m256i_i64[2] = *(_QWORD *)(a2 + 896);
v31 = 1;
v40 = 0;
sub_1401EAA40(Src, v24[48], (__int64)&v31, (__int128 *)v26.m256i_i8, v24[49], SHIDWORD(v24[49]));
}
if ( __OFSUB__(0, (_QWORD)v27) )
goto LABEL_50;
v19 = (_QWORD *)*((_QWORD *)&v27 + 1);
v35 = v28;
v36 = 0;
v30 = *((_QWORD *)&v27 + 1);
while ( v35 != v36 )
{
++v36;
v20 = v19 + 12;
sub_140168660(v19);
v19 = v20;
}
v13 = v27;
if ( !(_QWORD)v27 )
goto LABEL_50;
v14 = *((_QWORD *)&v27 + 1);
goto LABEL_29;
case 3LL:
if ( (unsigned __int16)(*(_WORD *)v3 ^ '__') | *(unsigned __int8 *)(v3 + 2) ^ '_' )
goto LABEL_17;
memcpy(Dst, (const void *)a2, sizeof(Dst));
memcpy(v24, (const void *)(a2 + 520), sizeof(v24));
v34 = *(_QWORD *)(a2 + 936);
v33 = *(_OWORD *)(a2 + 920);
Src[6] = 0;
Src[0] = (__int64)aAddrdata;
Src[1] = 3;
Src[2] = (__int64)&aAddrdata[18];
Src[3] = 4;
Src[4] = (__int64)Dst;
Src[5] = (__int64)&v33;
v41 = 1;
sub_14016D890((__int64)&v26, Src);
if ( v26.m256i_i8[0] == 6 )
{
v12 = v26.m256i_i64[1];
Src[6] = 0;
Src[0] = (__int64)aAddrdata;
Src[1] = 3;
Src[2] = (__int64)&aAddrdata[22];
Src[3] = 4;
Src[4] = (__int64)Dst;
Src[5] = (__int64)&v33;
v41 = 1;
sub_14016D890((__int64)&v29, Src);
if ( v29.m256i_i8[0] == 6 )
{
v41 = 1;
sub_14010F240(v12, v29.m256i_i64[1]);
memcpy(Src, (const void *)(a2 + 520), sizeof(Src));
LOBYTE(v31) = 6;
v41 = 0;
sub_1401F0BD0((char *)Src, (__int128 *)&v31);
}
else
{
v32 = v29;
memcpy(Src, (const void *)(a2 + 520), 0x168u);
v27 = *(_OWORD *)(a2 + 880);
v28 = *(_QWORD *)(a2 + 896);
v31 = 1;
v41 = 0;
sub_1401EAA40(Src, v24[48], (__int64)&v31, &v27, v24[49], SHIDWORD(v24[49]));
}
}
else
{
v32 = v26;
memcpy(Src, (const void *)(a2 + 520), 0x168u);
*(_OWORD *)v29.m256i_i8 = *(_OWORD *)(a2 + 880);
v29.m256i_i64[2] = *(_QWORD *)(a2 + 896);
v31 = 1;
v41 = 0;
sub_1401EAA40(Src, v24[48], (__int64)&v31, (__int128 *)v29.m256i_i8, v24[49], SHIDWORD(v24[49]));
}
if ( __OFSUB__(0, (_QWORD)v33) )
goto LABEL_50;
v21 = (_QWORD *)*((_QWORD *)&v33 + 1);
v35 = v34;
v36 = 0;
v30 = *((_QWORD *)&v33 + 1);
while ( v35 != v36 )
{
++v36;
v22 = v21 + 12;
sub_140168660(v21);
v21 = v22;
}
break;
case 4LL:
if ( *(_DWORD *)v3 != '____' )
goto LABEL_17;
memcpy(Dst, (const void *)a2, sizeof(Dst));
memcpy(v24, (const void *)(a2 + 520), sizeof(v24));
v34 = *(_QWORD *)(a2 + 936);
v33 = *(_OWORD *)(a2 + 920);
Src[6] = 0;
Src[0] = (__int64)&aAddrdata[3];
Src[1] = 4;
Src[2] = (__int64)&aAddrdata[22];
Src[3] = 4;
Src[4] = (__int64)Dst;
Src[5] = (__int64)&v33;
v39 = 1;
sub_14016E050((__int64)&v29, Src);
if ( v29.m256i_i8[0] == 6 )
{
v26.m256i_i64[2] = v29.m256i_i64[3];
*(_OWORD *)v26.m256i_i8 = *(_OWORD *)&v29.m256i_u64[1];
xxtea_custom(&v27, (__int64)&v26, v9, v10);
if ( v26.m256i_i64[0] )
sub_140001090(v26.m256i_i64[1], v26.m256i_i64[0], 1);
memcpy(Src, (const void *)(a2 + 520), sizeof(Src));
v32.m256i_i64[2] = v28;
*(_OWORD *)v32.m256i_i8 = v27;
LOBYTE(v31) = 6;
v39 = 0;
sub_1401F0300(Src, (__int128 *)&v31);
}
else
{
v32 = v29;
memcpy(Src, (const void *)(a2 + 520), 0x168u);
*(_OWORD *)v26.m256i_i8 = *(_OWORD *)(a2 + 880);
v26.m256i_i64[2] = *(_QWORD *)(a2 + 896);
v31 = 1;
v39 = 0;
sub_1401EAA40(Src, v24[48], (__int64)&v31, (__int128 *)v26.m256i_i8, v24[49], SHIDWORD(v24[49]));
}
if ( __OFSUB__(0, (_QWORD)v33) )
goto LABEL_50;
v15 = (_QWORD *)*((_QWORD *)&v33 + 1);
v35 = v34;
v36 = 0;
v30 = *((_QWORD *)&v33 + 1);
while ( v35 != v36 )
{
++v36;
v16 = v15 + 12;
sub_140168660(v15);
v15 = v16;
}
break;
case 5LL:
if ( *(_DWORD *)v3 ^ '____' | *(unsigned __int8 *)(v3 + 4) ^ '_' )
goto LABEL_17;
memcpy(Dst, (const void *)a2, sizeof(Dst));
memcpy(v24, (const void *)(a2 + 520), sizeof(v24));
v34 = *(_QWORD *)(a2 + 936);
v33 = *(_OWORD *)(a2 + 920);
Src[6] = 0;
Src[0] = (__int64)&aAddrdata[7];
Src[1] = 5;
Src[2] = (__int64)&aAddrdata[22];
Src[3] = 4;
Src[4] = (__int64)Dst;
Src[5] = (__int64)&v33;
v38 = 1;
sub_14016E050((__int64)&v29, Src);
if ( v29.m256i_i8[0] == 6 )
{
v26.m256i_i64[2] = v29.m256i_i64[3];
*(_OWORD *)v26.m256i_i8 = *(_OWORD *)&v29.m256i_u64[1];
v38 = 1;
rc4_custom((__int64 *)&v27, v26.m256i_i64);
memcpy(Src, (const void *)(a2 + 520), sizeof(Src));
v32.m256i_i64[2] = v28;
*(_OWORD *)v32.m256i_i8 = v27;
LOBYTE(v31) = 6;
v38 = 0;
sub_1401F0300(Src, (__int128 *)&v31);
}
else
{
v32 = v29;
memcpy(Src, (const void *)(a2 + 520), 0x168u);
*(_OWORD *)v26.m256i_i8 = *(_OWORD *)(a2 + 880);
v26.m256i_i64[2] = *(_QWORD *)(a2 + 896);
v31 = 1;
v38 = 0;
sub_1401EAA40(Src, v24[48], (__int64)&v31, (__int128 *)v26.m256i_i8, v24[49], SHIDWORD(v24[49]));
}
if ( __OFSUB__(0, (_QWORD)v33) )
goto LABEL_50;
v17 = (_QWORD *)*((_QWORD *)&v33 + 1);
v35 = v34;
v36 = 0;
v30 = *((_QWORD *)&v33 + 1);
while ( v35 != v36 )
{
++v36;
v18 = v17 + 12;
sub_140168660(v17);
v17 = v18;
}
break;
case 6LL:
if ( *(_DWORD *)v3 ^ '____' | *(unsigned __int16 *)(v3 + 4) ^ '__' )
goto LABEL_17;
memcpy(Dst, (const void *)a2, sizeof(Dst));
memcpy(v24, (const void *)(a2 + 520), sizeof(v24));
v34 = *(_QWORD *)(a2 + 936);
v33 = *(_OWORD *)(a2 + 920);
Src[6] = 0;
Src[0] = (__int64)&aAddrdata[12];
Src[1] = 6;
Src[2] = (__int64)&aAddrdata[22];
Src[3] = 4;
Src[4] = (__int64)Dst;
Src[5] = (__int64)&v33;
v37 = 1;
sub_14016E050((__int64)&v29, Src);
if ( v29.m256i_i8[0] == 6 )
{
v26.m256i_i64[2] = v29.m256i_i64[3];
*(_OWORD *)v26.m256i_i8 = *(_OWORD *)&v29.m256i_u64[1];
v37 = 1;
aes_custom((__int64)&v27, v26.m256i_i64);
memcpy(Src, (const void *)(a2 + 520), sizeof(Src));
v32.m256i_i64[2] = v28;
*(_OWORD *)v32.m256i_i8 = v27;
LOBYTE(v31) = 6;
v37 = 0;
sub_1401F0300(Src, (__int128 *)&v31);
}
else
{
v32 = v29;
memcpy(Src, (const void *)(a2 + 520), 0x168u);
*(_OWORD *)v26.m256i_i8 = *(_OWORD *)(a2 + 880);
v26.m256i_i64[2] = *(_QWORD *)(a2 + 896);
v31 = 1;
v37 = 0;
sub_1401EAA40(Src, v24[48], (__int64)&v31, (__int128 *)v26.m256i_i8, v24[49], SHIDWORD(v24[49]));
}
if ( __OFSUB__(0, (_QWORD)v33) )
goto LABEL_50;
sub_140170030((__int64)&v33);
break;
default:
LABEL_17:
v36 = a2;
sub_140287300(a2);
sub_1400D1530(v36 + 520);
result = 0;
if ( !__OFSUB__(0, *(_QWORD *)(v36 + 920)) )
{
v35 = v36 + 920;
sub_140170030(v36 + 920);
if ( *(_QWORD *)(v36 + 920) )
sub_140001090(*(_QWORD *)(v36 + 928), 96LL * *(_QWORD *)(v36 + 920), 8);
return 0;
}
return result;
}
v13 = v33;
if ( (_QWORD)v33 )
{
v14 = *((_QWORD *)&v33 + 1);
LABEL_29:
sub_140001090(v14, 96 * v13, 8);
}
LABEL_50:
sub_140287300((__int64)Dst);
return 1;
}

RC4部分代码:

alt text

alt text

xxtea部分代码:

动调可以直接拿到密钥

1
2
3
unsigned char key[] = {
0xA4, 0x60, 0x78, 0x7B, 0x02, 0x54, 0xEB, 0x54, 0x35, 0x9E, 0x7F, 0xFF, 0x27, 0xCA, 0x47, 0xBF,
};

alt text

动调aes的函数,可以跟进实际加密地方,两轮16字节的加密,一共32字节。

alt text

alt text

经过分析发现是AES-128,并且MixColumn魔改了,异或了0x44,sbox也是魔改过的。

alt text

alt text

  1. 断点三个函数调用处,发现是都调用了很多次,并且每次调用完后,会打包成”[123,56,22,..]”这样类似的字符串,发送回前端。

  2. 调试发现每次加密完的数据和下次调用其中一个加密函数加密前数据不一样,猜测发送前端后会被异或加密再发送回后端进行下一次加密。

  3. 调试验证取出上一次加密后数据,和下一次加密前数据,进行异或得到异或密钥,重新输入不同字符串,用得到的密钥进行异或,发现是可以成功的,也就是确实是异或加密且密钥唯一。

  4. 通过手动调试获取每轮前端的异或密钥,以及三种加密的调用流,可以同构出完整的原加密代码。

同构代码:

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
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#include <iostream>
#include <windows.h>
#include <algorithm>
#include "aes.h"

void encrypt(uint8_t* input_)
{
DWORD Delta = 0xBAE5A071;

unsigned char key[] = {
0xA4, 0x60, 0x78, 0x7B, 0x02, 0x54, 0xEB, 0x54, 0x35, 0x9E, 0x7F, 0xFF, 0x27, 0xCA, 0x47, 0xBF,
};

uint32_t* v38 = (uint32_t*)key;
uint32_t* input = (uint32_t*)input_;
int v17 = 46;
DWORD Sum = 0;
DWORD v1{};
DWORD v7 = 8;
DWORD v14 = v7 - 1;
v1 = input[v14];
do
{
Sum += Delta;
DWORD v19 = Sum >> 2;
DWORD count = 0;
do
{
v1 = input[count]
+ ((((v1 >> 3) ^ (input[count + 1] << 6)) + ((input[count + 1] >> 4) ^ (32 * v1)))
^ ((Sum ^ input[count + 1]) + (*((DWORD*)v38 + (((unsigned __int8)count ^ (unsigned __int8)v19) & 3)) ^ v1)));

input[count++] = v1;
} while (v14 != count);
v1 = input[v14] + ((((v1 >> 4) ^ (8 * *input)) + ((*input >> 6) ^ (4 * v1))) ^ ((Sum ^ *input) + (*((DWORD*)v38 + (((uint8_t)(v7 - 1) ^ (uint8_t)v19) & 3)) ^ v1)));
input[v14] = v1;

v17 = (unsigned int)(v17 - 1);
} while ((DWORD)v17);

}

unsigned char aes_key[176] = {
0xCF, 0x95, 0x5E, 0x20, 0x94, 0x15, 0x34, 0x64, 0x9A, 0x54, 0x53, 0xE9, 0x2F, 0x51, 0x33, 0x41,
0x2D, 0x48, 0x7C, 0xF5, 0x37, 0xAB, 0x09, 0x32, 0xB5, 0xFF, 0x4B, 0x7B, 0x53, 0xD5, 0x0F, 0x47,
0xBF, 0xFA, 0x79, 0x81, 0x11, 0x2A, 0x0E, 0x76, 0x94, 0xBA, 0xA8, 0xA1, 0xF8, 0xED, 0xF4, 0xDC,
0x4F, 0x85, 0x9C, 0x47, 0xCB, 0xF5, 0x52, 0x26, 0xEB, 0xE9, 0x5F, 0xF0, 0x62, 0x80, 0x75, 0x85,
0x0E, 0x2F, 0x02, 0x74, 0xB8, 0x5B, 0x0A, 0x4A, 0x6A, 0x56, 0xAA, 0x57, 0x01, 0xDA, 0xFB, 0x5A,
0x18, 0x7D, 0x49, 0x65, 0x14, 0xC4, 0x68, 0xE5, 0xCF, 0x52, 0x58, 0x56, 0xD9, 0x11, 0x74, 0x81,
0x4A, 0x2E, 0xA5, 0x54, 0xCB, 0x5D, 0xB9, 0x36, 0x80, 0xE1, 0x3C, 0x0C, 0x2B, 0x1E, 0x09, 0xB1,
0x8A, 0x0B, 0xA2, 0x65, 0x28, 0xCA, 0x63, 0x6A, 0x15, 0x65, 0xEB, 0xCC, 0xC7, 0x6F, 0x5C, 0xAF,
0x19, 0x43, 0x65, 0x8B, 0x26, 0x31, 0xC0, 0x3C, 0x66, 0x8A, 0x65, 0x1E, 0x34, 0xBC, 0x27, 0x36,
0x1E, 0x01, 0xC7, 0xC8, 0x07, 0x06, 0xE0, 0x9E, 0x2C, 0x91, 0xB0, 0x10, 0x03, 0xA5, 0xF2, 0xC4,
0x1A, 0xEC, 0xFB, 0x19, 0xA3, 0x5D, 0x63, 0xF0, 0xF1, 0x99, 0x7A, 0x1C, 0x5E, 0x87, 0x11, 0x1B
};

// 加密同构
int main()
{
uint8_t input[] = "12341234123412341234123412341234";

std::reverse(input, input + 32);

uint8_t xorkey1[]{ 0x0c,0xa2,0xd9,0xf7,0x95,0x66,0xa9,0x0b,0x35,0xe9,0x20,0x09,0x08,0xda,0x39,0xff,0x9f,0x73,0xc8,0xa7,0x07,0x97,0x55,0xd9,0x9c,0xb3,0x76,0x88,0x7d,0x33,0xa7,0x0c };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey1[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey2[]{ 0x00,0x00,0xb0,0xcf,0x4c,0xed,0x0e,0xc1,0x60,0x00,0xf2,0xf8,0x00,0x3a,0x35,0xf2,0x00,0x00,0x61,0xdc,0xa1,0x48,0xe8,0xde,0x00,0x53,0x00,0xf8,0x00,0x90,0xa3,0x4d };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey2[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey3[]{ 0xe9,0x81,0x88,0xfc,0x58,0xd1,0x1b,0xe9,0x21,0x24,0x64,0x04,0x29,0x6f,0x27,0xaf,0x7d,0x4a,0xad,0xd6,0x81,0x11,0xfa,0x00,0xe5,0x6e,0x00,0xc8,0xa5,0x7c,0x82,0xf2 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey3[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey4[]{ 0x00,0x8c,0xcd,0x2e,0x90,0xb8,0x00,0x8a,0x62,0xd3,0x00,0xbf,0xcd,0x32,0x43,0xfe,0xed,0xb6,0xb2,0xcc,0xf1,0xc3,0x00,0x5c,0xa2,0xa0,0x00,0xa5,0x2d,0xc4,0x3e,0x64 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey4[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey5[]{ 0x35,0xfb,0x03,0x2b,0x9e,0x9c,0x1a,0x27,0x6f,0x5a,0x5d,0x24,0x0b,0x26,0xac,0x83,0x67,0x60,0xaf,0x19,0x00,0xf8,0x00,0xe0,0xf2,0xc0,0xa7,0xde,0x22,0xa9,0x53,0xa1 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey5[i];
}

aes_encrypt_128(aes_key, input, input);
aes_encrypt_128(aes_key, input+16, input+16);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey6[]{ 0xa0,0x90,0xf8,0x5f,0x29,0x1c,0x5b,0xb8,0x7c,0xad,0x04,0x6b,0xe7,0xfa,0xba,0x82,0xe7,0x48,0x38,0xb0,0x1f,0xce,0xe7,0xc8,0x8d,0x1d,0xfb,0x21,0x8c,0x5d,0x87,0xa6 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey6[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey7[]{ 0xdd,0xf6,0x83,0x62,0x12,0x66,0x7d,0xca,0x2e,0xca,0x13,0x93,0xa7,0x3e,0x55,0xab,0x23,0x7f,0xe2,0x92,0xe6,0x78,0xb7,0xbb,0x3d,0xe9,0x7f,0x44,0x35,0x6e,0x89,0xc2 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey7[i];
}

aes_encrypt_128(aes_key, input, input);
aes_encrypt_128(aes_key, input + 16, input + 16);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey8[]{ 0x0c,0x1d,0x7d,0xd2,0xef,0x8e,0xb5,0x48,0x3b,0x00,0xfe,0xfa,0xf9,0x54,0xc6,0x45,0xed,0x67,0x00,0x12,0x3f,0x9e,0x96,0x48,0x2f,0x9f,0x91,0x0f,0x86,0x6d,0x40,0xc6 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey8[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey9[]{ 0xb6,0x79,0xcd,0x35,0xa6,0x21,0x21,0x0c,0x88,0x61,0xe7,0xe5,0x6d,0xc9,0x55,0x49,0xa4,0x54,0x85,0x43,0x98,0x8e,0x68,0x3f,0xdd,0x57,0xa5,0xf1,0xbd,0xc8,0x81,0x85 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey9[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey10[]{ 0x1b,0x2f,0x4f,0x5e,0x44,0x18,0x2f,0xe1,0x5b,0x36,0x3f,0x32,0xf6,0xf0,0x6b,0xf9,0x97,0xc9,0x58,0x61,0x0f,0xf4,0xa9,0xb4,0xb0,0xa3,0x15,0x72,0xa4,0xe9,0x58,0x39 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey10[i];
}

aes_encrypt_128(aes_key, input, input);
aes_encrypt_128(aes_key, input + 16, input + 16);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey11[]{ 0x68,0xf3,0x4a,0xc2,0x00,0x2b,0x8d,0x39,0x64,0x00,0x75,0x00,0xe6,0x32,0xc2,0xb4,0xc4,0x00,0x57,0x3c,0x87,0x00,0x75,0x00,0x94,0x68,0x1c,0x12,0x07,0x00,0xdb,0x09 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey11[i];
}

aes_encrypt_128(aes_key, input, input);
aes_encrypt_128(aes_key, input + 16, input + 16);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey12[]{ 0x00,0x40,0x7f,0xc6,0xd5,0x79,0xa4,0xfb,0xfe,0xa6,0x00,0x32,0xb9,0x6e,0x4f,0xf1,0x62,0xa3,0x00,0x47,0x37,0x4d,0xfd,0x00,0xbe,0x55,0xe2,0x00,0xbe,0x3f,0x00,0xb2 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey12[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey13[]{ 0x27,0xa1,0xed,0xb3,0x45,0xd5,0x5a,0x87,0x6c,0x0d,0x35,0x76,0x29,0x18,0xb1,0x9c,0x5c,0xe2,0x59,0x08,0xe7,0xe6,0x55,0xce,0x7c,0x6f,0x3c,0x5d,0xee,0xa0,0x73,0x11 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey13[i];
}

aes_encrypt_128(aes_key, input, input);
aes_encrypt_128(aes_key, input + 16, input + 16);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey14[]{ 0x75,0x9a,0x74,0x00,0x7a,0x69,0xae,0xed,0x00,0x00,0x00,0x00,0x3a,0x00,0x24,0xaf,0xa3,0x33,0x00,0x00,0x00,0x01,0x44,0x21,0x00,0xdc,0x23,0x00,0x27,0x0e,0x61,0x8a };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey14[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey15[]{ 0x00,0xd1,0x57,0x00,0x2b,0xf1,0x5e,0xea,0xa4,0x79,0x00,0x2c,0xd8,0x88,0x7c,0x00,0x5a,0x1d,0x00,0xfe,0x00,0xf1,0xbf,0x05,0x55,0xe6,0x82,0x00,0x11,0x00,0xe1,0x00 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey15[i];
}

aes_encrypt_128(aes_key, input, input);
aes_encrypt_128(aes_key, input + 16, input + 16);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey16[]{ 0xe9,0x11,0xf0,0x24,0xa1,0x34,0x3a,0xb1,0x1d,0x27,0xda,0xd0,0xe7,0x1f,0x5b,0xbc,0x08,0xde,0xf5,0xab,0x1b,0xca,0x83,0xd7,0xf9,0x52,0xe5,0x3c,0xa0,0xc9,0x0a,0x1a };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey16[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey17[]{ 0xd3,0xe6,0xcb,0x3a,0x00,0x8b,0x25,0x00,0x75,0xb7,0x24,0x12,0x4b,0xc4,0xbe,0x4e,0x4e,0x7e,0xb7,0xeb,0x02,0xeb,0x2b,0x23,0xac,0x1c,0xf9,0x9f,0x7d,0xbf,0xf9,0xf0 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey17[i];
}

aes_encrypt_128(aes_key, input, input);
aes_encrypt_128(aes_key, input + 16, input + 16);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey18[]{ 0x2a,0x1a,0x00,0x18,0x8a,0x00,0x36,0x00,0x3d,0x86,0x16,0x9e,0x00,0x00,0x48,0x00,0x92,0xa3,0x00,0x00,0x00,0xb9,0x6b,0x1f,0x41,0xa9,0x00,0xb9,0xa9,0x2b,0x00,0x00 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey18[i];
}

aes_encrypt_128(aes_key, input, input);
aes_encrypt_128(aes_key, input + 16, input + 16);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey19[]{ 0xaa,0xce,0x0d,0xe0,0xd2,0xfb,0xd2,0x12,0xb1,0x11,0xad,0x65,0x0c,0x45,0xf2,0xe0,0x4a,0x1a,0xed,0x47,0x14,0x44,0x59,0xe9,0x61,0xfa,0x09,0xaf,0xa5,0xb0,0x15,0x15 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey19[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey20[]{ 0xae,0x30,0x50,0x8e,0x8e,0x9e,0x35,0x41,0x7b,0x96,0x56,0x1e,0xe7,0xcc,0xa3,0xf7,0x10,0x59,0xa5,0x62,0xb5,0x57,0xea,0xbc,0x34,0xb7,0xd6,0x0e,0x3a,0x27,0x18,0xb3 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey20[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey21[]{ 0x5f,0x68,0xf7,0x00,0x1e,0xba,0x00,0x83,0x00,0xad,0x54,0xd0,0x91,0x00,0x79,0xb5,0xd8,0x96,0xed,0x67,0x99,0x6a,0xe0,0x6c,0xad,0xdb,0x5a,0x90,0xea,0xa4,0x6d,0xab };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey21[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey22[]{ 0x07,0x9f,0x6e,0x23,0x1e,0x88,0x00,0x00,0xe2,0x99,0x49,0x3f,0x34,0x5e,0x85,0xc9,0xb5,0x06,0x8c,0x4c,0x13,0x4e,0x2f,0x00,0xe1,0xdb,0x47,0xfa,0xba,0x91,0x4c,0xe7 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey22[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey23[]{ 0x16,0x00,0x2f,0x00,0x04,0xd5,0x5b,0x00,0x00,0x58,0xd0,0xb0,0xd1,0x00,0x1d,0x39,0xb9,0xa2,0x8d,0x00,0xc5,0x00,0x00,0x70,0x93,0x95,0x00,0x55,0x6b,0x00,0x00,0x00 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey23[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey24[]{ 0xa2,0x00,0xef,0xd2,0x56,0x00,0x14,0x00,0x49,0x59,0x35,0xd4,0x82,0x00,0xbf,0x1b,0x27,0xaa,0xd8,0x84,0x86,0x8a,0x00,0xf5,0x1c,0x00,0x00,0x2d,0xbf,0x00,0x8f,0xfc };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey24[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey25[]{ 0xc5,0x22,0x4e,0x80,0xbe,0x4e,0xe0,0xe2,0x9e,0x2c,0xc5,0x9c,0xcd,0x42,0x7f,0x65,0xb4,0xd4,0xaa,0xb4,0x15,0xe5,0x00,0xf8,0x55,0x5e,0xa2,0xf8,0x44,0x5c,0x20,0xa7 };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey25[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey26[]{ 0xed,0xed,0x00,0x34,0x83,0x7e,0xef,0x15,0x1d,0x83,0xab,0x98,0xc8,0x74,0xdf,0x34,0x0f,0x36,0xd2,0x7b,0xe3,0xcd,0xc4,0xb6,0x37,0x4e,0x98,0x6c,0xc4,0x0e,0x01,0x5c };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey26[i];
}

encrypt(input);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

uint8_t xorkey27[]{ 0x4d,0x00,0x00,0x65,0x88,0x59,0x48,0x48,0x00,0x00,0x4b,0x9b,0x66,0x00,0xcc,0xd2,0x1b,0x00,0xbd,0x00,0x61,0x00,0x00,0x63,0x00,0x00,0x94,0x00,0x39,0x3c,0x00,0xcb };

for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey27[i];
}

std::reverse(input, input + 32);

for (int i = 0; i < 32; i++)
printf("%02X ", input[i]);
printf("\n");

return 0;
}

后续找不到密文了,大概率是存在与前端的vm代码中,但并没有成功想到解析vmcode的代码。

出题人后续放出hint,放出了解析vmcode的python代码,解析得到流程以及密文。

alt text

将同构代码流程反向得到解密代码,尝试解密该密文发现解密失败,发现delta静态的时候和动调的时候不一样,猜测被修改,对delta下硬件断点跟踪。

alt text

alt text

发现在此处被修改,原先获取到的0xBAE5A071是错误的,而0x3CD46429是正确的,该处代码是对代码段进行CRC校验,检测软件断点的,所以直接动调,若有下断则会被赋值成错误的delta,将Delta修改为正确的0x3CD46429,即可解密。

alt text

注意一点,最后他是将最后一次加密完的密文push,最后再比对常量密文,所以需要将常量密文Reverse后才能正确解密。

alt text

EXP

aes.h

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
/*
*
* Chinese Academy of Sciences
* State Key Laboratory of Information Security
* Institute of Information Engineering
*
* Copyright (C) 2016 Chinese Academy of Sciences
*
* LuoPeng, luopeng@iie.ac.cn
* Updated in May 2016
*
*/
#ifndef AES_128_H
#define AES_128_H

#include <stdio.h>
#include <stdint.h>

#define AES_BLOCK_SIZE 16
#define AES_ROUNDS 10 // 12, 14
#define AES_ROUND_KEY_SIZE 176 // AES-128 has 10 rounds, and there is a AddRoundKey before first round. (10+1)x16=176.

/**
* @purpose: Key schedule for AES-128
* @par[in]key: 16 bytes of master keys
* @par[out]roundkeys: 176 bytes of round keys
*/
void aes_key_schedule_128(const uint8_t *key, uint8_t *roundkeys);

/**
* @purpose: Encryption. The length of plain and cipher should be one block (16 bytes).
* The plaintext and ciphertext may point to the same memory
* @par[in]roundkeys: round keys
* @par[in]plaintext: plain text
* @par[out]ciphertext: cipher text
*/
void aes_encrypt_128(const uint8_t *roundkeys, const uint8_t *plaintext, uint8_t *ciphertext);

/**
* @purpose: Decryption. The length of plain and cipher should be one block (16 bytes).
* The ciphertext and plaintext may point to the same memory
* @par[in]roundkeys: round keys
* @par[in]ciphertext: cipher text
* @par[out]plaintext: plain text
*/
void aes_decrypt_128(const uint8_t *roundkeys, const uint8_t *ciphertext, uint8_t *plaintext);

#endif

aes.cpp

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
/*
*
* Chinese Academy of Sciences
* State Key Laboratory of Information Security
* Institute of Information Engineering
*
* Copyright (C) 2016 Chinese Academy of Sciences
*
* LuoPeng, luopeng@iie.ac.cn
* Updated in Oct 2016
* Updated in Jan 2017, update muliple function on GF(2^8).
*
*/
#include <stdint.h>
#include <stdio.h>

#include "aes.h"

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

/*
* Sbox
*/
static uint8_t SBOX[] = {
0x36, 0x5F, 0xA0, 0x00, 0x4E, 0xA3, 0x4F, 0xF3, 0x58, 0x76, 0x19, 0x83, 0x14, 0x12, 0x77, 0x9F,
0x52, 0x6A, 0x2D, 0x54, 0xB5, 0xE3, 0x02, 0xDA, 0x8B, 0xC5, 0x6D, 0x57, 0xDD, 0x96, 0x5E, 0x2A,
0x22, 0x50, 0x8A, 0x0E, 0x60, 0x32, 0xF0, 0x4B, 0x53, 0x2B, 0x4D, 0x7F, 0x3F, 0xA6, 0xB9, 0x8F,
0xCE, 0x6C, 0x81, 0xD7, 0xCD, 0xDB, 0x5B, 0x5C, 0xC9, 0xED, 0x29, 0x63, 0xC8, 0xB3, 0xF1, 0x30,
0x47, 0xBD, 0x8D, 0xBA, 0x91, 0x42, 0xF7, 0xB7, 0x82, 0x35, 0x5A, 0x3A, 0xD5, 0x2C, 0xD0, 0x7E,
0x33, 0xA7, 0x49, 0xF9, 0x61, 0x13, 0xA1, 0x21, 0xCC, 0x27, 0x48, 0x34, 0x11, 0xBC, 0xCF, 0x9B,
0xAC, 0x20, 0xE4, 0x97, 0x40, 0x9E, 0xB6, 0x1A, 0x08, 0x65, 0x1B, 0x5D, 0x3E, 0x70, 0xE1, 0xC2,
0x3D, 0x05, 0xB8, 0x75, 0x0C, 0xFC, 0xC3, 0x23, 0xEE, 0xF6, 0x1F, 0xAD, 0x01, 0x1D, 0x85, 0xDC,
0x37, 0x64, 0xAE, 0x9C, 0xB4, 0x8C, 0xFD, 0x74, 0x7A, 0x1E, 0xF4, 0x1C, 0x0A, 0x51, 0x3C, 0x16,
0x38, 0x3B, 0xA8, 0x43, 0xA9, 0x78, 0xE7, 0xC6, 0x95, 0xCB, 0x90, 0xE2, 0xD4, 0x87, 0x71, 0x6E,
0xE8, 0x41, 0x17, 0x4A, 0x79, 0xF8, 0xDF, 0x26, 0x10, 0x92, 0x86, 0xC0, 0xB2, 0x04, 0x0B, 0x89,
0x7D, 0xB0, 0x68, 0xAF, 0x09, 0xE9, 0xEB, 0xD9, 0xD8, 0x44, 0x45, 0x8E, 0xF2, 0xAB, 0xEA, 0x06,
0xA5, 0xF5, 0xD1, 0x62, 0x18, 0x99, 0x6B, 0x39, 0x25, 0x7B, 0xB1, 0x46, 0xE6, 0x88, 0x7C, 0x69,
0x72, 0x84, 0x0D, 0x31, 0x4C, 0xD2, 0xE5, 0xEC, 0x59, 0xC7, 0xDE, 0x2E, 0x9D, 0x28, 0x94, 0xA2,
0x0F, 0xCA, 0x2F, 0xBE, 0x67, 0xD3, 0x15, 0x07, 0xFA, 0xA4, 0xFF, 0x6F, 0xAA, 0xC1, 0x56, 0x98,
0x55, 0x93, 0x66, 0x73, 0xD6, 0x9A, 0xE0, 0xFE, 0xBB, 0x80, 0x03, 0xC4, 0xFB, 0xBF, 0xEF, 0x24 };

/*
* Inverse Sboxs
*/
static uint8_t INV_SBOX[256] = {
0x03,0x7C,0x16,0xFA,0xAD,0x71,0xBF,0xE7,0x68,0xB4,0x8C,0xAE,0x74,0xD2,0x23,0xE0,0xA8,0x5C,0x0D,0x55,0x0C,0xE6,0x8F,0xA2,0xC4,0x0A,0x67,0x6A,0x8B,0x7D,0x89,0x7A,0x61,0x57,0x20,0x77,0xFF,0xC8,0xA7,0x59,0xDD,0x3A,0x1F,0x29,0x4D,0x12,0xDB,0xE2,0x3F,0xD3,0x25,0x50,0x5B,0x49,0x00,0x80,0x90,0xC7,0x4B,0x91,0x8E,0x70,0x6C,0x2C,0x64,0xA1,0x45,0x93,0xB9,0xBA,0xCB,0x40,0x5A,0x52,0xA3,0x27,0xD4,0x2A,0x04,0x06,0x21,0x8D,0x10,0x28,0x13,0xF0,0xEE,0x1B,0x08,0xD8,0x4A,0x36,0x37,0x6B,0x1E,0x01,0x24,0x54,0xC3,0x3B,0x81,0x69,0xF2,0xE4,0xB2,0xCF,0x11,0xC6,0x31,0x1A,0x9F,0xEB,0x6D,0x9E,0xD0,0xF3,0x87,0x73,0x09,0x0E,0x95,0xA4,0x88,0xC9,0xCE,0xB0,0x4F,0x2B,0xF9,0x32,0x48,0x0B,0xD1,0x7E,0xAA,0x9D,0xCD,0xAF,0x22,0x18,0x85,0x42,0xBB,0x2F,0x9A,0x44,0xA9,0xF1,0xDE,0x98,0x1D,0x63,0xEF,0xC5,0xF5,0x5F,0x83,0xDC,0x65,0x0F,0x02,0x56,0xDF,0x05,0xE9,0xC0,0x2D,0x51,0x92,0x94,0xEC,0xBD,0x60,0x7B,0x82,0xB3,0xB1,0xCA,0xAC,0x3D,0x84,0x14,0x66,0x47,0x72,0x2E,0x43,0xF8,0x5D,0x41,0xE3,0xFD,0xAB,0xED,0x6F,0x76,0xFB,0x19,0x97,0xD9,0x3C,0x38,0xE1,0x99,0x58,0x34,0x30,0x5E,0x4E,0xC2,0xD5,0xE5,0x9C,0x4C,0xF4,0x33,0xB8,0xB7,0x17,0x35,0x7F,0x1C,0xDA,0xA6,0xF6,0x6E,0x9B,0x15,0x62,0xD6,0xCC,0x96,0xA0,0xB5,0xBE,0xB6,0xD7,0x39,0x78,0xFE,0x26,0x3E,0xBC,0x07,0x8A,0xC1,0x79,0x46,0xA5,0x53,0xE8,0xFC,0x75,0x86,0xF7,0xEA };

/**
* 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++;
}

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

// SubBytes
for (i = 0; i < AES_BLOCK_SIZE; ++i) {
*(tmp+i) = SBOX[*(ciphertext+i)];
}
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 ^ 0x44;
ciphertext[i+1] = mul2(tmp[i+1] ^ tmp[i+2]) ^ tmp[i+1] ^ t ^ 0x44;
ciphertext[i+2] = mul2(tmp[i+2] ^ tmp[i+3]) ^ tmp[i+2] ^ t ^ 0x44;
ciphertext[i+3] = mul2(tmp[i+3] ^ tmp[i] ) ^ tmp[i+3] ^ t ^ 0x44;
}

// 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 ^ 0x44;
plaintext[i+1] ^= t ^ v ^ 0x44;
plaintext[i+2] ^= t ^ u ^ 0x44;
plaintext[i+3] ^= t ^ v ^ 0x44;
}

// Inverse ShiftRows
inv_shift_rows(plaintext);

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

roundkeys -= 16;

}

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

}

main.cpp

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
#include <iostream>
#include <windows.h>
#include <algorithm>
#include "aes.h"

static inline uint32_t f_inside(uint32_t z, uint32_t y, uint32_t sum, int p, const uint32_t* k) {
uint32_t e = (sum >> 2) & 0xFFu;
uint32_t t1 = ((z >> 3) ^ (y << 6));
uint32_t t2 = ((y >> 4) ^ (z * 32u));
uint32_t t3 = ((sum ^ y) + ((k[((p ^ e) & 3)] ^ z)));
return (t1 + t2) ^ t3;
}

static inline uint32_t g_last(uint32_t z, uint32_t y0, uint32_t sum, int p, const uint32_t* k) {
uint32_t e = (sum >> 2) & 0xFFu;
uint32_t t1 = ((z >> 4) ^ (y0 * 8u));
uint32_t t2 = ((y0 >> 6) ^ (z * 4u));
uint32_t t3 = ((sum ^ y0) + ((k[((p ^ e) & 3)] ^ z)));
return (t1 + t2) ^ t3;
}

static void dec_round(uint32_t* v_new, uint32_t sum, const uint32_t* k) {
const int n = 8;
uint32_t v_old[8];

v_old[7] = v_new[7] - g_last(v_new[6], v_new[0], sum, n - 1, k);

for (int p = n - 2; p >= 1; --p) {
v_old[p] = v_new[p] - f_inside(v_new[p - 1], v_old[p + 1], sum, p, k);
}

v_old[0] = v_new[0] - f_inside(v_old[7], v_old[1], sum, 0, k);

std::memcpy(v_new, v_old, sizeof(v_old));
}

void decrypt(uint8_t* input)
{
const unsigned char key_bytes[16] = {
0xA4, 0x60, 0x78, 0x7B, 0x02, 0x54, 0xEB, 0x54,
0x35, 0x9E, 0x7F, 0xFF, 0x27, 0xCA, 0x47, 0xBF,
};
uint32_t k[4];
std::memcpy(k, key_bytes, 16);
const uint32_t Delta = 0x3CD46429;//0xE4D0C2B5;//0xBAE5A071u;
uint32_t v[8];
std::memcpy(v, input, 32);
uint32_t rounds = 46;
uint32_t sum = Delta * rounds;
for (uint32_t r = 0; r < rounds; ++r) {
dec_round(v, sum, k);
sum -= Delta;
}
memcpy(input, v, 32);
}

unsigned char aes_key[176] = {
0xCF, 0x95, 0x5E, 0x20, 0x94, 0x15, 0x34, 0x64, 0x9A, 0x54, 0x53, 0xE9, 0x2F, 0x51, 0x33, 0x41,
0x2D, 0x48, 0x7C, 0xF5, 0x37, 0xAB, 0x09, 0x32, 0xB5, 0xFF, 0x4B, 0x7B, 0x53, 0xD5, 0x0F, 0x47,
0xBF, 0xFA, 0x79, 0x81, 0x11, 0x2A, 0x0E, 0x76, 0x94, 0xBA, 0xA8, 0xA1, 0xF8, 0xED, 0xF4, 0xDC,
0x4F, 0x85, 0x9C, 0x47, 0xCB, 0xF5, 0x52, 0x26, 0xEB, 0xE9, 0x5F, 0xF0, 0x62, 0x80, 0x75, 0x85,
0x0E, 0x2F, 0x02, 0x74, 0xB8, 0x5B, 0x0A, 0x4A, 0x6A, 0x56, 0xAA, 0x57, 0x01, 0xDA, 0xFB, 0x5A,
0x18, 0x7D, 0x49, 0x65, 0x14, 0xC4, 0x68, 0xE5, 0xCF, 0x52, 0x58, 0x56, 0xD9, 0x11, 0x74, 0x81,
0x4A, 0x2E, 0xA5, 0x54, 0xCB, 0x5D, 0xB9, 0x36, 0x80, 0xE1, 0x3C, 0x0C, 0x2B, 0x1E, 0x09, 0xB1,
0x8A, 0x0B, 0xA2, 0x65, 0x28, 0xCA, 0x63, 0x6A, 0x15, 0x65, 0xEB, 0xCC, 0xC7, 0x6F, 0x5C, 0xAF,
0x19, 0x43, 0x65, 0x8B, 0x26, 0x31, 0xC0, 0x3C, 0x66, 0x8A, 0x65, 0x1E, 0x34, 0xBC, 0x27, 0x36,
0x1E, 0x01, 0xC7, 0xC8, 0x07, 0x06, 0xE0, 0x9E, 0x2C, 0x91, 0xB0, 0x10, 0x03, 0xA5, 0xF2, 0xC4,
0x1A, 0xEC, 0xFB, 0x19, 0xA3, 0x5D, 0x63, 0xF0, 0xF1, 0x99, 0x7A, 0x1C, 0x5E, 0x87, 0x11, 0x1B
};

// 解密
int main()
{
uint8_t input[]{ 18, 104, 119, 159, 83, 111, 185, 223, 152, 168, 8, 71, 28, 98, 187, 134, 159, 126, 60, 1, 116, 184, 130, 175, 199, 219, 240, 235, 229, 20, 87, 30 };

// 注意要先Reverse
std::reverse(input, input + 32);

uint8_t xorkey28[]{ 0x4D,0x00,0x00,0x65,0x88,0x59,0x48,0x48,0x00,0x00,0x4B,0x9B,0x66,0x00,0xCC,0xD2,0x1B,0x00,0xBD,0x00,0x61,0x00,0x00,0x63,0x00,0x00,0x94,0x00,0x39,0x3C,0x00,0xCB };
for (int i = 0; i < 32; i++)
{
input[i] ^= xorkey28[i];
}

uint8_t xorkey26[]{ 0xed,0xed,0x00,0x34,0x83,0x7e,0xef,0x15,0x1d,0x83,0xab,0x98,0xc8,0x74,0xdf,0x34,0x0f,0x36,0xd2,0x7b,0xe3,0xcd,0xc4,0xb6,0x37,0x4e,0x98,0x6c,0xc4,0x0e,0x01,0x5c };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey26[i];

uint8_t xorkey25[]{ 0xc5,0x22,0x4e,0x80,0xbe,0x4e,0xe0,0xe2,0x9e,0x2c,0xc5,0x9c,0xcd,0x42,0x7f,0x65,0xb4,0xd4,0xaa,0xb4,0x15,0xe5,0x00,0xf8,0x55,0x5e,0xa2,0xf8,0x44,0x5c,0x20,0xa7 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey25[i];

uint8_t xorkey24[]{ 0xa2,0x00,0xef,0xd2,0x56,0x00,0x14,0x00,0x49,0x59,0x35,0xd4,0x82,0x00,0xbf,0x1b,0x27,0xaa,0xd8,0x84,0x86,0x8a,0x00,0xf5,0x1c,0x00,0x00,0x2d,0xbf,0x00,0x8f,0xfc };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey24[i];

uint8_t xorkey23[]{ 0x16,0x00,0x2f,0x00,0x04,0xd5,0x5b,0x00,0x00,0x58,0xd0,0xb0,0xd1,0x00,0x1d,0x39,0xb9,0xa2,0x8d,0x00,0xc5,0x00,0x00,0x70,0x93,0x95,0x00,0x55,0x6b,0x00,0x00,0x00 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey23[i];

uint8_t xorkey22[]{ 0x07,0x9f,0x6e,0x23,0x1e,0x88,0x00,0x00,0xe2,0x99,0x49,0x3f,0x34,0x5e,0x85,0xc9,0xb5,0x06,0x8c,0x4c,0x13,0x4e,0x2f,0x00,0xe1,0xdb,0x47,0xfa,0xba,0x91,0x4c,0xe7 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey22[i];

uint8_t xorkey21[]{ 0x5f,0x68,0xf7,0x00,0x1e,0xba,0x00,0x83,0x00,0xad,0x54,0xd0,0x91,0x00,0x79,0xb5,0xd8,0x96,0xed,0x67,0x99,0x6a,0xe0,0x6c,0xad,0xdb,0x5a,0x90,0xea,0xa4,0x6d,0xab };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey21[i];

uint8_t xorkey20[]{ 0xae,0x30,0x50,0x8e,0x8e,0x9e,0x35,0x41,0x7b,0x96,0x56,0x1e,0xe7,0xcc,0xa3,0xf7,0x10,0x59,0xa5,0x62,0xb5,0x57,0xea,0xbc,0x34,0xb7,0xd6,0x0e,0x3a,0x27,0x18,0xb3 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey20[i];

uint8_t xorkey19[]{ 0xaa,0xce,0x0d,0xe0,0xd2,0xfb,0xd2,0x12,0xb1,0x11,0xad,0x65,0x0c,0x45,0xf2,0xe0,0x4a,0x1a,0xed,0x47,0x14,0x44,0x59,0xe9,0x61,0xfa,0x09,0xaf,0xa5,0xb0,0x15,0x15 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey19[i];

uint8_t xorkey18[]{ 0x2a,0x1a,0x00,0x18,0x8a,0x00,0x36,0x00,0x3d,0x86,0x16,0x9e,0x00,0x00,0x48,0x00,0x92,0xa3,0x00,0x00,0x00,0xb9,0x6b,0x1f,0x41,0xa9,0x00,0xb9,0xa9,0x2b,0x00,0x00 };
aes_decrypt_128(aes_key, input, input); aes_decrypt_128(aes_key, input + 16, input + 16);
for (int i = 0; i < 32; i++) input[i] ^= xorkey18[i];

uint8_t xorkey17[]{ 0xd3,0xe6,0xcb,0x3a,0x00,0x8b,0x25,0x00,0x75,0xb7,0x24,0x12,0x4b,0xc4,0xbe,0x4e,0x4e,0x7e,0xb7,0xeb,0x02,0xeb,0x2b,0x23,0xac,0x1c,0xf9,0x9f,0x7d,0xbf,0xf9,0xf0 };
aes_decrypt_128(aes_key, input, input); aes_decrypt_128(aes_key, input + 16, input + 16);
for (int i = 0; i < 32; i++) input[i] ^= xorkey17[i];

uint8_t xorkey16[]{ 0xe9,0x11,0xf0,0x24,0xa1,0x34,0x3a,0xb1,0x1d,0x27,0xda,0xd0,0xe7,0x1f,0x5b,0xbc,0x08,0xde,0xf5,0xab,0x1b,0xca,0x83,0xd7,0xf9,0x52,0xe5,0x3c,0xa0,0xc9,0x0a,0x1a };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey16[i];

uint8_t xorkey15[]{ 0x00,0xd1,0x57,0x00,0x2b,0xf1,0x5e,0xea,0xa4,0x79,0x00,0x2c,0xd8,0x88,0x7c,0x00,0x5a,0x1d,0x00,0xfe,0x00,0xf1,0xbf,0x05,0x55,0xe6,0x82,0x00,0x11,0x00,0xe1,0x00 };
aes_decrypt_128(aes_key, input, input); aes_decrypt_128(aes_key, input + 16, input + 16);
for (int i = 0; i < 32; i++) input[i] ^= xorkey15[i];

uint8_t xorkey14[]{ 0x75,0x9a,0x74,0x00,0x7a,0x69,0xae,0xed,0x00,0x00,0x00,0x00,0x3a,0x00,0x24,0xaf,0xa3,0x33,0x00,0x00,0x00,0x01,0x44,0x21,0x00,0xdc,0x23,0x00,0x27,0x0e,0x61,0x8a };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey14[i];

uint8_t xorkey13[]{ 0x27,0xa1,0xed,0xb3,0x45,0xd5,0x5a,0x87,0x6c,0x0d,0x35,0x76,0x29,0x18,0xb1,0x9c,0x5c,0xe2,0x59,0x08,0xe7,0xe6,0x55,0xce,0x7c,0x6f,0x3c,0x5d,0xee,0xa0,0x73,0x11 };
aes_decrypt_128(aes_key, input, input); aes_decrypt_128(aes_key, input + 16, input + 16);
for (int i = 0; i < 32; i++) input[i] ^= xorkey13[i];

uint8_t xorkey12[]{ 0x00,0x40,0x7f,0xc6,0xd5,0x79,0xa4,0xfb,0xfe,0xa6,0x00,0x32,0xb9,0x6e,0x4f,0xf1,0x62,0xa3,0x00,0x47,0x37,0x4d,0xfd,0x00,0xbe,0x55,0xe2,0x00,0xbe,0x3f,0x00,0xb2 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey12[i];

uint8_t xorkey11[]{ 0x68,0xf3,0x4a,0xc2,0x00,0x2b,0x8d,0x39,0x64,0x00,0x75,0x00,0xe6,0x32,0xc2,0xb4,0xc4,0x00,0x57,0x3c,0x87,0x00,0x75,0x00,0x94,0x68,0x1c,0x12,0x07,0x00,0xdb,0x09 };
aes_decrypt_128(aes_key, input, input); aes_decrypt_128(aes_key, input + 16, input + 16);
for (int i = 0; i < 32; i++) input[i] ^= xorkey11[i];

uint8_t xorkey10[]{ 0x1b,0x2f,0x4f,0x5e,0x44,0x18,0x2f,0xe1,0x5b,0x36,0x3f,0x32,0xf6,0xf0,0x6b,0xf9,0x97,0xc9,0x58,0x61,0x0f,0xf4,0xa9,0xb4,0xb0,0xa3,0x15,0x72,0xa4,0xe9,0x58,0x39 };
aes_decrypt_128(aes_key, input, input); aes_decrypt_128(aes_key, input + 16, input + 16);
for (int i = 0; i < 32; i++) input[i] ^= xorkey10[i];

uint8_t xorkey9[]{ 0xb6,0x79,0xcd,0x35,0xa6,0x21,0x21,0x0c,0x88,0x61,0xe7,0xe5,0x6d,0xc9,0x55,0x49,0xa4,0x54,0x85,0x43,0x98,0x8e,0x68,0x3f,0xdd,0x57,0xa5,0xf1,0xbd,0xc8,0x81,0x85 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey9[i];

uint8_t xorkey8[]{ 0x0c,0x1d,0x7d,0xd2,0xef,0x8e,0xb5,0x48,0x3b,0x00,0xfe,0xfa,0xf9,0x54,0xc6,0x45,0xed,0x67,0x00,0x12,0x3f,0x9e,0x96,0x48,0x2f,0x9f,0x91,0x0f,0x86,0x6d,0x40,0xc6 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey8[i];

uint8_t xorkey7[]{ 0xdd,0xf6,0x83,0x62,0x12,0x66,0x7d,0xca,0x2e,0xca,0x13,0x93,0xa7,0x3e,0x55,0xab,0x23,0x7f,0xe2,0x92,0xe6,0x78,0xb7,0xbb,0x3d,0xe9,0x7f,0x44,0x35,0x6e,0x89,0xc2 };
aes_decrypt_128(aes_key, input, input); aes_decrypt_128(aes_key, input + 16, input + 16);
for (int i = 0; i < 32; i++) input[i] ^= xorkey7[i];

uint8_t xorkey6[]{ 0xa0,0x90,0xf8,0x5f,0x29,0x1c,0x5b,0xb8,0x7c,0xad,0x04,0x6b,0xe7,0xfa,0xba,0x82,0xe7,0x48,0x38,0xb0,0x1f,0xce,0xe7,0xc8,0x8d,0x1d,0xfb,0x21,0x8c,0x5d,0x87,0xa6 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey6[i];

uint8_t xorkey5[]{ 0x35,0xfb,0x03,0x2b,0x9e,0x9c,0x1a,0x27,0x6f,0x5a,0x5d,0x24,0x0b,0x26,0xac,0x83,0x67,0x60,0xaf,0x19,0x00,0xf8,0x00,0xe0,0xf2,0xc0,0xa7,0xde,0x22,0xa9,0x53,0xa1 };
aes_decrypt_128(aes_key, input, input); aes_decrypt_128(aes_key, input + 16, input + 16);
for (int i = 0; i < 32; i++) input[i] ^= xorkey5[i];

uint8_t xorkey4[]{ 0x00,0x8c,0xcd,0x2e,0x90,0xb8,0x00,0x8a,0x62,0xd3,0x00,0xbf,0xcd,0x32,0x43,0xfe,0xed,0xb6,0xb2,0xcc,0xf1,0xc3,0x00,0x5c,0xa2,0xa0,0x00,0xa5,0x2d,0xc4,0x3e,0x64 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey4[i];

uint8_t xorkey3[]{ 0xe9,0x81,0x88,0xfc,0x58,0xd1,0x1b,0xe9,0x21,0x24,0x64,0x04,0x29,0x6f,0x27,0xaf,0x7d,0x4a,0xad,0xd6,0x81,0x11,0xfa,0x00,0xe5,0x6e,0x00,0xc8,0xa5,0x7c,0x82,0xf2 };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey3[i];

uint8_t xorkey2[]{ 0x00,0x00,0xb0,0xcf,0x4c,0xed,0x0e,0xc1,0x60,0x00,0xf2,0xf8,0x00,0x3a,0x35,0xf2,0x00,0x00,0x61,0xdc,0xa1,0x48,0xe8,0xde,0x00,0x53,0x00,0xf8,0x00,0x90,0xa3,0x4d };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey2[i];

uint8_t xorkey1[]{ 0x0c,0xa2,0xd9,0xf7,0x95,0x66,0xa9,0x0b,0x35,0xe9,0x20,0x09,0x08,0xda,0x39,0xff,0x9f,0x73,0xc8,0xa7,0x07,0x97,0x55,0xd9,0x9c,0xb3,0x76,0x88,0x7d,0x33,0xa7,0x0c };
decrypt(input); for (int i = 0; i < 32; i++) input[i] ^= xorkey1[i];

std::reverse(input, input + 32);

printf("%.32s\n", input);

return 0;
}