本文目录:

最近遇到一个用py写的小工具(123盘不限每日下载流量),只有.exe可执行文件,想看看底层的API调用逻辑,于是顺手做了一次反编译

本教程使用的反编译工具仅支持Python3.9及以上版本用pyinstaller打包的程序,就以目前较新的Python 3.12为例,记录一下从.exe.py源码的逆向扒过程

准备工作

在开始之前,你需要准备好以下工具链:

  1. Linux 环境:拥有gcccmake编译环境(虽然win的MSVC也能编译,但是我不建议,win的开发环境太难说了)
  2. 一个比较好的ai(ds、gemini、gpt):用于最后反编译出的残缺代码的补全和修复

提取PyInstaller打包的EXE中的字节码

PyInstaller其实就是把py解释器、依赖库和脚本这些打包成了一个自解压的压缩包,首先要用pyinstxtractor.py把它解开

python pyinstxtractor.py test.exe

e8e857bf.png
这里有一个坑点:
必须使用和目标程序打包时相同的Python版本 来运行这个提取脚本
如果你用Python3.10去解包一个用Python3.12打包的程序,脚本会弹出警告[!] Skipping pyz extraction,因为最核心的业务代码(保存在 PYZ-00.pyz 中)因为底层marshal格式不兼容,根本没有被解开

如果提取顺利,你会得到一个 xxx.exe_extracted 文件夹,然后就可以去看下一步了
97d0d661.png

寻找主程序与修复Magic Number

解包出来的目录中,有很多以pyi_开头的文件,这些是PyInstaller的引导装载程序,不用管。你的反编译目标通常是和软件同名的 .pyc 文件,或者看起来像入口脚本的名字(我这次的是 android.pyc

魔数问题高版本的pycdc也许是解决好了,我这里不用做什么处理

在 Manjaro 下编译 pycdc 并执行反编译

面对Python3.12这种高版本,老牌的uncompyle6早就全军覆没了。我们现在唯一能指望的是C++编写的pycdc(Decompyle++)

在终端下把它Clone下来并编译:

git clone https://github.com/zrax/pycdc.git
cd pycdc-master
cmake .
make

A2B730F82.png
编译完成后,同目录下会生成pycdc可执行文件。拿着我们刚才在Windows下修好魔数的.pyc文件喂给它:
ae73959a.png

./pycdc ../pan.exe_extracted/android.pyc > source_code.py

830c7b67.png

把残缺的代码丢给ai进行逻辑重建

打开生成的source_code.py,你会发现对于Python 3.12,pycdc目前的支持依然是个半残状态。代码里大部分地方都有这注释:
# WARNING: Decompyle incomplete

此时的反编译产物通常是一个半成品骨架:

  • 控制流丢失while 循环可能被错误解析成了 if
  • 对象丢失:很多链式调用会变成 None.json()None.headers
  • 上下文管理器断层with open(...) 这种涉及文件流读写的核心逻辑大概率会从中间直接断掉。

面对几百行残缺的代码,如果手动去推导底层汇编还原逻辑,那是纯纯的体力活,这时候就该让ai登场了

你可以直接把残缺的代码片段复制给你常用的 AI 助手(比如我平时写代码用的那些大模型),并附上提示词:

这是一段用pycdc反编译不完整的Python3.12代码,请修复成一个可以直接运行的完整Python脚本
fec07fd2.png
经过ai修复后应该就能正常跑起来,我这里使用Gemini修复后是可以了
edb994db.png

总结

虽然高版本Python的反编译不能做到100%完美无损还原,但通过 pyinstxtractor 提取 + pycdc 转换结构 + ai补全逻辑 这套组合拳,逆向出核心的 API 接口和数据结构已经是轻而易举的事。

如果你要我反编译后的文件请在这里下载:https://fl.1p.hk:12229/download/sharefile/123pan.zip