n1ctfjunior-re

FlowerHidden

32位ida查看

image-20251119145209730

进入main有花指令

1
2
3
4
5
6
7
8
9
.text:00402FB0 loc_402FB0:                             ; DATA XREF: _main+3A↓o
.text:00402FB0 cmp eax, 4
.text:00402FB3 jz short locret_402FBA
.text:00402FB5 call loc_402A60
.text:00402FBA
.text:00402FBA locret_402FBA: ; CODE XREF: .text:00402FB3↑j
.text:00402FBA retn
.text:00402FBA ; ---------------------------------------------------------------------------
.text:00402FBB align 10h

去看loc_402A60

1
2
3
4
5
.text:00402A7A                 mov     eax, 1
.text:00402A7F imul ecx, eax, 3
.text:00402A82 movsx edx, byte_420100[ecx]
.text:00402A89 push edx
.text:00402A8A call sub_4023E0

从表 byte_420100 读取值,传入 sub_4023E0,ecx=3,imul有符号整数乘法

1
2
3
4
5
6
7
8
9
.data:00420100 byte_420100     db 0                    ; DATA XREF: sub_401D80+63B↑o
.data:00420100 ; sub_4024A0+4F↑r ...
.data:00420101 db 1
.data:00420102 db 2
.data:00420103 db 3
.data:00420104 db 4
.data:00420105 db 5
.data:00420106 db 6
.data:00420107 db 7

byte_420100取值范围0~7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text:004023E0 sub_4023E0      proc near               ; CODE XREF: sub_4024A0+57↓p
.text:004023E0 ; sub_4024A0+7A↓p ...
.text:004023E0
.text:004023E0 arg_0 = dword ptr 4
.text:004023E0
.text:004023E0 mov ebx, [esp+arg_0]
.text:004023E4 mov eax, 0Ah
.text:004023E9 mov ecx, ebx
.text:004023EB not eax
.text:004023ED and ebx, eax
.text:004023EF not eax
.text:004023F1 not ecx
.text:004023F3 and ecx, eax
.text:004023F5 or ebx, ecx
.text:004023F7 inc ebx
.text:004023F8 dec ebx
.text:004023F9 mul ebx
.text:004023FB div ebx
.text:004023FD xor ebx, eax
.text:004023FF add [esp+0], ebx
.text:00402402 retn 4
.text:00402402 sub_4023E0 endp

简化:

1
2
3
4
5
6
7
8
9
10
sub_4023E0:
mov ebx, [esp+4] ; ebx = arg
mov eax, 0Ah ; eax = 10
mov ecx, ebx ; ecx = arg
not eax ; eax = ~10
and ebx, eax ; ebx = arg & ~10
not eax ; eax = 10
not ecx ; ecx = ~arg
and ecx, eax ; ecx = ~arg & 10
or ebx, ecx ; ebx = (arg & ~10) | (~arg & 10)

(arg & ~mask) | (~arg & mask) 这个表达式是按位选择:当 mask 位为 1 时取原式=~arg ,为 0 时原式= arg 的那一位。代数上等价于 arg ^ mask(异或)。

本题mask=0xA(10),所以ebx=arg^0xA。

inc指令用于将一个寄存器的值加1,dec指令用于将一个寄存器的值减1。

当前ebx=arg^0xA,eax=10

1
2
3
4
5
mul     ebx                ; EDX:EAX = 10 * (arg^0xA)
div ebx ;(10 * (arg^0xA))/(arg^0xA)
xor ebx, eax ; ebx = EBX ^ 10
add [esp+0], ebx ; *(DWORD*)(esp) += ebx <-- 修改返回地址
ret 4

div这里,如果(arg^0xA)!=0,ebx = (arg^0xA) ^ 10=arg

到此这一长段乘除只是把 ebx 恢复为原始输入 arg ,是花指令

add这里,esp+0 是栈顶 返回地址(函数被调用时的 ret 地址)。因此它 arg 加到返回地址上(即修改返回地址,使得 ret 返回到 return_address + arg)。

[ ]取地址

平台 / ABI 参数 1 参数 2 参数 3 参数 4 参数 5+ 备注
x86 (32位, cdecl/stdcall) [esp+4] [esp+8] [esp+0xC] [esp+0x10] 继续往上递增 所有参数都压栈;[esp] 是返回地址
Windows x64 (MSVC ABI) RCX RDX R8 R9 [rsp+0x28] 开始 栈上预留 32 字节 shadow space (rsp+20hrsp+40h),即使没用
System V AMD64 (Linux, macOS, BSD) RDI RSI RDX RCX R8 R9

sub_402A60,两次输入,第二次输入会被switch四个方向

迷宫终点是38,移动42次,累加和为117

1
2
3
4
5
6
7
8
9
10
11
12
64  49  49  49  49  49  48  48  48  48  49   0
48 48 48 49 48 48 48 49 49 48 49 0
49 49 48 49 48 49 48 48 49 48 49 0
49 49 48 48 48 49 49 48 48 48 49 0
49 49 48 49 49 48 48 48 49 49 49 0
49 49 48 49 49 48 49 49 49 49 49 0
49 48 48 48 48 48 49 49 49 49 49 0
49 48 49 49 49 48 48 49 48 48 48 0
49 48 48 48 49 49 48 48 48 49 48 0
49 49 49 48 49 49 48 49 49 49 48 0
49 49 49 48 48 48 48 48 48 48 38 0
49 49 49 49 49 49 49 49 49 49 49 0

sddssddwwddsdssaassaaaassddssdddwwddwddsss,程序验证通过,但是不是flag。发现ipu文件还没有使用,而且第一个输入也没被使用。

关注迷宫的第一个输入,注意到这里是有一个指针指向第一次输入的,看这个指针的交叉引用,可以看到一个验证和分发程序。

sub_1D80

首先,读入了1pmoluy.ipu文件,经过文件名解码,文件读入与解码。然后得到 4 个指针,分别指向不同解密后函数的入口。

1
2
3
4
5
6
7
8
*(_DWORD *)dword_420FB0 = Buffer;
qmemcpy(v16, "FUNC", sizeof(v16));

*(_DWORD *)(dword_420FB0 + 4) = *(_DWORD *)dword_420FB0 + sub_401AC0(*(_DWORD *)dword_420FB0, v16, v13);

*(_DWORD *)(dword_420FB0 + 8) = *(_DWORD *)(dword_420FB0 + 4) + sub_401AC0(*(_DWORD *)(dword_420FB0 + 4), v16, v13);

*(_DWORD *)(dword_420FB0 + 12) = *(_DWORD *)(dword_420FB0 + 8) + sub_401AC0(*(_DWORD *)(dword_420FB0 + 8), v16, v13);

对比父进程名字的前 3 个字节。如果不匹配,byte_420100[6] = 10; → 改变全局控制流。

1
2
3
String2 = { -26, -21, -18, -113 };
for (m=0; m<4; m++) String2[m] ^= 0x8F;
_strnicmp(String1, String2, 3)

strings2单字节异或得到字符串”ida”,如果父进程是 IDA,则会把 byte_420100[6] 设为 10。

sub_2790,异常处理函数,这里又改成了1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __usercall sub_402790@<eax>(int a1@<ebp>)
{
if ( *(_DWORD *)(a1 + 0x10) == 2 )
{
++**(_DWORD **)(a1 + 8);
byte_420100[6] = 1;
*(_DWORD *)(a1 - 28) = sub_401370;
dword_420FC0 = *(_DWORD *)(a1 - 28);
__asm { retn }
}
*(_DWORD *)(a1 - 36) = 0;
*(_DWORD *)(a1 - 4) = -2;
return *(_DWORD *)(a1 - 36);
}

在反调试的函数中,调用了1pmoluy.ipu文件。文件中存储的是四个加密函数,经过解密后会被后面分发函数进行调用。然后根据路径进行顺序解密。

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
int __usercall sub_401370@<eax>(int a1@<eax>)
{
dword_420FB8 = a1;
if ( a1 == 1 )
{
(*(void (__cdecl **)(char *))dword_420FB0)(off_420234);
}
else
{
switch ( dword_420FB8 )
{
case 2:
(*(void (__cdecl **)(char *))(dword_420FB0 + 4))(off_420234);
break;
case 3:
(*(void (__cdecl **)(char *))(dword_420FB0 + 8))(off_420234);
break;
case 4:
(*(void (__cdecl **)(char *))(dword_420FB0 + 12))(off_420234);
break;
default:
return dword_420FB8;
}
}
sub_401210();
return dword_420FB8;
}

加密1 异或 左循环位移 异或 右循环位移
加密2 固定key生成固定box和对应固定key 这里dump其实就行
加密3 这里把boxdump下来试两下就会发现 这里仅仅是实现了加减法
加密4 根据key生成随机顺序换序 也可以dump下来然后固定换回来就行

Pyramid

chal.pyc -> pyramid.pyd -> a_long_way_to_treasure() -> pyramid.pyc(异或) -> checkinput.pyd(rc4) -> 白盒aes解flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: chal.py
# Bytecode version: 3.12.0rc2 (3531)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)

import pyramid
import os
text = 'A pyramid fortified with intricate defenses looms before you. \nIts secrets are locked behind layers of puzzles. \nYou stand at its base, challenged to unravel them all.'
print('・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・')
for line in text.split('\n'):
print(f' {line}')
print('・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・')
pyramid.a_long_way_to_treasure()
try:
os.remove('checkinput.pyd')
except Exception as e:
pass
img img
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
.rdata:0000000180008280 unk_180008280   db 0A9h                 ; DATA XREF: .rdata:0000000180007F80↑o
.rdata:0000000180008281 db 6Ch ; l
.rdata:0000000180008282 db 63h ; c
.rdata:0000000180008283 db 6Dh ; m
.rdata:0000000180008284 db 64h ; d
.rdata:0000000180008285 db 72h ; r
.rdata:0000000180008286 db 65h ; e
.rdata:0000000180008287 db 61h ; a
.rdata:0000000180008288 db 2Bh ; +
.rdata:0000000180008289 db 30h ; 0
.rdata:000000018000828A db 0B5h
.rdata:000000018000828B db 1Bh
.rdata:000000018000828C db 0BDh
.rdata:000000018000828D db 0Ch
.rdata:000000018000828E db 6Bh ; k
.rdata:000000018000828F db 6Fh ; o
.rdata:0000000180008290 db 81h
.rdata:0000000180008291 db 61h ; a
.rdata:0000000180008292 db 6Eh ; n
.rdata:0000000180008293 db 67h ; g
.rdata:0000000180008294 db 64h ; d
.rdata:0000000180008295 db 72h ; r
.rdata:0000000180008296 db 65h ; e
.rdata:0000000180008297 db 61h ; a
.rdata:0000000180008298 db 6Dh ; m
.rdata:0000000180008299 db 69h ; i
.rdata:000000018000829A db 74h ; t
.rdata:000000018000829B db 73h ; s
.rdata:000000018000829C db 6Dh ; m
.rdata:000000018000829D db 71h ; q
.rdata:000000018000829E db 67h ; g
.rdata:000000018000829F db 6Fh ; o
.rdata:00000001800082A0 db 62h ; b
.rdata:00000001800082A1 db 61h ; a
.rdata:00000001800082A2 db 6Eh ; n
.rdata:00000001800082A3 db 67h ; g
.rdata:00000001800082A4 db 64h ; d
img
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
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: layer2.py
# Bytecode version: 3.12.0rc2 (3531)
# Source timestamp: 2025-09-10 10:56:06 UTC (1757501766)

import ctypes
from ctypes import wintypes
import struct
import os
import importlib.util
import sys

class BUF(ctypes.Structure):
_fields_ = [('Length', wintypes.ULONG), ('Unused', wintypes.ULONG), ('Ptr', ctypes.c_void_p)]
key = input('Input your key: ')
tmp = 2166136261
for ch in key:
tmp = 16777619 * (tmp ^ ord(ch)) & 4294967295
key_bytes = struct.pack('<I', tmp)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)
SystemFunction033 = advapi32.SystemFunction033
FNPROTO = ctypes.WINFUNCTYPE(None, ctypes.POINTER(BUF), ctypes.POINTER(BUF))
fn = FNPROTO(ctypes.cast(SystemFunction033, ctypes.c_void_p).value)
data = b'\xb7\xc3\xbc\xe5 <skip>'
data_buffer = ctypes.create_string_buffer(data)
key_buffer = ctypes.create_string_buffer(key_bytes)
data_buf = BUF(len(data), 0, ctypes.addressof(data_buffer))
key_buf = BUF(4, 0, ctypes.addressof(key_buffer))
fn(ctypes.byref(data_buf), ctypes.byref(key_buf))
pyd_path = os.path.join(os.getcwd(), 'checkinput.pyd')
with open(pyd_path, 'wb') as f:
f.write(data_buffer.raw[:len(data)])
try:
spec = importlib.util.spec_from_file_location('checkinput', pyd_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
flag = input('Input your flag: ')
result = module.check(flag.encode('utf-8'))
if result:
print('Right!')
else:
print('Wrong!')
except Exception as e:
pass
print('Wrong key!')

关于key的运算,可以看到魔数2166136261与16777619,可以判断是FNV哈希算法,然后哈希值被打包成4字节的小端字节序格式(key_bytes),用作RC4解密的密钥。将解密后的数据放入当前目录下的checkinput.pyd文件中,使用importlib动态导入该模块,并获取其中的check函数。用户被提示输入flag,并调用module.check进行验证。

所以接下来需要求得RC4的密钥

已知:

  • 密文前四个字节:\xb7\xc3\xbc\xe5 明文前四个:4D 5A 90 00
  • 密钥长度为 4 字节

rc4短密钥爆破脚本:

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
/*
MistHill, created on 10:24:34 2013-7-3

compile:
Visual Studio 6:
CL /Og /Os /Oy /Ob1 /GT /Gs /Gf /Gy /G6 /MT rc4KStream75MT.c /link /RELEASE

Refs:
1) Optimizing C++/Code optimization/Faster operations
http://en.wikibooks.org/wiki/Optimizing_C%2B%2B/Code_optimization/Faster_operations
2) Writing Efficient C and C Code Optimization
http://www.codeproject.com/Articles/6154/Writing-Efficient-C-and-C-Code-Optimization

3) Multithreading Tutorial #1
http://www.computersciencelab.com/MultithreadingTut1.htm
4) Walkthrough: Debugging a Multithreaded Application
http://msdn.microsoft.com/en-us/library/bb157784(v=vs.90).aspx
*/
#include <windows.h>
#include <process.h>

#define TARGETKS1 0xe52c99fa

void prepare_key(unsigned char *key_data_ptr, int key_data_len, unsigned char *state);
BOOL GetKeyStream(unsigned char *buffer_ptr, int buffer_len, unsigned char *state);

unsigned _Recursion(void*);
unsigned __stdcall _RecursionT1(void*);
unsigned __stdcall _RecursionT2(void*);
unsigned __stdcall _RecursionT3(void*);
void Recursion(int idx, unsigned char *pKey, unsigned char *pKeyStream, unsigned char *pstate);

BOOL WINAPI ConsoleHandler(DWORD dwCtrlType);
void ShowExecutionTime(BOOL bBreaked);
void ShowMatchedKeystream(unsigned char*);

//static int TargetKS1 = 0x62383550, TargetKS2 = 0x6F0C1E2C; /* Target KS = 50 35 38 62 2C 1E 0C 6F */
#define KeyLength 4

static char szErrMsgCT[] ="Create thread%d failed!\n";
static char szFmtHex2[] ="%02X ";
static char szFmtDate[] ="\n%s\t%04d-%02d-%02d %02d:%02d:%02d.%03d";

static unsigned char stateinit[256];

static unsigned char Key[8], KeyT1[8], KeyT2[8], KeyT3[8];

// Size: just 4 is fine. Exec. time of function GetKeyStream() reduced!
static unsigned char KeyStream[4], KeyStreamT1[4], KeyStreamT2[4], KeyStreamT3[4];

static unsigned char state[256], stateT1[256], stateT2[256], stateT3[256];

static SYSTEMTIME lt0, lt1;
static DWORD dw0, dw1;

int main(void)
{
int i;
HANDLE hThread[3];
unsigned threadID[3];

if (SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ConsoleHandler, TRUE)==FALSE)
{
printf("Unable to install handler!\n");
return -1;
}

GetLocalTime(&lt0);
dw0 = GetTickCount();

for(i =0; i <256; i++)
stateinit[i] = i;

// Create the threads.
hThread[0] = (HANDLE)_beginthreadex(NULL,0, &_RecursionT1,NULL,0, &threadID[0] );
if(!hThread[0]) {
printf(szErrMsgCT,1);
return -1;
}

hThread[1] = (HANDLE)_beginthreadex(NULL,0, &_RecursionT2,NULL,0, &threadID[1] );
if(!hThread[1]) {
printf(szErrMsgCT,2);
CloseHandle(hThread[0]);
return -1;
}

hThread[2] = (HANDLE)_beginthreadex(NULL,0, &_RecursionT3,NULL,0, &threadID[2] );
if(!hThread[2]) {
printf(szErrMsgCT,3);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
return -1;
}

_Recursion(NULL);

WaitForMultipleObjects(3, hThread, TRUE, INFINITE);

CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(hThread[2]);

ShowExecutionTime(FALSE);

return 0;
}

unsigned _Recursion(void* pArguments)
{
register int i;

// 0x30~0x7A: T0(0x30~0x42), T1(0x43~0x55), T2(0x56~0x68), T3(0x69~0x7A)
for(i=0;i<64;i++) {
Key[0] = i;
Recursion(1, Key, KeyStream, state);
}
return 0;
}

unsigned __stdcall _RecursionT1(void* pArguments)
{
register int i;

for(i=64;i<128;i++) {
KeyT1[0] = i;
Recursion(1, KeyT1, KeyStreamT1, stateT1);
}
_endthreadex(0);
return 0;
}

unsigned __stdcall _RecursionT2(void* pArguments)
{
register int i;

for(i=128;i<192;i++) {
KeyT2[0] = i;
Recursion(1, KeyT2, KeyStreamT2, stateT2);
}
_endthreadex(0);
return 0;
}

unsigned __stdcall _RecursionT3(void* pArguments)
{
register int i;

for(i=192;i<256;i++) {
KeyT3[0] = i;
Recursion(1, KeyT3, KeyStreamT3, stateT3);
}
_endthreadex(0);
return 0;
}

void Recursion(int idx, unsigned char *pKey, unsigned char *pKeyStream, unsigned char *pstate)
{
register int i;

for(i=0;i<256;i++) {
pKey[idx] = i;
if(idx +1 < KeyLength)
Recursion(idx +1, pKey, pKeyStream, pstate);
else {
memcpy(pstate, stateinit,sizeof(stateinit));
prepare_key(pKey, KeyLength, pstate);

if( GetKeyStream(pKeyStream,sizeof(KeyStream), pstate) )
ShowMatchedKeystream(pKey);
}
}
}

void prepare_key(unsigned char *key_data_ptr, int key_data_len, unsigned char *state)
{
unsigned char swapByte;
unsigned char index1, index2;
int counter;

index1 = index2 =0;
for(counter =0; counter <256; counter++)
{
index2 = key_data_ptr[index1] + state[counter] + index2;

swapByte = state[counter];
state[counter] = state[index2];
state[index2] = swapByte;

index1++;
while(index1 == key_data_len)
index1 -= key_data_len;
}
}

BOOL GetKeyStream(unsigned char *buffer_ptr, int buffer_len, unsigned char *state)
{
unsigned char swapByte;
unsigned char x;
unsigned char y;
unsigned char xorIndex;
int counter;

x = y =0;

for(counter =0; counter < buffer_len; counter ++)
{
x++;
y = state[x] + y;

swapByte = state[x];
state[x] = state[y];
state[y] = swapByte;

xorIndex = state[x] + state[y];

buffer_ptr[counter] = state[xorIndex];
}

if( *(int*)buffer_ptr == TARGETKS1 )
return TRUE;
else
return FALSE;
}

BOOL WINAPI ConsoleHandler(DWORD dwCtrlType)
{
if(dwCtrlType == CTRL_C_EVENT) {
int i;
printf("\r");
for(i=0;i<KeyLength;i++)
printf(szFmtHex2, Key[i]);
printf(", ");
for(i=0;i<KeyLength;i++)
printf(szFmtHex2, KeyT1[i]);
printf(", ");
for(i=0;i<KeyLength;i++)
printf(szFmtHex2, KeyT2[i]);
printf(", ");
for(i=0;i<KeyLength;i++)
printf(szFmtHex2, KeyT3[i]);

return TRUE;
}
else if(dwCtrlType == CTRL_BREAK_EVENT)
ShowExecutionTime(TRUE);

return FALSE;
}

void ShowExecutionTime(BOOL bBreaked)
{
int i;

GetLocalTime(&lt1);
dw1 = GetTickCount();

if(bBreaked) {
printf("\nCurrent Keys:\n\t");
for(i=0;i<KeyLength;i++)
printf(szFmtHex2, Key[i]);
printf("\n\t");
for(i=0;i<KeyLength;i++)
printf(szFmtHex2, KeyT1[i]);
printf("\n\t");
for(i=0;i<KeyLength;i++)
printf(szFmtHex2, KeyT2[i]);
printf("\n\t");
for(i=0;i<KeyLength;i++)
printf(szFmtHex2, KeyT3[i]);
printf("\n");
}

printf(szFmtDate,"Start:", lt0.wYear, lt0.wMonth, lt0.wDay, lt0.wHour, lt0.wMinute, lt0.wSecond, lt0.wMilliseconds);
printf(szFmtDate,"End:", lt1.wYear, lt1.wMonth, lt1.wDay, lt1.wHour, lt1.wMinute, lt1.wSecond, lt1.wMilliseconds);
printf("\n\nExecution time:\t%d.%d seconds.\n", (dw1 - dw0)/1000, (dw1 - dw0)%1000);
}

void ShowMatchedKeystream(unsigned char *pKey)
{
int j;

printf("\n\tFound:\t");
for(j=0;j<KeyLength;j++)
printf(szFmtHex2, pKey[j]);

dw1 = GetTickCount();
printf("\t%d.%d sec.\n", (dw1 - dw0)/1000, (dw1 - dw0)%1000);
}
img

而后用得到的密钥B7 BC 71 42对密文进行解密,可以发现能够得到正确的pe格式

里面是一个白盒aes加密算法

解白盒aes方法:https://www.zskkk.cn/posts/15785/

img img

key= 009CF29131C8E4EA81BD5DD248E6F3E0

密文:61E2312BDB5D41BF03F604A7F478680E41AB532035C2B87894E140F40A9F0F0795C6208C653C8C2732B026A83614F04F6D44CB66BB784726881EABC3FDF283CB

flag{7h3_Pyr4m1d_0f_Py7h0n_4w4175_175_M4573r_R3v3r53r_uJ6gG3qVs}