Ikoct的饮冰室

你愿意和我学一辈子二进制吗?

0%

UTCTF2024逆向方向部分wp

参赛ID:1K0CT, 无队伍

解出:Fruit Deals, PES-128

Fruit Deals | vba病毒

附件是一个EXCEL表格 xml可以执行vba宏 可以使用oletools中的olevba.exe导出vba宏或直接打开EXCEL查看:

olevba.exe -c input > output

image-20240404095758389

得到本题的两个模块 分别是用随机数的base64编码填充一个页, 按照这个页中的数据来拼接一条cmd Shellcode 按照题目描述 要通过Shellcode从服务器下载一个文件 获取这个文件名即是flag

base64填充的页是Sheet2 很明显被隐藏同样在显示代码界面将其属性改为可见然后手动拼接Shellcode得到flag:utflag{banANA-Hakrz09182afd4.exe}

image-20240404100416705

PES-128 | 并行式加密

总体来说题目的加密逻辑不难 但是多线程并行的加密方式弥补了这一点 具体看IDA伪代码:

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
main:
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 v3; // rax
_BYTE *v4; // rbp
__int64 v5; // rdx
_DWORD *v6; // rax
char *index; // rcx
int v8; // edx
int v9; // eax
unsigned __int64 v10; // rcx
unsigned int v11; // eax
unsigned int v12; // edx
unsigned int v13; // eax
__int64 v14; // rsi
__int64 v15; // r13
void *end; // rbp
_QWORD *v17; // rax
__int64 v18; // rdi
std::thread *v19; // rbp
char id; // bl
std::thread *v21; // r13
__int64 arg; // rax
__m128i v23; // xmm0
unsigned __int8 *v24; // r12
std::thread *v25; // rbx
const char *v26; // rsi
unsigned __int8 *reslut; // rdx
__int64 v28; // r14
__int64 v29; // rcx
char *v30; // rbx
bool v31; // zf
_BYTE *v32; // r13
__int64 (__fastcall *v33)(); // rax
char v34; // al
__int64 (__fastcall *v36)(); // rax
size_t v37; // rax
size_t v38; // rdx
bool v39; // cf
unsigned __int64 v40; // rax
unsigned __int64 v41; // rbx
_BYTE *v42; // r14
std::thread *v43; // r8
char *v44; // r9
char *v45; // r15
char *v46; // r10
__m128i v47; // xmm5
_BYTE *v48; // rax
__m128i v49; // [rsp+0h] [rbp-188h] BYREF
size_t padding; // [rsp+18h] [rbp-170h]
void *src; // [rsp+20h] [rbp-168h]
std::thread *v52; // [rsp+28h] [rbp-160h]
__int64 lenth; // [rsp+30h] [rbp-158h]
__int64 *v54; // [rsp+38h] [rbp-150h]
char *v55; // [rsp+40h] [rbp-148h]
char *v56; // [rsp+48h] [rbp-140h]
__int64 v57; // [rsp+50h] [rbp-138h] BYREF
__int64 v58; // [rsp+58h] [rbp-130h] BYREF
void *hex_vec[2]; // [rsp+60h] [rbp-128h] BYREF
_BYTE *v60; // [rsp+70h] [rbp-118h]
__int64 v61; // [rsp+80h] [rbp-108h] BYREF
_QWORD *v62; // [rsp+88h] [rbp-100h]
__int64 v63; // [rsp+90h] [rbp-F8h]
__int64 v64; // [rsp+98h] [rbp-F0h]
void *input[2]; // [rsp+A0h] [rbp-E8h] BYREF
__int64 v66[2]; // [rsp+B0h] [rbp-D8h] BYREF
__int64 v67[25]; // [rsp+C0h] [rbp-C8h] BYREF

v67[17] = __readfsqword(0x28u);
input[1] = 0LL;
v54 = v66;
input[0] = v66;
LOBYTE(v66[0]) = 0;
v3 = *(std::cin[0] - 24);
v4 = *(&std::cin[30] + v3);
if ( !v4 )
std::__throw_bad_cast();
if ( v4[56] )
{
v5 = v4[67];
}
else
{
std::ctype<char>::_M_widen_init(*(&std::cin[30] + v3), a2, a3);
v5 = 10LL;
v36 = *(*v4 + 48LL);
if ( v36 != std::ctype<char>::do_widen )
v5 = (v36)(v4, 10LL, 10LL);
}
std::getline<char,std::char_traits<char>,std::allocator<char>>(std::cin, input, v5);
to_vec(hex_vec, input);
lenth = (LOBYTE(hex_vec[1]) - LOBYTE(hex_vec[0])) & 0xF;
padding = 16 - lenth;
v6 = operator new(16 - lenth);
src = v6;
if ( (16 - lenth) < 8 )
{
if ( ((16 - lenth) & 4) != 0 )
{
*v6 = 0;
*(v6 + padding - 4) = 0;
}
else
{
v34 = padding;
if ( padding )
{
*src = 0;
if ( (v34 & 2) != 0 )
*(src + padding - 2) = 0;
}
}
}
else
{
index = src;
*src = 0LL;
v8 = padding;
*&index[padding - 8] = 0LL;
v9 = index;
v10 = (index + 8) & 0xFFFFFFFFFFFFFFF8LL;
v11 = (v8 + v9 - v10) & 0xFFFFFFF8;
if ( v11 >= 8 )
{
v12 = v11 & 0xFFFFFFF8;
v13 = 0;
do
{
v14 = v13;
v13 += 8;
*(v10 + v14) = 0LL;
}
while ( v13 < v12 );
}
}
v15 = v60;
end = hex_vec[1];
if ( padding > v60 - hex_vec[1] )
{
v37 = hex_vec[1] - hex_vec[0];
if ( padding > 0x7FFFFFFFFFFFFFFFLL - (hex_vec[1] - hex_vec[0]) )
std::__throw_length_error("vector::_M_range_insert");
v38 = padding;
if ( padding < v37 )
v38 = hex_vec[1] - hex_vec[0];
v39 = __CFADD__(v38, v37);
v40 = v38 + v37;
v41 = v40;
if ( v39 )
{
v41 = 0x7FFFFFFFFFFFFFFFLL;
}
else
{
v42 = 0LL;
if ( !v40 )
goto LABEL_63;
if ( v40 > 0x7FFFFFFFFFFFFFFFLL )
v41 = 0x7FFFFFFFFFFFFFFFLL;
}
v48 = operator new(v41);
v15 = v60;
v42 = v48;
LABEL_63:
v43 = hex_vec[0];
v44 = &v42[end - hex_vec[0]];
v45 = (hex_vec[1] - end);
v46 = &v44[padding];
v49 = _mm_unpacklo_epi64(v42, (hex_vec[1] + v42 - hex_vec[0] + padding));
if ( end == hex_vec[0] )
{
qmemcpy(v44, src, padding);
if ( !v45 )
goto LABEL_65;
}
else
{
v56 = &v44[padding];
v52 = hex_vec[0];
v55 = &v42[end - hex_vec[0]];
memmove(v42, hex_vec[0], end - hex_vec[0]);
v43 = v52;
qmemcpy(v55, src, padding);
v46 = v56;
if ( !v45 )
goto LABEL_70;
}
v52 = v43;
memmove(v46, end, v45);
v43 = v52;
LABEL_65:
if ( !v43 )
{
LABEL_66:
v47 = _mm_load_si128(&v49);
v60 = &v42[v41];
*hex_vec = v47;
goto LABEL_10;
}
LABEL_70:
operator delete(v43, v15 - v43);
goto LABEL_66;
}
memmove(hex_vec[1], src, padding);
hex_vec[1] = hex_vec[1] + padding;
LABEL_10:
v52 = v67;
memset(v67, 0, 0x80uLL);
v61 = 16LL;
v62 = 0LL;
v63 = 0LL;
v64 = 0LL;
v17 = operator new[](512LL, 64LL);
*v17 = 0LL;
v17[63] = 0LL;
memset(((v17 + 1) & 0xFFFFFFFFFFFFFFF8LL), 0, 8LL * ((v17 - ((v17 + 8) & 0xFFFFFFF8) + 512) >> 3));
v18 = v62;
v62 = v17;
if ( v18 )
operator delete[](v18, 64LL);
v19 = v52;
id = 1;
v21 = v52;
v49 = _mm_unpacklo_epi64(hex_vec, &v61);
do
{
v57 = 0LL;
arg = operator new(0x28uLL);
v23 = _mm_load_si128(&v49);
*arg = &off_556C970A5C80;
*(arg + 8) = id;
*(arg + 32) = binswap;
*(arg + 16) = v23;
v58 = arg;
std::thread::_M_start_thread(&v57, &v58, &pthread_create);
if ( v58 )
(*(*v58 + 8LL))(v58);
v24 = *v19;
if ( *v19 )
goto LABEL_73;
++id;
v19 = (v19 + 8);
*(v19 - 1) = v57;
}
while ( id != 17 );
v25 = (v52 + 128);
do
{
std::thread::join(v21);
v21 = (v21 + 8);
}
while ( v25 != v21 );
v26 = "%ld\n\n";
__printf_chk(1LL, "%ld\n\n", hex_vec[1] - hex_vec[0]);
reslut = hex_vec[0];
v28 = lenth - 16;
if ( lenth - 16 + hex_vec[1] - hex_vec[0] )
{
do
{
v29 = std::cout[0];
v30 = std::cout + *(std::cout[0] - 24LL);
v31 = v30[225] == 0;
*(v30 + 6) = *(v30 + 6) & 0xFFFFFFB5 | 8;
if ( v31 )
{
v32 = *(v30 + 30);
if ( !v32 )
std::__throw_bad_cast();
if ( !v32[56] )
{
std::ctype<char>::_M_widen_init(*(v30 + 30), v26, reslut);
v33 = *(*v32 + 48LL);
if ( v33 != std::ctype<char>::do_widen )
(v33)(v32, 32LL);
v29 = std::cout[0];
reslut = hex_vec[0];
}
v30[225] = 1;
}
v30[224] = 48;
*(&std::cout[2] + *(v29 - 24)) = 2LL;
v26 = v24[reslut];
std::ostream::operator<<(std::cout, v26);
reslut = hex_vec[0];
++v24;
}
while ( (v28 + hex_vec[1] - hex_vec[0]) > v24 );
}
if ( v62 )
operator delete[](v62, 64LL);
if ( v67[15]
|| v67[14]
|| v67[13]
|| v67[12]
|| v67[11]
|| v67[10]
|| v67[9]
|| v67[8]
|| v67[7]
|| v67[6]
|| v67[5]
|| v67[4]
|| v67[3]
|| v67[2]
|| v67[1]
|| v67[0] )
{
LABEL_73:
std::terminate();
}
operator delete(src, padding);
if ( hex_vec[0] )
operator delete(hex_vec[0], v60 - hex_vec[0]);
if ( input[0] != v54 )
operator delete(input[0], v66[0] + 1);
return 0LL;
}

对无符号的C++程序静态分析的效果比动态分析的效率差很多 如果没有很强的反调试措施尽量通过动调来获取某个方法/函数的作用 对于反调试措施强的程序可以通过方法/程序中的报错信息来识别内置方法/函数

其中开启线程进行加密的主要逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
v49 = _mm_unpacklo_epi64(hex_vec, &v61);
do
{
v57 = 0LL;
arg = operator new(0x28uLL);
v23 = _mm_load_si128(&v49);
*arg = &off_556C970A5C80;
*(arg + 8) = id;
*(arg + 32) = binswap;
*(arg + 16) = v23;
v58 = arg;
std::thread::_M_start_thread(&v57, &v58, &pthread_create);
if ( v58 )
(*(*v58 + 8LL))(v58);
v24 = *v19;
if ( *v19 )
goto LABEL_73;
++id;
v19 = (v19 + 8);
*(v19 - 1) = v57;
}while ( id != 17 );

要启动的线程函数, 线程函数的参数通过arg传入 线程函数:

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
void __fastcall binswap(_QWORD *a1, __int64 *data_to_encrypt, unsigned __int8 id)
{
__int64 piece; // r12
signed __int8 *v5; // r13
volatile signed __int32 *v6; // r15
unsigned int index; // ebp
char *nowpiece; // rsi
char v9; // al
int trans; // edx
unsigned __int64 v11; // rax
signed __int8 v12; // bl
__int64 v13; // rsi
signed __int8 v14; // r10
signed __int8 v15; // r8
__int64 v16; // rcx
unsigned __int64 v17; // rdx
__int64 v18; // rdi
unsigned __int64 v19; // rcx
unsigned __int64 v20; // rsi
volatile signed __int8 *v21; // rsi
signed __int8 v22; // al
volatile unsigned __int32 v23; // r14d
unsigned int v24; // eax
unsigned int v25; // r12d
int v26; // edi
bool v27; // zf
signed __int8 v28; // r12
volatile signed __int8 *v29; // rsi
signed __int8 v30; // al
volatile signed __int32 *v32; // [rsp+8h] [rbp-80h]
pthread_t v34; // [rsp+18h] [rbp-70h]
unsigned int threadid; // [rsp+28h] [rbp-60h]
int v36; // [rsp+2Ch] [rbp-5Ch]
unsigned __int64 base; // [rsp+38h] [rbp-50h]
__int64 v38[9]; // [rsp+40h] [rbp-48h] BYREF

piece = *data_to_encrypt; // data in vector
v38[1] = __readfsqword(0x28u);
if ( piece != data_to_encrypt[1] ) // to end
{
v5 = a1 + 25;
base = 0LL;
v34 = pthread_self();
v32 = (&unk_556C970A6280 + ((32 * (a1 + 25)) & 0x780));
v6 = v32 + 16;
threadid = id;
do
{
index = threadid;
v36 = 16;
do
{
nowpiece = (piece + (index + base));
v9 = *nowpiece;
trans = *nowpiece & 1;
if ( (*nowpiece & 1) != 0 )
trans = 1 << (table[8 * (threadid - 1)] - 1);
if ( (v9 & 2) != 0 )
trans |= 1 << (table[8 * (threadid - 1) + 1] - 1);
if ( (v9 & 4) != 0 )
trans |= 1 << (table[8 * (threadid - 1) + 2] - 1);
if ( (v9 & 8) != 0 )
trans |= 1 << (table[8 * (threadid - 1) + 3] - 1);
if ( (v9 & 0x10) != 0 )
trans |= 1 << (table[8 * (threadid - 1) + 4] - 1);
if ( (v9 & 0x20) != 0 )
trans |= 1 << (table[8 * (threadid - 1) + 5] - 1);
if ( (v9 & 0x40) != 0 )
trans |= 1 << (table[8 * (threadid - 1) + 6] - 1);
if ( v9 < 0 )
trans |= 1 << (table[8 * (threadid - 1) + 7] - 1);
*nowpiece = trans;
v38[0] = v34;
v11 = std::_Hash_bytes(v38, 8uLL, 0xC70F6907uLL);
v12 = *v5;
v13 = *a1;
v14 = *v5 + 1;
v15 = *v5 + 2;
v16 = *a1 + 1LL;
v17 = v11 % (v16 >> 1);
if ( *a1 > 1uLL )
{
v18 = 0LL;
while ( 2 )
{
v19 = v16 >> 1;
if ( (v13 & 1) == 0 )
{
while ( 1 )
{
if ( v19 == v17 )
{
v20 = 0LL;
v17 = 0LL;
}
else
{
v20 = v17 << 6;
}
v21 = (a1[1] + v18 + v20);
v22 = _InterlockedCompareExchange8(v21, v14, v12);
if ( v12 == v22 )
goto LABEL_26;
if ( v14 == v22 )
{
v28 = v15;
if ( v14 == _InterlockedCompareExchange8(v21, v15, v14) )
goto LABEL_50;
}
++v17;
}
}
LABEL_43:
if ( v19 == v17 )
{
v17 = 0LL;
v29 = (a1[1] + v18);
if ( v19 != 1 )
goto LABEL_45;
}
else
{
v29 = (a1[1] + v18 + (v17 << 6));
if ( v19 - 1 != v17 )
{
LABEL_45:
v30 = _InterlockedCompareExchange8(v29, v14, v12);
if ( v12 == v30 )
goto LABEL_26;
if ( v14 == v30 )
{
v28 = v15;
if ( v14 == _InterlockedCompareExchange8(v29, v15, v14) )
{
LABEL_50:
v17 >>= 1;
++v18;
if ( v19 <= 1 )
goto LABEL_53;
LOBYTE(v13) = v19;
v16 = v19 + 1;
continue;
}
}
goto LABEL_42;
}
}
break;
}
v28 = v15;
if ( v12 == _InterlockedCompareExchange8(v29, v15, v12) )
goto LABEL_50;
LABEL_42:
++v17;
goto LABEL_43;
}
v28 = *v5 + 2;
LABEL_53:
*a1 += a1[2];
a1[2] = 0LL;
*v5 = v28;
_InterlockedAdd(v6, 1u);
if ( *v32 )
syscall(202LL, v6, 1LL, 0x7FFFFFFFLL);
LABEL_26:
_InterlockedAdd(v32, 1u);
LABEL_27:
v23 = *v6;
v24 = 0;
while ( v12 == *v5 )
{
v25 = v24 + 1;
if ( v24 <= 0xB )
{
_mm_pause();
}
else
{
sched_yield();
if ( v25 == 16 )
{
if ( syscall(202LL, v6, 0LL, v23, 0LL) )
{
v26 = *__errno_location();
if ( v26 != 11 && v26 != 4 )
std::__throw_system_error(v26);
}
if ( v12 == *v5 )
goto LABEL_27;
break;
}
}
v24 = v25;
}
_InterlockedSub(v32, 1u);
v27 = v36-- == 1;
index = 7 * index % 0x11;
piece = *data_to_encrypt;
}
while ( !v27 );
base += 16LL;
}
while ( data_to_encrypt[1] - piece > base );
}
}

实际上的加密逻辑非常短 大部分是在防止数据竞争 加密逻辑是通过一张表根据当前线程的ID对输入的16进制1字节数据进行二进制位替换 看起来是每次加密16字节的数据块 实际上每加密1个字节就会进入线程规划 所以当作每个字节单独加密 通过动态调试知道线程规划是当前线程加密完1字节的数据后启动线程id(当前id + 1) % 17的线程 再看加密逻辑 当再次轮换到相同线程时将要加密的下一个字节的index_new定为7 * index_now % 0x11 而每个线程初始的index设为线程id 知道了这些就能写出keygen:

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
# 先计算出加密的顺序 再逆序解密
# calculate_process.py:
threads = []
for i in range(16):
thread = []
base = 0
for _ in range(3):
now = i + 1
for _ in range(16):
thread.append(now + base)
now = (7 * now) % 0x11
base += 16
threads.append(thread)
print(threads)
# keygen.py:
enc = "75ac713a945e9f78f657b735b7e1913cdece53b8853f3a7daade83b319c49139f8f655b0b77b"
enc = [int(enc[2 * i:2 * i + 2], 16) for i in range(len(enc) // 2)]
while(len(enc) % 0x10):
enc.append(0)
enc.append(0)
indexs = [[1, 7, 15, 3, 4, 11, 9, 12, 16, 10, 2, 14, 13, 6, 8, 5, 17, 23, 31, 19, 20, 27, 25, 28, 32, 26, 18, 30, 29, 22, 24, 21, 33, 39, 47, 35, 36, 43, 41, 44, 48, 42, 34, 46, 45, 38, 40, 37], [2, 14, 13, 6, 8, 5, 1, 7, 15, 3, 4, 11, 9, 12, 16, 10, 18, 30, 29, 22, 24, 21, 17, 23, 31, 19, 20, 27, 25, 28, 32, 26, 34, 46, 45, 38, 40, 37, 33, 39, 47, 35, 36, 43, 41, 44, 48, 42], [3, 4, 11, 9, 12, 16, 10, 2, 14, 13, 6, 8, 5, 1, 7, 15, 19, 20, 27, 25, 28, 32, 26, 18, 30, 29, 22, 24, 21, 17, 23, 31, 35, 36, 43, 41, 44, 48, 42, 34, 46, 45, 38, 40, 37, 33, 39, 47], [4, 11, 9, 12, 16, 10, 2, 14, 13, 6, 8, 5, 1, 7, 15, 3, 20, 27, 25, 28, 32, 26, 18, 30, 29, 22, 24, 21, 17, 23, 31, 19, 36, 43, 41, 44, 48, 42, 34, 46, 45, 38, 40, 37, 33, 39, 47, 35], [5, 1, 7, 15, 3, 4, 11, 9, 12, 16, 10, 2, 14, 13, 6, 8, 21, 17, 23, 31, 19, 20, 27, 25, 28, 32, 26, 18, 30, 29, 22, 24, 37, 33, 39, 47, 35, 36, 43, 41, 44, 48, 42, 34, 46, 45, 38, 40], [6, 8, 5, 1, 7, 15, 3, 4, 11, 9, 12, 16, 10, 2, 14, 13, 22, 24, 21, 17, 23, 31, 19, 20, 27, 25, 28, 32, 26, 18, 30, 29, 38, 40, 37, 33, 39, 47, 35, 36, 43, 41, 44, 48, 42, 34, 46, 45], [7, 15, 3, 4, 11, 9, 12, 16, 10, 2, 14, 13, 6, 8, 5, 1, 23, 31, 19, 20, 27, 25, 28, 32, 26, 18, 30, 29, 22, 24, 21, 17, 39, 47, 35, 36, 43, 41, 44, 48, 42, 34, 46, 45, 38, 40, 37, 33], [8, 5, 1, 7, 15, 3, 4, 11, 9, 12, 16, 10, 2, 14, 13, 6, 24, 21, 17, 23, 31, 19, 20, 27, 25, 28, 32, 26, 18, 30, 29, 22, 40, 37, 33, 39, 47, 35, 36, 43, 41, 44, 48, 42, 34, 46, 45, 38], [9, 12, 16, 10, 2, 14, 13, 6, 8, 5, 1, 7, 15, 3, 4, 11, 25, 28, 32, 26, 18, 30, 29, 22, 24, 21, 17, 23, 31, 19, 20, 27, 41, 44, 48, 42, 34, 46, 45, 38, 40, 37, 33, 39, 47, 35, 36, 43], [10, 2, 14, 13, 6, 8, 5, 1, 7, 15, 3, 4, 11, 9, 12, 16, 26, 18, 30, 29, 22, 24, 21, 17, 23, 31, 19, 20, 27, 25, 28, 32, 42, 34, 46, 45, 38, 40, 37, 33, 39, 47, 35, 36, 43, 41, 44, 48], [11, 9, 12, 16, 10, 2, 14, 13, 6, 8, 5, 1, 7, 15, 3, 4, 27, 25, 28, 32, 26, 18, 30, 29, 22, 24, 21, 17, 23, 31, 19, 20, 43, 41, 44, 48, 42, 34, 46, 45, 38, 40, 37, 33, 39, 47, 35, 36], [12, 16, 10, 2, 14, 13, 6, 8, 5, 1, 7, 15, 3, 4, 11, 9, 28, 32, 26, 18, 30, 29, 22, 24, 21, 17, 23, 31, 19, 20, 27, 25, 44, 48, 42, 34, 46, 45, 38, 40, 37, 33, 39, 47, 35, 36, 43, 41], [13, 6, 8, 5, 1, 7, 15, 3, 4, 11, 9, 12, 16, 10, 2, 14, 29, 22, 24, 21, 17, 23, 31, 19, 20, 27, 25, 28, 32, 26, 18, 30, 45, 38, 40, 37, 33, 39, 47, 35, 36, 43, 41, 44, 48, 42, 34, 46], [14, 13, 6, 8, 5, 1, 7, 15, 3, 4, 11, 9, 12, 16, 10, 2, 30, 29, 22, 24, 21, 17, 23, 31, 19, 20, 27, 25, 28, 32, 26, 18, 46, 45, 38, 40, 37, 33, 39, 47, 35, 36, 43, 41, 44, 48, 42, 34], [15, 3, 4, 11, 9, 12, 16, 10, 2, 14, 13, 6, 8, 5, 1, 7, 31, 19, 20, 27, 25, 28, 32, 26, 18, 30, 29, 22, 24, 21, 17, 23, 47, 35, 36, 43, 41, 44, 48, 42, 34, 46, 45, 38, 40, 37, 33, 39], [16, 10, 2, 14, 13, 6, 8, 5, 1, 7, 15, 3, 4, 11, 9, 12, 32, 26, 18, 30, 29, 22, 24, 21, 17, 23, 31, 19, 20, 27, 25, 28, 48, 42, 34, 46, 45, 38, 40, 37, 33, 39, 47, 35, 36, 43, 41, 44]]
key = [
0x02, 0x08, 0x06, 0x01, 0x03, 0x05, 0x04, 0x07, 0x06, 0x01,
0x04, 0x08, 0x05, 0x02, 0x03, 0x07, 0x07, 0x08, 0x03, 0x05,
0x01, 0x02, 0x04, 0x06, 0x04, 0x01, 0x03, 0x06, 0x02, 0x08,
0x05, 0x07, 0x07, 0x05, 0x08, 0x06, 0x01, 0x04, 0x03, 0x02,
0x07, 0x04, 0x08, 0x05, 0x06, 0x02, 0x03, 0x01, 0x07, 0x06,
0x04, 0x08, 0x01, 0x03, 0x02, 0x05, 0x03, 0x01, 0x08, 0x04,
0x07, 0x02, 0x06, 0x05, 0x03, 0x04, 0x08, 0x06, 0x02, 0x05,
0x01, 0x07, 0x08, 0x01, 0x06, 0x02, 0x07, 0x05, 0x04, 0x03,
0x02, 0x07, 0x05, 0x08, 0x01, 0x04, 0x03, 0x06, 0x03, 0x04,
0x02, 0x06, 0x05, 0x08, 0x07, 0x01, 0x01, 0x04, 0x03, 0x05,
0x07, 0x06, 0x02, 0x08, 0x04, 0x07, 0x03, 0x06, 0x05, 0x01,
0x08, 0x02, 0x06, 0x07, 0x04, 0x01, 0x05, 0x03, 0x02, 0x08,
0x03, 0x08, 0x04, 0x06, 0x07, 0x02, 0x05, 0x01
]
key = [key[i] - 1 for i in range(len(key))]
for i in range(0x2F, -1, -1):
for id in range(15, -1, -1):
now = 0
for j in range(8):
if enc[indexs[id][i]] & (1 << key[8 * id + j]):
now |= 1 << j
enc[indexs[id][i]] = now
for s in enc:
print(chr(s), end="")
# utflag{i_got_the_need_for_amdahls_law}

In The Dark(unsolved) | 混淆 | 游戏逆向

题目给出了一个没有图形化界面的游戏 可以输入wasd进行操作 但是由于代码进行了混淆所以几乎不可能通过静态分析得到游戏逻辑 听大佬说可以用ALF++通杀游戏逆向 以后研究一下