保姆级教程:用PyInstaller打包的Python程序,如何一步步还原成源码(附解密脚本)
2026/6/13 3:08:00 网站建设 项目流程

逆向工程实战:从PyInstaller打包的EXE中还原Python源码全流程

当你拿到一个用PyInstaller打包的Python程序,却发现没有原始代码时该怎么办?本文将带你完整走通从识别打包工具到最终还原.py文件的每个关键步骤。不同于简单的工具介绍,我们会深入每个操作背后的原理,并提供可直接复用的解密脚本。

1. 逆向工程前的准备工作

逆向PyInstaller打包的程序需要一套特定的工具链。以下是必备工具及其作用:

  • Detect It Easy (DIE):用于快速识别文件类型和打包工具
  • pyinstxtractor:PyInstaller专用解包工具
  • uncompyle6:将.pyc文件反编译为.py源码
  • 010 Editor:十六进制编辑器,用于分析文件头
  • Python环境:需与打包时使用的Python版本一致

重要提示:Python版本必须严格匹配。用Python 3.8打包的exe,必须用Python 3.8环境进行解包,否则会出现magic number不匹配的错误。

安装核心工具的命令如下:

pip install uncompyle6 git clone https://github.com/extremecoders-re/pyinstxtractor

2. 解包PyInstaller生成的EXE文件

使用pyinstxtractor进行解包是逆向的第一步。这个工具能解析PyInstaller的特殊打包格式,提取出内部的.pyc字节码文件。

典型解包操作:

python pyinstxtractor.py target.exe

解包后会生成target.exe_extracted目录,其中包含这些关键文件:

文件/目录作用
PYZ-00.pyz_extracted存放所有依赖库的.pyc文件
pyimod00_crypto_key.pyc存放加密密钥(如果使用了加密)
main.pyc主程序的字节码文件

常见问题排查

  • 如果解包失败,首先检查Python版本是否匹配
  • 加密过的exe可能需要先提取密钥才能完整解包
  • 某些加固过的exe可能需要手动修复文件头

3. 处理加密的PyInstaller打包文件

PyInstaller支持使用--key参数进行加密打包。识别加密的方法很简单:

  1. 检查PYZ-00.pyz_extracted目录中的文件
  2. 如果看到.pyc.encrypted后缀的文件,说明使用了加密

解密需要两个关键信息:

  • 加密密钥(存储在pyimod00_crypto_key.pyc中)
  • PyInstaller的加密算法版本(区分4.0前后)

提取密钥的步骤:

uncompyle6 -o key.py pyimod00_crypto_key.pyc

然后根据PyInstaller版本选择对应的解密脚本:

PyInstaller < 4.0 解密脚本

from Crypto.Cipher import AES import zlib def decrypt_file(encrypted_path, output_path, key): with open(encrypted_path, 'rb') as inf: iv = inf.read(16) cipher = AES.new(key, AES.MODE_CFB, iv) plaintext = zlib.decompress(cipher.decrypt(inf.read())) with open(output_path, 'wb') as outf: outf.write(b'\x55\x0d\x0d\x0a\0\0\0\0') # Python 3.8头 outf.write(plaintext)

PyInstaller ≥ 4.0 解密脚本

import tinyaes import zlib def decrypt_file(encrypted_path, output_path, key): with open(encrypted_path, 'rb') as inf: iv = inf.read(16) cipher = tinyaes.AES(key, iv) plaintext = zlib.decompress(cipher.CTR_xcrypt_buffer(inf.read())) with open(output_path, 'wb') as outf: outf.write(b'\x55\x0d\x0d\x0a\0\0\0\0') # Python 3.8头 outf.write(plaintext)

4. 反编译.pyc字节码文件

获得正常的.pyc文件后,使用uncompyle6进行反编译:

uncompyle6 -o output.py input.pyc

对于批量处理,可以使用这个脚本:

import os from pathlib import Path def batch_decompile(input_dir, output_dir): os.makedirs(output_dir, exist_ok=True) for pyc in Path(input_dir).rglob("*.pyc"): cmd = f"uncompyle6 -o {output_dir}/{pyc.stem}.py {pyc}" os.system(cmd)

反编译常见问题及解决方案

  1. Magic number不匹配

    • 症状:ValueError: Bad magic number in .pyc file
    • 解决:手动修正.pyc文件头,或使用正确Python版本
  2. 反编译失败

    • 症状:输出无意义代码或报错
    • 可能原因:代码被混淆或优化过
    • 解决:尝试其他反编译工具如pycdc
  3. 部分代码缺失

    • 可能原因:使用了Cython扩展
    • 解决:需要更高级的逆向技术

5. 高级技巧与实战经验分享

在实际逆向过程中,会遇到各种特殊情况。以下是几个实用技巧:

技巧1:修复损坏的.pyc文件头

有时解包得到的.pyc文件头可能损坏,可以手动修复:

  1. 用010 Editor打开.pyc文件
  2. 根据Python版本写入正确的magic number
  3. 保存后重新尝试反编译

各Python版本的magic number对应表:

Python版本Magic Number (十六进制)
3.742 0D 0D 0A
3.855 0D 0D 0A
3.961 0D 0D 0A
3.106F 0D 0D 0A

技巧2:处理混淆过的代码

遇到混淆代码时,可以尝试:

  1. 使用astor库重构AST
  2. 手动分析控制流
  3. 使用调试器动态跟踪执行

技巧3:提取嵌入的资源文件

PyInstaller打包的资源文件可以通过这些步骤提取:

from PyInstaller.utils.win32.resource import GetResources resources = GetResources('target.exe') for res in resources: with open(res.name, 'wb') as f: f.write(res.data)

逆向工程既是技术也是艺术。每个PyInstaller打包的程序都可能带来独特的挑战,但掌握了这套方法论后,你就能系统性地解决大多数逆向问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询