2026黄河流域wp(Misc全)

Misc

signin?

给了这样子一个txt文件

随便阅读一下可以发现语义压根没啥内容,题目也说明了“毕竟签到题通常不会真的要求选手精读一大段废话”

让我们看形式本身,猜测就是看标点符号

猜测需要标点进行映射,我们可以尝试一下,按照一般的排列逻辑也是,。;:

1
2
3
4
, = 0
。 = 1
; = 2
: = 3

只需要每四个四进制转为一个ASCII即可

试了一下发现能解出flag头,继续写得脚本

1
2
3
4
5
6
7
8
9
import sys

text = open(sys.argv[1] if len(sys.argv) > 1 else "ai_reply.txt", encoding="utf-8").read()
mp = {",": "0", "。": "1", ";": "2", ":": "3"}

s = "".join(mp[c] for c in text if c in mp)
out = "".join(chr(int(s[i:i+4], 4)) for i in range(0, len(s) - 3, 4))

print(out)

sdpcsec{welcome_2026_4nd_competiton!}

Cake

打开来俩文件

cake_knife.txt就只有这样子三行十六进制数

另一个cake_base.bin放到Winhex看看,发现啥都看不出

猜测需要那个knife去处理这个蛋糕的base

所以这题的关键点落在了 cake_knife.txt 中的三个 32 位整数:

1
2
3
0xb47e923c
0x5aeb49a7
0xa3cd7af0

三个数,每个数都是8位十六进制数,很明显是某个算法的内部状态

需要我们联想到ZipCrypto

这是一个很老的传统ZIP加密手段,属于流加密,只要正确的密钥流就能解密了

要注意这边的ZipCrypto只是拿来作为一种加密算法,不是像普通zip加密这样子

1
2
3
4
5
普通 ZIP 加密:
ZIP 容器头不加密,只加密里面的文件数据

这题:
把整个 ZIP 文件本身当成一段普通数据,再用 ZipCrypto 算法加密

ZipCrypto是这样子运行的

当加密的时候,不会直接拿密码去加密

而是先用密码生成三个内部状态key0,key1,key2

然后对他们初始化,初始化好之后把密码的每一个字节喂进去,不断更新这三个key

那这题已经直接把最后的三个key都给我们了,我们只需要进行解密就好了

怎么解密呢,分为三步

第一步:生成密钥流字节k

1
2
3
def decrypt_byte(key2):
temp = (key2 | 2) & 0xffffffff # 确保最低位为 0,次低位为 1
return ((temp * (temp ^ 1)) >> 8) & 0xff

key2 | 2,保证temp是偶数,然后计算temp * (temp ^ 1),右移 8 位,取低 8 位作为密钥流字节 k

第二步:解密得到明文字节p

1
p = c ^ k

第三步,更新密钥状态

1
2
3
4
5
6
def update_keys(key0, key1, key2, plain):
key0 = crc32_update(key0, plain) # 更新 CRC32
key1 = (key1 + (key0 & 0xff)) & 0xffffffff
key1 = (key1 * 134775813 + 1) & 0xffffffff # 线性同余
key2 = crc32_update(key2, (key1 >> 24) & 0xff)
return key0, key1, key2

这边三个key各司其职

1
2
3
key0:用明文字节更新 CRC32。
key1:加上 key0的低 8 位,然后乘以常数 134775813(0x8088405)并加 1。
key2:用 key1的高 8 位更新另一个 CRC32

就是以上三步,我们来回做这三步对每一个字节进行解密,最后就能得到一个文件

完整解密脚本如下:

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
import zlib
import zipfile
import os
import cv2

KEY0 = 0xb47e923c
KEY1 = 0x5aeb49a7
KEY2 = 0xa3cd7af0

def crc32_update(old_crc, c):
return (zlib.crc32(bytes([c]), old_crc ^ 0xffffffff) ^ 0xffffffff) & 0xffffffff

def decrypt_byte(key2):
temp = (key2 | 2) & 0xffffffff
return ((temp * (temp ^ 1)) >> 8) & 0xff

def update_keys(key0, key1, key2, plain):
key0 = crc32_update(key0, plain)
key1 = (key1 + (key0 & 0xff)) & 0xffffffff
key1 = (key1 * 134775813 + 1) & 0xffffffff
key2 = crc32_update(key2, (key1 >> 24) & 0xff)
return key0, key1, key2

def decrypt_zipcrypto(data, key0, key1, key2):
out = bytearray()

for c in data:
k = decrypt_byte(key2)
p = c ^ k
out.append(p)
key0, key1, key2 = update_keys(key0, key1, key2, p)

return bytes(out)

with open("cake_base.bin", "rb") as f:
enc = f.read()

dec = decrypt_zipcrypto(enc, KEY0, KEY1, KEY2)

print(dec[:4])

with open("cake_decrypted.zip", "wb") as f:
f.write(dec)

os.makedirs("out", exist_ok=True)

with zipfile.ZipFile("cake_decrypted.zip", "r") as z:
z.extractall("out")

print(os.listdir("out"))

运行后就能解密这个cake的base,发现文件头是一个zip,解压即可

解压得到这样子三个文件:

接着就是对这三个文件进行探秘了

这边我不知道为什么上边俩文件到最后都没用到,不知道怎么用(),txt里边可能是哈希吧,但是我爆破不出来

而flag的提取也只和这个avi文件有关

发现有一些像素逐帧发生了改变,但是不确定读哪一个坐标,所以进行了遍历

我们直接遍历所有坐标,然后检查 RGB 三个通道中是否存在可打印 ASCII 字符

需要注意,OpenCV 读取图片时默认通道顺序是 BGR,因此脚本中需要转成 RGB 或者直接遍历三个通道。

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

cap = cv2.VideoCapture("scream.avi")

frames = []
while True:
ret, frame = cap.read()
if not ret:
break
frames.append(frame)

cap.release()

h, w = frames[0].shape[:2]

for y in range(h):
for x in range(w):
s = ""

for frame in frames:
b, g, r = frame[y, x]

# OpenCV 默认是 BGR,这里按 RGB 顺序检查
for v in [r, g, b]:
v = int(v)
if 32 <= v <= 126:
s += chr(v)

if "flag{" in s:
print(x, y, s)

运行后发现了在(123,45)的地方有,flag是flag{W0w_d3lici0us_c4ke!!}

encrypt

上来给了俩文件,一个exe一个png,怀疑是exe对png做了什么处理,我们先分析exe

先塞到DIE看看

不难发现是PyInstaller打包的Python程序,我们尝试提取Python字节码

1
python3 pyinstxtractor.py Encrypt.exe

用pyinstxtractor解包一下

解出来很多东西啊

1
2
3
4
5
pyiboot / pyimod / pyi_rth  → PyInstaller 运行时
PIL / numpy / dll / pyd → 第三方库和运行环境
struct.pyc → Python 标准库
srpm_cli.pyc → 很像题目自己的入口文件
PYZ.pyz → 真正 Python 模块压缩包

主要还是看srpm_cli.pyc和PYZ.pyz

srpm_cli.pyc由于python版本有点高,是python3.13的,不太好反编译,不过在线工具还是能反编译出一点

1
from encrypt import encrypt_image

能反编译出这句话就够了,我们接着去找encrypt模块即可

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
import sys
import re
import dis
import types

sys.path.insert(0, ".")

from pyimod01_archive import ZlibArchiveReader

z = ZlibArchiveReader("PYZ.pyz", 0)

for name in z.toc:
if re.search(r"encrypt|srpm|image", name, re.I):
print("[MODULE]", name)

for modname in ["encrypt", "srpm_utils"]:
print("=" * 80)
print("MODULE:", modname)

code = z.extract(modname)

for obj in code.co_consts:
if isinstance(obj, types.CodeType):
print("\n--- FUNCTION:", obj.co_name, "---")
print("varnames:", obj.co_varnames)
print("names:", obj.co_names)
dis.dis(obj)

分析PYZ.pyz,可以看到逻辑

1
2
3
4
5
Image.open
convert("RGB")
np.array
reshape(-1)
swapped[index], swapped[target] = swapped[target], swapped[index]

即主逻辑是对图片 RGB 三个通道分别做多轮像素交换,本质是 swap 交换

所以可以通过反向遍历来恢复原图

根据3.png 的文件名提示,猜测 rounds=3

加密时大致流程为:

1
2
3
4
5
for r in range(rounds):
for c in range(3):
for i in range(n):
target = (i * i + (2 * r + 3) * i + 7 * (c + 1)) % n
swap(i, target)

逆过程的时候我们只需要将轮数、像素下标反向执行即可

1
2
3
4
5
for r in range(rounds - 1, -1, -1):
for c in range(3):
for i in range(n - 1, -1, -1):
target = (i * i + (2 * r + 3) * i + 7 * (c + 1)) % n
swap(i, target)

写得脚本

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
#!/usr/bin/env python3
from PIL import Image
import numpy as np
import sys


def undo_one_round(flat: np.ndarray, round_index: int, channel_index: int) -> None:
n = flat.size
a = 2 * round_index + 3
b = 7 * (channel_index + 1)
# inverse of: for i in range(n): swap(i, target(i))
for i in range(n - 1, -1, -1):
j = (i * i + a * i + b) % n
flat[i], flat[j] = flat[j], flat[i]


def decrypt(input_png: str, output_png: str, rounds: int) -> None:
arr = np.array(Image.open(input_png).convert('RGB'))
h, w, _ = arr.shape
out = np.empty_like(arr)
for c in range(3):
flat = arr[:, :, c].reshape(-1).copy()
for r in range(rounds - 1, -1, -1):
undo_one_round(flat, r, c)
out[:, :, c] = flat.reshape(h, w)
Image.fromarray(out, 'RGB').save(output_png)


if __name__ == '__main__':
if len(sys.argv) != 4:
print(f'Usage: {sys.argv[0]} <encrypted.png> <output.png> <rounds>')
sys.exit(1)
decrypt(sys.argv[1], sys.argv[2], int(sys.argv[3]))

成功解得下图

明显flag这个图片有关,但是尝试了经典隐写都没有成果

这边想到由于题目先通过像素置换隐藏图片,说明还原后的图可能还藏有频域信息

因此我们可以继续尝试傅里叶变换分析

对还原后的图片做灰度处理,然后进行 FFT:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

img = Image.open("dec3.png").convert("L")
arr = np.array(img)

f = np.fft.fft2(arr)
fshift = np.fft.fftshift(f)

spectrum = np.log(np.abs(fshift) + 1)

plt.figure(figsize=(10, 10))
plt.imshow(spectrum, cmap="gray")
plt.axis("off")
plt.savefig("fft_result.png", bbox_inches="tight", pad_inches=0)

运行后我们得到了文件fft_result.png,可以在频谱图边缘发现隐藏文字:

所以flag是flag{Wei_Hai_journey}

鲨士比亚王国的金融危机

上来就是这样子两张图

这边的flag.png 是 889×889,观察一下可以发现明显是像素螺旋打乱,也符合题目的漩涡

SCB.png 是 2587×307

发现很巧啊,SCB.png中白色像素数量刚好889 × 889 ,和我们flag.png一样

所以猜测我们可以先对 flag.png 做反螺旋恢复,然后再把这些像素替换掉SCB.png的白色像素,黑色的 SCB 保留

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
#!/usr/bin/env python3
from pathlib import Path
from zipfile import ZipFile
from PIL import Image
import numpy as np


flag = np.array(Image.open('flag.png').convert('RGB'))
scb = np.array(Image.open('SCB.png').convert('RGB'))
n = flag.shape[0]
assert flag.shape == (n, n, 3)
assert scb.shape[0] * scb.shape[1] >= n * n

def spiral_indices(n: int):
top, left = 0, 0
bottom, right = n - 1, n - 1
out = []
while top <= bottom and left <= right:
for x in range(left, right + 1):
out.append((top, x))
for y in range(top + 1, bottom + 1):
out.append((y, right))
if top < bottom:
for x in range(right - 1, left - 1, -1):
out.append((bottom, x))
if left < right:
for y in range(bottom - 1, top, -1):
out.append((y, left))
top += 1
bottom -= 1
left += 1
right -= 1
return out

path = [(y, n - 1 - x) for y, x in spiral_indices(n)][::-1]
coin = np.empty_like(flag)
coin.reshape(-1, 3)[:] = flag[[y for y, x in path], [x for y, x in path]]
Image.fromarray(coin).save('SCB_coin.png')

white = np.all(scb == 255, axis=2)
assert int(white.sum()) == n * n
res = np.full_like(scb, 255)
res[~white] = [0, 0, 0]
res[white] = coin.reshape(-1, 3)
Image.fromarray(res).save('revealed.png')

r, g, b = res[:, :, 0].astype(int), res[:, :, 1].astype(int), res[:, :, 2].astype(int)
green = (g - r > 20) & (g - b > 20) & (g < 250)
mask = np.full_like(res, 255)
mask[green] = [0, 0, 0]
Image.fromarray(mask).save('revealed_green_mask.png')

print(f'wrote: {"SCB_coin.png"}')
print(f'wrote: {"revealed.png"}')
print(f'wrote: {"revealed_green_mask.png"}')

成功还原出硬币

填到刚刚的文件里

得到flag——flag{You_saved_SCB_by_the_coin}

Upper Tower

上来只有两张照片,但是题目还有提示,题目暗示了Tupper,而文本的寂静暗示了SilentEye

上来先分析一下1.png,考虑图片隐写

对 PNG 的 RGB 通道做 LSB 检查,发现蓝色通道最低位中隐藏了一段数据。提取脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from PIL import Image
import numpy as np

img = np.array(Image.open("1.png").convert("RGBA"))

# 取蓝色通道 LSB
bits = (img[:, :, 2] & 1).ravel()

out = bytearray()
for i in range(0, len(bits) // 8 * 8, 8):
v = 0
for b in bits[i:i + 8]:
v = (v << 1) | int(b)
out.append(v)

data = bytes(out)

# 前 4 字节为后续十进制字符串长度
ln_bits = int.from_bytes(data[:4], "big")
digits = data[4:4 + ln_bits // 8].decode()

print(digits[:100])
print(len(digits))

可以得到一串非常大的十进制整数。

接着就是Tupper了,利用Tupper公式还原密码

Tupper塔珀自指公式通常以 17 像素为高度,将大整数作为纵坐标进行绘制

渲染脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from PIL import Image
import numpy as np

k = int(digits)

h = 17
w = (k.bit_length() + 16) // 17

arr = np.zeros((h, w), dtype=np.uint8)

for x in range(w):
for y in range(h):
bit = ((k + y) // 17 >> (17 * x + y)) & 1
arr[h - 1 - y, x] = 255 if bit else 0

Image.fromarray(arr, "L").resize(
(w * 10, h * 10),
Image.Resampling.NEAREST
).save("tupper.png")

我们成功得到了Tupper公式绘图的成果

生成的图片中可以看到密码是4thHHLY

所以现在我们手里有一串密码,还有一个2.jpg,可以想一些加密手段

结合题目描述中的“寂静”,不难想到应该对应的是SilentEye

得到flag

AD ASTRA

上来就一个wav和一个png文件

先看看这个flag.png,先看看文件类型file flag.png

发现 flag.png 并不是真正的 PNG,而是一个Webp文件

我们知道Webp的文件头是这样子写的

1
2
3
52 49 46 46        -> "RIFF"
xx xx xx xx -> RIFF size,小端序
57 45 42 50 -> "WEBP"

所以size是 0x10be4(注意小端序啊)

所以正常的Webp结束位置应该是 8 + 0x10be4 = 0x10be8

但是发现这边结束后还有追加数据

明显是一个zip啊

提取一下追加的,用什么其实都可以,正好今天群里在聊这个,foremost也行,binwalk也行,直接dd if也可以

1
dd if=flag.png of=hidden.zip bs=1 skip=68588

得到9个txt文件

发现这些文件内容都是 base64 片段。按文件名顺序拼接并解码:

1
cat hidden/*.txt | base64 -d > clue.png

得到这样子一张图

合并成一句就是:

1
To the stars we come from

因此继续分析AD ASTRA.wav

一开始可以尝试常见音频隐写方向,比如频谱图、LSB等

但是都没什么收获

进一步检查 WAV 数据区,发现其隐藏了 DeepSound 数据

DeepSound 会把数据藏在 WAV 音频采样的低位中,可以通过解码低 4 bit 检查是否存在 DeepSound 头

检测脚本如下:

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

path = "AD ASTRA.wav"
data = open(path, "rb").read()

pos = 12
data_start = None

while pos + 8 <= len(data):
cid = data[pos:pos+4]
size = struct.unpack("<I", data[pos+4:pos+8])[0]

if cid == b"data":
data_start = pos + 8
break

pos += 8 + size + (size & 1)

if data_start is None:
raise SystemExit("no data chunk")

def decode_normal(buf):
out = bytearray()

for i in range(0, len(buf) // 4 * 4, 4):
out.append(((buf[i] & 0x0f) << 4) | (buf[i+2] & 0x0f))

return bytes(out)

ds = decode_normal(data[data_start:data_start + 104])

print("data_start =", data_start)
print("header_hex =", ds[:26].hex())
print("magic =", ds[:4])
print("mode =", ds[4])
print("encrypted =", ds[5])
print("hash =", ds[6:26].hex())

full = decode_normal(data[data_start:])
open("deepsound_stream.bin", "wb").write(full)

运行结果:

1
2
3
4
5
6
data_start = 46
header_hex = 445343320401f54db3d444654ff613ca115add3377e62a17205e
magic = b'DSC2'
mode = 4
encrypted = 1
hash = f54db3d444654ff613ca115add3377e62a17205e

这里的 DSC2 是 DeepSound 的标志、

说明我们的 AD ASTRA.wav 中确实存在 DeepSound 隐写数据,并且是加密状态

使用前面提示图得到的密码:

1
To the stars we come from

用 DeepSound 打开 AD ASTRA.wav,输入该密码,可以成功提取出下一层文件:

接下来这个加密的docx毫无头绪,最后我直接爆破了,不知道是不是非预期

直接hashcat爆破哈希值得到docx的密码是skadi2530(是斯卡蒂啊

(浊蒂真好看,虽然不是深海队的吃不到buff)

图片挪开就能得到flag了

sdpcsec{AD_ASTRA_INFINITUM}

Do you know RA2?

比赛没做出来,赛后Alex教的,谢谢Alex

打开来三个文件,我们一个个看

先看这个总部发来的讯息.wav

1
ffprobe -hide_banner -show_format -show_streams "总部发来的讯息.wav"

听一下,这个刺耳朵的声音很像SSTV

频谱图看着也很像,SSTV解一下看看

用虚拟声卡比较好

可以得到这样子一张图片

写了密码packed up and ready

1
2
3
4
5
6
7
from collections import Counter
from math import log2

data = open("盟军战车工厂", "rb").read()
cnt = Counter(data)
entropy = -sum((n/len(data)) * log2(n/len(data)) for n in cnt.values())
print(entropy)

中间那个文件,算熵,发现接近8,高熵且13.0mb,像是vc容器

用刚刚的密码成功加载

没什么文件,就一个png

看着有点怪,猜测有隐写,但是想不到是什么隐写,这个时候就想到读一下最后一个txt文件

发现这边提到了一个新型坦克-幻影坦克

GitHub - TankFactory/Mirage_Cloak: 幻影/无影及其杂交坦克编解码工具

对应了这样子一个幻影坦克的类lsb隐写术

大致原理上文也说了,就是一种基于棋盘格幻影坦克图的隐写术

我们看到的png需要把像素分成两类

1
2
黑格 / 低亮格:RGB 接近 0
白格 / 高亮格:RGB 接近 255

然后利用RGB离0和255的偏移量来存数据

我们这个图每个通道存2bit

1
2
3
4
5
6
7
8
9
10
11
低亮格:
0 附近 -> 00
2t 附近 -> 01
4t 附近 -> 10
6t 附近 -> 11

高亮格:
255 附近 -> 00
255-2t 附近 -> 01
255-4t 附近 -> 10
255-6t 附近 -> 11

t是threshold,我们图的t是8

利用这个项目就可以进行解密得到这样子一个31B的文件

这就是容器的隐藏卷密码了

这次挂载得到了flag.png

又是一张浊蒂的照片,我怀疑和上一题同一个出题人,浊蒂真好看

不难发现照片右下角藏着一个二维码,但是怎么扫都扫不出,发现是又做了一层2x2棋盘化

所以我们肉眼看着像有网纹一样

其实随便看几个像素就很明显

1
2
3
4
5
6
0: (194, 211, 216, 255)
1: (22, 25, 25, 255)
2: (196, 213, 218, 255)
3: (24, 25, 25, 255)
4: (195, 215, 217, 255)
5: (24, 25, 25, 255)

可以看见是亮暗交错的

原理就是把图片切成2x2小格

1
2
A B
B A

A是一层图,B是一层图

1
2
3
4
hidden = (
arr[0:2*H:2, 1:2*W:2].astype(np.uint16) +
arr[1:2*H:2, 0:2*W:2].astype(np.uint16)
) // 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
52
53
54
55
56
57
58
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from PIL import Image, ImageOps
import numpy as np
import sys


def main():
if len(sys.argv) < 2:
print("Usage: python3 extract_flag_from_png.py flag.png")
raise SystemExit(1)

in_path = sys.argv[1]
img = Image.open(in_path).convert("RGB")
arr = np.array(img)

h, w, _ = arr.shape
H, W = h // 2, w // 2

# 提取棋盘格中的隐藏层
hidden = (
arr[0:2*H:2, 1:2*W:2].astype(np.uint16) +
arr[1:2*H:2, 0:2*W:2].astype(np.uint16)
) // 2

hidden = hidden.astype(np.uint8)
hidden_img = Image.fromarray(hidden)

# 灰度化 + 自动对比度
gray = ImageOps.autocontrast(ImageOps.grayscale(hidden_img))
gray.save("hidden_layer.png")

# 裁剪右下角二维码
qr = gray.crop((800, 470, 920, 570))
qr = ImageOps.autocontrast(qr)
qr = qr.resize((960, 800), Image.Resampling.NEAREST)

# 二值化 + 反色
qr_bw = qr.point(lambda p: 255 if p > 140 else 0)
qr_out = ImageOps.invert(qr_bw)
qr_out.save("extracted_qr.png")

print("[+] saved hidden layer: hidden_layer.png")
print("[+] saved QR image: extracted_qr.png")

try:
import cv2
data, points, _ = cv2.QRCodeDetector().detectAndDecode(
np.array(qr_out.convert("RGB"))
)
print("[+] QR content:", data)
except Exception:
print("[!] OpenCV unavailable, scan extracted_qr.png manually")


if __name__ == "__main__":
main()

得到flag:sdpcsec{Focusing_light_energy}

问卷

做好即可,感谢出题人的付出

SDPCSEC{SE#_Y@U_NE7T_Y2AR!!!}

LLM问卷

没开玩笑,我真全用的网页,花了0元,如果谁愿意教我ai的高级用法可以私信我,老了用不来()


2026黄河流域wp(Misc全)
https://mei-you-qian.github.io/2026/06/10/2026黄河流域/
作者
Meiyouqian
发布于
2026年6月10日
许可协议