记一次反编译PyInstaller打包的可执行文件获得其Python源码的过程


笔者因为一些原因,需要反编译别人打包好的Python3写的exe程序获得其源码,但是本人对于Python的反编译是一窍不通的,于是在十分钟的谷歌学习后,这篇文章诞生了

第一步

首先,我们安装完python并且配置好环境变量后,去下载pyinstxtractor.py这个工具,他能把PyInstaller打包的exe文件里包含的依赖库和已编译好的.pyd或者.pyc字节码文件给“解压”出来,这其中,.pyd文件的反编译特别复杂(因为.pyd其实是已经编译成.c后封装成类似.dll的东西了,根本看不出Python的源码了),技术力不足的我这部分无能为力,本次讲的是.pyc的反编译。

python pyinstxtractor.py Test.exe

运行工具“解压”完成后,

我们看到目录中生成了一个文件夹:

图中的Test.exe_extracted文件夹便是Test.exe文件被“解压”后的结果,然后我们找到类型为.pyc的字节码文件(或者如下图所示的类型为文件的文件)

然后把他们改为后缀名为.pyc的字节码文件(因为上述工具解压过程无法识别这些二进制的文件所以没有自动改后缀)

【这里剧透下:其实是因为这些字节码文件标头的幻数被人删除了】

第二步

接着,我们开始对上述“解压”出来的已编译的.pyc字节码文件进行反编译

首先,pip安装uncompyle6:https://pypi.org/project/uncompyle6/

pip install uncompyle6

然后试着直接使用一次:

uncompyle6 Test.pyc

然后我们发现,提示的是“导入错误:Test.pyc中有无法识别的幻数227”

这个227其实是十六进制的数字,我们用WinHex打开Test.pyc查看一下:

我们发现,并没有什么特征,我们继续把同目录的struct文件打开看一下:

我们发现,这里也有一个“E3”,而十六进制的E3恰好就是227,诶,我们发现,幻数227是错误的,说明,在这个E3前面,本来应该有一个正确的幻数,在编译成.pyc字节码文件的过程中,可能被人篡改或者删除了,而我这个情况是被人删除了,那我们手动插入这个数字进去试试:

然后我们再试一次反编译:

提示成功,源码也显示了出来,查看不方便的话可以这样写:

uncompyle6 Test.pyc > Test.py

这样根目录就会出现反编译完成的.py源码文件了

后记

新版本的pyinstxtractor.py已经增加了自动补全python版本幻数的功能了:

https://github.com/extremecoders-re/pyinstxtractor

批量反编译

笔者又在github上找到了一个批量反编译.pyc字节码文件的脚本:

https://github.com/jazlopez/py-recursive-uncompyle6

这个脚本会自动搜索自身所在的目录及其子目录下的所有.pyc字节码文件,然后通过安装好的uncompyle6进行反编译,不足之处是,反编译后只会把反编译完的.py源码文件扔在原文件旁,而不是另建文件夹储存。

不过,我们可以修改这个脚本中的uncompyle_to参数来指定输出文件夹

uncompyle_to = os.path.join(parent, i["dirname"], i["name"])

因为笔者没有这个需求,所以这个代码逻辑的修改就留给读者你了,改完记得去给原项目PR哦


文章作者: SekiBetu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 SekiBetu !
评论
  目录