首先声明一点,逆向这块我是纯小白,我是通过看各种博客,反复折腾才搞出来的,写的有错误的地方,还请各位大佬多多指正
0 前置条件
确认需要逆向的exe文件是不是通过pyinstaller打包的,如果不是,那么这个方法就是无效的
我们可以通过图标来确定,pyinstaller打包的图标一般如下两种
1 需要用到的环境及工具
(1)电脑需要有python环境,我用的是python3.9
(2)pyinstxtractor.py ---- 将.exe解包
官方GitHub地址 https://github.com/countercept/python-exe-unpacker/blob/master/pyinstxtractor.py
(3)uncompyle6 ---- .pyc转.py
# 安装可以加上清华镜像源,自行搜索安装即可
pip install uncompyle6
(4)WinHex ---- 16进制编辑(用其他也可以)
2 将exe文件进行解包
将pyinstxtractor.py文件和需要解包的exe文件(我这里叫xxxx.exx)放在同一个目录下,执行如下命令
python pyinstxtractor.py xxxx.exe
解包后会生成一个xxxx.exe_extracted文件夹,我们可以通过这个文件夹看到这个exe文件是通过什么版本的python打包的
可以看到,我这个exe文件是通过python3.8打包的,但具体是哪个版本的,就无法得知
在xxxx.exe_extracted文件中,我们只需要关注该目录下没有后缀名的文件和PYZ-00.pyz_extracted这个文件夹
没有后缀名的文件,在我这个例子中有两个: 1 和 struct
其中,这个1文件其实就是程序的入口文件,PYZ-00.pyz_extracted文件夹存放主程序的一些依赖库,包括自己写的
PYZ-00.pyz_extracted这个文件夹下的文件大概如下,分两种情况
1 文件都是以pyc结尾的,说明没有加密,我们可以用uncompyle6 将其反编译成.py文件(也就是源码)
2 文件都是以.pyc.encrypted 结尾的,说明经过了加密,感兴趣的可以研究如何解密,我这里就不说明了
3 将pyc文件转为py文件
将pyc文件转为py文件,最重要的是需要补全magic head。想要快速将pyc转为py文件,而不需要补全magic head,请直接看3.3节。
3.1 反编译程序入口文件
上面说过,在我这个例子中,1这个文件就是程序的入口文件,一般来说你的exe文件如果是demo.exe,那么你这个入口文件大概率是demo。
(1)重命名程序入口文件
上面说过1这个文件是没有后缀名的,需要给它加上.pyc的后缀名,变为1.pyc;同理,将struct文件改为struct.pyc
(2)用WinHex打开上面1.pyc 和 struct.pyc,对比字节码的差异,补全magic head
这里我就有点懵,因为我看其它博客struct.pyc文件打开后,第一行并不是E3开头,而是类似下面这种
这里无法根据struct.pyc进行补全,我又搜索其它博客,发现有人和我情况一样,struct.pyc打开直接就是E3开头,可惜没有人回答这个问题
不多说,直接上解决办法:在exe解包的目录下有一个base_library.zip压缩包,打开这个压缩包,随便找一个oyc文件,使用WinHex打开,这里我打开的是base_library中的abc.pyc文件
对比两个文件,发现 55 0d 0d 0a 01这第一行的字节码就是我们需要的magic head
我们直接把abc.pyc文件中的第一行复制,添加到1.pyc文件中的第一行
保存,然后用 uncompyle6 反编译
uncompyle6 -o 1.py 1.pyc
反编译后,没有报错,并且生成了1.py文件,打开1.pyc文件,能够看到源码,说明magic head是正确的
3.2 反编译依赖库
反编译程序入口后,我们可以看到,该程序依赖了一个demo的库,这个库肯定是作者自己写的
依赖的demo库在PYZ-00.pyz_extracted文件夹中可以找到,打开demo.pyc与1.pyc进行对比
这里我们可以发现,依赖库缺失的字节是在中间位置,这里我们看到缺少的是12-15位的四个字节 00 00 00 00
补全缺失的四个字节
保存,然后用 uncompyle6 反编译
uncompyle6 -o demo.py demo.pyc
反编译后,没有报错,并且生成了demo.py文件,打开demo.pyc文件,能够看到源码,说明我们补全的字节码是正确的