【wp】2021CISCN华南赛区分区赛-BadGameAndCrazy

考完期末就来填一下坑,顺便总结一下逆向题目中的密码算法识别,是分区赛搞了大半天磕出来的一道逆向题BadGameAndCrazy,这道题真的是各种原装密码算法的大杂烩,非常值得总结(终于不是MISC了Ohhhhh,虽然是因为没有杂项题可以做

做完以后以为这个题这么简单会被打穿的(毕竟就是堆了一堆密码算法+爆破密钥这样,自己推完密码算法以后才发现hint直接给出来了就离谱555555),结果出乎意料地跟一血失之交臂拿了二血,最后也只是几个队解了而已(隐约记得是五六个队来着

【Reverse】BadGameAndCrazy

SMC处理

看到main()函数:

看到printf()scanf()这里有乱码,而且主函数中前面也没有能修改的,所以猜测在主函数执行之前的某个函数有smc处理,由经验可以猜到很大概率就是初始化函数_libc_csu_init(),去看函数内容果然有。

funcs_4177A9是一个函数地址表,用for循环依次调用,可以看到sub_4020D0()中就有对该数组asc_41D1E0的自修改,同时还有对其余常量数组的修改。

懒得静态还原了,直接动态调试把smc过了,断点设在主函数就好。

可以看到字符串被还原了。

主函数逻辑

接下来看sub_4011B0(),是很多赋值操作,也可以用动态调试直接过掉。

需要注意的是,这里是用常量和输入的42个字符(传进来的参数a1,主函数的v12,输入部分)来填传进来的参数a2(也就是主函数的v5)这一大块空间。为了省事 迅速地判断是怎么填的,输入字符可以用asdfghjklqwertyuiopzxcvbnm1234567890ASDFGH这一串,不仅是可见字符而且还能确定顺序,这样在动态调试之后直接看主函数的v5就知道缺什么值了(当然这种方法只适合原数组里可见字符较少、而且填上去大致是连续的情况)。

这样可以推断出v5这块大空间(后面称为STRING)里装的是:

1
STRING=INPUT[0:4]+"\xf4\xa86\xd2"+INPUT[4:12]+"\rh\xd3\xec\xef\xbcQhA\xd4\x0e\xf8)\x10)`\xf6\xb9y\x1aP\xe7>\xec/\xca\xd3\xfc"+INPUT[12:38]+"\x94Zm{"+INPUT[38:42]

再往后看check部分都是由sub_401880()这个函数完成,只是参数不一样,很明显是个vmp,通过参数来控制程序流程。

check:

sub_401880()

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
_BOOL8 __fastcall sub_401880(unsigned __int8 a1, unsigned __int8 a2, __int64 a3)
{
const void *v3; // rax
const void *v4; // rax
const void *v5; // rax
void *v7; // [rsp+8h] [rbp-C8h]
_QWORD *v8; // [rsp+18h] [rbp-B8h]
_QWORD *v9; // [rsp+28h] [rbp-A8h]
_QWORD *v10; // [rsp+38h] [rbp-98h]
void *v11; // [rsp+40h] [rbp-90h]
__m128i *v12; // [rsp+50h] [rbp-80h]
__m128i *v13; // [rsp+60h] [rbp-70h]
__m128i *v14; // [rsp+70h] [rbp-60h]
void *s1; // [rsp+78h] [rbp-58h]
_DWORD *v16; // [rsp+88h] [rbp-48h]
bool v18; // [rsp+CFh] [rbp-1h]

switch ( a1 )
{
case 8u:
v8 = (_QWORD *)sub_4016C0(a2);
v18 = *v8 == *(_QWORD *)sub_4014E0(a3);
break;
case 0x5Cu:
v11 = (void *)sub_4016C0(a2);
v4 = (const void *)sub_4013B0(&byte_41D1A0, a3, 30LL);
v18 = memcmp(v11, v4, 0x1EuLL) == 0;
break;
case 0x72u:
v7 = (void *)sub_4016C0(a2);
v5 = (const void *)sub_401520(a3);
v18 = memcmp(v7, v5, 0x20uLL) == 0;
break;
case 0x91u:
v12 = (__m128i *)sub_4016C0(a2);
v18 = _mm_movemask_epi8(_mm_cmpeq_epi8(*v12, *(__m128i *)sub_401340(&byte_41D180, a3))) == 0xFFFF;
break;
case 0x94u:
v14 = (__m128i *)sub_4016C0(a2);
v18 = _mm_movemask_epi8(_mm_cmpeq_epi8(*v14, *(__m128i *)sub_401580(a3))) == 0xFFFF;
break;
case 0x9Du:
v13 = (__m128i *)sub_4016C0(a2);
v18 = _mm_movemask_epi8(_mm_cmpeq_epi8(*v13, *(__m128i *)sub_4015D0(a3))) == 0xFFFF;
break;
case 0xACu:
v10 = (_QWORD *)sub_4016C0(a2);
v18 = *v10 == *(_QWORD *)sub_4012E0(&byte_41D1BF, a3);
break;
case 0xB4u:
s1 = (void *)sub_4016C0(a2);
v3 = (const void *)sub_401480(a3);
v18 = memcmp(s1, v3, 0x14uLL) == 0;
break;
case 0xB5u:
v9 = (_QWORD *)sub_4016C0(a2);
v18 = *v9 == *(_QWORD *)sub_401620(&byte_41D1C8, a3);
break;
case 0xF2u:
v16 = (_DWORD *)sub_4016C0(a2);
v18 = *v16 == *(_DWORD *)sub_401670(a3, 4LL);
break;
default:
v18 = 0;
break;
}
return v18;
}

可以看到,switch的每个case基本上都是由sub_4016C0()+其他函数组成,而sub_4016C0()是根据对应参数返回一个常量数组用作比较,每个case的最后一行都是用==或者memcpy()或者_mm_cmpeq_epi8()来做这个比较。

sub_4016C0()

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
char *__fastcall sub_4016C0(unsigned __int8 a1)
{
switch ( a1 )
{
case 0xCu:
return &byte_41D110;
case 0x20u:
return &byte_41D0F0;
case 0x4Fu:
return &byte_41D101;
case 0x68u:
return &byte_41D140;
case 0x77u:
return &byte_41D0A0;
case 0x8Cu:
return &byte_41D080;
case 0x9Fu:
return &byte_41D0D0;
case 0xA9u:
return &byte_41D070;
case 0xC9u:
return &byte_41D0E1;
case 0xDDu:
return &byte_41D0BF;
}
return &byte_41D160;
}

由此可见,在反复用来check的函数sub_401880()中,第一个参数是用来控制程序流程(即进入哪个加密算法进行处理),第二个参数用来操控用于比较的常量数组,第三个参数是传入本部分最开头提到的大空间v5的部分值作为明文(v5v11在空间上是连续的)。

流程不多,直接手推vm即可。考点应该在各种加密算法的识别上,没有魔改我真是谢谢他,不然就做不出来了x

加密算法识别

所有的加密算法基本是用常量数组+大致加密流程在推,这里放一下各个case的结果和标志,方便以后做题的时候找加密算法xd

混淆后的实现方法可以直接在题目里看,太长不贴(

注意传进去的STRING是明文还是密钥要用具体的实现方式来对比。

[对称密码] AES

具体实现:AES/aes.c at master · dhuertas/AES

在本题中对应sub_401880()里的case 0x91u

sub_401340() -> sub_4039B0()里可以看到AES经典选择流程(AES128 or AES192 or AES256):

还有sub_401340() -> sub_4039B0() -> sub_404560()里AES的S盒:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static uint8_t s_box[256] = {
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, // 0
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, // 1
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, // 2
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, // 3
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, // 4
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, // 5
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, // 6
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, // 7
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, // 8
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, // 9
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, // a
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, // b
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, // c
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, // d
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, // e
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};// f

这里选择的是AES256,所以有:

1
2
# sub_401880(0x91u, 0x20u, (__int64)&v6 + 4)
AES256(text='!!Successfully!!',key=STRING[12:44])==[0xD1, 0x1F, 0xA5, 0x6A, 0xCE, 0x96, 0x26, 0x3A, 0x95, 0xD3, 0xFC, 0x60, 0xF7, 0x3D, 0x2D, 0xD2]

[对称密码] Blowfish

具体实现:BlowFish加解密原理与代码实现 - 云+社区 - 腾讯云

在本题中对应sub_401880()里的case 0xACu

sub_4012E0() -> sub_40BCD0()里可以看到两个memcpy()的地方用到了关键常量P盒ORIG_P和S盒ORIG_S

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
static const unsigned long ORIG_P[16 + 2] = {
0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L,
0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L,
0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL,
0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L,
0x9216D5D9L, 0x8979FB1BL
};
static const unsigned long ORIG_S[4][256] = {
{ 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L,
0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L,
0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L,
0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL,
0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL,
0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L,
0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL,
0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL,
0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L,
0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L,
0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL,
0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL,
0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL,
0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L,
0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L,
0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L,
0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L,
0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L,
0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL,
0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L,
0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L,
0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L,
0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L,
0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL,
0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L,
0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL,
0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL,
0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L,
0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL,
0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L,
0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL,
0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L,
0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L,
0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL,
0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L,
0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L,
0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL,
0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L,
0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL,
0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L,
0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L,
0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL,
0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L,
0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L,
0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L,
0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L,
0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L,
0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL,
0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL,
0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L,
0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L,
0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L,
0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L,
0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL,
0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L,
0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL,
0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL,
0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L,
0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L,
0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L,
0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L,
0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L,
0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L,
0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL },
{ 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L,
0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L,
0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L,
0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL,
0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L,
0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L,
0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL,
0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L,
0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L,
0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L,
0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL,
0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL,
0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L,
0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L,
0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L,
0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L,
0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL,
0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL,
0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL,
0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L,
0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL,
0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L,
0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L,
0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL,
0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL,
0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L,
0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL,
0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L,
0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL,
0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL,
0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L,
0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L,
0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L,
0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L,
0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L,
0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L,
0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L,
0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL,
0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L,
0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL,
0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L,
0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L,
0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L,
0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L,
0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L,
0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L,
0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L,
0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L,
0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L,
0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L,
0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L,
0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L,
0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L,
0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L,
0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L,
0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L,
0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL,
0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL,
0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L,
0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL,
0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L,
0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L,
0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L,
0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L },
{ 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L,
0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L,
0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL,
0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L,
0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L,
0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L,
0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL,
0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL,
0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL,
0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L,
0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L,
0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL,
0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L,
0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL,
0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L,
0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL,
0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L,
0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL,
0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L,
0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL,
0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L,
0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L,
0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL,
0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L,
0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L,
0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L,
0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L,
0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL,
0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L,
0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL,
0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L,
0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL,
0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L,
0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL,
0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL,
0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL,
0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L,
0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L,
0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL,
0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL,
0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL,
0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL,
0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL,
0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L,
0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L,
0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L,
0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L,
0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL,
0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL,
0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L,
0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L,
0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L,
0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L,
0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L,
0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L,
0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L,
0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L,
0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L,
0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L,
0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL,
0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L,
0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL,
0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L,
0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L },
{ 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL,
0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL,
0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL,
0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L,
0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L,
0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L,
0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L,
0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L,
0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L,
0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L,
0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L,
0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L,
0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L,
0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L,
0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L,
0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL,
0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL,
0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L,
0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL,
0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL,
0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL,
0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L,
0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL,
0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL,
0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L,
0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L,
0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L,
0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L,
0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL,
0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL,
0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L,
0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L,
0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L,
0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL,
0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L,
0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L,
0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L,
0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL,
0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L,
0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L,
0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L,
0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL,
0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL,
0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L,
0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L,
0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L,
0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L,
0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL,
0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L,
0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL,
0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL,
0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L,
0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L,
0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL,
0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L,
0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL,
0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L,
0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL,
0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L,
0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L,
0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL,
0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L,
0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL,
0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L }
};

所以有:

1
2
# sub_401880(0xACu, 0xDDu, (__int64)v5)
Blowfish(text="Decrypt!",key=STRING[0:8])==[0x06, 0x8F, 0x5A, 0xFF, 0xCB, 0xD6, 0xE9, 0x0B]

[对称密码] DES

具体实现:myReverseExps/DES.cpp at main · c10udlnk/myReverseExps

在本题中对应sub_401880()里的case 0xB5u

sub_401620() -> sub_4107A0()里可以看到这四个memcpy()的地方用到了跟关键常量差不多的数组(依次是Rotate_Table[1:17]PC1_Table各值-1,IP_Table各值+4、PC2_Table各值-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
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
const int PC1_Table[56]={57, 49, 41, 33, 25, 17,  9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4};
const int Rotate_Table[17]={0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
const int PC2_Table[48]={14, 17, 11, 24, 1, 5, 3, 28,
15, 6, 21, 10, 23, 19, 12, 4,
26, 8, 16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55, 30, 40,
51, 45, 33, 48, 44, 49, 39, 56,
34, 53, 46, 42, 50, 36, 29, 32};
const int IP_Table[64]={58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7};
const int E_Table[48]={32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1};
const int S_Box[8][4][16]={
// S1
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
// S2
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
// S3
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
// S4
{ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
// S5
{ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
// S6
{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
// S7
{ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
// S8
{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}};
const int P_Table[32]={16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25};
const int inv_IP_Table[64]={40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25};

所以有:

1
2
# sub_401880(0xB5u, 0xC9u, (__int64)v10)
DES(text='ComeOn!!',key=STRING[66:74])==[0x52, 0x8E, 0xA9, 0x48, 0x4B, 0x59, 0xE4, 0x51]

[对称密码] RC4

具体实现:myReverseExps/RC4.cpp at main · c10udlnk/myReverseExps

在本题中对应sub_401880()里的case 0x5Cu

这个函数相对比较简单,没有前两个那么复杂,直接逆算法可以发现跟RC4一模一样,就是最后把跟密钥流xor那步拆开了,xor是常见的拆分/混淆方法a^b = ~a&b|~b&a

所以有:

1
2
# sub_401880(0x5Cu, 0x77u, (__int64)&v7)
RC4(text='You have made a huge progress!',key=STRING[44:48])==[0x6F, 0xC5, 0xCF, 0x22, 0x4C, 0xFD, 0x49, 0xC2, 0x73, 0x4F, 0x4E, 0x99, 0xED, 0x71, 0x2D, 0xDD, 0x08, 0x58, 0x51, 0x5A, 0xD8, 0x38, 0xD1, 0x59, 0x2C, 0x2F, 0xE4, 0x4A, 0x66, 0x0F]

[哈希] MD2

具体实现:MD2哈希算法实现(附源码)_洛奇看世界-CSDN博客

在本题中对应sub_401880()里的case 0x94u

sub_401580() -> sub_4112E0() -> sub_410FF0()byte_419D90有MD2的常量数组:

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

所以有:

1
2
# sub_401880(0x94u, 0x68u, (__int64)&v9[4])
MD2(STRING[62:66])==[0xC6, 0x56, 0xA6, 0xEA, 0xD7, 0x37, 0x24, 0x03, 0x0B, 0x2D, 0x0B, 0xEC, 0x8A, 0x9E, 0x99, 0xDD]

[哈希] MD5

具体实现:C语言实现md5函数代码_xhhjin的专栏-CSDN博客_c语言md5

在本题中对应sub_401880()里的case 0x9Du

sub_4015D0 -> sub_415400()里有很熟悉的MD5块初始化:

1
2
3
4
5
6
7
8
9
void __fastcall sub_415400(__int64 a1)
{
*(_DWORD *)(a1 + 64) = 0;
*(_QWORD *)(a1 + 72) = 0LL;
*(_DWORD *)(a1 + 80) = 0x67452301;
*(_DWORD *)(a1 + 84) = 0xEFCDAB89;
*(_DWORD *)(a1 + 88) = 0x98BADCFE;
*(_DWORD *)(a1 + 92) = 0x10325476;
}

(有时候MD5的这个常量也值得注意↓,来自MD5/md5.c at master · pod32g/MD5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const uint32_t k[64] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee ,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 ,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be ,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 ,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa ,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 ,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed ,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a ,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c ,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 ,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 ,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 ,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 ,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 ,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 ,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };

本题有:

1
2
# sub_401880(0x9Du, 0x9Fu, (__int64)v11)
MD5(STRING[74:])==[0x2D, 0x4C, 0x4C, 0xAF, 0xB8, 0xE6, 0x64, 0xC0, 0x05, 0x56, 0xB0, 0x28, 0x06, 0xAB, 0x7E, 0x10]

[哈希] SHA1

具体实现:sha1/sha1.hpp at master · vog/sha1

在本题中对应sub_401880()里的case 0xB4u

可以看到sub_401480() -> sub_4162B0()sha1的常数相关:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void __fastcall sub_4162B0(__int64 a1)
{
*(_DWORD *)(a1 + 64) = 0;
*(_QWORD *)(a1 + 72) = 0LL;
*(_DWORD *)(a1 + 80) = 0x67452301;
*(_DWORD *)(a1 + 84) = 0xEFCDAB89;
*(_DWORD *)(a1 + 88) = 0x98BADCFE;
*(_DWORD *)(a1 + 92) = 0x10325476;
*(_DWORD *)(a1 + 96) = 0xC3D2E1F0;
*(_DWORD *)(a1 + 100) = 0x5A827999;
*(_DWORD *)(a1 + 104) = 0x6ED9EBA1;
*(_DWORD *)(a1 + 108) = 0x8F1BBCDC;
*(_DWORD *)(a1 + 112) = 0xCA62C1D6;
}

所以有:

1
2
# sub_401880(0xB4u, 0x8Cu, (__int64)&v8)
SHA1(STRING[48:52])==[0x65, 0xBC, 0xA7, 0xCC, 0x3A, 0x77, 0x1F, 0xFC, 0x55, 0xFE, 0x3A, 0xA3, 0x2A, 0xB4, 0x9C, 0x4B, 0xCA, 0xE3, 0x84, 0x91]

[哈希] SHA256

具体实现:SHA256/sha256.c at main · ilvn/SHA256

在本题中对应sub_401880()里的case 0x72u

sub_401520() -> sub_417110()里有SHA256块的初始化:

1
2
3
4
5
6
7
8
9
void sha256_init(sha256_context *ctx)
{
ctx->len[0] = ctx->len[1] = 0;
ctx->hash[0] = 0x6a09e667; ctx->hash[1] = 0xbb67ae85;
ctx->hash[2] = 0x3c6ef372; ctx->hash[3] = 0xa54ff53a;
ctx->hash[4] = 0x510e527f; ctx->hash[5] = 0x9b05688c;
ctx->hash[6] = 0x1f83d9ab; ctx->hash[7] = 0x5be0cd19;

} /* sha256_init */

SHA256同样也有需要注意的常量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static const uint32_t K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

本题有:

1
2
# sub_401880(0x72u, 0xCu, (__int64)v9)
SHA256(STRING[58:62])==[0x50, 0xC0, 0xCE, 0x77, 0xB9, 0xD0, 0x0D, 0x0F, 0x15, 0x9D, 0xC5, 0x63, 0x0F, 0x2D, 0xB4, 0x54, 0xC9, 0xC6, 0x43, 0x8F, 0xCD, 0x95, 0xF6, 0x3B, 0x73, 0x92, 0x9D, 0x6E, 0xA9, 0xF9, 0xAB, 0x40]

[古典密码] Base58

具体实现:

在本题中对应sub_401880()里的case 0x08u

sub_4014E0() -> sub_4075F0()里是一个很熟悉的base58编码,而且byte_41D250也是明显的Base58编码表:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

所以有:

1
2
# sub_401880(8u, 0x4Fu, (__int64)&v8 + 4)
Base58(STRING[52:58])==[0x78, 0x57, 0x51, 0x79, 0x78, 0x4E, 0x36, 0x55]

[古典密码] ROT13

具体实现:ROT13 加密与解密 - ESHLkangi - 博客园

在本题中对应sub_401880()里的case 0xF2u

sub_401670() -> sub_415890()里就是一个很明显的ROT13位移(

所以有:

1
2
# sub_401880(0xF2u, 0xA9u, (__int64)&v6)
ROT13(STRING[8:12])==[0x76, 0x72, 0x68, 0x64]

整理解密爆破得flag

最后整理前面各密码算法的分析,并按照STRING分片顺序排序有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# sub_401880(0xACu, 0xDDu, (__int64)v5)
Blowfish("Decrypt!",STRING[0:8])==[0x06, 0x8F, 0x5A, 0xFF, 0xCB, 0xD6, 0xE9, 0x0B]
# sub_401880(0xF2u, 0xA9u, (__int64)&v6)
ROT13(STRING[8:12])==[0x76, 0x72, 0x68, 0x64]
# sub_401880(0x91u, 0x20u, (__int64)&v6 + 4)
AES256('!!Successfully!!',STRING[12:44])==[0xD1, 0x1F, 0xA5, 0x6A, 0xCE, 0x96, 0x26, 0x3A, 0x95, 0xD3, 0xFC, 0x60, 0xF7, 0x3D, 0x2D, 0xD2]
# sub_401880(0x5Cu, 0x77u, (__int64)&v7)
RC4(STRING[44:48],'You have made a huge progress!')==[0x6F, 0xC5, 0xCF, 0x22, 0x4C, 0xFD, 0x49, 0xC2, 0x73, 0x4F, 0x4E, 0x99, 0xED, 0x71, 0x2D, 0xDD, 0x08, 0x58, 0x51, 0x5A, 0xD8, 0x38, 0xD1, 0x59, 0x2C, 0x2F, 0xE4, 0x4A, 0x66, 0x0F]
# sub_401880(0xB4u, 0x8Cu, (__int64)&v8)
SHA1(STRING[48:52])==[0x65, 0xBC, 0xA7, 0xCC, 0x3A, 0x77, 0x1F, 0xFC, 0x55, 0xFE, 0x3A, 0xA3, 0x2A, 0xB4, 0x9C, 0x4B, 0xCA, 0xE3, 0x84, 0x91]
# sub_401880(8u, 0x4Fu, (__int64)&v8 + 4)
Base58(STRING[52:58])==[0x78, 0x57, 0x51, 0x79, 0x78, 0x4E, 0x36, 0x55]
# sub_401880(0x72u, 0xCu, (__int64)v9)
SHA256(STRING[58:62])==[0x50, 0xC0, 0xCE, 0x77, 0xB9, 0xD0, 0x0D, 0x0F, 0x15, 0x9D, 0xC5, 0x63, 0x0F, 0x2D, 0xB4, 0x54, 0xC9, 0xC6, 0x43, 0x8F, 0xCD, 0x95, 0xF6, 0x3B, 0x73, 0x92, 0x9D, 0x6E, 0xA9, 0xF9, 0xAB, 0x40]
# sub_401880(0x94u, 0x68u, (__int64)&v9[4])
MD2(STRING[62:66])==[0xC6, 0x56, 0xA6, 0xEA, 0xD7, 0x37, 0x24, 0x03, 0x0B, 0x2D, 0x0B, 0xEC, 0x8A, 0x9E, 0x99, 0xDD]
# sub_401880(0xB5u, 0xC9u, (__int64)v10)
DES('ComeOn!!',STRING[66:74])==[0x52, 0x8E, 0xA9, 0x48, 0x4B, 0x59, 0xE4, 0x51]
# sub_401880(0x9Du, 0x9Fu, (__int64)v11)
MD5(STRING[74:])==[0x2D, 0x4C, 0x4C, 0xAF, 0xB8, 0xE6, 0x64, 0xC0, 0x05, 0x56, 0xB0, 0x28, 0x06, 0xAB, 0x7E, 0x10]

之前的STRING是:

1
STRING=INPUT[0:4]+"\xf4\xa86\xd2"+INPUT[4:12]+"\rh\xd3\xec\xef\xbcQhA\xd4\x0e\xf8)\x10)`\xf6\xb9y\x1aP\xe7>\xec/\xca\xd3\xfc"+INPUT[12:38]+"\x94Zm{"+INPUT[38:42]

对称密码部分都是爆破密钥(基本都是只用爆破4字节,其余是STRING的已知部分),哈希直接爆破(也是4字节),古典密码转换一下就好。

当时做题的时候是在可见字符范围(32,127)之间爆破的,爆破了两三组以后发现都是小写字母,所以后来直接用小写字母范围爆破会快很多;但没想到DES密钥这里有多解,导致一直没交上去,后来出了hint才知道有字符范围,那就是唯一解了= =。

这里为了方便复现就把exp的爆破范围改成hint给的qwertyuiop

最后exp是:

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
from hashlib import md5,sha256,sha1
from Crypto.Cipher import AES,Blowfish,DES
from Crypto.Hash import MD2
from arc4 import ARC4
import base58

STRING=b'----\xf4\xa86\xd2--------\rh\xd3\xec\xef\xbcQhA\xd4\x0e\xf8)\x10)`\xf6\xb9y\x1aP\xe7>\xec/\xca\xd3\xfc--------------------------\x94Zm{----'
flag=b''
charset=list(map(ord,"qwertyuiop"))

#STRING[:4]
blowfish_arr=bytes([0x06, 0x8F, 0x5A, 0xFF, 0xCB, 0xD6, 0xE9, 0x0B])
for i1 in charset:
for i2 in charset:
for i3 in charset:
for i4 in charset:
key=bytes([i1,i2,i3,i4]+list(STRING[4:8]))
blowfish=Blowfish.new(key,Blowfish.MODE_ECB)
if blowfish.decrypt(blowfish_arr)==b'Decrypt!':
print(b"STRING[0:4] -> "+key[:4])
flag+=key[:4]
break
else:
continue
break
else:
continue
break
else:
continue
break

#STRING[8:12]
rot13_arr=bytes([0x76, 0x72, 0x68, 0x64])
data=[]
for x in rot13_arr:
tmp=x-ord('a')
data.append((tmp+13)%26+ord('a'))
flag+=bytes(data)
print(b"STRING[8:12] -> "+bytes(data))

#STRING[12:44]
aes_arr=bytes([0xD1, 0x1F, 0xA5, 0x6A, 0xCE, 0x96, 0x26, 0x3A, 0x95, 0xD3, 0xFC, 0x60, 0xF7, 0x3D, 0x2D, 0xD2])
for i1 in charset:
for i2 in charset:
for i3 in charset:
for i4 in charset:
key=bytes([i1,i2,i3,i4]+list(STRING[16:44]))
aes=AES.new(key,AES.MODE_ECB)
if aes.decrypt(aes_arr)==b'!!Successfully!!':
print(b"STRING[12:16] -> "+key[:4])
flag+=key[:4]
break
else:
continue
break
else:
continue
break
else:
continue
break

#STRING[44:48]
rc4_arr=bytes([0x6F, 0xC5, 0xCF, 0x22, 0x4C, 0xFD, 0x49, 0xC2, 0x73, 0x4F, 0x4E, 0x99, 0xED, 0x71, 0x2D, 0xDD, 0x08, 0x58, 0x51, 0x5A, 0xD8, 0x38, 0xD1, 0x59, 0x2C, 0x2F, 0xE4, 0x4A, 0x66, 0x0F])
for i1 in charset:
for i2 in charset:
for i3 in charset:
for i4 in charset:
key=bytes([i1,i2,i3,i4])
rc4=ARC4(key)
if rc4.encrypt(rc4_arr)==b'You have made a huge progress!':
print(b"STRING[44:48] -> "+key)
flag+=key
break
else:
continue
break
else:
continue
break
else:
continue
break

#STRING[48:52]
sha1_arr=bytes([0x65, 0xBC, 0xA7, 0xCC, 0x3A, 0x77, 0x1F, 0xFC, 0x55, 0xFE, 0x3A, 0xA3, 0x2A, 0xB4, 0x9C, 0x4B, 0xCA, 0xE3, 0x84, 0x91])
for i1 in charset:
for i2 in charset:
for i3 in charset:
for i4 in charset:
key=bytes([i1,i2,i3,i4])
if sha1(key).digest()==sha1_arr:
print(b"STRING[44:48] -> "+key)
flag+=key
break
else:
continue
break
else:
continue
break
else:
continue
break

#STRING[52:58]
b58_arr=bytes([0x78, 0x57, 0x51, 0x79, 0x78, 0x4E, 0x36, 0x55])
print(b"STRING[52:58] -> "+base58.b58decode(b58_arr))
flag+=base58.b58decode(b58_arr)

#STRING[58:62]
sha256_arr=bytes([0x50, 0xC0, 0xCE, 0x77, 0xB9, 0xD0, 0x0D, 0x0F, 0x15, 0x9D, 0xC5, 0x63, 0x0F, 0x2D, 0xB4, 0x54, 0xC9, 0xC6, 0x43, 0x8F, 0xCD, 0x95, 0xF6, 0x3B, 0x73, 0x92, 0x9D, 0x6E, 0xA9, 0xF9, 0xAB, 0x40])
for i1 in charset:
for i2 in charset:
for i3 in charset:
for i4 in charset:
key=bytes([i1,i2,i3,i4])
if sha256(key).digest()==sha256_arr:
print(b"STRING[58:62] -> "+key)
flag+=key
break
else:
continue
break
else:
continue
break
else:
continue
break

#STRING[62:66]
md2_arr=bytes([0xC6, 0x56, 0xA6, 0xEA, 0xD7, 0x37, 0x24, 0x03, 0x0B, 0x2D, 0x0B, 0xEC, 0x8A, 0x9E, 0x99, 0xDD])
for i1 in charset:
for i2 in charset:
for i3 in charset:
for i4 in charset:
key=bytes([i1,i2,i3,i4])
if MD2.MD2Hash(key).digest()==md2_arr:
print(b"STRING[62:66] -> "+key)
flag+=key
break
else:
continue
break
else:
continue
break
else:
continue
break

#STRING[66:74]
des_arr=bytes([0x52, 0x8E, 0xA9, 0x48, 0x4B, 0x59, 0xE4, 0x51])
for i1 in charset:
for i2 in charset:
for i3 in charset:
for i4 in charset:
key=bytes([i1,i2,i3,i4]+list(STRING[70:74]))
des=DES.new(key,DES.MODE_ECB)
if des.decrypt(des_arr)==b'ComeOn!!':
print(b"STRING[66:70] -> "+key[:4])
flag+=key[:4]
break
else:
continue
break
else:
continue
break
else:
continue
break

#STRING[74:]
md5_arr=bytes([0x2D, 0x4C, 0x4C, 0xAF, 0xB8, 0xE6, 0x64, 0xC0, 0x05, 0x56, 0xB0, 0x28, 0x06, 0xAB, 0x7E, 0x10])
for i1 in charset:
for i2 in charset:
for i3 in charset:
for i4 in charset:
key=bytes([i1,i2,i3,i4])
if md5(key).digest()==md5_arr:
print(b"STRING[74:] -> "+key)
flag+=key
break
else:
continue
break
else:
continue
break
else:
continue
break

#flag=STRING[:4]+STRING[8:16]+STRING[44:70]+STRING[74:]
print(flag)
print("flag{"+md5(flag).hexdigest()+"}")
# b'epewieuqqwirrroewwyoowuowiptepquyeqiwepqer'
# flag{9704622ee6d66a8789f39a43a6eac60e}

最后是提交md5(输出flag的部分做的也是md5处理,也可以直接输进程序里拿到flag:

**flag:**flag{9704622ee6d66a8789f39a43a6eac60e}

文章作者: c10udlnk
文章链接: https://c10udlnk.top/p/wpFor-2021CISCNsemifinal/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 c10udlnk_Log