2021巅峰极客

逆向题解~

baby_maze

常见的迷宫题,但考法却不常见,没有直接的地图,只是给出每走一步的程序的反馈,提示是否遇到障碍,是否到可以通行,是否到达终点。

程序就是通过每走一步,调用一个函数。

感觉上方法很多的,这里我是采用与程序交互写一个dfs来跑。

首先交互采用的pexpect模块,然后把程序中提示正确信息的字符串都改为:“1\r\n”,到达终点的字符串改为了:“2\r\n”,方便判断交互数据。

其次写这个dfs来与程序交互跑迷宫和常规的有地图自己跑要注意一点,在每次走一步后返回到上一层的时候要加一个步骤:往回走的步骤,因为这是在程序交互。

刚开始我写这个迷宫,以为程序可能就是几十步吧,所以也没有去做什么过滤,后面跑的时候发现步数远不止几十,,起码上百,说明这个地图是很大的,这样直接跑时间上肯定是不行的。。

接下来改进,想到我可以开始初始化一个大的迷宫,让程序在跑的时候根据回显是障碍物来在初始化的迷宫上记录这是一个障碍点(maze[x][y] = 1)。

最后程序在10分钟跑出了结果,勉强能接受,虽然还是很慢。

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
import pexpect
from time import *

next = [[0, -1], [1, 0], [0,1], [-1, 0]]
d = "ASDW"
flag = [0]*1000
back = {'W':'S', 'S':'W', 'A':'D', 'D':'A'}

def do_str(ans):
s = ''
for i in ans:
if i == 0:
break
s += i
return s;

def dfs(step, x, y):
print(do_str(flag))
for i in range(4):
#print(do_str(flag))
flag[step] = d[i]
flag[step+1] = 0

nx = x+next[i][0]
ny = y+next[i][1]

if maze[nx][ny] == 1 or book[nx][ny] == 1:
continue

r.sendline(d[i])
ans = r.readline()
#print(ans)
if ans == b'1\r\n':
book[nx][ny] = 1
dfs(step+1, nx, ny)
book[nx][ny] = 0
r.sendline(back[d[i]])
r.readline()
elif ans == b'2\r\n':
print("found: ", do_str(flag))
t1 = time()
print("time: ", t1-t)
break
else:
maze[nx][ny] = 1

t = time()
maze=[[0]*1000]*1000
book=[[0]*1000]*1000
for i in range(1000):
book[i]=[0]*1000
r = pexpect.spawn('./maze')
r.readline()
r.readline()
ans = r.readline()
print(ans)
maze[0][0] = 1
maze[1][0] = 1
flag[0] = 'S'
r.sendline('S')
ans = r.readline()
dfs(1, 1, 0)
1
2
found:  SSSSSSSSSDDDDDDWWWWAAWWAAWWDDDDDDDDDDDDDDDDDDDDSSDDSSAASSSSAAAAWWAAWWWWAASSSSSSAASSDDSSSSDDWWWWDDSSDDDDWWDDDDDDWWAAAAWWDDDDWWAAWWWWDDSSDDSSSSSSSSSSDDDDSSAAAASSSSSSAASSSSAAWWAASSSSDDDDDDDDDDSSDDSSAASSSSAASSSSSSSSDDWWWWWWDDWWWWDDWWWWDDSSSSSSSSAASSSSDDDDSSDDDDWWDDSSDDSSDDDDDDDDSSDDSSSSDDDDSSDDSSSSSSDDSSSSDDDDSSSSDDDDDDSSSSDDSSDSSASSSSAASSDDSSAASSDDDDDDSSDDDDWWDDSSSSSSDDDDWWAAWWWWDDDDSSSSDDDDDDSSAASSSSSSDDDDDDDDSSDDDDSSSSSSDDWWDDDDDDSSSSSSSSAASSDDSSSSSSAASSDDS
time: 655.1350808143616

medical_app

算是很常规的一个安卓题了,就native层逻辑很明显的加密。

做的时候发现这个不同架构的so去ida反编译的结果区别真的大,,没有经验,我开始选择了熟悉的x86架构的去看😅:

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
char __cdecl Java_come_crack_crackme2_MainActivity_chk(int a1, int a2, int a3)
{
const char *v3; // edi
size_t v4; // ecx
int v5; // eax
unsigned int v6; // ecx
int v7; // eax
int v8; // edx
int v9; // ecx
int v10; // esi
int v11; // edi
int v12; // ecx
unsigned int v13; // eax
int v14; // ecx
unsigned int v15; // edx
unsigned int v16; // edi
int v17; // ebx
int v18; // esi
int v19; // edx
int v20; // edi
unsigned int v21; // ebx
unsigned int v22; // edi
unsigned int v23; // esi
unsigned int v24; // ecx
unsigned int v25; // eax
unsigned int v27; // [esp+8h] [ebp-264h]
unsigned int v28; // [esp+Ch] [ebp-260h]
unsigned int v29; // [esp+10h] [ebp-25Ch]
int v30; // [esp+10h] [ebp-25Ch]
unsigned int v31; // [esp+14h] [ebp-258h]
int v32; // [esp+14h] [ebp-258h]
unsigned int v33; // [esp+18h] [ebp-254h]
int v34; // [esp+18h] [ebp-254h]
unsigned int v35; // [esp+1Ch] [ebp-250h]
unsigned int v36; // [esp+20h] [ebp-24Ch]
unsigned int v37; // [esp+24h] [ebp-248h]
char *v38; // [esp+2Ch] [ebp-240h]
unsigned int v39; // [esp+30h] [ebp-23Ch]
int v40; // [esp+34h] [ebp-238h]
unsigned int v41; // [esp+38h] [ebp-234h]
int v42; // [esp+40h] [ebp-22Ch]
int v43; // [esp+4Ch] [ebp-220h]
_OWORD v44[16]; // [esp+50h] [ebp-21Ch]
_OWORD v45[17]; // [esp+150h] [ebp-11Ch]

v3 = (const char *)z(a1, a3);
v4 = strlen(v3);
v5 = 0;
if ( v4 == 36 )
{
v38 = (char *)v3;
v44[15] = 0LL;
v44[14] = 0LL;
v44[13] = 0LL;
v44[12] = 0LL;
v44[11] = 0LL;
v44[10] = 0LL;
v44[9] = 0LL;
v44[8] = 0LL;
v44[7] = 0LL;
v44[6] = 0LL;
v44[5] = 0LL;
v44[4] = 0LL;
v44[3] = 0LL;
v44[2] = 0LL;
v44[1] = 0LL;
v44[0] = 0LL;
v45[15] = 0LL;
v45[14] = 0LL;
v45[13] = 0LL;
v45[12] = 0LL;
v45[11] = 0LL;
v45[10] = 0LL;
v45[9] = 0LL;
v45[8] = 0LL;
v45[7] = 0LL;
v45[6] = 0LL;
v45[5] = 0LL;
v45[4] = 0LL;
v45[3] = 0LL;
v45[2] = 0LL;
v45[1] = 0LL;
v45[0] = 0LL;
do
{
*((_BYTE *)v44 + v5) = v5;
*((_BYTE *)v45 + v5) = *((_BYTE *)&d + (v5 & 0xF));
++v5;
}
while ( v5 != 256 );
v6 = 0;
v7 = -256;
do
{
v8 = *((unsigned __int8 *)v45 + v7);
v9 = v8 + v6;
v10 = *((char *)&v45[16] + v7);
v11 = v10 + v9 + 255;
v12 = v10 + v9;
if ( v12 >= 0 )
v11 = v12;
v6 = v12 - (v11 & 0xFFFFFF00);
*((_BYTE *)v45 + v7) = *((_BYTE *)v44 + v6);
*((_BYTE *)v44 + v6) = v8;
++v7;
}
while ( v7 );
v13 = 0;
v14 = -36;
v15 = 0;
do
{
v16 = v13 + 256;
if ( (int)(v13 + 1) >= 0 )
v16 = v13 + 1;
v13 = v13 - (v16 & 0xFFFFFF00) + 1;
v17 = *((unsigned __int8 *)v44 + v13);
v18 = v15 + v17 + 255;
v19 = v17 + v15;
if ( v19 >= 0 )
v18 = v19;
v15 = v19 - (v18 & 0xFFFFFF00);
v20 = v14;
*((_BYTE *)v44 + v13) = *((_BYTE *)v44 + v15);
*((_BYTE *)v44 + v15) = v17;
v38[v14 + 36] ^= *((_BYTE *)v44 + (unsigned __int8)(v17 + *((_BYTE *)v44 + v13)));
++v14;
}
while ( v20 != -1 );
v21 = *((_DWORD *)v38 + 8);
v37 = *(_DWORD *)v38;
v22 = *((_DWORD *)v38 + 1);
v27 = *((_DWORD *)v38 + 3);
v28 = *((_DWORD *)v38 + 4);
v31 = *((_DWORD *)v38 + 5);
v33 = *((_DWORD *)v38 + 6);
v39 = *((_DWORD *)v38 + 2);
v29 = *((_DWORD *)v38 + 7);
v43 = -11;
v23 = -1621657930;
do
{
v40 = (v23 >> 2) & 3;
v42 = *((_DWORD *)&d + v40);
v37 += (((v21 >> 5) ^ (4 * v22)) + ((v22 >> 3) ^ (16 * v21))) ^ ((v23 ^ v22) + (v42 ^ v21));
v41 = v31;
v32 = *((_DWORD *)&d + (v40 ^ 1));
v22 += (((v37 >> 5) ^ (4 * v39)) + ((v39 >> 3) ^ (16 * v37))) ^ ((v23 ^ v39) + (v37 ^ v32));
v36 = v33;
v34 = *((_DWORD *)&d + (v40 ^ 2));
v24 = v39 + ((((v22 >> 5) ^ (4 * v27)) + ((v27 >> 3) ^ (16 * v22))) ^ ((v23 ^ v27) + (v22 ^ v34)));
v35 = v29;
v30 = *((_DWORD *)&d + (v40 ^ 3));
v39 = v24;
v27 += (((v24 >> 5) ^ (4 * v28)) + ((v28 >> 3) ^ (16 * v24))) ^ ((v23 ^ v28) + (v24 ^ v30));
v25 = v28 + ((((v27 >> 5) ^ (4 * v41)) + ((v41 >> 3) ^ (16 * v27))) ^ ((v23 ^ v41) + (v27 ^ v42)));
v28 = v25;
v31 = v41 + ((((v25 >> 5) ^ (4 * v36)) + ((v36 >> 3) ^ (16 * v25))) ^ ((v23 ^ v36) + (v25 ^ v32)));
v33 = v36 + ((((v31 >> 5) ^ (4 * v35)) + ((v35 >> 3) ^ (16 * v31))) ^ ((v23 ^ v35) + (v31 ^ v34)));
v29 = v35 + ((((v33 >> 5) ^ (4 * v21)) + ((v21 >> 3) ^ (16 * v33))) ^ ((v23 ^ v21) + (v33 ^ v30)));
v21 += (((v29 >> 5) ^ (4 * v37)) + ((v37 >> 3) ^ (16 * v29))) ^ ((v23 ^ v37) + (v29 ^ v42));
v23 -= 1621657930;
++v43;
}
while ( v43 );
*((_DWORD *)v38 + 1) = v22;
*(_DWORD *)v38 = v37;
*((_DWORD *)v38 + 2) = v24;
*((_DWORD *)v38 + 3) = v27;
*((_DWORD *)v38 + 4) = v25;
*((_DWORD *)v38 + 5) = v31;
*((_DWORD *)v38 + 7) = v29;
*((_DWORD *)v38 + 6) = v33;
*((_DWORD *)v38 + 8) = v21;
LOBYTE(v5) = memcmp(v38, &unk_3440, 0x24u) == 0;
}
return v5;
}

和之前看release模式编译的800多行c++代码比起来,其实还好。很明显开始一个rc4加密,接着一个tea,仔细看下,可以知道是xxtea。

然后有几个函数,看得出来是加密函数,但没有引用关系。但这样看,不好看出这个xxtea是否经过魔改。

所以我决定去看下armV7的so,然后调试一波,感觉发现了新天地,,这清晰的加密流程。。从这才知道不同版本的so反编译结果如此之大,其实这个armV7的so应该才是作者自己写的,以后看so的时候应该首先armV7的so。

1
2
3
4
5
6
7
8
9
10
11
12
13
bool __fastcall Java_come_crack_crackme2_MainActivity_chk(int a1, int a2, int a3)
{
char *v3; // r4
unsigned __int8 v5[260]; // [sp+0h] [bp-118h] BYREF

v3 = (char *)z(a1, a3);
if ( strlen(v3) != 36 )
return 0;
memset(v5, 0, 0x100u);
z2(v5, (unsigned __int8 *)d, 0x10u);
z3(v5, (unsigned __int8 *)v3, 0x24u);
z4((unsigned int *)v3, 9u, d);
return memcmp(v3, &ss, 0x24u) == 0;

上面z2,z3就是rc4的初始化和加密,看z4:相当清晰的xxtea,确定只是改了delat。

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
unsigned int __fastcall z4(unsigned int *a1, unsigned int a2, unsigned int *a3)
{
unsigned int v3; // r9
unsigned int v6; // r4
int v7; // lr
unsigned int result; // r0
unsigned int v9; // r10
int v10; // r1
int v11; // r3

v3 = a2 - 1;
v6 = a1[a2 - 1];
v7 = sub_1258(52) + 6;
result = -1621657930;
v9 = 0;
while ( v7 >= 1 )
{
v9 -= 1621657930;
--v7;
v10 = 0;
v11 = (v9 >> 2) & 3;
while ( v3 != v10 )
{
v6 = ((((4 * a1[v10 + 1]) ^ (v6 >> 5)) + ((a1[v10 + 1] >> 3) ^ (16 * v6))) ^ ((a3[v10 & 3 ^ v11] ^ v6)
+ (a1[v10 + 1] ^ v9)))
+ a1[v10];
a1[v10++] = v6;
}
result = (((4 * *a1) ^ (v6 >> 5)) + ((*a1 >> 3) ^ (16 * v6))) ^ ((*a1 ^ v9) + (a3[v3 & 3 ^ v11] ^ v6));
v6 = result + a1[v3];
a1[v3] = v6;
}
return result;
}

找密文,用之前逆xxtea写的脚本解一下,然后找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
#include <stdio.h>

unsigned int len = 9; //长度是输入字符串长度/4,因为加密是32位为一个单位
unsigned int delat = 0x60A8894A;
unsigned int key[] = {0x1, 0x10, 0x100, 0x1000};

unsigned int enc[] =
{
0x68E5973E, 0xC20C7367, 0x98AFD41B, 0xFE4B9DE2, 0x01A5B60B,
0x3D36D646, 0xDBCC7BAF, 0xA0414F00, 0x762CE71A
};

unsigned int get_sum(int n, unsigned int delat)
{
unsigned int sum = 0;

for(int i = 0; i < 52/n+6; i++)
sum -= delat;

return sum;
}

void de_xxtea()
{

unsigned int sum = get_sum(len, delat);
do
{
unsigned char sum1 = (unsigned char)(sum >> 2);
enc[len-1] -= ((key[((len-1)^sum1)&3]^enc[len-2])+(enc[0]^sum)) ^ (((4*enc[0])^(enc[len-2]>>5))+((16*enc[len-2])^(enc[0]>>3)));

int i = len-2;
do
{
enc[i] -= ((key[(i^sum1)&3]^enc[i-1])+(enc[i+1]^sum)) ^ (((4*enc[i+1])^(enc[i-1]>>5))+((16*enc[i-1])^(enc[i+1]>>3)));
i--;
}while(i != 0);
enc[0] -= ((key[(0^sum1)&3]^enc[len-1])+(enc[1]^sum)) ^ (((4*enc[1])^(enc[len-1]>>5))+((16*enc[len-1])^(enc[1]>>3)));

sum += delat;
}while(sum != 0);

}

int main(void)
{
int i = 0;

de_xxtea();
for(i = 0; i < 4*len; i++)
{
printf("%d, ", ((unsigned char *)&enc)[i]);
}
}
//86, 4, 176, 212, 156, 99, 77, 48, 150, 206, 192, 5, 147, 190, 59, 130, 82, 75, 22, 178, 138, 51, 183, 77, 109, 123, 153, 80, 194, 177, 12, 18, 225, 132, 10, 147
1
2
3
4
5
6
7
8
9
10
11
12
13
>>> s = [0x00, 0x59, 0xE3, 0x80, 0xD3, 0x67, 0x42, 0x33, 0x96, 0xC4, 0xC6, 0x0D, 0x94, 0xBD, 0x6E, 0xD2, 0x5D, 0x18, 0x48, 0xB3, 0x8E, 0x32, 0xE0, 0x46, 0x38, 0x77, 0x9B, 0x54, 0xCE, 0xB0, 0x5F, 0x19, 0xE2, 0x81, 0x5E, 0xD8]
>>> t = "012345678901234567890123456789123456"
>>> t
'012345678901234567890123456789123456'
>>> ans = [ord(t[i])^s[i] for i in range(36)]
>>> ans
[48, 104, 209, 179, 231, 82, 116, 4, 174, 253, 246, 60, 166, 142, 90, 231, 107, 47, 112, 138, 190, 3, 210, 117, 12, 66, 173, 99, 246, 137, 110, 43, 209, 181, 107, 238]
>>> e = [86, 4, 176, 212, 156, 99, 77, 48, 150, 206, 192, 5, 147, 190, 59, 130, 82, 75, 22, 178, 138, 51, 183, 77, 109, 123, 153, 80, 194, 177, 12, 18, 225, 132, 10, 147]
>>> flag = [ans[i]^e[i] for i in range(36)]
>>> flag
[102, 108, 97, 103, 123, 49, 57, 52, 56, 51, 54, 57, 53, 48, 97, 101, 57, 100, 102, 56, 52, 48, 101, 56, 97, 57, 52, 51, 52, 56, 98, 57, 48, 49, 97, 125]
>>> bytes(flag)
b'flag{194836950ae9df840e8a94348b901a}'

so_get_source

进入网站,上传一个一句化木马拿到shell,然后把网站打包下来。

image-20210801094123439

发现flag.php与index.php都是被加密后的,而这里有一个可疑的php_screw_plus.so文件,这和逆向就更贴近了。

搜索一下php_screw_plus.so,发现这个就是对我们的php文件实现加解密功能的文件。

到ida中去找到pm9screw_ext_fopen函数:打开待加密或者解密的文件。

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
FILE *__fastcall pm9screw_ext_fopen(FILE *stream)
{
const __m128i *v1; // rax
__m128i v2; // xmm0
int v3; // eax
_QWORD *v4; // rax
__int64 v5; // rdx
_OWORD *v6; // rbx
unsigned int v7; // er12
__int64 v8; // rdx
unsigned __int64 v9; // rax
__int64 v10; // rsi
char v11; // cl
FILE *v12; // rax
FILE *v13; // rbp
__m128i v15; // [rsp+0h] [rbp-138h] BYREF
int v16; // [rsp+1Ch] [rbp-11Ch] BYREF
struct stat stat_buf; // [rsp+20h] [rbp-118h] BYREF
char nptr[16]; // [rsp+B0h] [rbp-88h] BYREF
__m128i v19; // [rsp+C0h] [rbp-78h]
__m128i v20; // [rsp+D0h] [rbp-68h] BYREF
__m128i v21; // [rsp+E0h] [rbp-58h]
__int128 v22; // [rsp+F0h] [rbp-48h]
__int128 v23; // [rsp+100h] [rbp-38h]
unsigned __int64 v24; // [rsp+118h] [rbp-20h]

v24 = __readfsqword(0x28u);
v20 = 0LL;
v21 = 0LL;
v22 = 0LL;
v23 = 0LL;
v15 = 0LL;
v1 = (const __m128i *)md5("GH65Hws2jedf3fl3MeK");
v20 = _mm_loadu_si128(v1);
v19 = v20;
v2 = _mm_load_si128(&v15);
v21 = _mm_loadu_si128(v1 + 1);
*(__m128i *)nptr = v2;
v3 = fileno(stream);
__fxstat(1, v3, &stat_buf);
v16 = stat_buf.st_size;
v4 = malloc(0x200000uLL);
v5 = v16;
*v4 = 0LL;
v6 = v4;
__fread_chk(v4, 0x200000LL, v5, 1LL, stream);
v7 = teg_yek(stream);
fclose(stream);
if ( *(_OWORD *)&v19 == *v6 )
{
v8 = (unsigned int)v16;
if ( v16 > 16 )
{
v9 = 16LL;
v10 = (unsigned int)(v16 - 17) + 17LL;
do
{
while ( 1 )
{
v11 = *((_BYTE *)v6 + v9);
if ( v9 > 0x1F )
break;
*((_BYTE *)&stat_buf.__unused[1] + v9++) = v11;
if ( v10 == v9 )
goto LABEL_7;
}
*((_BYTE *)v6 + v9++ - 32) = v11;
}
while ( v10 != v9 );
}
LABEL_7:
screw_aes(0LL, v6, v8, &v20, &v16, v7, v15.m128i_i64[0], v15.m128i_i64[1]);
v16 = strtol(nptr, 0LL, 10);
}
v12 = tmpfile();
v13 = v12;
if ( v16 <= 0 )
fwrite("ACCESS DENIED", 0xDuLL, 1uLL, v12);
else
fwrite(v6, v16, 1uLL, v12);
free(v6);
rewind(v13);
return v13;
}

都有函数名的,所以分析起来难度不大,主要就是一个aes_256_cbc加密,我们只需要找密钥,iv在这里就是不需要的,因为iv的错误只会影响前16字节的解密,我们猜测程序的flag放在16字节后,因为iv我没找到,感觉不好找。

首先是一个对GH65Hws2jedf3fl3MeK进行md5加密,追踪变量,发现它的结果是作为了后面aes_256_cbc的密钥。

image-20210801101838900

但这里有一个问题,md5加密结果是16字节,而这里密钥是256位的,要32字节嗯。。

然后看看md5函数及外面取结果的函数:

image-20210801102132852

image-20210801102147464

所以说,程序是直接使用的加密结果的hex形式作为32位密钥。

接下来使用openssl来解密试试,-d:解密 -K:指定密钥,-iv:指定iv,-in:指定要加密或解密的文件,且注意key和iv要以hex形式给出

1
openssl aes-256-cbc -d -K 3834326434326239383837366635383166306466626566623063643262356333 -iv 1 -in flag.php > ans.txt

解密,得到一个乱码文件。

再次回到程序中分析加密函数:发现在加密之后有一个异或,解密之前同样对应一个异或。

image-20210801102919133

而这个v9,我向上找该变量的赋值及回溯,在读文件这里找到。。但这也是不知道的。

image-20210801103055301

好在上面异或的v9变量只是一个字节,所以考虑爆破,找到flag/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import os

f = open("flag1.php", "rb")
text = f.read()

for i in range(255):
f1 = open('flag.php', "wb")
for j in text:
f1.write(bytes([j^i]))
os.system('openssl aes-256-cbc -d -K 3834326434326239383837366635383166306466626566623063643262356333 -iv 1 -in flag.php > ans.txt')
a = open('ans.txt', 'rb')
ans = a.read()
if b'flag' in ans:
print("*"*100)
print(i)
break

解密结果:(这里我去除了解密结果中的开始的16字节乱码字符,因为它会导致的我博客使用的gulp出错。

1
2
3
****************flag{47a3f7b1-499c-4e45-ed3e-404602cfef96}";

echo "no my code</
-------------本文结束感谢您的阅读-------------