本文将详细讲解如何使用pyi-archive_viewer提取 PyInstaller 打包生成的 EXE 文件中的 PYC 字节码文件,并使用uncompyle6工具将其反编译成 Python源码。

提取 PYC 文件

.pyc文件是 Python 字节码(Bytecode)文件,由 Python 解释器自动生成,用于缓存已编译的 Python 代码,以加快后续的模块加载速度。

PYC 保留了足够的信息可用来还原原始代码结构;无优化的.pyc文件几乎可以100%还原;

可以使用pyi-archive_viewer命令提取 EXE 文件中的字节码文件;

运行py-archive_viewer,查看程序的捆绑文件:

py-archive_viewer 只对 PyInstaller生成的 EXE 可执行文件有用;

pyi-archive_viewer main.exe

main.exe为例,该命令会列出程序捆绑的文件,并进入交互模式,输出大致如下:

Options in 'main.exe' (PKG/CArchive):
 pyi-contents-directory _internal
Contents of 'main.exe' (PKG/CArchive):
 position, length, uncompressed_length, is_compressed, typecode, name
 0, 248, 344, 1, 'm', 'struct'
 248, 2861, 5304, 1, 'm', 'pyimod01_archive'
 3109, 14025, 34022, 1, 'm', 'pyimod02_importers'
 22113, 1564, 3065, 1, 's', 'pyi_rth_inspect'
 23677, 589, 982, 1, 's', 'main'
 24266, 56219, 109440, 1, 'b', 'VCRUNTIME140.dll'
 80485, 45317, 84760, 1, 'b', '_bz2.pyd'

 ...
 
?

其中main就是需要提取的文件,通常和程序名一样;这里假定 Python 程序只有一个文件,实际上可能存在多个;

输入命令x main提取文件,保存为main.pyc,输入q退出程序:

? x main
Output filename? main.pyc
? q

保存的字节码文件不是一个完整的文件,目前还不能直接使用,PyInstaller 在处理过程中,移除了MAGIC信息;我们需要将其补全;

补全 MAGIC

main.exe中再提取base_library.zip文件,方法上文中提到;这是个压缩文件,将其解压;

使用十六进制编辑器,打开base_library.zip中的任意.pyc文件;

E3 00 00 00之前的内容复制到main.pyc文件的头部,使其看起来像这样:

A7 0D 0D 0A 00 00 00 00 06 F5 69 68 19 00 00 00
E3 00 00 00 ...

这部分内容会根据 Python 版本不同而有所不同,所以不要直接复制这个示例;

反编译 PYC

现在可以使用uncompyle6对 PYC 进行反编译;uncompyle6可以将 Python 字节码转换回等效的 Python 源代码;

安装 uncompyle6

使用 pip 进行安装:

pip install uncompyle6

安装完成后,执行命令:

uncompyle6 .\main.pyc --output .

你将在当前目录得到反编译后的文件。