ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

如何用 pyinstxtractor 快速还原 PyInstaller 打包程序的完整源码

如何用 pyinstxtractor 快速还原 PyInstaller 打包程序的完整源码 如何用 pyinstxtractor 快速还原 PyInstaller 打包程序的完整源码【免费下载链接】pyinstxtractorPyInstaller Extractor项目地址: https://gitcode.com/gh_mirrors/py/pyinstxtractor拿到一个由 PyInstaller 打包的 exe却找不到对应的 .py 源码pyinstxtractor 正是为这个场景而生的开源提取器——它用纯 Python 实现、零第三方依赖一条命令就能拆开 PyInstaller 程序的外壳取出全部 pyc 字节码文件并自动修复文件头让反编译工具开箱即用。本文不按照抄命令的老套路走而是沿着 PyInstaller 程序的三层内部结构逐一拆解先讲清为什么能还原再带你亲手完成一次从提取到反编译的完整链路。悬念为什么打包过的程序仍然能找回源码假设你接手一个维护任务程序是别人用 PyInstaller 打包好的可执行文件唯一的源码副本早已丢失。此刻你手头只有一个看似黑盒的 exe但其实它并没有想象中那么黑。关键在于理解 PyInstaller 打包的本质。它并不会把 Python 代码编译成机器码——那才是真正难以还原的东西。PyInstaller 做的是封装先把你的 .py 源码翻译成字节码bytecode也就是 Python 解释器真正执行的一种中间代码然后把字节码、依赖模块、动态库连同一个小型引导器bootloader一起塞进可执行文件。程序运行时引导器负责把这些内容解压进内存再交给 Python 解释器执行。字节码不是机器码它保留了类名、函数名、字符串常量、调用关系等大量结构化信息。所以打包从来不等于加密只要能把壳拆开源码就有机会被还原。第一层外壳pyinstxtractor 凭什么一眼认出 PyInstaller 程序pyinstxtractor 的全部逻辑只封装在一个文件 pyinstxtractor.py 中仅使用 Python 标准库同时兼容 Python 2.x 和 3.x也不需要预先安装 PyInstaller。换句话说克隆下来就能直接跑几乎没有任何环境门槛。它识别 PyInstaller 程序的依据是一个固定魔数MEI\014\013\012\013\016。PyInstaller 打包产物会在文件末尾写入这段标记pyinstxtractor 从文件尾部向前扫描定位它就像在快递箱上找到了此面朝上的标识。定位成功后它还能顺带读出两件关键情报打包器版本2.0 或 2.1和打包时使用的 Python 版本如 3.8。这两条信息既决定了后续的解析策略也为你挑选反编译工具提供了依据。第二层归档CArchive 里藏着什么识别外壳之后真正的内容物存放在一种叫 CArchive 的归档结构中。你可以把它想象成一只行李箱PyInstaller 把主程序、依赖模块、动态库、资源文件全部压缩后装进去并在箱内附上一张物品清单目录表 TOC逐条记录每件物品的存放位置、压缩前后大小和类型。pyinstxtractor 的拆箱流程相当直观先定位目录表逐条读取条目遇到 zlib 压缩的数据就解压再按条目类型分类处理。其中依赖声明和运行时选项这类并非文件的条目会被直接跳过而标记为可执行 Python 脚本的条目会以 Possible entry point可能入口点的形式单独打印出来——这通常就是你的主程序逆向分析时从它入手效率最高。第三层内核PYZ 归档与 pyc 文件头自动修复继续向深处走CArchive 里往往还藏着一个 PYZ 归档里面装着程序用到的所有第三方 Python 模块例如 os、json、requests 等库的字节码。PYZ 的目录表由 Python 内置的 marshal 模块序列化而成pyinstxtractor 会将其反序列化出来再逐个解压每个模块。这里有一个版本分水岭值得记住PyInstaller 5.3 之前打包时会保留 pyc 文件头5.3 之后文件头被移除只剩裸字节码。而 pyc 文件头恰恰是反编译工具识别文件的关键。pyinstxtractor 的处理方式很聪明——它从已解出的文件中采样正确的魔数再按 Python 版本补上时间戳、文件大小或哈希字段把文件头接回去。这正是它自动修复 pyc 文件头这一核心卖点的由来。即便遇到加密的 PYZ 归档pyinstxtractor 也不会直接报错退出而是把内容原样导出为 .encrypted 文件留给后续深入分析。pyinstxtractor 实战从一条命令到反编译出源码理论讲完动手验证。假设你手上有一个 myapp.exe在它所在目录执行python pyinstxtractor.py myapp.exe典型的成功输出如下[] Processing myapp.exe [] Pyinstaller version: 2.1 [] Python version: 38 [] Length of package: 5612452 bytes [] Found 59 files in CArchive [] Beginning extraction...please standby [] Possible entry point: myapp.pyc [] Found 133 files in PYZ archive [] Successfully extracted pyinstaller archive: myapp.exe看到 Successfully extracted 即为成功。当前目录会生成 myapp.exe_extracted 文件夹其中 myapp.pyc 是主程序字节码PYZ-00.pyz_extracted/ 是所有第三方模块的解压目录其余是动态库与资源文件。值得一提的是Linux 下的 ELF 可执行文件同样支持原生提取无需额外工具。接下来做 pyc 文件反编译把字节码还原成可读的 .py 源码uncompyle6 myapp.exe_extracted/myapp.pyc myapp.py uncompyle6 myapp.exe_extracted/PYZ-00.pyz_extracted/__future__.pyc工具选择有一条简单规则Uncompyle6 覆盖 Python 2.7 到 3.8更新的版本建议改用 Decompylepycdc。先反编译入口点文件再顺着 import 语句逐层追踪能快速建立整个程序的代码地图。新手最常踩的三个坑与绕坑技巧坑一Unmarshalling FAILED。这是最高频的报错几乎都源于 Python 版本不匹配。解压 PYZ 依赖 marshal 模块其格式与 Python 版本强相关。最稳妥的做法是查看输出中的 Python version 字段换用相同版本的解释器重新运行提取器。坑二pyc 反编译不出来。多数情况是反编译器不支持对应字节码版本例如 Uncompyle6 对 Python 3.9 之后无能为力。先确认打包时的 Python 版本再选择匹配的反编译器即可。坑三提示不是 PyInstaller 归档。报错表示在文件末尾找不到魔数标记说明该文件并非 PyInstaller 产物需要换用其他分析思路。写在最后边界与你的下一步pyinstxtractor 是一把趁手的逆向分析工具但也请只在你有权访问的程序上使用自己打包的产物、已授权的测试目标都是合理场景。尊重原作者版权与许可协议是每个使用者应有的底线。现在就可以动手了。克隆仓库跑一条命令把第一个 PyInstaller 程序拆开看看git clone https://gitcode.com/gh_mirrors/py/pyinstxtractor cd pyinstxtractor python pyinstxtractor.py myapp.exe回顾全文核心PyInstaller 打包的本质是封装而非加密pyinstxtractor 用魔数识别外壳、解析 CArchive 与 PYZ 双层归档、自动修复 pyc 文件头从提取到 pyc 文件反编译一条完整链路即可还原出可读源码。✅ 工具已就绪下一步就交给你的好奇心。【免费下载链接】pyinstxtractorPyInstaller Extractor项目地址: https://gitcode.com/gh_mirrors/py/pyinstxtractor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进