首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
0
9
[原创]KCTF 2026 - 第二题:巳时·绿光幽语 分析
发表于: 2026-8-12 11:22
715
[原创]KCTF 2026 - 第二题:巳时·绿光幽语 分析
V1NKe
2
2026-8-12 11:22
715
## 基本信息 | 项目 | 值 | |------|-----| | MD5 | d2fc58976cac7403cee3a8b8f2560081 | | SHA-256 | f6b192f9ee87c4ad2bc8681291ca428cf8e98fec26fa5d7b82c6e791a7a90ead | | 架构 | x86-64 (PE64) | | 打包方式 | PyInstaller 6.x (Python 3.13) | --- ## 一、初步分析 ### 1.1 PE 结构 ``` .text 0x140001000 - 0x14002f000 代码段(PyInstaller bootloader C 代码) .rdata 0x14002f418 - 0x140043000 只读数据(字符串、导入表等) .data 0x140043000 - 0x140049000 可读写数据(CRT 全局变量) .pdata 0x140049000 - 0x14004c000 异常处理表 .fptable 0x14004c000 - 0x14004d000 函数指针表 .rsrc 0x14004d000 - 0x14005c000 资源段(图标、清单) .reloc 0x14005c000 - 0x14005d000 重定位表 [overlay] 0x54600 - 0x717f63 PyInstaller 归档(PE 覆盖层) ``` PE 覆盖层从文件偏移 `0x54600` 开始,即 PyInstaller 归档数据。归档末尾(偏移 `0x717f0b`)存放 PyInstaller Cookie(魔数 `MEI\x0c\x0b\x0a\x0b\x0e`),记录了包长度、TOC 偏移、Python 版本(313)等元信息。 ### 1.2 PyInstaller 归档 TOC 归档包含 21 个条目: | 类型 | 名称 | 说明 | |------|------|------| | m | struct | Python 模块 | | m | pyimod01_archive ~ pyimod04_pywin32 | PyInstaller 引导模块 | | s | pyiboot01_bootstrap | 引导脚本 | | s | pyi_rth_inspect | 运行时钩子 | | s | **main** | **主脚本** | | b | python313.dll, libcrypto-3.dll 等 | 二进制依赖文件 | | b | base_library.zip | 标准库 ZIP | | z | PYZ.pyz | PYZ 归档(112 个标准库模块) | ### 1.3 障眼法:main.py 使用 Python 3.13 的 `marshal` 模块反序列化 `main` 条目的字节码,结果如下: ```python # main.py 反编译结果 import sys sys.exit(0) ``` 完整反汇编: ``` 0 RESUME 0 1 LOAD_CONST 0 (0) LOAD_CONST 1 (None) IMPORT_NAME 0 (sys) STORE_NAME 0 (sys) 3 LOAD_NAME 0 (sys) LOAD_ATTR 2 (exit) PUSH_NULL LOAD_CONST 0 (0) CALL 1 POP_TOP RETURN_CONST 1 (None) ``` `co_consts = (0, None)`,`co_names = ('sys', 'exit')`,无嵌套代码对象。 **主脚本仅执行 `sys.exit(0)`,不包含任何挑战逻辑。** 这是一个障眼法,引导逆向分析者误以为程序什么也不做。 ### 1.4 PYZ 归档分析 PYZ 归档包含 112 个模块,全部为 Python 3.13 标准库模块(`__future__`、`argparse`、`base64`、`email.*`、`importlib.*`、`json.*`、`zipfile.*` 等)。 对所有 112 个模块的解压数据进行全文搜索: - 搜索 `KCTF`、`kctf`、`flag{`、`CTF{` → **无命中** - 搜索中文关键词 `恭喜`、`提示`、`还原`、`输入`(UTF-8 及 UTF-16LE 编码)→ **无命中** - 搜索 `my_function` → **无命中** **PYZ 归档中不含任何用户代码或挑战逻辑。** --- ## 二、突破:python313.dll 中的注入代码 ### 2.1 发现 my_function 对 PyInstaller 归档中的全部 21 个条目(包括 DLL、PYD 等二进制文件)解压后搜索 `my_function`,在 **python313.dll** 中发现命中: ``` python313.dll 解压后大小:7,127,552 字节 my_function 字符串偏移:5090537 (0x4DACE9) ``` python313.dll 的解压数据是 Python 3.13 的完整 DLL 二进制。`my_function` 出现在 DLL 内部的冻结模块(frozen module)数据区域中。 ### 2.2 定位挑战代码所在模块 以 `<module>` 字符串为线索,在 python313.dll 中搜索冻结模块的代码对象起点。最终在偏移 `5046496 (0x4CA770)` 处成功用 `marshal.loads()` 加载出一个模块级代码对象: ``` co_name: <module> co_filename: <frozen os> co_consts 数量: 159 ``` **挑战代码被注入到了 `<frozen os>` 模块中。** `os` 是 Python 标准库的核心模块,作为冻结模块编译进 python313.dll。作者在标准 `os` 模块代码末尾(第 1188 行之后)追加了挑战代码。 由于 `os` 模块在 Python 启动过程中被自动导入,这段附加代码**在 `main.py` 的 `sys.exit(0)` 执行之前就已运行**。 ### 2.3 os 模块中的异常追加代码 标准 `os` 模块的最后一个函数是 `process_cpu_count`(第 1173 行)。从第 1183 行起是注入的挑战代码。模块的 `co_names` 在标准名称之后追加了以下条目: ``` names[113]: x # 临时变量 names[114]: my_function # 被篡改的函数 names[115]: join # bytes.join names[116]: buffer # 缓冲区 names[117]: w # 写入索引 names[118]: i # 循环变量 names[119]: b # 字节项 names[120]: to_bytes # 转换方法 names[121]: print # 输出 names[122]: decode # 解码 names[123]: input # 用户输入 names[124]: key # 密钥 names[125]: len # 长度 names[126]: encode # 编码 names[127]: b_key # 密钥字节 names[128]: c # 循环变量 names[129]: buf # 缓冲区 names[130]: range # 范围 names[131]: __code__ # 代码对象 names[132]: my # 函数引用 names[133]: replace # 替换 names[134]: succ # 成功标志 names[135]: Exception # 异常 names[136]: e # 异常对象 ``` 模块的 `co_consts` 在标准常量之后追加了以下关键条目: ``` const[143]: <code my_function line 1188> # 被篡改的函数 const[144]: b'' # 空字节(占位) const[145]: (b'\xb3\xda...', ..., b'\xb0\xd0...') # 8 段提示密文(各 16 字节) const[146]: 85 # 提示 XOR 密钥 (0x55) const[147]: 'utf-8' # 编码 const[148]: 6 # 密钥长度 const[149]: b'\xecbmucryb6tcr*c...' # co_code 密文(26 字节) const[150]: ('co_code',) # 属性名 const[151]: b'\x9f\xe3\x9b\x91\xf5\xee...' # co_consts 值密文(15 字节) const[152]: ('co_consts',) # 属性名 ``` --- ## 三、挑战逻辑还原 ### 3.1 被篡改的 my_function 注入的 `my_function` 代码对象如下: ```python def my_function(): print(666) # 被篡改:本应 print("恭喜成功!") ``` 反汇编确认: ``` 1188 RESUME 0 1189 LOAD_GLOBAL 1 (print + NULL) LOAD_CONST 1 (666) CALL 1 POP_TOP RETURN_CONST 0 (None) ``` `co_code`(26 字节): ``` 95 00 5b 01 00 00 00 00 00 00 00 5b 03 00 00 00 00 00 00 00 53 01 35 01 00 00 ``` `co_consts`:`(None, 666)` ### 3.2 提示文本 程序运行时显示的提示由 `const[145]` 中的 8 段 16 字节密文逐段 XOR `0x55` 后拼接得到: ```python hint = b'' for segment in const_145: # 8 段,每段 16 字节 hint += bytes(b ^ 0x55 for b in segment) ``` 解码结果(UTF-8): ``` 提示,需要还原的代码 def my_function(): print("恭喜成功!") 请输入key还原代码(请输入6个字符) ``` ### 3.3 XOR 还原机制 程序读取用户输入的 6 字符 key 后,执行两轮 XOR 解密: **第一轮——还原 co_consts 中的字符串值:** ```python b_key = key.encode('utf-8') # 6 字节 buf = bytes(const_151[i] ^ b_key[i % 6] for i in range(len(const_151))) target_string = buf.decode('utf-8') # 应为 "恭喜成功!" ``` **第二轮——还原 co_code(验证用):** ```python buf = bytes(const_149[i] ^ b_key[i % 6] for i in range(len(const_149))) target_co_code = buf # 应与原始 co_code 一致 ``` 随后通过 Python 的运行时字节码替换机制修改 `my_function`: ```python my = my_function.__code__ my = my.replace(co_consts=(None, target_string)) my_function.__code__ = my my_function() # 若 key 正确,输出 "恭喜成功!" ``` ### 3.4 密钥推导(已知明文攻击) 提示文本直接展示了目标代码 `print("恭喜成功!")`,因此明文字符串已知。 目标字符串 `"恭喜成功!"` 的 UTF-8 编码为 15 字节: ``` 恭 = E6 81 AD 喜 = E5 96 9C 成 = E6 88 90 功 = E5 8A 9F ! = EF BC 81 ``` 与密文 `const[151]`(同样 15 字节)逐字节异或: | 位置 | 密文 | 明文 | XOR 结果 | ASCII | |------|------|------|----------|-------| | 0 | 0x9F | 0xE6 | 0x79 | y | | 1 | 0xE3 | 0x81 | 0x62 | b | | 2 | 0x9B | 0xAD | 0x36 | 6 | | 3 | 0x91 | 0xE5 | 0x74 | t | | 4 | 0xF5 | 0x96 | 0x63 | c | | 5 | 0xEE | 0x9C | 0x72 | r | | 6 | 0x9F | 0xE6 | 0x79 | y(循环) | | 7 | 0xEA | 0x88 | 0x62 | b | | 8 | 0xA6 | 0x90 | 0x36 | 6 | | 9 | 0x91 | 0xE5 | 0x74 | t | | 10 | 0xE9 | 0x8A | 0x63 | c | | 11 | 0xED | 0x9F | 0x72 | r | | 12 | 0x96 | 0xEF | 0x79 | y | | 13 | 0xDE | 0xBC | 0x62 | b | | 14 | 0xB7 | 0x81 | 0x36 | 6 | 密钥为 6 字节循环:`y b 6 t c r` ### 3.5 验证 用密钥 `"yb6tcr"` 对 `const[149]`(26 字节)做 XOR,结果与原始 `co_code` 完全一致: ``` const[149] XOR "yb6tcr" = 95 00 5b 01 00 00 00 00 00 00 00 5b 03 00 00 00 00 00 00 00 53 01 35 01 00 00 原始 co_code = 95 00 5b 01 00 00 00 00 00 00 00 5b 03 00 00 00 00 00 00 00 53 01 35 01 00 00 匹配 = True ``` 用密钥 `"yb6tcr"` 对 `const[151]`(15 字节)做 XOR,结果为 `"恭喜成功!"` 的 UTF-8 编码: ``` const[151] XOR "yb6tcr" = E6 81 AD E5 96 9C E6 88 90 E5 8A 9F EF BC 81 "恭喜成功!".encode('utf-8') = E6 81 AD E5 96 9C E6 88 90 E5 8A 9F EF BC 81 匹配 = True ``` 还原后的 `my_function` 反汇编: ``` 1188 RESUME 0 1189 LOAD_GLOBAL 1 (print + NULL) LOAD_CONST 1 ('恭喜成功!') CALL 1 POP_TOP RETURN_CONST 0 (None) ``` 即 `print("恭喜成功!")`,与提示中的目标代码完全吻合。 --- ## 四、设计手法总结 | 手法 | 说明 | |------|------| | **障眼法** | `main.py` 仅含 `sys.exit(0)`,使分析者误以为程序无实质逻辑 | | **注入隐藏** | 挑战代码注入到 `python313.dll` 内的 `<frozen os>` 冻结模块中,不在 `main.py` 或 PYZ 归档中 | | **自动触发** | `os` 模块在 Python 启动时自动导入,注入代码先于 `main.py` 执行 | | **运行时字节码替换** | 利用 Python `__code__` 对象可在运行时修改 `co_consts` 的特性,实现"输入正确密钥→函数行为改变" | | **XOR 对称加密** | 用 6 字节循环 XOR 加密目标字符串和 co_code,密钥即 flag | | **已知明文攻击** | 提示文本直接展示目标代码 `print("恭喜成功!")`,明文字符串已知,XOR 密钥可直接求出 | | **提示加密** | 提示文本本身也用单字节 XOR (0x55) 加密,增加一层简单混淆 | ## 五、注 由 AI 完成。
回复或点赞可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2026-8-12 11:24 被V1NKe编辑 ,原因:
收藏
・
0
点赞
・
9
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
git_51951meggadf3df
非常支持你的观点!
4天前
mb_dvqqrcce
感谢你的贡献,论坛因你而更加精彩!
5天前
晨曦。
为你点赞!
2026-9-9 07:25
mb_lthgjpwj
为你点赞!
2026-8-21 07:33
huangyalei
你的分享对大家帮助很大,非常感谢!
2026-8-17 16:24
pexillove
感谢你的积极参与,期待更多精彩内容!
2026-8-14 15:20
小调调
你的分享对大家帮助很大,非常感谢!
2026-8-13 17:53
doduhuang
你的分享对大家帮助很大,非常感谢!
2026-8-13 10:41
只会逆一点点
你的分享对大家帮助很大,非常感谢!
2026-8-13 10:10
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
5
)
xingbing
雪 币:
158
活跃值:
(5651)
能力值:
( LV2,RANK:10 )
在线值:
发帖
2
回帖
1373
粉丝
2
关注
私信
xingbing
2
楼
学习
2026-8-12 14:38
0
mb_rqlksylg
雪 币:
96
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
69
粉丝
0
关注
私信
mb_rqlksylg
3
楼
good
2026-8-13 09:02
0
mb_qztkkwxt
雪 币:
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
58
粉丝
0
关注
私信
mb_qztkkwxt
4
楼
学习
2026-8-13 10:37
0
mb_npsajqlx
雪 币:
22
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
34
粉丝
0
关注
私信
mb_npsajqlx
5
楼
666
2026-8-13 11:33
0
manyuegong33
雪 币:
426
活跃值:
(335)
能力值:
( LV2,RANK:10 )
在线值:
发帖
4
回帖
59
粉丝
8
关注
私信
manyuegong33
6
楼
111
2026-8-14 11:23
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
V1NKe
2
12
发帖
56
回帖
196
RANK
关注
私信
他的文章
[原创]KCTF 2026 - 第十题:卯时·曦光初现 分析
212
[原创]KCTF 2026 - 第九题:丑寅同墟·星海抉择 分析
26
[原创]KCTF 2026 - 第二题:巳时·绿光幽语 分析
715
[原创]KCTF 2026 - 签到题:辰时·钟鸣破晓 分析
156
[原创]Tcache利用总结
17998
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部