刚刚比完不久,本来想着出个misc全,但是有最后有一道一解的misc还是做不太出,先水一篇好了

所以本文只有潮痕留声和失序货栈,纯水()

Misc

潮痕留声-HHB2026

首先是潮痕留声,好久没有手搓了,这一次手搓了一道还是蛮开心的

打开附件,发现只有一个data.png

拿到png先看看十六进制

我们追踪png的文件尾AE 42 60 82,发现文件后冗余大量的信息

对冗余信息进行信息探查,发现了十六进制末尾写的是4030B405

倒转一下正好就是0x504B0304,即zip压缩包的开始标志

想到题目可能是将压缩包的十六进制倒转后拼接在了png文件之后,我们提取一下,再倒转回去即可

利用cyberchef进行reverse即可

下载后发现是一个加密的压缩包

这个加密方法可以排除是明文爆破的可能了,伪加密发现也不是

继续探查信息

查看属性发现明显提示2026_????_CHB,形似掩码

于是想到本题可能考察我们的是压缩包的掩码爆破

这边可以用工具,也可以用脚本,相对来说还是工具会快一些

直接选择掩码爆破,写好掩码即可,除了ARCHPR,passware kit等工具,或是python脚本等等均可

进行爆破,很容易得到压缩包密码为2026_D4fX_CHB

得到新图片tide_trace.png

又是一张png文件,继续查看十六进制

发现在文件尾后依旧藏有信息,且看文件头可以发现是一个多媒体文件

我们直接利用Foremost进行提取,得到了一个音频文件

直接听没有什么信息,怀疑音频隐写,放入Audacity进行查看

右键选择查看频谱图

明显藏有明文,进行处理

简单拉伸一下,发现是上下、左右都进行了翻转(看这个4最明显),我们手动反转回来

现在我们得到了一个很类似flag的文件,但是不知道这个六乘六的矩阵如何处理,不知道flag是如何阅读的

回到原来解压出的tide_trace.png,题目提示的潮痕还没用到,怀疑可能是宽高被修改过,我们可以利用CRC看看宽高有没有问题,有问题的话就CRC爆破出来正确的

import struct, zlib

d = open("tide_trace.png", "rb").read()
crc = struct.unpack(">I", d[29:33])[0]
rest = d[24:29]

for w in range(1, 2001):
    c = zlib.crc32(b"IHDR" + struct.pack(">I", w))
    for h in range(1, 2001):
        if zlib.crc32(struct.pack(">I", h) + rest, c) & 0xffffffff == crc:
            print("width =", w, "height =", h)
            quit()

发现图片高度有问题,应该是 960 × 960才对

我们知道,在PNG文件签名之后就是IHDR,内容固定13字节

4 字节:宽度
4 字节:高度
1 字节:位深
1 字节:颜色类型
1 字节:压缩方式
1 字节:过滤方式
1 字节:隔行方式

所以我们宽度确实是0x3C0,即960,但是高度不是,改成0x3C0即可

即可得到上图

接着又发现这图的颜色类型为6

0:灰度
2:RGB 真彩色
3:索引颜色
4:灰度 + Alpha
6:RGB + Alpha

所以本题是RGBA图片,出题人多放个Alpha肯定不会瞎放,我们查一下

from PIL import Image
import numpy as np

a = np.array(Image.open("tide_trace.png").convert("RGBA"))[:, :, 3]
v, n = np.unique(a, return_counts=True)

for x, y in zip(v, n):
    print(x, y)

发现确实不干净,alpha通道有255和254两种,只有最低像素位不一样,一个是1一个是0,明显存在LSB隐写

但是是对半分的,检查一下RGB的最低位好像都是差不多对半分的

说明不是直接存的,是某种关系,最常见的就是异或了,我们可以试一下,一共也没几种

channels = {
    "R": rgba[:, :, 0] & 1,
    "G": rgba[:, :, 1] & 1,
    "B": rgba[:, :, 2] & 1,
    "A": rgba[:, :, 3] & 1,
}
names = list(channels)
for i in range(len(names)):
    for j in range(i + 1, len(names)):
        name1 = names[i]
        name2 = names[j]

        result = channels[name1] ^ channels[name2]
        print(
            name1,
            name2,
            result.mean()
        )

发现只有green通道和alpha通道异或存在明显的异常值,只有7.11%的位置不同,很不自然

想到直接异或生图看看

from PIL import Image
import numpy as np

p = np.array(Image.open("tide_trace.png").convert("RGBA"))
x = ((p[:, :, 3] & 1) ^ (p[:, :, 1] & 1)) * 255
Image.fromarray(x.astype("uint8")).save("xor.png")

明显是一张路线图,还有起点终点

我们按这个路线,走一遍刚刚拿到的6乘6字符表即可得到flag

flag{60a8d749-3760-4560-8bc7-86f2faa7754d}

失序货栈-HHB2026

题目说是序号乱的一塌糊涂,但是说有局部重叠,还有校验码,猜测确实是提示

打开附件发现是一大堆的BOX,从BOX-01 到 BOX-127

但是发现题目里边的大小差的很多,有部分大小为271的文件,还有更多是大小在1540左右的文件

看了看,或者直接用file检查

file BOX-* | head -20

发现所有的文件本身都是Zip压缩包

但是那些小的的存储方式不一样

改后缀看看,发现所有这些附件里边都是一个同名的文件,不过加密了

尝试用编号可以轻松解密

继续测试其他文件,可以确定密码都是编号

我们观察这个解密后的记录,不难发现里边就是三部分构成的

第一个是标签BOX-01

第二个是data,看这个样子像是Base32编码的内容

最后是crc32,但是01不行,我们继续尝试看看有没有能校验成功的

发现04的是对的上的,是对base32解码后内容的CRC32校验值

这个应该是重点,因为题目里强调了校验

所以我们现在要对这些内容进行审查,看看哪些可以base 32解码,哪些可以crc校验正确

import base64
import binascii
import io
import re
import zipfile
import zlib
from pathlib import Path


# 匹配内层记录:
# BOX-04 | data=xxxx | crc32=12345678
pattern = re.compile(
    rb"^(BOX-\d+) "
    rb"\| data=([A-Z2-7=]+) "
    rb"\| crc32=([0-9a-fA-F]{8})"
    rb"(?:\r?\n)?$"
)


def box_number(filename: str) -> int | None:
    """
    从 BOX-04 中提取数字 4,
    用于按照编号排序。
    """
    match = re.fullmatch(r"BOX-(\d+)", filename)
    if not match:
        return None
    return int(match.group(1))


outer_path = Path("失序货栈.zip")

# 记录统计结果
total = 0
crc_ok_count = 0
crc_bad_count = 0
base32_error_count = 0
format_error_count = 0
decrypt_error_count = 0

crc_ok_boxes = []
crc_bad_boxes = []
base32_error_boxes = []

with zipfile.ZipFile(outer_path, "r") as outer_zip:
    # 取出所有 BOX-* 文件
    box_files = []
    for info in outer_zip.infolist():
        filename = Path(info.filename).name
        if info.is_dir():
            continue
        num = box_number(filename)
        if num is None:
            continue
        box_files.append((num, filename, info))

    # 按货箱编号排序,仅为了输出更规整
    box_files.sort(key=lambda item: item[0])

    for _, filename, info in box_files:
        total += 1

        # BOX-04 的内层 ZIP 密码为 04
        password = filename.split("-", 1)[1].encode("ascii")

        try:
            # 从外层 ZIP 中读取 BOX 文件
            inner_zip_data = outer_zip.read(info)

            # BOX 文件本身又是一个 ZIP
            with zipfile.ZipFile(io.BytesIO(inner_zip_data), "r") as inner_zip:
                # 内层通常只有一个文件
                members = [
                    member
                    for member in inner_zip.infolist()
                    if not member.is_dir()
                ]
                if not members:
                    print(f"[FORMAT ERROR] {filename}: 内层 ZIP 为空")
                    format_error_count += 1
                    continue

                member = members[0]
                # 使用货箱编号作为密码解密
                raw = inner_zip.read(member, pwd=password)

        except Exception as error:
            print(f"[DECRYPT ERROR] {filename}: {error}")
            decrypt_error_count += 1
            continue

        # 解析内层文本记录
        match = pattern.fullmatch(raw)
        if not match:
            print(f"[FORMAT ERROR] {filename}: 记录格式无法匹配")
            format_error_count += 1
            continue

        label, encoded, crc_hex = match.groups()
        label = label.decode("ascii")

        # 将文本形式的十六进制 CRC 转换成整数
        expected_crc = int(crc_hex, 16)

        try:
            # Base32 解码,得到真正参与 CRC 计算的原始字节
            decoded_data = base64.b32decode(encoded)
        except binascii.Error as error:
            print(
                f"[BASE32 ERROR] {filename:<7} "
                f"encoded_len={len(encoded):4d} "
                f"error={error}"
            )
            base32_error_count += 1
            base32_error_boxes.append(filename)
            continue

        # 计算解码后原始字节的 CRC32
        actual_crc = zlib.crc32(decoded_data) & 0xFFFFFFFF

        # 对比实际 CRC 和记录中给出的 CRC
        if actual_crc == expected_crc:
            status = "CRC OK"
            crc_ok_count += 1
            crc_ok_boxes.append(filename)
        else:
            status = "CRC BAD"
            crc_bad_count += 1
            crc_bad_boxes.append(filename)

        print(
            f"[{status:<7}] "
            f"{filename:<7} "
            f"encoded_len={len(encoded):4d} "
            f"data_len={len(decoded_data):4d} "
            f"expected={expected_crc:08x} "
            f"actual={actual_crc:08x}"
        )


# ==============================
# 汇总输出(按编号排序后展示)
# ==============================
crc_bad_boxes.sort(key=box_number)
base32_error_boxes.sort(key=box_number)

print()
print("=" * 70)
print("全部货箱校验完成")
print("=" * 70)
print(f"BOX 文件总数:   {total}")
print(f"CRC 校验正确:   {crc_ok_count}")
print(f"CRC 校验错误:   {crc_bad_count}")
print(f"Base32 解码失败: {base32_error_count}")
print(f"记录格式错误:   {format_error_count}")
print(f"内层解密失败:   {decrypt_error_count}")

if crc_bad_boxes:
    print()
    print("CRC 校验错误的货箱:")
    for filename in crc_bad_boxes:
        print(f"  {filename}")

if base32_error_boxes:
    print()
    print("Base32 解码失败的货箱:")
    for filename in base32_error_boxes:
        print(f"  {filename}")

校验发现了有72条连Base32都过不了

仔细看看,发现他们是Base32长度都是2017

我们知道Base32是每8个字符表示的一组编码数据

所以被8取余是1,3,6的无法被合法Base32解码,因此这72条不行,而且值得注意的是这些都是长的,记得我们刚开始就发现有五分之一在271左右,另外五分之四明显大,现在这明显大的要么crc检验过不了,要么干脆Base 32都失败

很有可能是干扰项啊,我们先将他们排除,看看剩下的

剩下了27条短数据,有7个crc32错误的

BOX-10
BOX-14
BOX-30
BOX-72
BOX-77
BOX-88
BOX-93

由于题目说我们有正确的crc32,所以我们其实可以尝试crc32来修复

说是修复,其实算爆破才是

我们知道CRC32是这样子得到的

import zlib

crc = zlib.crc32(data) & 0xFFFFFFFF
print(f"{crc:08x}")

所以我们可以对原来的进行爆破看看能不能改后和crc32一样,一样就是改对了,从而修复

那注意这边我们单字节修复和多字节修复的代价是完全不一样的,因为本质是爆破

所以如果是单字节修复,那么每个位置每个字节有256个值,也就×255种而已,但是如果是两个字节就要指数级上升了,几千万几亿次这样子,所以我们这边只考虑先拿crc32去爆破修复单字节

import base64
import re
import zipfile
import zlib
from pathlib import Path


BAD_BOXES = [
    "BOX-10",
    "BOX-14",
    "BOX-30",
    "BOX-72",
    "BOX-77",
    "BOX-88",
    "BOX-93",
]

PATTERN = re.compile(
    rb"^(BOX-\d+) \| data=([A-Z2-7=]+) \| crc32=([0-9a-f]{8})\r?\n?$"
)

OUTPUT = Path("repaired_records")
OUTPUT.mkdir(exist_ok=True)


def read_box(name):
    """解密 BOX 文件,并返回解码后的数据和目标 CRC。"""
    password = name.split("-")[1].encode()

    with zipfile.ZipFile(name) as z:
        member = z.namelist()[0]
        raw = z.read(member, pwd=password)

    label, encoded, crc_hex = PATTERN.fullmatch(raw).groups()

    return {
        "name": label.decode(),
        "data": bytearray(base64.b32decode(encoded)),
        "crc": int(crc_hex, 16),
    }


def crc_ok(box):
    return (
        zlib.crc32(box["data"]) & 0xFFFFFFFF
    ) == box["crc"]


def repair_one_byte(box):
    """穷举修复一个错误字节。"""
    data = box["data"]

    for pos in range(len(data)):
        old = data[pos]

        for new in range(256):
            if new == old:
                continue

            data[pos] = new

            if crc_ok(box):
                print(
                    f"[修复] {box['name']}: "
                    f"offset={pos}, {old:02x} -> {new:02x}"
                )
                return True

        data[pos] = old

    return False


def save_box(box):
    encoded = base64.b32encode(box["data"])

    record = (
        f"{box['name']} | data=".encode()
        + encoded
        + f" | crc32={box['crc']:08x}\n".encode()
    )

    path = OUTPUT / f"{box['name']}.txt"
    path.write_bytes(record)

    print(f"[保存] {path}")

boxes = {
    name: read_box(name)
    for name in BAD_BOXES
}

for name in BAD_BOXES:

    box = boxes[name]

    if not repair_one_byte(box):
        print(f"[失败] {name} 没有找到单字节修复方案")

for box in boxes.values():
    if crc_ok(box):
        save_box(box)
    else:
        print(f"[未保存] {box['name']} CRC 错误")

得到了6个BOX的修复方案,但是88没有,说明88至少也是坏了2个字节

试试看爆破2字节修复

import base64
import re
import zipfile
import zlib


PATTERN = re.compile(
    rb"^(BOX-\d+) \| data=([A-Z2-7=]+) "
    rb"\| crc32=([0-9a-fA-F]{8})\r?\n?$"
)


def read_box(name):
    password = name.split("-")[1].encode()

    with zipfile.ZipFile(name) as z:
        member = z.namelist()[0]
        raw = z.read(member, pwd=password)

    label, encoded, crc_hex = PATTERN.fullmatch(raw).groups()

    return (
        label.decode(),
        bytearray(base64.b32decode(encoded)),
        int(crc_hex, 16),
    )


name, data, expected_crc = read_box("BOX-88")

print(f"数据长度:{len(data)}")
print(f"目标 CRC:{expected_crc:08x}")
print(
    f"当前 CRC:"
    f"{zlib.crc32(data) & 0xffffffff:08x}"
)

found = None

for pos1 in range(len(data)):
    old1 = data[pos1]

    for pos2 in range(pos1 + 1, len(data)):
        old2 = data[pos2]

        for new1 in range(256):
            if new1 == old1:
                continue

            data[pos1] = new1

            for new2 in range(256):
                if new2 == old2:
                    continue

                data[pos2] = new2

                actual_crc = (
                    zlib.crc32(data)
                    & 0xffffffff
                )

                if actual_crc == expected_crc:
                    found = (
                        pos1, old1, new1,
                        pos2, old2, new2,
                    )
                    break

            if found:
                break

            # 当前第二个位置测试完后恢复
            data[pos2] = old2

        if found:
            break

        data[pos1] = old1
        data[pos2] = old2

    if found:
        break


if found:
    pos1, old1, new1, pos2, old2, new2 = found

    print("\n找到双字节修复方案:")
    print(
        f"位置 {pos1}: "
        f"{old1:02x} -> {new1:02x}"
    )
    print(
        f"位置 {pos2}: "
        f"{old2:02x} -> {new2:02x}"
    )
    print(
        f"修复后 CRC:"
        f"{zlib.crc32(data) & 0xffffffff:08x}"
    )

    encoded = base64.b32encode(data)

    repaired = (
        f"{name} | data=".encode()
        + encoded
        + f" | crc32={expected_crc:08x}\n".encode()
    )

    with open("BOX-88-repaired.txt", "wb") as f:
        f.write(repaired)

    print("已保存:BOX-88-repaired.txt")

else:
    print("没有找到双字节修复方案")

成功修复,于是我们修好了27个BOX

之后就是找顺序了,我们修好了肯定是要合起来的,题目这边给了提示

说是有局部重叠的,我们就看看有多少重叠的,对所有片段两两比较,测试不同的重叠长度

import base64
import re
import zlib
from pathlib import Path


# 脚本所在目录
SCRIPT_DIR = Path(__file__).resolve().parent

# 27 个片段所在目录
FRAGMENT_DIR = SCRIPT_DIR / "repaired_records"

# 测试 1~20 字节重叠
MIN_OVERLAP = 1
MAX_OVERLAP = 20

# 内层记录格式:
# BOX-04 | data=XXXX | crc32=12345678
PATTERN = re.compile(
    rb"^(BOX-\d+) "
    rb"\| data=([A-Z2-7=]+) "
    rb"\| crc32=([0-9a-fA-F]{8})"
    rb"(?:\r?\n)?$"
)


def box_number(name):
    """用于按照 BOX 编号排序。"""
    return int(name.split("-")[1])


def load_fragments():
    """读取并 Base32 解码所有短片段。"""
    fragments = {}

    if not FRAGMENT_DIR.exists():
        print(f"[错误] 找不到目录:{FRAGMENT_DIR}")
        print("请把 27 个片段放入 repaired_records 目录。")
        return fragments

    paths = sorted(
        FRAGMENT_DIR.glob("BOX-*"),
        key=lambda path: box_number(path.stem)
    )

    for path in paths:
        if not path.is_file():
            continue

        raw = path.read_bytes()
        match = PATTERN.fullmatch(raw)

        if not match:
            print(f"[跳过] {path.name}: 记录格式不正确")
            continue

        label, encoded, crc_hex = match.groups()
        name = label.decode("ascii")
        expected_crc = int(crc_hex, 16)

        # 真正的短片段 Base32 长度为 48
        if len(encoded) != 48:
            print(
                f"[跳过] {name}: "
                f"Base32 长度为 {len(encoded)},不是短片段"
            )
            continue

        try:
            data = base64.b32decode(encoded)
        except Exception as error:
            print(f"[跳过] {name}: Base32 解码失败:{error}")
            continue

        # 真正的片段解码后为 28 或 29 字节
        if len(data) not in (28, 29):
            print(
                f"[跳过] {name}: "
                f"解码后长度为 {len(data)}"
            )
            continue

        actual_crc = zlib.crc32(data) & 0xFFFFFFFF
        crc_status = actual_crc == expected_crc

        fragments[name] = {
            "data": data,
            "expected_crc": expected_crc,
            "actual_crc": actual_crc,
            "crc_ok": crc_status
        }

        status = "CRC OK" if crc_status else "CRC BAD"

        print(
            f"[读取] {name:<7} "
            f"长度={len(data):2d} "
            f"{status:<7} "
            f"expected={expected_crc:08x} "
            f"actual={actual_crc:08x}"
        )

    return fragments


def find_exact_matches(fragments, overlap):
    """
    两两比较全部片段。

    如果 left 的最后 overlap 字节等于
    right 的前 overlap 字节,则记录 left -> right。
    """
    matches = []

    for left_name, left in fragments.items():
        for right_name, right in fragments.items():
            if left_name == right_name:
                continue

            left_tail = left["data"][-overlap:]
            right_head = right["data"][:overlap]

            if left_tail == right_head:
                matches.append((left_name, right_name))

    return matches


def build_chain(fragments, matches):
    """
    根据匹配关系尝试构建唯一完整链。

    完整的 27 个片段应该有:
    - 26 条连接;
    - 1 个起点;
    - 1 个终点;
    - 每个中间片段只有一个前驱和一个后继。
    """
    names = set(fragments)

    successor = {}
    predecessor = {}

    for left, right in matches:
        # 一个片段有多个后继,不能唯一排序
        if left in successor and successor[left] != right:
            return None

        # 一个片段有多个前驱,不能唯一排序
        if right in predecessor and predecessor[right] != left:
            return None

        successor[left] = right
        predecessor[right] = left

    # 找到没有前驱的片段
    starts = [
        name
        for name in names
        if name not in predecessor
    ]

    if len(starts) != 1:
        return None

    chain = []
    visited = set()
    current = starts[0]

    while True:
        if current in visited:
            # 出现环
            return None

        chain.append(current)
        visited.add(current)

        if current not in successor:
            break

        current = successor[current]

    # 必须刚好包含所有片段
    if len(chain) != len(names):
        return None

    return chain


def print_matches(matches):
    """打印具体匹配关系。"""
    for left, right in sorted(
        matches,
        key=lambda item: box_number(item[0])
    ):
        print(f"  {left} -> {right}")


def main():
    fragments = load_fragments()

    print()
    print("=" * 70)
    print(f"共读取到 {len(fragments)} 个短片段")
    print("=" * 70)

    if not fragments:
        return

    if len(fragments) != 27:
        print(
            f"[警告] 正常情况下应有 27 个片段,"
            f"当前只有 {len(fragments)} 个。"
        )

    bad_crc = [
        name
        for name, fragment in fragments.items()
        if not fragment["crc_ok"]
    ]

    if bad_crc:
        print()
        print("CRC32 未通过的片段:")
        print("、".join(sorted(bad_crc, key=box_number)))
    else:
        print()
        print("全部片段 CRC32 校验通过。")

    print()
    print("开始测试不同的重叠长度:")
    print()

    valid_results = []
    all_results = []

    max_possible = min(
        MAX_OVERLAP,
        min(len(item["data"]) for item in fragments.values())
    )

    for overlap in range(MIN_OVERLAP, max_possible + 1):
        matches = find_exact_matches(fragments, overlap)
        chain = build_chain(fragments, matches)

        all_results.append(
            {
                "overlap": overlap,
                "matches": matches,
                "chain": chain
            }
        )

        if chain:
            status = "可以组成完整链"
            valid_results.append(
                (overlap, matches, chain)
            )
        else:
            status = "不能组成完整链"

        print(
            f"重叠长度 {overlap:2d} 字节:"
            f"{len(matches):2d} 条精确匹配,"
            f"{status}"
        )

    print()
    print("=" * 70)

    if valid_results:
        # 选择能够组成完整链的最大重叠长度
        best_overlap, best_matches, best_chain = max(
            valid_results,
            key=lambda item: item[0]
        )

        print(f"确定重叠长度:{best_overlap} 字节")
        print(f"匹配关系数量:{len(best_matches)}")

        print()
        print("具体匹配关系:")
        print_matches(best_matches)

        print()
        print("恢复出的完整顺序:")
        print(" -> ".join(best_chain))

    else:
        print("没有任何重叠长度能够组成完整链。")

        # 没有完整链时,显示匹配数量最多的结果
        best = max(
            all_results,
            key=lambda item: (
                len(item["matches"]),
                item["overlap"]
            )
        )

        print()
        print(
            f"匹配数量最多的是 {best['overlap']} 字节,"
            f"共有 {len(best['matches'])} 条匹配。"
        )

        print()
        print("具体匹配关系:")
        print_matches(best["matches"])

    print("=" * 70)


if __name__ == "__main__":
    main()

得到了最长重叠长度是9字节

所以其实我们前边的BOX-88如果是多字节crc损坏也不要紧,爆破不出的情况下也可以尝试直接利用重叠关系进行覆盖,只要大部分能和前边的对应上就能覆盖

left.data[-9:] == right.data[:9]

所以我们成功按照覆盖关系恢复出了BOX顺序

进行拼接即可

import base64
import re
from pathlib import Path

order = [
    "BOX-04", "BOX-14", "BOX-31", "BOX-94", "BOX-83", "BOX-72",
    "BOX-81", "BOX-50", "BOX-37", "BOX-77", "BOX-06", "BOX-69",
    "BOX-40", "BOX-10", "BOX-85", "BOX-80", "BOX-09", "BOX-30",
    "BOX-79", "BOX-67", "BOX-76", "BOX-93", "BOX-07", "BOX-68",
    "BOX-92", "BOX-88", "BOX-49"
]

folder = Path("repaired_records")
parts = []

for name in order:
    raw = (folder / f"{name}.txt").read_bytes()
    encoded = re.search(rb"data=([A-Z2-7=]+)", raw).group(1)
    parts.append(base64.b32decode(encoded))

stream = parts[0]

for left, right in zip(parts, parts[1:]):
    assert left[-9:] == right[:9], "重叠不匹配"
    stream += right[9:]

Path("stream.bin").write_bytes(stream)

print("拼接完成")
print("长度:", len(stream))
print("文件:stream.bin")

最终我们得到了一个长度为 523 字节的数据

看看文件十六进制,发现文件头是78 da

这是常见的 zlib 压缩流头部

所以我们直接使用 zlib.decompress() 解压即可:

from pathlib import Path
import zlib

content = zlib.decompress(
    Path("stream.bin").read_bytes()
).decode()

print(content)

成功得到了这份传送带日志,备注也再一次重复了重叠内容是唯一能确定顺序的信号,原始索引已经全丢完了

同时得到了本题的flag

flag{dffc94e8-0571-4e68-bbc3-f1534766f794}

Frame by Frame-HHB2026

有想过是找原视频比对得到,但是找到了没比对出来

这个好像是错的

期待有做出来的师傅在评论区分享一下

问卷

黄鹤杯初赛就到此为止了

flag{d1f4c8e9-7b2a-4f6e-8c3d-9a1b5e7f2c4d}

更多推荐