llurry
文章6
标签5
分类3

文章分类

文章归档

2026 CCSSSC Reverse WP

2026 CCSSSC Reverse WP

周末参加了这次软件系统安全赛初赛,又是坐牢的一天啊,不过应该是进复赛了,在这篇文章中分享一下解题过程

re1

题目附件给了一个mp4和一个elf文件,先ida分析Loader,通过交叉应用找到main函数

main.png

C++程序首先检查当前目录下是否存在 video.mp4文件,如果视频存在,程序会读取内置的全局变量 stager_pyc_base64[0],然后将这段 Base64 字符串解码,并将解码后的二进制数据写入到名为 stager.pyc 的文件中,最后给stager.pyc 赋予执行权限 (chmod 0755),然后调用 Python 解释器运行这个脚本 (run_python_script(v16))

解码base64后就拿到了隐藏的pyc

cyber.png

发现了一个硬编码的二进制常量字符串 10101010,出题逻辑: 将真实的 Payload 转换为二进制串 -> 与 0xAA (10101010) 进行异或加密 -> 将加密后的 0 和 1 渲染为黑白像素方块,生成 video.mp4
进行解密:
由于加密是对称的(XOR),需要利用 OpenCV 读取视频,提取像素块还原二进制,再与 0xAA 异或

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
import re

def fix_and_find_flag():
# 1. 读取提取出的乱码文件
with open('extracted_payload.bin', 'rb') as f:
data = f.read()

# 2. 修复黑白颠倒:对每个字节进行按位取反 (XOR 0xFF)
fixed_data = bytearray([b ^ 0xFF for b in data])

# 3. 将修复好的真实的 ELF 文件保存下来
with open('fixed_payload.elf', 'wb') as f:
f.write(fixed_data)
print("[+] 成功修复文件,已保存为 fixed_payload.elf (Linux 可执行文件)")

# 4. 尝试直接从修复后的二进制中暴力搜索 dart{} 格式的字符串
try:
# 将二进制强制转换为 ASCII 文本(忽略无法识别的字符)
text = fixed_data.decode('ascii', errors='ignore')

# 搜索 dart{...}
match = re.search(r'dart\{.*?\}', text)
if match:
print("\n" + "="*50)
print("🎉 直接在 ELF 文件中找到了 Flag:")
print(match.group(0))
print("="*50 + "\n")
else:
print("\n[-] 没有直接搜到明文 Flag。")
print("[*] 出题人可能把 Flag 动态加密了。请在 Linux 虚拟机中运行 ./fixed_payload.elf,或者把它扔进 IDA Pro 里逆向!")
except Exception as e:
print(f"[-] 搜索出错: {e}")

if __name__ == '__main__':

提取出的 payload 并不是压缩包,而是一个完整的 Linux ELF 可执行文件

继续ida分析这个fixed_payload.elf,main函数非常短,在栈上分配了 336 字节的数组 v4。使用qmemcpy将 .data 段 off_4020 处的 336 字节拷贝到 v4。程序并未对 v4 进行任何处理,只是打印了提示:每个 MD5 哈希对应一个 ASCII 字符…” 的伪装信息后就退出了。跟进数据段 off_4020,发现这里连续存放了 42 个指针(刚好 336 字节),每个指针指向一个 32 位的 MD5 字符串。

ida.png

程序没有动态加密,而是将 Flag 拆成了单个字符,并将每个字符的 MD5 值按顺序硬编码在了数据段中。 通过简单的单字符 MD5 查表(或跑脚本爆破),将这 42 个 MD5 逐一映射回明文
拼接所有破解出的单字符,得到: dart{2ab1fb8a-b830-45e7-8830-66c7e3b3e05a}

re2

查壳后发现是upx加壳的,并且有魔改,当时懒得脱了,插个眼后面复盘一下

re3

附件一个pyinstaller打包的elf,一个.pcap,不出意料的话就是elf程序有加密逻辑,而流量中有加密结果,先流量分析发现客户像服务器端发送了三个文件加密结果,最终目标是解密flag.txt的加密结果(hex编码)

pcap.png

解包后再将pyc扔进pylingual,拿到py源码

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
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: 'client.py'
# Bytecode version: 3.10.b1 (3439)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)

import base64
import sys
import os
import json
import socket
import hashlib
import crypt_core
import builtins
def _oe(_d, _k1, _k2, _rn):
# ***<module>._oe: Failure: Compilation Error
try:
_b = base64.b85decode(_d.encode())
_r = []
for _i, _x in enumerate(_b):
return ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn), _i, 3) or ((_k1, _k2, _rn),
_r.append(_x, _k if _k else None)
_s = bytes(_r).decode()
_res = []
for _c in _s:
if _c.isalpha():
_base = ord('A') if _c.isupper() else ord('a')
_res.append((chr, ord(_c), _base, _rn, 26, _base))
else:
if _c.isdigit():
_res.append(str(int(_c), _rn or 10))
else:
_res.append(_c)
return ''.join(_res)
except:
return _d
_globs = dict(__name__='__main__', __file__=__file__, __package__=None, _oe=_oe)
for _k in dir(builtins):
if not _k.startswith('_'):
_globs[_k] = getattr(builtins, _k)
_globs['base64'] = base64
_globs['sys'] = sys
_globs['os'] = os
_globs['json'] = json
_globs['socket'] = socket
_globs['hashlib'] = hashlib
_globs['crypt_core'] = crypt_core
def _obf_check():
if hasattr(sys, 'gettrace'):
_tr = sys.gettrace()
if _tr is not None:
return False
return True
def _obf_exec(_code):
# ***<module>._obf_exec: Failure: Different bytecode
if not _obf_check():
return None
else:
exec(compile, _code, chr(60) | chr(111) | chr(98) | chr(102) | chr(101) | chr(120) | chr(99))
_1667 = '###'
_obf_exec(base64.b85decode(_1667).decode())

真正的逻辑被 Base85 编码隐藏在 _1667 这个超长字符串里了,代码最后一行意味着它在运行时解码并直接 exec() 内存中的代码。先把真正的python逻辑dump出来
1
2
3
4
5
6
7
8
9
import base64

_1667 = 'UurNQJs@mhZDM3$Iv^-BFd$waF)}tOAS... (把完整的字符串复制过来) ...Uu0!rWM5-pY-1=X3I'
real_code = base64.b85decode(_1667).decode()

with open("real_client.py", "w") as f:
f.write(real_code)

print("解码完成,请查看 real_client.py")

运行脚本得到
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
_j0 = lambda: (30 ^ 126) + (520 % 26)
_j1 = lambda: (158 ^ 184) + (820 % 54)
_j2 = lambda: (37 ^ 2) + (687 % 25)
_j3 = lambda: (72 ^ 112) + (474 % 30)
_j4 = lambda: (173 ^ 82) + (257 % 73)
_j5 = lambda: (117 ^ 203) + (331 % 54)
_j6 = lambda: (242 ^ 46) + (846 % 33)
_j7 = lambda: (21 ^ 148) + (425 % 77)
_j8 = lambda: (139 ^ 134) + (427 % 21)
_j9 = lambda: (245 ^ 62) + (413 % 85)
_j10 = lambda: (242 ^ 65) + (892 % 30)
_j11 = lambda: (22 ^ 58) + (740 % 59)
_j12 = lambda: (139 ^ 248) + (771 % 74)
_j13 = lambda: (219 ^ 230) + (262 % 63)
_j14 = lambda: (17 ^ 89) + (622 % 38)
_j15 = lambda: (229 ^ 205) + (369 % 25)
_j16 = lambda: (111 ^ 33) + (433 % 50)
_j17 = lambda: (41 ^ 142) + (512 % 21)

class _Obf3776:
def __init__(self):
self._v = 751
def _m(self):
return self._v * 5

#!/usr/bin/env python3

import socket
import json
import os
import sys
import hashlib
import time

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import crypt_core


class CustomBase64:
CUSTOM_ALPHABET = _oe("8<<BLok1UrR}_R>27yTmms1djUI&{(7Ls{Apm;c@eJQYZA-rTHu4po}aw559KBaUw?kHpDBVghrW#KRr", 83, 214, 17)
STANDARD_ALPHABET = (
_oe("0fj{dfJO_COA?e)7n4^Mo>&>3T^^WT1BYWEqGTnZX)3I6F|~Czuy#AYdpNp$J-J~b;VEk7AYtVtX5cz}", 83, 214, 17)
)
ENCODE_TABLE = str.maketrans(STANDARD_ALPHABET, CUSTOM_ALPHABET)
DECODE_TABLE = str.maketrans(CUSTOM_ALPHABET, STANDARD_ALPHABET)

@classmethod
def decode(cls, data: str) -> bytes:
import base64

std_b64 = data.translate(cls.DECODE_TABLE)
return base64.b64decode(std_b64)


SERVER_HOST = ""
SERVER_PORT = 9999
KEY_B64 = _oe("C7MAupdc5tRBM!52kv4Wmp~Hle`A4N5`t?5nObY+L~6Pz5wdF*y=E$zQv!xZ", 83, 214, 17)
KEY = CustomBase64.decode(KEY_B64)
FILES_TO_SEND = [_oe("I-p}FvS)q0emD", 83, 214, 17), _oe("B(-BJ_<B6O", 83, 214, 17), _oe("C$MxRtZ99{emD", 83, 214, 17)]


def _opaque_true():
_x = 0
for _i in range(100):
_x += _i * (_i - _i + 1)
return _x >= 0


def _opaque_false():
_a, _b = 5, 7
return (_a * _b) == (_b * _a + 1)


def _dead_calc():
_dead = 0
for _i in range(50):
_dead = (_dead + _i) % 17
if _dead > 100:
_dead = _dead * 2 + 1
return _dead


def encrypt_file(key: bytes, plaintext: bytes) -> bytes:
_state = 0
_result = None
while _state < 3:
if _state == 0:
if _opaque_true():
_result = crypt_core.encode_data(plaintext, key[:16])
_state = 2
else:
_dead_calc()
_state = 1
elif _state == 1:
_dead_calc()
_state = 2
elif _state == 2:
if _opaque_false():
_result = None
_state = 3
return _result


def send_single_file(sock, filename, plaintext):
_s = 0
_ct = None
_pl = None
while _s < 5:
if _s == 0:
_ct = encrypt_file(KEY, plaintext)
_s = 1
elif _s == 1:
_pl = {_oe("B&>2Jvtu`)", 83, 214, 17): filename, _oe("C#-fVpm;c-emD", 83, 214, 17): _ct.hex()}
_s = 2
elif _s == 2:
if _opaque_true():
sock.sendall(json.dumps(_pl).encode(_oe("KfPvt;{", 83, 214, 17)) + b"\n")
_s = 4
else:
_dead_calc()
_s = 3
elif _s == 3:
_dead_calc()
_s = 4
elif _s == 4:
if not _opaque_false():
time.sleep(0.1)
_s = 5


def _verify_cmd(cmd):
_state = 10
_hash_val = None
_valid = False

while _state < 50:
if _state == 10:
if len(cmd) > 0:
_state = 20
else:
_state = 49
elif _state == 20:
_hash_val = hashlib.md5(cmd.encode()).hexdigest()
_state = 30
elif _state == 30:
if _opaque_true():
_valid = _hash_val == _oe("VWK4=qGuqYBxK?sVWlBw<RW0^B4q9&VB;re<0L2U", 83, 214, 17)
_state = 40
else:
_dead_calc()
_state = 49
elif _state == 40:
if _valid:
_state = 50
else:
_state = 49
elif _state == 49:
return False

return _valid


def _get_server_host(args):
_s = 100
_host = None

while _s < 200:
if _s == 100:
if len(args) > 2:
_s = 110
else:
_s = 120
elif _s == 110:
_host = args[2]
_s = 200
elif _s == 120:
if _opaque_true():
_host = ""
_s = 200
elif _s == 200:
if _opaque_false():
_host = _oe("Ywsm};Xh>fDF", 83, 214, 17)
_s = 201

return _host


def main():
_state = 0
_sock = None
_idx = 0
_printed_header = False

while _state < 100:
if _state == 0:
if _opaque_false():
print(_oe("2B2dm_GLArX8", 83, 214, 17))
_state = 1
elif _state == 1:
if len(sys.argv) < 2:
_state = 5
else:
_state = 2
elif _state == 2:
if _verify_cmd(sys.argv[1]):
_state = 3
else:
_state = 4
elif _state == 3:
if not _printed_header:
print("=" * 50)
print(_oe("8K7l9zh`rSYcQZO7{6mSyk;f8F$cA4C9`^SyD5F)", 83, 214, 17))
print("=" * 50)
_printed_header = True
_state = 10
elif _state == 4:
print("������������")
_state = 99
elif _state == 5:
print("�÷���python client.py <command> [SERVER_HOST]")
_state = 99
elif _state == 10:
try:
_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_state = 11
except Exception:
_state = 99
elif _state == 11:
_host = _get_server_host(sys.argv)
_state = 12
elif _state == 12:
try:
_sock.connect((_host, SERVER_PORT))
_state = 20
except Exception as e:
print(f"[!] ����ʧ�ܣ�{e}")
_state = 99
elif _state == 20:
if _idx < len(FILES_TO_SEND):
_state = 21
else:
_state = 30
elif _state == 21:
_fname = FILES_TO_SEND[_idx]
_state = 22
elif _state == 22:
if os.path.exists(_fname):
_state = 23
else:
_state = 28
elif _state == 23:
with open(_fname, "rb") as _f:
_data = _f.read()
_state = 24
elif _state == 24:
if _opaque_true():
print(f"[*] �����ļ�")
_state = 25
elif _state == 25:
if not _opaque_false():
send_single_file(_sock, _fname, _data)
_state = 26
elif _state == 26:
_idx += 1
_state = 20
elif _state == 28:
print(f"[-] �������")
_state = 29
elif _state == 29:
_idx += 1
_state = 20
elif _state == 30:
if _opaque_true():
time.sleep(0.2)
_state = 31
elif _state == 31:
if _sock:
_sock.close()
_state = 99
elif _state == 99:
break


if __name__ == _oe("42g9itaJ>C", 83, 214, 17):
_dead_calc()
if _opaque_true():
main()
else:
_dead_calc()

其中有魔改的base64解码,然后调用了crypt_core.encode_data,密文的长度全部是 16 的整数倍,所以只有前16字节参与加密
去混淆后获取到密钥:passvkcDKWLAA45ocFAXBPM63X4G8XzzTE1B
1
2
3
4
5
6
7
8
9
import base64
CUSTOM = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890!@'
STD = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
table = str.maketrans(CUSTOM, STD)
key_b64 = 'eUYme4MkN1KSC1bWJZJ2w3FUJCiEXT13D2u1KmiNtfhXKZYE'
std_b64 = key_b64.translate(table)
key = base64.b64decode(std_b64)
print(key)
print(key[:16])

ida分析crypt_core.so,交叉引用找到关键函数sub_60B0,发现就是魔改SM4

ida2.png

最终解密脚本

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
from __future__ import annotations

import argparse
import json
import subprocess
import sys
from pathlib import Path


# ===== 常量 =====

BLOCK_SIZE = 16
KEY = b"passvkcDKWLAA45o"

SBOX = bytes.fromhex(
"ecca0ef308f02aa23b182b5c37bd12a8"
"05d3a1574f96fcf5a7141966589bbfb4"
"39d51e1a30bc6c80b7ed4106d91767cd"
"1d2cae240313c65383110af7c04dc49e"
"8d001fc33f359fcb729d166facce3c5e"
"a6e17b343632b895918952c1e7a33348"
"04cf10eb25bb8e0f816eb343458f49f8"
"4b59074adefdc8d0848bfbdadb28d43e"
"a42f56beef86c762ea76e9d674a56bf9"
"987d3a265aaf870d1b2eb2e36accf1ff"
"d7f61cc9e870204e233dc2aadc0bf25f"
"7afa889747d10c02317ff4751593388a"
"429071dd73557eb55b294c9ae08cb0e5"
"642701dfad2179949251697c22635085"
"2de2404644a982b661d8d2b968abb15d"
"655477a0c5ba609ce4feee99e6786d09"
)

FK = (0x3B1F86A4, 0x83F7332D, 0x58ADBA8E, 0x71DC3F73)

CK = (
0x9A148706, 0x657904A4, 0xB0535D2D, 0x865C7AA7,
0xF7FEF2D4, 0xF09D3A8B, 0x67CB0390, 0xF3B1D1AA,
0x1941EDE3, 0xCDD55650, 0x272AA612, 0x397B1DC6,
0x767AAB6B, 0x71A39044, 0x8A77F592, 0x7B5A7907,
0x97D18251, 0xCA1960CB, 0x44B54134, 0x3F30C70A,
0x5EB36C72, 0x5569E716, 0x51BF832C, 0xF13A95BC,
0x92D9F824, 0xE75CED15, 0x4558D865, 0xBE5250CD,
0x8F658E94, 0xB4EA5DC0, 0xB0377FCE, 0x4DF44762,
)


# ===== 基础函数 =====

def rol32(x: int, n: int) -> int:
x &= 0xFFFFFFFF
return ((x << n) | (x >> (32 - n))) & 0xFFFFFFFF


def tau(x: int) -> int:
return (
(SBOX[(x >> 24) & 0xFF] << 24)
| (SBOX[(x >> 16) & 0xFF] << 16)
| (SBOX[(x >> 8) & 0xFF] << 8)
| SBOX[x & 0xFF]
)


def l_transform(x: int) -> int:
return x ^ rol32(x, 2) ^ rol32(x, 10) ^ rol32(x, 18) ^ rol32(x, 24)


def l_prime(x: int) -> int:
return x ^ rol32(x, 13) ^ rol32(x, 23)


# ===== 密钥扩展 =====

def expand_round_keys(key: bytes) -> list[int]:
if len(key) != BLOCK_SIZE:
raise ValueError("invalid key length")

words = [int.from_bytes(key[i:i + 4], "big") for i in range(0, 16, 4)]
state = [words[i] ^ FK[i] for i in range(4)]

rk = []
for i in range(24):
mix = state[i + 1] ^ state[i + 2] ^ state[i + 3] ^ CK[i]
new = state[i] ^ l_prime(tau(mix))
state.append(new)
rk.append(new)

return rk


# ===== 分组加解密 =====

def crypt_block(block: bytes, rk: list[int]) -> bytes:
if len(block) != BLOCK_SIZE:
raise ValueError("invalid block size")

state = [int.from_bytes(block[i:i + 4], "big") for i in range(0, 16, 4)]

for i in range(24):
mix = state[i + 1] ^ state[i + 2] ^ state[i + 3] ^ rk[i]
state.append(state[i] ^ l_transform(tau(mix)))

return b"".join(w.to_bytes(4, "big") for w in state[-1:-5:-1])


def pkcs7_unpad(data: bytes) -> bytes:
if not data or len(data) % BLOCK_SIZE:
raise ValueError("invalid padding")

pad = data[-1]
if pad < 1 or pad > BLOCK_SIZE or data[-pad:] != bytes([pad]) * pad:
raise ValueError("invalid padding")

return data[:-pad]


def decrypt(ct: bytes, key: bytes = KEY) -> bytes:
if len(ct) % BLOCK_SIZE:
raise ValueError("invalid ciphertext length")

rk = list(reversed(expand_round_keys(key)))
pt = b"".join(
crypt_block(ct[i:i + 16], rk)
for i in range(0, len(ct), 16)
)
return pkcs7_unpad(pt)


# ===== PCAP 解析 =====

def extract_json_messages(pcap: Path) -> list[dict[str, str]]:
out = subprocess.check_output(
["tshark", "-r", str(pcap), "-q", "-z", "follow,tcp,raw,0"],
text=True,
)

msgs = []
for line in out.splitlines():
line = line.strip()
if not line or any(c not in "0123456789abcdef" for c in line):
continue

raw = bytes.fromhex(line)
if raw.startswith(b"{"):
msgs.append(json.loads(raw.decode()))

return msgs


# ===== 输出 =====

def print_result(name: str, pt: bytes) -> None:
print(f"=== {name} ===")
try:
print(pt.decode())
except UnicodeDecodeError:
print(pt.hex())
print()


# ===== 主程序 =====

def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--pcap", type=Path, default=Path("capture.pcap"))
parser.add_argument("--ciphertext")
parser.add_argument("--raw", action="store_true")
args = parser.parse_args()

# 单条解密模式
if args.ciphertext:
pt = decrypt(bytes.fromhex(args.ciphertext))
output = pt.hex() if args.raw else pt.decode(errors="ignore")
print(output)
return 0

# PCAP 模式
msgs = extract_json_messages(args.pcap)
if not msgs:
print("no messages found", file=sys.stderr)
return 1

for m in msgs:
pt = decrypt(bytes.fromhex(m["ciphertext"]))
print_result(m["filename"], pt)

return 0


if __name__ == "__main__":
raise SystemExit(main())

— END —

本文作者:llurry
本文链接:https://llurry.github.io/2026/03/16/2026%E8%BD%AF%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%AE%89%E5%85%A8%E8%B5%9Bwp/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可