-
-
[原创]第二题:巳时·绿光幽语 WP
-
发表于: 4天前 4
-
附件只有一个 Windows x64 可执行文件:
字符串中可以直接看到大量 PyInstaller bootloader 的报错文本,例如:
使用 pyinstxtractor-ng 解包:
可以得到:
其中 main.pyc 只有 175 字节。用 Python 3.13 的 dis 查看:
对应代码就是:
PYZ 中也只有常规标准库,没有正常意义上的题目主程序。
为了确认原生 PE 部分是否藏了额外校验,将题目程序的代码段与 PyInstaller 6.20.0 Windows x64 run.exe 比较。
题目程序入口为 0x14000d4c0,.text 大小为 0x2d8c0,与 PyInstaller 6.20.0 对应 bootloader 完全一致:
.rdata 只有构建时间戳造成的少数字节变化。Ghidra 反编译 0x1400040e0 后也是标准 PyInstaller bootloader 主流程。
因此真正值得检查的是打包进去的运行时文件,尤其是:
题目中的 DLL 信息:
CodeView/PDB 中还能看到本地构建路径:
它是作者自行编译的 CPython 3.13.1,而不是 python.org 发布的官方 DLL。
导出表共有 1647 项,与官方 Python 3.13.1 的导出符号集合完全一致。普通 WinAPI import 也没有多出明显的校验函数。因此继续检查 DLL 内嵌的 frozen Python modules。
准备一套 Python 3.13.1 Windows embeddable 环境,将其中的 python313.dll 替换为题目解出的 DLL。随后运行下面的脚本,把 frozen module 的 code object 导出来:
对题目 DLL 和官方 Python 3.13.1 的 frozen modules 分别计算 code object 哈希,只有两个模块不同:
继续递归比较 code object 后可以发现:
题目版 frozen os 额外出现一个 code object:
以及以下新增名称:
这就是题目的实际校验逻辑。
额外函数本身非常简单:
其 Python 3.13 co_code 为:
模块级新增代码可以整理成下面的等价逻辑:
前面的提示字符串逐字节 XOR 0x55 后为:
校验没有直接执行 key == xxx。输入的 6 字节 key 会直接作为循环 XOR key 解密新的 co_code。错误 key 通常会让 CodeType.replace() 得到非法字节码,或者让后面的成功字符串无法以 UTF-8 解码,异常被外层 except 捕获后重新输入。
这里不需要枚举 6 字节输入。
原始 my_function 的控制流是:
最终需要恢复的是:
两者的 Python bytecode 控制结构完全相同,区别只在 co_consts[1]。程序后面也确实单独执行:
因此第一阶段解密得到的 co_code 就是当前 my_function.__code__.co_code 本身。
令:
逐字节异或:
26 字节的完整 keystream 为:
周期正好为 6,因此:
再用它解密 succ:
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。