PyInstaller提取器pyinstxtractor完整实战:一条命令拆开打包程序,还原pyc字节码
【免费下载链接】pyinstxtractorPyInstaller Extractor项目地址: https://gitcode.com/gh_mirrors/py/pyinstxtractor
一个找不到源码的深夜:当 exe 变成黑盒
凌晨一点,运维群里弹出一条消息:"线上那个统计工具崩了,可当初交付源码的人已经离职。"你面前只剩一个myapp.exe——一个 PyInstaller 打包的可执行文件。双击运行一切正常,可当你想定位报错、弄清它背后到底执行了什么逻辑时,整个目录里除了这个孤零零的 exe,什么都没有。
这正是 PyInstaller 提取器 pyinstxtractor 的用武之地:它是纯 Python 编写的开源脚本,无需安装 PyInstaller、不依赖任何第三方库,一条命令就能把可执行文件内部的 Python 字节码(.pyc)完整取出,并自动修复文件头,让反编译工具可以直接识别。源码没有消失,它只是被封进了盒子,而这个工具负责拆箱。
60 秒快速上手:克隆、提取、反编译三步走
先跑通流程,再研究原理。第一步,拿到工具:
git clone https://gitcode.com/gh_mirrors/py/pyinstxtractor cd pyinstxtractor第二步,把目标可执行文件作为参数传进去:
python pyinstxtractor.py myapp.exeWindows 用户写法相同,路径按自己环境写全即可(C:\path\to\myapp.exe、/path/to/myapp.exe都支持)。脚本运行完,当前目录会多出一个myapp.exe_extracted文件夹,里面装着:
- 主程序字节码,如
myapp.pyc - 第三方依赖模块目录
PYZ-00.pyz_extracted/ - 程序运行所需的动态库(.dll / .so)与数据文件
到这里,提取就完成了。想还原成可读的 Python 源码,再对 .pyc 调用反编译器即可:
uncompyle6 myapp.exe_extracted/myapp.pyc > myapp.py克隆 → 提取 → 反编译,整条链路就这三步。至于每个环节背后发生了什么,请看下一节。
三层包裹拆箱原理:pyinstxtractor 如何还原打包源码
把 PyInstaller 打包出的可执行文件想象成一个多层快递包裹,理解起来会轻松很多。
外层是快递箱本身,也就是 exe 或 ELF 可执行文件。PyInstaller 把所有内容塞进一个叫 CArchive 的容器,相当于快递箱的主货舱,装着主程序模块、动态库、数据文件等。
封条是文件末尾的魔数。PyInstaller 产物结尾固定带着一串MEI\014\013\012\013\016标记,相当于快递单上的二维码。pyinstxtractor 启动后第一件事就是从文件尾部往回找这串魔数:找到,确认"这确实是 PyInstaller 的包裹";找不到,直接提示文件并非 PyInstaller 产物,避免你在错误的工具上浪费时间。
装箱清单是 CArchive 的 TOC 目录表。每件货物的位置、压缩前后大小、是否压缩、文件类型都记录在这张表里。pyinstxtractor 读出这张表,等于拿到了整箱货物的摆放索引,可以逐件精准取出,并按标记用 zlib 解压还原。
内层小盒子是 PYZ 归档。第三方模块(os、re、requests 这类)不会直接躺在主货舱里,而是先被打包进一个 PYZ 归档,再整体放进 CArchive。所以拆箱要拆两层:先拆外层货舱,遇到标记为 PYZ 的文件,再拆内层小盒子,用 Python 内置的 marshal 模块把模块清单解出来。
最后一环是修复封面。每个 .pyc 文件开头本应有一串文件头(magic、时间戳、大小等元信息),反编译器靠它判断字节码版本。PyInstaller 5.3 之前的版本会保留文件头,5.3 之后则不再存储——拆出来的字节码等于"没封面的书"。pyinstxtractor 会从归档中探测正确的 magic 值并补齐文件头,这也是它最贴心的一步:省掉了手工拼接文件头的繁琐工作。
一句话总结:找封条 → 读清单 → 拆外箱 → 拆内盒 → 补封面。整个过程只用 struct、zlib、marshal 三个标准库模块,所以脚本零依赖,Python 2.x 和 3.x 都能直接跑。
实战演示:一次完整的 PyInstaller 可执行文件提取过程
实际操作时,脚本会打印一串以[+]开头的进度信息。下面是一份典型输出,我们逐行读一读它说了什么:
[+] Processing myapp.exe [+] Pyinstaller version: 2.1+ [+] Python version: 3.8 [+] Length of package: 5612452 bytes [+] Found 59 files in CArchive [+] Beginning extraction...please standby [+] Possible entry point: pyiboot01_bootstrap.pyc [+] Possible entry point: myapp.pyc [+] Found 133 files in PYZ archive [+] Successfully extracted pyinstaller archive: myapp.exe- Pyinstaller version: 2.1+:识别出的打包器版本区间。2.1 与 2.0 的归档格式在 cookie 结构上有差异,脚本据此选择不同的解析方式。
- Python version: 3.8:打包时使用的 Python 版本。务必记住这个数字,后面选解释器和反编译器都要靠它。
- Found 59 files in CArchive:外层货舱有 59 件货物,主程序模块、动态库都在其中。
- Possible entry point: myapp.pyc:脚本根据文件类型标记推测出的程序入口。入口文件是启动时最先执行的模块,逆向分析从这里下手最省力。
- Found 133 files in PYZ archive:内层 PYZ 里装着 133 个第三方模块,这个数量能直观反映程序依赖了哪些库。
- Successfully extracted:整箱拆完,提取阶段收官。
拆完之后别急着走,按这份速查清单过一遍,能少走不少弯路:
- 确认
myapp.pyc是主程序而不是引导模块(pyiboot01_bootstrap这类属于启动引导,不是业务逻辑)。 - 在
PYZ-00.pyz_extracted/里翻一遍第三方模块,判断程序的功能方向。 - 检查有没有
.encrypted后缀的文件——有则说明 PYZ 归档加了密,需要另行研究解密逻辑。 - 依据 Python version 选择匹配的反编译器,再对入口文件下手。
四条提取经验:版本匹配与入口分析的最佳实践
经验一:用与打包环境相同版本的 Python 运行提取器。结论先行:这是规避Unmarshalling FAILED报错最有效的办法。原因是 PYZ 归档的模块表要用 marshal 模块反序列化,而 marshal 的格式与 Python 小版本强相关,解释器版本不一致就可能解不开。输出里的Python version: 3.8就是给你对版本用的。
经验二:优先反编译 Possible entry point 列出的文件。入口文件是程序运行的起点,顺着它的 import 语句逐层追踪,比在海量 .pyc 里盲搜高效得多。面对复杂的业务程序,这条路径能帮你快速画出代码地图,效率翻倍。
经验三:遇到加密归档不要慌。加密的 PYZ 无法直接解密时,脚本会把内容原样导出为.encrypted文件而不是中途崩溃。这意味着你能先拿到"加密的货",再结合主程序中的解密逻辑或调试工具寻找突破口。
经验四:提取前先确认目标身份。如果脚本提示找不到 cookie 或魔数,多半说明文件根本不是 PyInstaller 产物。先检查文件末尾是否有MEI魔数标记,比反复试错快得多。
新手避坑:PyInstaller 提取中最容易犯的四个错误
别在版本不对的解释器下硬跑。报Unmarshalling FAILED时,第一反应应该是换 Python 版本,而不是用同一套环境反复重试。版本匹配是提取成功的第一前提,这不是玄学,是 marshal 格式的硬约束。
别以为提取出来就是源码。.pyc 是字节码,不是可读的 Python 文本。打开看到一串"乱码"很正常——那是在提醒你:反编译器还没上场。
别拿老工具反编译新字节码。Uncompyle6 对 Python 3.9 之后的字节码无能为力,遇到新版本要改用 Decompyle++(pycdc)等工具。选错反编译器,换来的只会是一堆报错。
别忽略提取目录之外的细节。提取成功不代表万事大吉。加密文件、动态库依赖、数据文件都可能是后续分析的关键,只盯着 .pyc 会漏掉重要线索。
横向对比:主流 PyInstaller 提取工具怎么选
| 方案 | 运行前提 | 加密 PYZ | 典型场景 | 上手难度 |
|---|---|---|---|---|
| pyinstxtractor | 本机装有 Python | 原样导出 .encrypted | 日常提取、学习研究 | 低 |
| pyinstxtractor-ng | 无需 Python,独立二进制 | 支持解密 | 无 Python 环境的机器 | 低 |
| pyinstxtractor-web | 浏览器即可 | 视实现而定 | 临时快速查看 | 极低 |
| 手工逆向分析 | 十六进制工具 + 扎实功底 | 视个人能力 | 深度研究、畸形样本 | 高 |
pyinstxtractor 的定位很清晰:零依赖、开箱即用、覆盖 PyInstaller 2.0 到 6.19.0 的几乎所有主流版本,是绝大多数场景下的第一选择;需要独立运行或解密能力时,再考虑它的衍生版本。
边界提醒:授权范围内使用,尊重代码归属
需要说清楚:这个工具提取的是字节码,而不是"偷走"别人的代码。请在明确授权的范围内使用——自己打包的程序、已获许可的安全测试目标、教学与学习场景,都是合适的应用方向。提取他人的商业软件并用于牟利,既违反著作权,也可能触犯法律。技术本身是中立的,使用它的分寸,在你手里。
动手一试:把第一个打包程序拆开看看
从"打不开的黑盒"到"逐行可读的源码",中间只差一次克隆、一条命令、一次反编译。现在就去 clone 一份 pyinstxtractor,拿你手头第一个 PyInstaller 打包程序练手——当你亲眼看着那些 .pyc 变成熟悉的 Python 代码时,会真正理解什么叫"拆箱见真章"。
【免费下载链接】pyinstxtractorPyInstaller Extractor项目地址: https://gitcode.com/gh_mirrors/py/pyinstxtractor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考