-
-
[原创]巳时·绿光幽语 题解(Writeup)
-
发表于: 2026-8-11 12:41 6
-
程序运行后循环打印一段提示:需要还原的代码是
要求输入 6 个字符的 key 来"还原代码"。输入正确的 key 后程序会调用还原出的 my_function() 并输出 恭喜成功!。
错误 key(或长度不等于 6 的输入)会反复重新提示,最多循环 20 次后以退出码 0 结束。
用 pyinstxtractor-ng 提取 CArchive(21 个条目,PYZ 含 112 个模块)后,遇到三个反常现象:
入口 main.pyc 是空壳:反汇编后只有
一个"什么都干不了"的入口,与实际运行行为完全矛盾。
PYZ 里 112 个模块全是标准库:email、importlib、json、logging、pathlib、urllib、zipfile 等,没有任何业务模块;base_library.zip 内部逐模块扫描也全是标准库。
提示字符串在任何地方都搜不到:以 UTF-8 / GBK / UTF-16LE 三种编码对 1.exe 原始字节及全部提取文件做二进制搜索,提示/还原/恭喜成功/请输入key 全部 0 命中。说明提示文本是运行时拼装/解密出来的,而非明文存储。
排查顺序:CArchive 条目 → PYZ 模块 → base_library.zip → exe 原始字节(含资源段)→ 全部排除后,目标锁定在 python313.dll。
在 python313.dll 中直接搜到了 my_function 的 UTF-8 字节,其周围是完整的 marshal 流。用 Python 3.14(可解 3.13 marshal v5)扫描定位到:
结论:这份 python313.dll 是改造过的 CPython 运行时——作者把 os 模块冻结(frozen)进 DLL,并在其中注入了挑战代码。PyInstaller 启动时 import os 即触发这段代码,因此:
把 marshal 流导出并拼回 .pyc(补 3.13 魔数头 f3 0d 0d 0a + 12 字节 0),用 pydisasm(xdis)反汇编。模块级挑战代码在 os.py 正常定义之后(1185~1227 行),还原为 Python 伪码:
当前(混淆态)的 my_function 反汇编:
即函数体就是 print(consts[1]),还原后 consts[1] 变为真实字符串。
异或是可逆的:
而题目提示已经给出了还原目标代码 def my_function(): print("恭喜成功!"),所以 co_consts[1] 的明文就是 恭喜成功!,其 UTF-8 编码恰好是 15 字节,与 succ(15 字节)等长:
于是直接由前 6 字节解出 key:
用 yb6tcr 解 succ 全部 15 字节:E6 81 AD E5 96 9C E6 88 90 E5 8A 9F EF BC 81 ✅ 与 恭喜成功! 完全一致。
再用它解 c(字节码):
解出的 26 字节与函数骨架 RESUME; LOAD_GLOBAL print; LOAD_CONST 1; CALL 1; POP_TOP; RETURN_CONST None 完全吻合(混淆态与还原态字节码相同,仅常量不同)。
附:3.13 字节码对应关系(从反汇编反推):0x53=LOAD_CONST、0x35=CALL、0x20=POP_TOP、0x67=RETURN_CONST、0x5b=LOAD_GLOBAL、0x95=RESUME。
实测(真实 EXE):
| 项目 | 内容 |
|---|---|
| 文件 | 1.exe(约 7.4 MB,PyInstaller onefile 打包的 Python 3.13 程序) |
| 运行提示 | 需要还原的代码 def my_function(): print("恭喜成功!") 请输入key还原代码(请输入6个字符) |
| 题目目标 | 求出 6 字符 key,还原(解密)my_function 的代码 |