二、字节码迷踪——Python pyc跨版本逆向题目信息题目名称字节码迷踪题目分类REVERSE题目难度中级题目分值350附件py_obf_10.zipFlag格式flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}x 为小写字母或数字题目展示图2-1字节码迷踪题目页面题目分析题目描述说你发现了一个可疑的 Python 编译文件集合这些 .pyc 文件被认为是某个加密程序的组成部分其中隐藏着重要的 flag 信息。由于原始源代码已经丢失你只能通过分析编译后的字节码来还原程序逻辑并提取 flag。解压 py_obf_10.zip 后只得到一个文件 py_obf_10.pyc1179 bytes。先看一下 pyc 文件头确认 Python 版本Magic number: 0x0dcb (3531) 对应版本: Python 3.12.0当前分析环境是 Python 3.10.2没办法直接用内置的 marshal dis 加载 3.12 的字节码。这里有两种思路要么本地装 Python 3.12要么用跨版本工具 xdis / uncompyle6 直接加载。考虑到只是要看常量和符号用 xdis 更省事pip install uncompyle6图2-2在线pyc反编译站点https:// tool.lu/pyc/▶1.提取常量与符号用 xdis.load_module() 跨版本加载字节码可以拿到完整的模块结构。模块级 co_consts 里有几个关键对象textco_consts:[0] 0[1] None[2] Code311: decrypt_flag -解密函数[3] Code311: main -主函数[4] __main__main 函数的常量列表里直接暴露了所有关键信息pythonconsts (None,aWNuaHRra3lgP2ZhaCJ3eTw3In19N2oiPGY9OCJ5dmdjfnxtPzdjY3ly, # Base64编码的 flag15, # XOR密钥请输入flag: , # 提示语正确, # 成功消息错误, # 失败消息)varnames (encoded_flag, xor_key, user_input, correct_flag)decrypt_flag 函数有两个参数encoded_data, key内部使用 base64.b64decode 解码后逐字节 XOR它还有一个生成器 genexpr闭包捕获了外层的 key。符号表里出现了 base64、b64decode、join、chr函数逻辑基本就一目了然了。▶2.还原源代码根据上面的常量、变量名、符号表可以完整还原出原始 Python 代码import base64 def decrypt_flag(encoded_data, key): Base64 解码后逐字节 XOR 解密 decoded base64.b64decode(encoded_data) return .join(chr(b ^ key) for b in decoded) def main(): encoded_flag aWNuaHRra3lgP2ZhaCJ3eTw3In19N2oiPGY9OCJ5dmdjfnxtPzdjY3ly xor_key 15 user_input input(请输入flag: ).strip() correct_flag decrypt_flag(encoded_flag, xor_key) if user_input correct_flag: print(正确) else: print(错误) if __name__ __main__: main()▶3.解密过程加密逻辑非常清晰base64_decode(data) - XOR(0x0f) - chr() - join。直接照着写一个反向脚本即可import base64 encoded aWNuaHRra3lgP2ZhaCJ3eTw3In19N2oiPGY9OCJ5dmdjfnxtPzdjY3ly decoded base64.b64decode(encoded) xor_key 15 flag .join(chr(b ^ xor_key) for b in decoded) print(flag)逐字节看一下解密过程前 5 个字符就能确认方向是对的textEncoded (Base64): aWNuaHRra3lgP2ZhaCJ3eTw3In19N2oiPGY9OCJ5dmdjfnxtPzdjY3lyDecoded (42 bytes): 69 63 6e 68 74 6b 6b 79 60 3f 66 61 68 22 77 79 ...XOR 0x0f逐字节:0x69 ^ 0x0f 0x66 f0x63 ^ 0x0f 0x6c l0x6e ^ 0x0f 0x61 a0x68 ^ 0x0f 0x67 g0x74 ^ 0x0f 0x7b {... (共 42 字节)如果手头没有 xor_key 这个常量也可以对 0~255 所有密钥暴力搜索一遍只有 key15 能产生符合 flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 格式约束的结果。图2-3脚本运行得到FlagFlagFLAGflag{ddvo0ing-xv38-rr8e-3i27-vyhlqsb08llv}技术总结本题核心考点集中在 Python 字节码层面• 识别 .pyc 文件的 Magic Number定位 Python 版本这里是 3.12.0• 使用 xdis 等跨版本工具加载不同版本字节码绕开版本不匹配的限制• 从 co_consts 和 co_names 还原程序逻辑不需要完整反编译• Base64 XOR 双重编码的识别与解密遇到不知道密钥的情况可以暴力搜索。整体难度不高但要求选手对 Python 字节码结构、marshal 格式以及 pyc 文件头有一定了解否则会被版本问题卡住。