N1CTF Junior 2025 WriteUp

5.6k words

注:只做了reverse方向的题目。从2月3日HGAME CTF开始到2月8日的VNCTF再到2月9日的N1CTF Junior,长线作战使得此时已经有些乏力了,三道逆向题目中,第一道(easy-re)由于缺少root过的arm架构安卓手机,在艰难分析手撕ollvm后因发现关键值需要动态调试获取而望洋兴叹,只得作罢…

Reverse方向:

5mc:

反编译观察main:

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
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
_BYTE *v5; // rdi
int v6; // eax
_BYTE *v7; // rsi
_BYTE *v8; // rcx
_BYTE *v9; // r15
_BYTE *v10; // r12
__int64 v11; // r14
unsigned __int8 v12; // bl
unsigned __int8 v13; // al
char v14; // r8
int v15; // eax
_BYTE *v16; // rcx
__int64 v17; // rdi
unsigned __int8 v18; // bl
unsigned __int8 v19; // cl
char v20; // r8
__int64 i; // rbx
__int64 j; // rbx
int v23; // edi
__int64 v24; // rbx
_OWORD *v25; // rax
_OWORD *v26; // rcx
__int128 v27; // xmm1
void *v28; // rdi
__int64 k; // rbx
__int64 m; // r9
const __m128i *v31; // r8
__int64 v32; // rax
__int8 *v33; // rdx
const __m128i *v34; // rcx
__m128i v35; // xmm0
__m128i v36; // xmm2
__m128i v37; // xmm1
int v38; // eax
const char *v39; // rcx
__int64 v40[18]; // [rsp+20h] [rbp-E0h]
DWORD flOldProtect[4]; // [rsp+B0h] [rbp-50h] BYREF
LPVOID lpAddress[18]; // [rsp+C0h] [rbp-40h]
char Buf1[40]; // [rsp+150h] [rbp+50h] BYREF

v40[0] = (__int64)sub_7FF7C9755250;
v40[1] = (__int64)&unk_7FF7C9754A30;
v40[2] = (__int64)&unk_7FF7C9754DD0;
v40[3] = (__int64)&unk_7FF7C97554F0;
v40[4] = (__int64)&unk_7FF7C97555D0;
v40[5] = (__int64)&unk_7FF7C9754C10;
v40[6] = (__int64)&unk_7FF7C9754EB0;
v40[7] = (__int64)&unk_7FF7C9755090;
v40[8] = (__int64)&unk_7FF7C9755330;
v40[9] = (__int64)&unk_7FF7C9754CF0;
v40[10] = (__int64)&unk_7FF7C9755170;
v40[11] = (__int64)&unk_7FF7C9755410;
v40[12] = (__int64)&unk_7FF7C9754B30;
v40[13] = (__int64)&unk_7FF7C9755790;
v40[14] = (__int64)&unk_7FF7C9754F90;
v40[15] = (__int64)&unk_7FF7C97556B0;
v40[16] = (__int64)&unk_7FF7C9755870;
printf("flag:");
scanf("%s", Buf1);
v3 = -1i64;
do
++v3;
while ( Buf1[v3] );
if ( v3 == 32 ) //flag的长度为32
{
srand(0x1BF52u);
v5 = off_7FF7C9755068;
v6 = 0;
v7 = off_7FF7C9755070;
v8 = off_7FF7C9755068;
v9 = off_7FF7C9755078;
v10 = off_7FF7C9755080;
do
*v8++ = v6++;
while ( v6 < 256 );
v11 = 512i64;
do
{
v12 = rand();
v13 = rand();
v14 = v5[v12];
v5[v12] = v5[v13];
v5[v13] = v14;
--v11;
}
while ( v11 );
v15 = 0;
v16 = v7;
do
*v16++ = v15++;
while ( v15 < 32 );
v17 = 32i64;
do
{
v18 = rand() % 32;
v19 = rand() % 32;
v20 = v7[v18];
v7[v18] = v7[v19];
v7[v19] = v20;
--v17;
}
while ( v17 );
for ( i = 0i64; i < 32; ++i )
v9[i] = rand();
for ( j = 0i64; j < 32; ++j )
v10[j] = rand();
v23 = 0;
v24 = 0i64;
do
{
v25 = VirtualAlloc(0i64, 0xD2ui64, 0x1000u, 4u);
lpAddress[v24] = v25;
if ( !v25 )
return -1;
v26 = (_OWORD *)v40[v24];
++v23;
++v24;
*v25 = *v26;
v25[1] = v26[1];
v25[2] = v26[2];
v25[3] = v26[3];
v25[4] = v26[4];
v25[5] = v26[5];
v25[6] = v26[6];
v27 = v26[7];
v26 += 8;
v25[7] = v27;
v25[8] = *v26;
v25[9] = v26[1];
v25[10] = v26[2];
v25[11] = v26[3];
v25[12] = v26[4];
*((_WORD *)v25 + 104) = *((_WORD *)v26 + 40);
}
while ( v23 < 17 );
v28 = lpAddress[0];
for ( k = 0i64; k < 16; ++k )
{
for ( m = 0i64; m < 17; ++m )
{
if ( m != k + 1 )
{
v31 = (const __m128i *)lpAddress[m];
v32 = 0i64;
v33 = (__int8 *)lpAddress[k + 1];
if ( v31 <= (const __m128i *)(v33 + 209) && &v31[13].m128i_i8[1] >= v33 )
goto LABEL_37;
v34 = v31 + 2;
do
{
v35 = _mm_loadu_si128(v34 - 2);
v34 += 4;
v36 = _mm_loadu_si128((const __m128i *)&v33[v32 + 32]);
v34[-6] = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&v33[v32]), v35);
v34[-5] = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&v33[v32 + 16]), _mm_loadu_si128(v34 - 5));
v37 = _mm_loadu_si128((const __m128i *)&v33[v32 + 48]);
v32 += 64i64;
v34[-4] = _mm_xor_si128(v36, _mm_loadu_si128(v34 - 4));
v34[-3] = _mm_xor_si128(v37, _mm_loadu_si128(v34 - 3));
}
while ( v32 < 192 );
if ( v32 < 210 )
{
LABEL_37:
do
{
v31->m128i_i8[v32] ^= v33[v32];
++v32;
}
while ( v32 < 210 );
}
}
}
memset(lpAddress[k + 1], 0, 0xD2ui64);
VirtualProtect(v28, 0xD2ui64, 0x20u, flOldProtect);
((void (__fastcall *)(char *, void **))v28)(Buf1, &off_7FF7C9755068); //SMC函数
VirtualProtect(v28, 0xD2ui64, 4u, flOldProtect);
}
v38 = memcmp(Buf1, &unk_7FF7C9754B08, 0x20ui64); //比较结果
v39 = "right\n";
if ( v38 )
v39 = "wrong\n";
printf(v39);
return 0;
}
else
{
printf("wrong\n");
return 0;
}
}

发现了一个SMC的加密,然后就是比较了,密文为[0x5B, 0x2D, 0xE9, 0x66, 0xED, 0x39, 0x90, 0x23, 0xAF, 0xDA, 0xEB, 0x2E, 0xD1, 0x0D, 0xBB, 0xBD, 0x57, 0x52, 0x02, 0xB0, 0xBA, 0x9D, 0x52, 0xFA, 0x67, 0xEE, 0xA3, 0x85, 0xA9, 0x84, 0xE2, 0x6F],动态调试着重看SMC部分,发现SMC部分的代码一共执行16次,且函数一共有许多种(有点像VM),执行逻辑为:

01 02 03(5,3) 04(1,7) 01 02 03(2,6) 04(4,4) 01 02 03(5,3) 04(3,5) 01 02 03(6,2) 04(7,1)

列出这些函数,第一种:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__int64 __fastcall sub_1FC33450000(__int64 a1, __int64 *a2)
{
__int64 result; // rax
__int64 v3; // [rsp+10h] [rbp-10h]
int i; // [rsp+1Ch] [rbp-4h]

result = *a2; //第一个对照表:256字节
v3 = *a2;
for ( i = 0; i <= 31; ++i ) //循环32次
{
result = *(unsigned __int8 *)(v3 + *(unsigned __int8 *)(a1 + i)); //加密方式:在a2中找到以a1为索引的值
*(_BYTE *)(a1 + i) = result; //写回原字符
}
return result;
}

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

继续往后看第二种加密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
__int64 __fastcall sub_1FC33450000(__int64 a1, __int64 a2)
{
__int64 result; // rax
char v3[44]; // [rsp+0h] [rbp-40h]
int v4; // [rsp+2Ch] [rbp-14h]
__int64 v5; // [rsp+30h] [rbp-10h]
int j; // [rsp+38h] [rbp-8h]
int i; // [rsp+3Ch] [rbp-4h]

result = *(_QWORD *)(a2 + 8);
v5 = result; //设置v5的值为新的对照表(32字节长度)
v4 = 32;
for ( i = 0; i <= 31; ++i )
{
result = *(unsigned __int8 *)(i + a1);
v3[*(unsigned __int8 *)(v5 + i)] = result;
}
for ( j = 0; j <= 31; ++j )
{
result = (unsigned __int8)v3[j];
*(_BYTE *)(*(unsigned __int8 *)(v5 + j) + a1) = result; //按给定的32位对照表两次打乱给出的32字节的数据
}
return result;
}

动态调试得到第二个对照表:[0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06, 0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05, 0x0E, 0x03, 0x12, 0x04, 0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B, 0x17, 0x0A],接着看第三个加密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
_BYTE *__fastcall sub_20367C90000(__int64 a1, __int64 a2)
{
_BYTE *result; // rax
_BYTE *v3; // [rsp+8h] [rbp-18h]
__int64 v4; // [rsp+10h] [rbp-10h]
int i; // [rsp+1Ch] [rbp-4h]

v4 = *(_QWORD *)(a2 + 16); //异或表v4
result = *(_BYTE **)(a2 + 24); //加和表v3
v3 = result;
for ( i = 0; i <= 31; ++i )
{
*(_BYTE *)(a1 + i) = (*(_BYTE *)(v4 + i) ^ *(_BYTE *)(a1 + i)) + v3[i]; //异或并加和
result = (_BYTE *)(a1 + i);
*result = ((int)(unsigned __int8)*result >> 5) | (8 * *result); //低五位|高三位
}
return result;
}

同理得到第三、四个表:[0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13, 0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF, 0x18, 0x4F, 0x26, 0x18, 0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9, 0x9E, 0xC4][0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41, 0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8, 0x1E, 0xBA, 0x6A, 0xBE, 0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C, 0xE2, 0x43],看第四个加密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
_BYTE *__fastcall sub_20367C90000(__int64 a1, __int64 a2)
{
_BYTE *result; // rax
_BYTE *v3; // [rsp+8h] [rbp-18h]
__int64 v4; // [rsp+10h] [rbp-10h]
int i; // [rsp+1Ch] [rbp-4h]

v4 = *(_QWORD *)(a2 + 16);
result = *(_BYTE **)(a2 + 24);
v3 = result;
for ( i = 0; i <= 31; ++i )
{
*(_BYTE *)(a1 + i) = *(_BYTE *)(v4 + i) ^ (*(_BYTE *)(a1 + i) + v3[i]); //加和并异或
result = (_BYTE *)(a1 + i);
*result = ((int)(unsigned __int8)*result >> 1) | (*result << 7);
}
return result;
}

发现和第三个相比变化不大,到第七个函数的时候是第三种改了改参数:

1
2
3
*(_BYTE *)(a1 + i) = (*(_BYTE *)(v4 + i) ^ *(_BYTE *)(a1 + i)) + v3[i];
result = (_BYTE *)(a1 + i);
*result = ((int)(unsigned __int8)*result >> 2) | (*result << 6);

也是同类型的,这里不再分析,第八个函数同理:

1
2
3
*(_BYTE *)(a1 + i) = *(_BYTE *)(v4 + i) ^ (*(_BYTE *)(a1 + i) + v3[i]);
result = (_BYTE *)(a1 + i);
*result = ((int)(unsigned __int8)*result >> 4) | (16 * *result);

由于类型基本一样,这类可以分成两种:一种是先异或后加和,一种是先加和后异或,编写解密脚本:

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
#第一种加密方式
def SMC_E1(input_data, offset_table):
encrypted_data = bytearray(input_data)
for i in range(32):
encrypted_data[i] = offset_table[encrypted_data[i]]
return encrypted_data
#第一种解密方式
def SMC_D1(encrypted_data, offset_table):
reverse_table = [0] * 256
for original_value, offset_value in enumerate(offset_table):
reverse_table[offset_value] = original_value
decrypted_data = bytearray(encrypted_data)
for i in range(32):
decrypted_data[i] = reverse_table[decrypted_data[i]]
return decrypted_data
#第一种加密方式的对照表
array1 = [0xB0, 0xF0, 0x21, 0xCF, 0xF2, 0x04, 0x3A, 0x68, 0x84, 0x7B, 0x39, 0x86, 0x36, 0x87, 0x9B, 0xF7,
0x3D, 0x18, 0x1E, 0x61, 0x1B, 0x2E, 0x6C, 0xDF, 0x2C, 0xAE, 0x65, 0x9D, 0xEB, 0x2F, 0xDA, 0xF4,
0xDE, 0xCA, 0x56, 0x92, 0x75, 0x3B, 0x62, 0x45, 0x06, 0x3C, 0x52, 0x33, 0x6E, 0x25, 0xCE, 0xA3,
0xD2, 0x44, 0xA1, 0x4A, 0x58, 0xB1, 0xA0, 0x2A, 0x47, 0x0A, 0x02, 0xAF, 0x50, 0xC3, 0xDC, 0xEA,
0xE5, 0x0D, 0x67, 0x91, 0xE1, 0x51, 0xE3, 0xC1, 0xAA, 0x95, 0x5C, 0x79, 0x72, 0x1C, 0x3F, 0xB8,
0xE8, 0x1F, 0xFF, 0x7A, 0x73, 0x26, 0x54, 0x9E, 0xED, 0xA9, 0x41, 0x20, 0xEF, 0xA6, 0x48, 0x97,
0x4F, 0xD4, 0xBB, 0x23, 0x66, 0xD9, 0xE4, 0x0B, 0x30, 0x15, 0xD7, 0x6B, 0x19, 0xCD, 0xC4, 0x08,
0xB4, 0xC8, 0x14, 0xFD, 0x7F, 0x28, 0x0E, 0x05, 0x0F, 0x4B, 0x6F, 0xF5, 0x90, 0x76, 0xBF, 0x60,
0xE7, 0x24, 0x78, 0x6D, 0x71, 0xA8, 0x43, 0xB5, 0x0C, 0x31, 0xF9, 0xA2, 0x9C, 0x99, 0xF6, 0x2D,
0xDB, 0xB7, 0xC9, 0x85, 0x81, 0x03, 0x64, 0x1D, 0x07, 0x34, 0x5A, 0xBD, 0x37, 0x4C, 0xA7, 0x5F,
0x46, 0xE9, 0x35, 0x93, 0x8D, 0xA5, 0xFB, 0x42, 0x01, 0xC2, 0x17, 0x12, 0x1A, 0x77, 0xC6, 0x53,
0x83, 0x4D, 0xB2, 0x10, 0x2B, 0xF8, 0x88, 0x6A, 0x3E, 0xD0, 0x7C, 0x63, 0x40, 0x27, 0xBE, 0xD5,
0x38, 0xD1, 0x74, 0xB6, 0x57, 0x94, 0xAB, 0x8A, 0xB9, 0xBC, 0x7D, 0xB3, 0x96, 0x7E, 0xFC, 0xAD,
0x22, 0x4E, 0xFA, 0xE0, 0xCB, 0x8B, 0xEE, 0x32, 0xA4, 0x16, 0xFE, 0x5B, 0x13, 0xDD, 0xC0, 0x9A,
0x5E, 0x8E, 0x29, 0xF3, 0x8F, 0x49, 0xE6, 0x9F, 0xF1, 0xC5, 0x70, 0x55, 0x8C, 0x11, 0xCC, 0x5D,
0xEC, 0x00, 0xAC, 0x89, 0xD3, 0x82, 0x69, 0xD6, 0xBA, 0xD8, 0x59, 0x98, 0x09, 0x80, 0xE2, 0xC7]
#第二种加密方式
def SMC_E2(a1, a2):
v3 = bytearray(32)
for i in range(32):
v3[a2[i]] = a1[i]
return bytes(v3)
#第二种解密方式
def SMC_D2(shuffled_data, a2):
v3 = bytearray(32)
reverse_map = [0] * 32
for i in range(32):
reverse_map[a2[i]] = i
for i in range(32):
v3[reverse_map[i]] = shuffled_data[i]
return bytes(v3)
#第二种加密方式的对照表
array2 = [0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06, 0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05,
0x0E, 0x03, 0x12, 0x04, 0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B, 0x17, 0x0A]
#第三种加密方式
def SMC_E3(input_data, xor_table, add_table, v1, v2):
transformed_data = bytearray(input_data)
for i in range(32):
temp = transformed_data[i] ^ xor_table[i]
temp = (temp + add_table[i]) & 0xFF
transformed_data[i] = ((temp >> v1) | (temp << v2)) & 0xFF
return transformed_data
#第三种解密方式
def SMC_D3(encrypted_data, xor_table, add_table, v1, v2):
decrypted_data = bytearray(encrypted_data)
for i in range(32):
temp = decrypted_data[i]
temp = ((temp << v1) | (temp >> v2)) & 0xFF
temp = (temp - add_table[i]) & 0xFF
decrypted_data[i] = temp ^ xor_table[i]
return decrypted_data
#第四种加密方式
def SMC_E4(input_data, xor_table, add_table, v1, v2):
transformed_data = bytearray(input_data)
for i in range(32):
temp = transformed_data[i] + add_table[i] & 0xFF
temp ^= xor_table[i]
transformed_data[i] = ((temp >> v1) | (temp << v2)) & 0xFF
return transformed_data
#第四种解密方式
def SMC_D4(encrypted_data, xor_table, add_table, v1, v2):
decrypted_data = bytearray(encrypted_data)
for i in range(32):
temp = decrypted_data[i]
temp = ((temp << v1) | (temp >> v2)) & 0xFF
temp ^= xor_table[i]
decrypted_data[i] = (temp - add_table[i]) & 0xFF
return decrypted_data
#第三四种加密方式的表
xor_table = [0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13, 0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF,
0x18, 0x4F, 0x26, 0x18, 0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9, 0x9E, 0xC4]
add_table = [0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41, 0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8,
0x1E, 0xBA, 0x6A, 0xBE, 0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C, 0xE2, 0x43]
#加密过程:用于测试
input_data = b'12345678901234567890123456789012'
print(f"Original Data: {input_data}")

input_data = SMC_E1(input_data, array1)
print(f"0# E1 Data: {input_data}")
input_data = SMC_E2(SMC_E2(input_data, array2), array2)
print(f"1# E2 data: {input_data}")
input_data = SMC_E3(input_data, xor_table, add_table, 5, 3)
print(f"2# E3 Data: {input_data}")
input_data = SMC_E4(input_data, xor_table, add_table, 1, 7)
print(f"3# E4 Data: {input_data}")

input_data = SMC_E1(input_data, array1)
print(f"4# E1 Data: {input_data}")
input_data = SMC_E2(SMC_E2(input_data, array2), array2)
print(f"5# E2 data: {input_data}")
input_data = SMC_E3(input_data, xor_table, add_table, 2, 6)
print(f"6# E3 data: {input_data}")
input_data = SMC_E4(input_data, xor_table, add_table, 4, 4)
print(f"7# E4 data: {input_data}")

input_data = SMC_E1(input_data, array1)
print(f"8# E1 Data: {input_data}")
input_data = SMC_E2(SMC_E2(input_data, array2), array2)
print(f"9# E2 data: {input_data}")
input_data = SMC_E3(input_data, xor_table, add_table, 5, 3)
print(f"A# E3 Data: {input_data}")
input_data = SMC_E4(input_data, xor_table, add_table, 3, 5)
print(f"B# E4 Data: {input_data}")

input_data = SMC_E1(input_data, array1)
print(f"C# E1 Data: {input_data}")
input_data = SMC_E2(SMC_E2(input_data, array2), array2)
print(f"D# E2 data: {input_data}")
input_data = SMC_E3(input_data, xor_table, add_table, 6, 2)
print(f"E# E3 data: {input_data}")
input_data = SMC_E4(input_data, xor_table, add_table, 7, 1)
print(f"F# E4 data: {input_data}")
#解密过程
input_data = b'\x5b\x2d\xe9\x66\xed\x39\x90\x23\xaf\xda\xeb\x2e\xd1\x0d\xbb\xbd\x57\x52\x02\xb0\xba\x9d\x52\xfa\x67\xee\xa3\x85\xa9\x84\xe2\x6f'
input_data = SMC_D4(input_data, xor_table, add_table, 7, 1)
print(f"F# D4 data: {input_data}")
input_data = SMC_D3(input_data, xor_table, add_table, 6, 2)
print(f"E# D3 data: {input_data}")
input_data = SMC_D2(SMC_D2(input_data, array2), array2)
print(f"D# D2 data: {input_data}")
input_data = SMC_D1(input_data, array1)
print(f"C# D1 Data: {input_data}")

input_data = SMC_D4(input_data, xor_table, add_table, 3, 5)
print(f"B# D4 data: {input_data}")
input_data = SMC_D3(input_data, xor_table, add_table, 5, 3)
print(f"A# D3 data: {input_data}")
input_data = SMC_D2(SMC_D2(input_data, array2), array2)
print(f"9# D2 data: {input_data}")
input_data = SMC_D1(input_data, array1)
print(f"8# D1 Data: {input_data}")

input_data = SMC_D4(input_data, xor_table, add_table, 4, 4)
print(f"7# D4 data: {input_data}")
input_data = SMC_D3(input_data, xor_table, add_table, 2, 6)
print(f"6# D3 data: {input_data}")
input_data = SMC_D2(SMC_D2(input_data, array2), array2)
print(f"5# D2 data: {input_data}")
input_data = SMC_D1(input_data, array1)
print(f"4# D1 Data: {input_data}")

input_data = SMC_D4(input_data, xor_table, add_table, 1, 7)
print(f"3# D4 data: {input_data}")
input_data = SMC_D3(input_data, xor_table, add_table, 5, 3)
print(f"2# D3 data: {input_data}")
input_data = SMC_D2(SMC_D2(input_data, array2), array2)
print(f"1# D2 data: {input_data}")
input_data = SMC_D1(input_data, array1)
print(f"0# D1 Data: {input_data}")

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
F# D4 data: bytearray(b'?F1\xee\x0f\xd0\x1f\xa1\xe9=\x85\x9f\xcd\xd8\xa0\x19\x95\xac\xbd\x82\x89\xd2\xa5\xad\xf6H\xd0W\x92o\r0')
E# D3 data: bytearray(b'C\x01\x89"^fL\x18\xc4\x1d%a\xd6\x0ey\x81_>#\xfa\x8e\x88\xc9\xa98S\x11\xe0\xe2v\xff\r')
D# D2 data: b'^%ya\r\xd6\x88\x8e\xc4\x18\x11\xfaf\x81_\x0e\x89v#\x01\xff8\x1d>\xa9SL\xe0"C\xe2\xc9'
C# D1 Data: bytearray(b'\xe0-K\x13A\xf7\xb6\xe1n\x11\xed\xd2d\x94\x9fv\xf3}c\xa8R\xc0\x97\xb8Y\xaf\x9d\xd3\xd0\x86\xfe\x92')
B# D4 data: bytearray(b'\xe9\x03\xdf\x87\xa3\xad2/MZ\xeb \x82\xf6\x81\x84i\xea\xd3\x9f\xba\x1a\x10%O>\xcd\xab\xc4\xe1\x87\r')
A# D3 data: bytearray(b'\xd12x\xef\x8d\xe5\xcd\xe5\x95\x19\t\x841\xa6qW\x17\xec6-\x83\x1b.\xf0l\x98\x94@\xd6\xe9\x90\x9a')
9# D2 data: b'\x8d\tq\x84\x9a1\x1b\x83\x95\xe5\x94-\xe5W\x17\xa6x\xe962\x90l\x19\xec\xf0\x98\xcd@\xef\xd1\xd6.'
8# D1 Data: bytearray(b'\xa4\xfc\x84\x08\xdf\x89\x14\xb0I@\xc5\x8f@\xc4\xaa]\x82\xa1\x0c\xd7|\x16l\xf0\x01\xfbm\xbc\\\xc1\xf7\x15')
7# D4 data: bytearray(b'\xa6\x9d\xcd\x9f\x18\xcc&+,\xd6\x1c~i\x0e\xab"\x12\x9b|\xa7\x0f9\x06[\x99\x00\xd3^\x83\xb9\xffR')
6# D3 data: bytearray(b't,\xbca\xf9g\x7f\xdc\x8e\t4\x8f\x84\x08\xf3_2\xfb\xa1\xf8d\xf8\x18\xaf\xefA\x0eLL\x03\x83\xc2')
5# D2 data: b'\xf94\xf3\x8f\xc2\x84\xf8d\x8e\xdc\x0e\xf8g_2\x08\xbc\x03\xa1,\x83\xef\t\xfb\xafA\x7fLatL\x18'
4# D1 Data: bytearray(b'\x8a\x99\xe3\xe4\xa9\x08\xb5\x96\xe1>v\xb5B\x9f\xd7o\xc9\x952\x18\xb0\\\xfc\xa6;Zt\x9d\x13\xc2\x9d\x11')
3# D4 data: bytearray(b'\xd7\xa9DXjT\x00M\xfd.l\xeb\xe9\x7f\xae\x19m\xaa\xd8j\xad\x80\xd5\x9d\xb3\x05\xc9\x0ed0\xc3\xa3')
2# D3 data: bytearray(b'\x14\xed\xcd\xd2\xe4\x08\x97\xd9\x7f\x97\x19\x0b\x1c\xb1\xd4\xe4\x97\xd4\x97\x97\xfd\xd4v\xe1\xff\xe1\x14\x14\xca#\x08\xf5')
1# D2 data: b'\xe4\x19\xd4\x0b\xf5\x1c\xd4\xfd\x7f\xd9\x14\x97\x08\xe4\x97\xb1\xcd#\x97\xed\x08\xff\x97\xd4\xe1\xe1\x97\x14\xd2\x14\xcav'
0# D1 Data: bytearray(b'flag{Master_of_5mc_XoR_aDD_r0r!}')

则flag为:flag{Master_of_5mc_XoR_aDD_r0r!}.

df5:

查看main:

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
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rdi
const char *v4; // rdx
__int64 v5; // r8
__int64 v6; // rax
const char *v7; // rcx
_BYTE *v8; // rsi
int v9; // eax
_BYTE *v10; // r14
_BYTE *v11; // rcx
_BYTE *v12; // r15
_BYTE *v13; // r12
__int64 v14; // rbp
unsigned __int8 v15; // bl
unsigned __int8 v16; // al
char v17; // r8
int v18; // eax
_BYTE *v19; // rcx
__int64 v20; // rsi
unsigned __int8 v21; // bl
unsigned __int8 v22; // al
char v23; // r8
__int64 i; // rbx
__int64 j; // rbx
int v26; // eax
__int64 v28[4]; // [rsp+28h] [rbp-70h]
char Buf1[40]; // [rsp+48h] [rbp-50h] BYREF

v3 = 0i64;
v28[0] = (__int64)sub_7FF7BB5410E0; //四种不同的加密方式
v28[1] = (__int64)sub_7FF7BB5412A0;
v28[2] = (__int64)sub_7FF7BB541610;
v28[3] = (__int64)sub_7FF7BB5416B0;
sub_7FF7BB541020("flag:", argv, envp);
sub_7FF7BB541080("%s", Buf1);
v6 = -1i64;
do
++v6;
while ( Buf1[v6] );
if ( v6 == 32 )
{
srand(0x1BF52u);
v8 = off_7FF7BB565B90;
v9 = 0;
v10 = off_7FF7BB565B98;
v11 = off_7FF7BB565B90;
v12 = off_7FF7BB565BA0;
v13 = off_7FF7BB565BA8;
do
*v11++ = v9++;
while ( v9 < 256 );
v14 = 512i64;
do
{
v15 = rand();
v16 = rand();
v17 = v8[v15];
v8[v15] = v8[v16];
v8[v16] = v17;
--v14;
}
while ( v14 );
v18 = 0;
v19 = v10;
do
*v19++ = v18++;
while ( v18 < 32 );
v20 = 32i64;
do
{
v21 = rand() % 32;
v22 = rand() % 32;
v23 = v10[v21];
v10[v21] = v10[v22];
v10[v22] = v23;
--v20;
}
while ( v20 );
for ( i = 0i64; i < 32; ++i )
v12[i] = rand();
for ( j = 0i64; j < 32; ++j )
v13[j] = rand();
do
((void (__fastcall *)(char *, void **))v28[Buf1[v3++] & 3])(Buf1, &off_7FF7BB565B90); //选择什么样的加密方式由输入值决定
while ( v3 < 32 );
v26 = memcmp(Buf1, &unk_7FF7BB565AD0, 0x20ui64);
v7 = "right\n";
v4 = "wrong\n";
if ( v26 )
v7 = "wrong\n";
}
else
{
v7 = "wrong\n";
}
sub_7FF7BB541020(v7, v4, v5);
return 0;
}

发现函数结构和5mc很相似,flag密文为:[0x65, 0x3E, 0x43, 0xB8, 0xBA, 0xDB, 0xF6, 0x88, 0x25, 0x1B, 0x28, 0xC7, 0xC0, 0x54, 0xA6, 0x4A, 0x90, 0x37, 0xBC, 0x29, 0x41, 0xAA, 0x28, 0xDB, 0x9A, 0x59, 0x63, 0x9E, 0x4B, 0xCF, 0x2E, 0x41],但极其诡异的是加密方式的选择由输入的值来决定:输入值从第0个索引开始遍历,计算该值按位与3的值并调用函数列表v28中的这个索引对应的函数,带入输入值和一些数组的偏移量进行加密,加密之后的结果又决定了下一个值该使用哪个加密,若加密非单字节加密,则基本上无解,先将这四个加密函数反编译,先看索引为0的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
__int64 __fastcall sub_7FF7BB5410E0(unsigned __int8 *a1, __int64 *a2)
{
v2 = *a2;
v4 = a1[1];
*a1 = *(_BYTE *)(*a1 + *a2);
v5 = *(_BYTE *)(v4 + v2);
v6 = a1[2];
a1[1] = v5;
v7 = *(_BYTE *)(v6 + v2);
v8 = a1[3];
a1[2] = v7;
…中间部分省略…
v61 = *(_BYTE *)(v60 + v2);
v62 = a1[30];
a1[29] = v61;
v63 = *(_BYTE *)(v62 + v2);
result = a1[31];
a1[30] = v63;
a1[31] = *(_BYTE *)(result + v2);
return result;
}

发现这个函数等效的就是上一题的S盒替换,并且动态调试查看发现S盒也没有改变,再看索引为1的函数:

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
__int64 __fastcall sub_7FF7BB5412A0(char *a1, __int64 a2)
{
unsigned __int8 *v2; // r9
__int64 v4; // rdx
__int64 v5; // r8
char v6; // al
__int64 v7; // rcx
__int64 result; // rax
char v9[31]; // [rsp+0h] [rbp-20h]
unsigned __int8 v10; // [rsp+1Fh] [rbp-1h]

v2 = *(unsigned __int8 **)(a2 + 8);
v4 = v2[1];
v5 = *v2;
v9[v5] = *a1;
v9[v4] = a1[1];
v6 = a1[2];
v7 = v2[3];
v9[v2[2]] = v6;
v9[v7] = a1[3];

v9[v2[31]] = a1[31];
a1[v5] = v9[0];
a1[v2[1]] = v9[1];

a1[v2[30]] = v9[30];
result = v10;
a1[v2[31]] = v10;
return result;
}

发现这个函数也是上一题的打乱函数,并且打乱用的对照表也没变,再看索引为2的函数:

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
__m128i *__fastcall sub_7FF7BB541610(const __m128i *a1, __int64 a2)
{
unsigned __int64 v2; // r8
__int8 *v3; // r10
unsigned __int64 v4; // r9
unsigned __int64 v5; // r9
__m128i *result; // rax
unsigned __int64 v7; // r8
__int64 v8; // r10
__int8 *v9; // rdx
char v10; // cl
unsigned __int64 v11; // r9
__int64 v12; // rdx
unsigned __int64 v13; // r8
__m128i v14; // xmm0

v2 = *(_QWORD *)(a2 + 24); //上一题的第四个表
v3 = &a1[1].m128i_i8[15];
v4 = *(_QWORD *)(a2 + 16); //上一题的第三个表
if ( ((unsigned __int64)a1 > v2 + 31 || (unsigned __int64)v3 < v2) && ((unsigned __int64)a1 > v4 + 31 || (unsigned __int64)v3 < v4) )
{
v11 = v4 – v2;
v12 = 2i64;
v13 = v2 – (_QWORD)a1;
do
{
result = (__m128i *)((char *)a1 + v13); //v2,第四个表
v14 = _mm_loadu_si128(a1++);
a1[-1] = _mm_add_epi8(_mm_xor_si128(_mm_loadu_si128((__m128i *)((char *)result + v11)), v14),_mm_loadu_si128(result)); //先异或后相加
--v12;
}
while ( v12 );
}
else
{
v5 = v4 - v2;
result = (__m128i *)a1;
v7 = v2 - (_QWORD)a1;
v8 = 32i64;
do
{
v9 = &result->m128i_i8[v7];
v10 = result->m128i_i8[0] ^ result->m128i_i8[v7 + v5];
result = (__m128i *)((char *)result + 1);
result[-1].m128i_i8[15] = *v9 + v10; //先异或后相加
--v8;
}
while ( v8 );
}
return result;
}

发现还是上一题的加密方式,是其中的第三种,但是移除了最后的位移动,再看索引为3的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
char __fastcall sub_7FF7BB5416B0(_BYTE *a1)
{
char result; // al

*a1 = __ROR1__(*a1, 3);
a1[1] = __ROR1__(a1[1], 3);


a1[30] = __ROR1__(a1[30], 3);
result = __ROR1__(a1[31], 3);
a1[31] = result;
return result;
}

发现这部分补齐了位移动,只不过换成了定值3,至此四种加密方式已经解析完毕,但困难的是获取这四种加密方式的顺序,仔细考虑后发现,如果解密后对应字符按位与3的值不符合要求,则证明不是这种解密,基于此编写解密脚本:

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
#第一种加密方式
def DFS_E1(input_data, offset_table):
encrypted_data = bytearray(input_data)
for i in range(32):
encrypted_data[i] = offset_table[encrypted_data[i]]
return encrypted_data
#第一种解密方式
def DFS_D1(encrypted_data, offset_table):
reverse_table = [0] * 256
for original_value, offset_value in enumerate(offset_table):
reverse_table[offset_value] = original_value
decrypted_data = bytearray(encrypted_data)
for i in range(32):
decrypted_data[i] = reverse_table[decrypted_data[i]]
return decrypted_data
#第一种加密方式的对照表
array1 = [0xB0, 0xF0, 0x21, 0xCF, 0xF2, 0x04, 0x3A, 0x68, 0x84, 0x7B, 0x39, 0x86, 0x36, 0x87, 0x9B, 0xF7,
0x3D, 0x18, 0x1E, 0x61, 0x1B, 0x2E, 0x6C, 0xDF, 0x2C, 0xAE, 0x65, 0x9D, 0xEB, 0x2F, 0xDA, 0xF4,
0xDE, 0xCA, 0x56, 0x92, 0x75, 0x3B, 0x62, 0x45, 0x06, 0x3C, 0x52, 0x33, 0x6E, 0x25, 0xCE, 0xA3,
0xD2, 0x44, 0xA1, 0x4A, 0x58, 0xB1, 0xA0, 0x2A, 0x47, 0x0A, 0x02, 0xAF, 0x50, 0xC3, 0xDC, 0xEA,
0xE5, 0x0D, 0x67, 0x91, 0xE1, 0x51, 0xE3, 0xC1, 0xAA, 0x95, 0x5C, 0x79, 0x72, 0x1C, 0x3F, 0xB8,
0xE8, 0x1F, 0xFF, 0x7A, 0x73, 0x26, 0x54, 0x9E, 0xED, 0xA9, 0x41, 0x20, 0xEF, 0xA6, 0x48, 0x97,
0x4F, 0xD4, 0xBB, 0x23, 0x66, 0xD9, 0xE4, 0x0B, 0x30, 0x15, 0xD7, 0x6B, 0x19, 0xCD, 0xC4, 0x08,
0xB4, 0xC8, 0x14, 0xFD, 0x7F, 0x28, 0x0E, 0x05, 0x0F, 0x4B, 0x6F, 0xF5, 0x90, 0x76, 0xBF, 0x60,
0xE7, 0x24, 0x78, 0x6D, 0x71, 0xA8, 0x43, 0xB5, 0x0C, 0x31, 0xF9, 0xA2, 0x9C, 0x99, 0xF6, 0x2D,
0xDB, 0xB7, 0xC9, 0x85, 0x81, 0x03, 0x64, 0x1D, 0x07, 0x34, 0x5A, 0xBD, 0x37, 0x4C, 0xA7, 0x5F,
0x46, 0xE9, 0x35, 0x93, 0x8D, 0xA5, 0xFB, 0x42, 0x01, 0xC2, 0x17, 0x12, 0x1A, 0x77, 0xC6, 0x53,
0x83, 0x4D, 0xB2, 0x10, 0x2B, 0xF8, 0x88, 0x6A, 0x3E, 0xD0, 0x7C, 0x63, 0x40, 0x27, 0xBE, 0xD5,
0x38, 0xD1, 0x74, 0xB6, 0x57, 0x94, 0xAB, 0x8A, 0xB9, 0xBC, 0x7D, 0xB3, 0x96, 0x7E, 0xFC, 0xAD,
0x22, 0x4E, 0xFA, 0xE0, 0xCB, 0x8B, 0xEE, 0x32, 0xA4, 0x16, 0xFE, 0x5B, 0x13, 0xDD, 0xC0, 0x9A,
0x5E, 0x8E, 0x29, 0xF3, 0x8F, 0x49, 0xE6, 0x9F, 0xF1, 0xC5, 0x70, 0x55, 0x8C, 0x11, 0xCC, 0x5D,
0xEC, 0x00, 0xAC, 0x89, 0xD3, 0x82, 0x69, 0xD6, 0xBA, 0xD8, 0x59, 0x98, 0x09, 0x80, 0xE2, 0xC7]
#第二种加密方式
def DFS_E2(a1, a2):
v3 = bytearray(32)
for i in range(32):
v3[a2[i]] = a1[i]
return bytes(v3)
#第二种解密方式
def DFS_D2(shuffled_data, a2):
v3 = bytearray(32)
reverse_map = [0] * 32
for i in range(32):
reverse_map[a2[i]] = i
for i in range(32):
v3[reverse_map[i]] = shuffled_data[i]
return bytes(v3)
#第二种加密方式的对照表
array2 = [0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06, 0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05,
0x0E, 0x03, 0x12, 0x04, 0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B, 0x17, 0x0A]
#第三种加密方式
def DFS_E3(input_data, xor_table, add_table):
transformed_data = bytearray(input_data)
for i in range(32):
temp = transformed_data[i] ^ xor_table[i]
transformed_data[i] = (temp + add_table[i]) & 0xFF
return transformed_data
#第三种解密方式
def DFS_D3(encrypted_data, xor_table, add_table):
decrypted_data = bytearray(encrypted_data)
for i in range(32):
temp = (decrypted_data[i] - add_table[i]) & 0xFF
decrypted_data[i] = temp ^ xor_table[i]
return decrypted_data
#第三种加密方式的表
xor_table = [0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13, 0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF,
0x18, 0x4F, 0x26, 0x18, 0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9, 0x9E, 0xC4]
add_table = [0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41, 0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8,
0x1E, 0xBA, 0x6A, 0xBE, 0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C, 0xE2, 0x43]
#第四种加密方式
def DFS_E4(input_data):
transformed_data = bytearray(input_data)
for i in range(32):
transformed_data[i] = ((transformed_data[i] >> 3) | (transformed_data[i] << 5)) & 0xFF
return transformed_data
#第四种解密方式
def DFS_D4(encrypted_data):
decrypted_data = bytearray(encrypted_data)
for i in range(32):
decrypted_data[i] = ((decrypted_data[i] << 3) | (decrypted_data[i] >> 5)) & 0xFF
return decrypted_data
#加密部分,用于测试
input_data = b'12345678901234567890123456789012'
print(f"Original Data: {input_data}")
for i in range(32):
if(bytearray(input_data)[i] & 3 == 0):
input_data = DFS_E1(input_data, array1)
print(f"{i+1}# E1 data: {input_data}")
elif(bytearray(input_data)[i] & 3 == 1):
input_data = DFS_E2(DFS_E2(input_data, array2), array2)
print(f"{i+1}# E2 data: {input_data}")
elif(bytearray(input_data)[i] & 3 == 2):
input_data = DFS_E3(input_data, xor_table, add_table)
print(f"{i+1}# E3 data: {input_data}")
elif(bytearray(input_data)[i] & 3 == 3):
input_data = DFS_E4(input_data)
print(f"{i+1}# E4 data: {input_data}")
#单个加密函数
def testcrypt(input_data, index):
if(bytearray(input_data)[index] & 3 == 0):
test = DFS_E1(input_data, array1)
elif(bytearray(input_data)[index] & 3 == 1):
test = DFS_E2(DFS_E2(input_data, array2), array2)
elif(bytearray(input_data)[index] & 3 == 2):
test = DFS_E3(input_data, xor_table, add_table)
elif(bytearray(input_data)[index] & 3 == 3):
test = DFS_E4(input_data)
return test
#验证函数
def verify(input_data, index):
print(f"Testing index:{index}")
tag = []
test = [None]*4
test[0] = DFS_D1(input_data, array1)
test[1] = DFS_D2(DFS_D2(input_data, array2), array2)
test[2] = DFS_D3(input_data, xor_table, add_table)
test[3] = DFS_D4(input_data)
for i in range(4):
if(testcrypt(test[i], index) == input_data):
tag.append(i)
try:
assert(len(tag) == 1)
unique_solution = test[tag[0]]
return tag, unique_solution, True
except:
solutions = []
for i in range(len(tag)):
solutions.append(test[tag[i]])
return tag, solutions, False
#DFS部分
dead_end_count = 0

def dfs_decrypt(input_data, depth=0, total_depth=32):
global dead_end_count

if depth == total_depth:
if input_data[:4] == b'flag':
print(f"Correct decryption found: {input_data}")
return True
return False
index_to_check = total_depth - depth - 1
tag, solutions, is_unique = verify(input_data, index_to_check)

if is_unique:
if dfs_decrypt(solutions, depth + 1, total_depth):
return True
else:
if len(solutions) == 0:
dead_end_count += 1
print(f"Incremented dead end count to: {dead_end_count} at depth {depth}")
return False
for decrypted_data in solutions:
if dfs_decrypt(decrypted_data, depth + 1, total_depth):
return True
return False

input_data = b'e>C\xb8\xba\xdb\xf6\x88%\x1b(\xc7\xc0T\xa6J\x907\xbc)A\xaa(\xdb\x9aYc\x9eK\xcf.A'
print(f"Encrypted flag: {input_data}")
if not dfs_decrypt(input_data):
print("Failed to find a solution")

运行脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Encrypted flag: b'e>C\xb8\xba\xdb\xf6\x88%\x1b(\xc7\xc0T\xa6J\x907\xbc)A\xaa(\xdb\x9aYc\x9eK\xcf.A'
Testing index:31
Testing index:30
Testing index:29
Testing index:28
Incremented dead end count to: 1 at depth 3
Testing index:28
Testing index:27

Testing index:4
Testing index:3
Testing index:2
Testing index:1
Incremented dead end count to: 103 at depth 30
Testing index:1
Testing index:0
Incremented dead end count to: 104 at depth 31
Testing index:0
Correct decryption found: bytearray(b'flag{Ea5y_enCrypt_And_decrYpt!!}')

得到flag:flag{Ea5y_enCrypt_And_decrYpt!!}.