-
-
KCTF 2026 第二题:巳时·绿光幽语 writeup
-
发表于: 3天前 155
-
题目将答案称为六字符 key,正确值为:
它不是 flag{...} 形式。将其输入原始程序后会输出:
题目.rar 中只有一个文件:题目.exe。
sample.exe 与 extracted/题目.exe 的 SHA-256 完全一致,因此可将前者作为分析副本。
PyInstaller CArchive 包含常规引导模块、base_library.zip、PYZ.pyz 和运行时 DLL。提取并反汇编 main 后,内容仅为:
PYZ.pyz 中也只有标准库模块。因此表面的 Python 入口是干扰项,真正的题目逻辑不在普通 PyInstaller 脚本内。
直接运行程序会显示一个六字符 key 输入提示,并展示待恢复函数:
运行时加载的 python313.dll 与官方 Python 3.13.1 DLL 存在显著差异,因此后续分析转向该定制运行时。
进程转储和解包后的运行时显示:修改版 python313.dll 中含有 marshal 序列化的 <frozen os> 模块。在 DLL 原始文件偏移 0x4d00e0,可由 CPython 3.13 加载出一个 code object;其常量中包含新增的 my_function,名称表中还包含:
嵌套的原始函数故意是无害的:
修改后的冻结模块尾部可还原为如下等价伪代码:
校验使用的两段密文为:
CODE_CIPHER 的长度为 26,恰好等于原始 my_function.__code__.co_code 的长度:
校验器的核心计算为:
而希望得到的字节码就在同一个 code object 中,所以可以直接逐字节反推:
因此,唯一同时满足全部 26 个字节约束的六字节周期 key 是:
再用相同 key 解密 SUCCESS_CIPHER,可获得 UTF-8 文本 恭喜成功!。最终恢复出的函数等价于:
直接向目标程序输入恢复出的 key:
实际输出:
作为反向对照,六字符输入 abcdef 不会输出成功信息,而是重新回到输入提示。
附带的 solve_key.py 可自动完成字节级恢复。脚本执行流程为:
该 DLL 内嵌的是 Python 3.13 marshal / bytecode 数据,应使用 CPython 3.13 运行:
本次分析的 DLL 来自 PyInstaller 运行时临时 _MEI... 目录。该目录名会随进程变化;传入由题目运行时解包或从 CArchive 提取出的 python313.dll 即可。
预期输出:
Token 和时长均来自已完成的目标追踪记录。当前环境未暴露更细粒度的 provider/model 标识,因此模型信息记录为 GPT-5(Codex coding agent)。
| 属性 | 值 |
|---|---|
| 格式 | PE32+ x86-64 控制台程序 |
| 打包方式 | PyInstaller |
| 大小 | 7,438,179 bytes |
| SHA-256 | f6b192f9ee87c4ad2bc8681291ca428cf8e98fec26fa5d7b82c6e791a7a90ead |