首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
0
0
[原创]wp: 第二题:巳时·绿光幽语
发表于: 2026-8-11 12:40
32
[原创]wp: 第二题:巳时·绿光幽语
the_hs
1
2026-8-11 12:40
32
## 0. 结论 **key:`yb6tcr`** --- ## 1. 程序结构 `q2.exe` 是 PyInstaller 打包程序。解包后得到: ```text q2.exe_extracted/ ├── main.pyc ├── python313.dll └── ... ``` 其中 `main.pyc` 是 Python 3.13 字节码,magic 为 `f3 0d 0d 0a`。 用 `xdis` 反汇编后可以看到它只是一个壳: ```asm LOAD_CONST 0 LOAD_CONST None IMPORT_NAME sys STORE_NAME sys LOAD_NAME sys LOAD_ATTR exit PUSH_NULL LOAD_CONST 0 CALL 1 POP_TOP RETURN_CONST None ``` 等价于: ```python import sys sys.exit(0) ``` 所以真正的逻辑不在 `main.pyc`,而在被修改过的 `python313.dll` 中。 --- ## 2. 定位隐藏逻辑 在 `python313.dll` 里可以直接搜到: ```text my_function ``` 其附近还有如下可疑数据: ```python encrypted_code = bytes.fromhex( "ec626d7563727962367463722a63037563727962367443721e62" ) encrypted_success = bytes.fromhex( "9fe39b91f5ee9feaa691e9ed96deb7" ) ``` 进一步观察附近字节,可以发现这是 Python `marshal` 序列化数据。该数据属于 DLL 中冻结的 `os` 模块。 本样本中 frozen `os` 模块的 marshal blob 位于文件偏移: ```text 0x4d00e0 ``` 使用与样本一致的 Python 3.13 解析: ```python from pathlib import Path import marshal data = Path("q2.exe_extracted/python313.dll").read_bytes() root = marshal.loads(memoryview(data)[0x4D00E0:]) ``` 解析结果中可以看到一个被插入的 `my_function`: ```text Name: my_function Constants: (None, 666) Names: ('print',) Bytecode: 95005b0100000000000000005301350100000000000020006700 ``` 即初始占位函数是: ```python def my_function(): print(666) ``` --- ## 3. frozen `os` 模块中的自定义逻辑 `my_function` 在 `root.co_consts` 中的下标是 143。后面的常量依次是: ```python 143: <code object my_function> 144: b'' 145: 8 段被异或加密的提示文本 146: 85 # 0x55,提示文本的 XOR key 147: 'utf-8' 148: 6 # 要求的 key 长度 149: 加密的 co_code 150: ('co_code',) 151: 加密的成功字符串 152: ('co_consts',) ``` 把第 145 项中的 8 段 bytes 拼接后,每个字节异或 `0x55`,得到: ```text 提示,需要还原的代码 def my_function(): print("恭喜成功!") 请输入key还原代码(请输入6个字符) ``` 对 frozen `os` 模块顶层代码反汇编,插入逻辑的核心等价于: ```python for x in range(20): def my_function(): print(666) print(decoded_prompt) key = input() if len(key) != 6: continue b_key = key.encode() c = encrypted_code buf = xor_repeating(c, b_key) my = my_function.__code__ my = my.replace(co_code=buf) succ = encrypted_success buf = xor_repeating(succ, b_key) my = my.replace( co_consts=(None, buf.decode("utf-8")) ) my_function.__code__ = my my_function() ``` 也就是说,程序并不是直接比较 key,而是: 1. 用输入的 6 字节 key 循环异或解密 `co_code`; 2. 用同一个 key 循环异或解密成功字符串; 3. 将解密结果设置成 `my_function.__code__`; 4. 调用还原后的函数。 --- ## 4. 已知明文恢复 key 提示中已经给出了目标输出: ```text 恭喜成功! ``` 其 UTF-8 编码为: ```text e6 81 ad e5 96 9c e6 88 90 e5 8a 9f ef bc 81 ``` 加密后的成功字符串为: ```text 9f e3 9b 91 f5 ee 9f ea a6 91 e9 ed 96 de b7 ``` 由于 key 长度为 6,并且循环异或,所以直接计算前 6 个字节: ```python cipher = bytes.fromhex("9fe39b91f5ee9feaa691e9ed96deb7") plain = "恭喜成功!".encode("utf-8") key = bytes(c ^ p for c, p in zip(cipher, plain))[:6] print(key) ``` 得到: ```python b'yb6tcr' ``` 十六进制为: ```text 79 62 36 74 63 72 ``` 验证后两段密文均使用该 key 循环异或: ```python key = b"yb6tcr" assert xor_repeating(encrypted_success, key) == "恭喜成功!".encode() assert xor_repeating(encrypted_code, key).hex() == ( "95005b0100000000000000005301350100000000000020006700" ) ``` 解密出的 `co_code` 与占位函数字节码相同,语义为: ```asm RESUME LOAD_GLOBAL print LOAD_CONST 1 CALL 1 POP_TOP RETURN_CONST None ``` 真正的变化是 `co_consts` 从: ```python (None, 666) ``` 被替换为: ```python (None, "恭喜成功!") ``` 因此调用 `my_function()` 后输出目标字符串。
登录后可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
收藏
・
0
点赞
・
0
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
the_hs
1
18
发帖
22
回帖
90
RANK
关注
私信
他的文章
[原创]wp:第八题:亥子合辰·塔影迷楼
22
[原创] wp: 第七题:戌时·暗能潜流
51
[原创]wp: 第二题:巳时·绿光幽语
32
[讨论]被kimi k3吓哭
345
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部