背景
手上有个简单的小程序,用来识别公司应用的登录窗口,自动填写用户名密码,点击登录(要是有保存用户名密码功能多好啊)
今天忽然想看一下实现原理是啥,源码是啥
主要工具及环境
DIE pyinstxtractor uncompyle6 pycdc 编译好的pycdc vs2019 win10x64 python3.9.6
分析exe
下载Detect It Easy 软件,并打开我们的小程序
上面的PyInstaller表明这是一个python程序,使用pyinstaller打包成exe
首先解包这个exe
既然是python打包的,先解包看看里面有啥
- 下载pyinstxtractor ,随后使用python pyinstxtractor xxx.exe解包,输出如下
- 由此我们得到了所有的pyc文件存放于xxxx_extracted目录下,pyc文件是python编译后产生的文件,还需将其反编译成py文件才能得到源码
反编译pyc文件
解出来了一堆pyc文件,pyc是py文件编译后生成的,需要反编译一下
- 首先安装
pip install uncompyle6
,也可从网站下载源码 - 运行命令
uncompyle6 xxxx_extracted\xxxx.pyc
- 如果pyc是python3.8及以下版本,则可直接得到源码文件,否则将得到如下提示
换个方式反编译pyc文件
由于这个exe是python3.9生成的,uncompyle6不支持。只能另觅他法,我们换pycdc再试一下
- 下载pycdc 这是一个c++写的反编译pyc的工具
- 使用cmake配置好pycdc工程,编译得到pycdas.exe pycdc.exe两个程序,拷贝到我们的e:\xxxx目录下,编译好的pycdc
- 运行命令
pycdc xxxx_extracted\xxxx.pyc > xxxx.py
- 如果幸运则直接得到完整python文件,如果pyc内有pycdc不支持的指令,则只能得到部分py代码,并报错
打开xxxx.py看一下
中间代码略
可以看出由于有不支持的指令JUMP_IF_NOT_EXC_MATCH,反编译工作只执行了一部分
到底少了点什么呢?
大杀器–反编译字节码看看
既然不能直接得到py文件,我们使用大杀器吧
-
执行命令
pycdas.exe xxxx.exe_extracted\xxxx.pyc > xxxx.txt
打开xxxx.txt
我们看到已经得到了完整的字节码,LOAD_GLOBAL 读取一个全局变量,类似java字节码的感觉,对照一下左右的代码很容易读懂。
-
随后就需要我们耐心的读xxxx.txt中的字节码,将pycdc生成的xxxx.py中缺少的部分自行补上,
-
最后由于生成的xxxx.py部分语句并不符合语法,需要自己修改一下,再通读一下代码进行修正。
总结
- 我们首先使用DIE 工具探测出exe文件 是pyinstaller生成的
- 随后使用了uncompyle6 尝试反编译,由于uncompyle6不支持python3.9生成的pyc,这一步没有成功
- 随后使用了pycdc尝试反编译,由于碰到了不支持的JUMP_IF_NOT_EXC_MATCH指令,成功了一部分
- 最后使用了大杀器pycdas,得到了字节码,补全了代码(照着字节码看我们自己也能翻译出来python源码)