反编译 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: