反编译 pyinstaller 产生的可执行文件

  在一次计算中使用别人发布的由python编写然后编译打包的二进制程序进行操作时,总是报错"缺少链ID",但检查pdb文件已经添加了链ID。   为查明报错原因,对此二进制可执行文件进行了反编译。下面记录了操作过程:

  python是解释型语言,故python编译打包成的可执行文件很容易被反编译,而像C,C++这样的编译型语言得到的可执行文件,则较难被反编译。   反编译pyinstaller 产生的可执行文件,可以分为两个步骤,一是由可执行文件获取pyc(pyo)文件,二是由pyc(pyo)文件得到py文件。

获取pyc文件

  在Linux上运行pyintaller打包的可执行文件时,它会将打包好的文件解压到临时文件夹(/tmp)中的_MEIxxxxxx 路径中暂时存放,执行完毕之后再删除,所以会存在解压缩的时间。然而这个_MEIxxxxxx路径中主要是.so文件,并不含有源码。   但是pyinstaller自带脚本archive_viewer.py,可以由可执行文件解压得到pyc文件:

1
python archive_viewer.py exefilename 
一共有四个可用命令:
1
2
3
4
U: go Up one level
O <name>: open embedded archive name
X <name>: extract name
Q: quit
archive_viewer.png

  列表中有两个部分需要关注,一个是out00-PYZ.pyz,其中包含主程序引用到的所有库;一个是主程序对应的文件名,其中会包含主程序。   比如,一个显示天气的程序,其主程序名称为show.py,其中调用了calc.py,则需要

1
2
x show 提取到 show.pyc 
o out00-PYZ.pyz 然后查看调用的库,然后 x calc 提取到 calc.pyc
  这样我们就得到了show.pyccalc.pyc

从pyc获取py文件

方法

方法比较多,比如 1. 在线程序,比如python反编译在线pyc反编译等 2. uncompyle6,是python脚本,故而可以批量运行,使用方法为 uncompyle6 file.pyc 3. easypythondecompiler

注意

  pyinstaller编译成pyc时,会把pyc的magic value去掉,如果使用easypythondecompiler的话,需要再把magic value补上(使用 010 Editor 编辑器)。magic value一共8个字节,前四个对应于编译时所用python的版本,后四个对应于编译时间,比如python2.7 的03 f3 0d 0a 01 23 45 67,python3.4 的ee 0c 0d 0a 01 23 45 67.如果不知道编译时所用的python版本,可以通过一个trick来寻找:在可执行文件包含的前几个文件对应的pyc文件(比如 pyimod01_os_path)中,前4个字节已经存在。 20180611-010_Editor.png   如此,便可反编译出show.pycalc.py等文件。


Ref: - Get Python Code From PYINSTALLER - python-pyinstaller-reverse-engineer