来源:网络
Python 打包成 .exe 的本质,并不是像 C++ 那样把代码翻译成了机器码(0和1)。它的本质是:把你的 .py 文件压缩了一下,然后和 Python 解释器捆绑在一起。
既然只是压缩,那就可以“解压(反编译)”。
不同的打包工具,反编译的方法不一样,常见的有三种:
怎么快速判断?
文本搜索(最简单,不需要装任何工具)
几乎所有打包工具都会在 exe 文件里留下自己的"签名"或"版权声明"。
操作步骤:
注意: 记事本打开 exe 后内容全是乱码,只需要搜索,看能不能匹配到上面的关键词就行。
用Python脚本扫描
上面的记事本方法有时候会漏掉,因为记事本对某些编码的显示不完整。写一个 Python 脚本来扫描,准确率更高:
import osdef detect_packer(exe_path): with open(exe_path,'rb') as f: content = f.read() # 从 exe 里读出来的原始二进制数据,没法直接做文字搜索 try: # 用 UTF-8 规则把二进制翻译成文字,遇到翻译不了的东西,直接跳过,不要报错 text = content.decode('utf-8',errors='ignore') except: # errors='ignore' 理论上已经不会报错了。但实际场景中,怕遇到极端情况(比如文件损坏、权限不足), # 写个 except 保底,用最原始的 str() 强制转换。 # 虽然结果里会多很多 \x00\xff 这种乱码,但程序至少不会崩溃,而且关键词搜索依然能工作。 text = str(content) # 定义各种打包工具的"指纹" fingerprints = { "PyInstaller": ["pyinstaller", "pyi-", "PYINSTALLER", "MEIPASS"], "Nuitka": ["nuitka", "NUITKA", "Nuitka-Options", "onefile_"], "cx_Freeze": ["cx_Freeze", "cxfreeze", "CX_FREEZE"], "Py2Exe": ["py2exe", "PY2EXE"], "PyArmor": ["pyarmor", "PYARMOR", "pytransform"], "Auto PY to EXE": ["autopytoexe"], "Cython": ["cython", "CYTHON", "PyInit"], } detected = [] for tool,keywords in fingerprints.items(): for kw in keywords: if kw.lower() in text.lower(): detected.append(f'✔ 检测到: {tool} (匹配到关键词: {kw})') break if not detected: detected.append('✖ 未检测到已知的 Python 打包工具特征') detected.append('可能是 C/C++/C#/Go/Rust 等原生编译的程序') detected.append('也可能是加了壳或做了混淆') return detected# 使用if __name__ == '__main__': exe_path = r"C:\你的路径\你的文件.exe" results = detect_packer(exe_path) # 结果展示 print("=" * 50) print(f"扫描目标: {os.path.basename(exe_path)}") print("=" * 50) for r in results: print(r)
运行后会告诉你这个 exe 到底是什么工具打包的。
注意:“Auto PY to EXE” 本质上是一个用 tkinter 写的图形化界面(GUI),它的底层是 PyInstaller(简单来说就是调用 PyInstaller 的图像化软件)。用脚本扫,扫出来的可能依然是 PyInstaller 的特征。不管是不是直接按照 PyInstaller 的方法去反编译就行了,完全不用管 Auto PY to EXE。
如果确定是 PyInstaller 打包的,用以下流程反编译:
下载反编译工具 pyinstxtractor:
提取文件:
找到真正的入口文件并反编译:
打开提取出的文件夹,找到与原程序同名的 .pyc 文件(比如程序叫 app.exe,就找 app.pyc)。
用pip install 命令下载另一个工具 uncompyle6 或 decompyle3。
注意:uncompyle6 这个库的作者已经很久没维护它了,而 Python 本身还在更新。新版本的 Python 导致了 uncompyle6 严重不兼容,用它反编译的时候可能会报错ImportError: cannot import name '...'。这个时候直接放弃使用,换成它的升级版替代品 decompyle3,二者的语法一模一样。
输入命令(假设程序叫app.exe)
cd app.exe_extracted# 命令一:# 把结果偷偷塞进文件里,什么都不在屏幕上打出来。uncompyle6 app.pyc > app.py# 命令二:# 把结果存到指定文件夹,同时把反编译的整个过程在屏幕上打出。uncompyle6 -o "save\path" spartwind.pyc
注意:用命令二(-o)更稳妥。
因为,如果反编译失败了(比如文件损坏或者被加密),命令一(>)会把屏幕上的报错信息也写进 .py 文件里,导致你打开一看里面全是乱码报错,还以为反编译成功了。而命令二(-o)如果失败了,它会在屏幕上打印一堆红色报错,不会生成 .py 文件,一看就知道"哦,失败了",不会搞混。
如果打包时加了强加密(如 PyArmor),反编译出来会是乱码。这个目前没有通用的破解方法。
Nuitka 打包时,把 .py 翻译成 .c(C 语言源代码),用 C 编译器(GCC/MSVC)把 .c 编译成机器码。C 语言编译成机器码的过程是不可逆的,所以想将它打包的 exe 反编译回最原始的 .py 源码,很难。
Cython 通常是和其他打包工具配合使用的。
第 1 步:用 Cython 把核心 .py → 编译成 .pyd(机器码)第 2 步:用 PyInstaller 把入口 .py + .pyd → 打包成 exe
这样做是专门防止代码被反编译,故意只用 Cython 把核心代码编译成 .pyd 文件。
所以如果使用 pyinstxtractor 生成的文件夹里,全是一个个 .pyd 文件。就没必要用uncompyle6 或 decompyle3试了,因为它们只能反编译 .pyc,面对 .pyd 会直接报错。
pyd 和 .pyc 是什么?
反编译他人程序在多数国家属于违法行为,技术细节仅供学习参考。如果只是想对接功能,尝试套壳调用(subprocess)。
长按或扫描下方二维码,免费获取 Python公开课和大佬打包整理的几百G的学习资料,内容包含但不限于Python电子书、教程、项目接单、源码等等
▲扫描二维码-免费领取
推荐阅读
10个强大的Python数据科学技巧
太香了!Python 优化提速的 8 个小技巧!
精心整理了8个让Python "优化提速" 的小技巧!
8 个提升 Python 数据分析效率的代码技巧