pycdc:把 Python 字节码翻回源码的工具
手上只有 .pyc 文件时,最直接的需求通常不是'看懂字节码',而是先把源码尽量还原出来。pycdc 就是干这个的:它把 Python 字节码反编译成可读的 Python 源码,覆盖的版本范围很宽,从 Python 1.0 一直到 3.13。
这类工具里,pycdc 的一个特点是它不是单纯把指令逐行翻译,而是尽量按语法结构重建代码,所以在函数、类、控制流这些地方,结果通常比'字节码直译'顺眼得多。代价也很现实:复杂场景下不一定能 100% 还原,尤其是控制流绕得比较深的时候,还是要配合反汇编结果看。
为什么我会先看 pycdc
如果只是想快速确认一个 .pyc 里到底写了什么,pycdc 比很多同类工具省事。它的支持范围广,输出也更接近正常 Python 代码,适合先把问题缩小,再决定要不要手工补细节。
| 功能特性 | pycdc | 其他工具 |
|---|---|---|
| 版本支持范围 | Python 1.0-3.13 | 通常只支持特定版本 |
| 还原精度 | 基于 AST 语法树重构 | 简单的指令翻译 |
| 输出格式 | 完整的 Python 源代码 | 仅字节码或简化代码 |
pycdc 的项目是用 C++ 写的,结构也比较清楚,大致可以理解成三层:先读字节码,再重建语法树,最后生成源码。这个分层思路不花哨,但好维护,碰到新版本字节码时也方便往里补。
编译和使用
先把仓库拉下来:
git clone https://github.com/zrax/pycdc cd pycdc
然后编译:
cmake -DCMAKE_BUILD_TYPE=Release .
make -j$(nproc)
编译完一般会得到两个可执行文件:
pycdc:反编译器pycdas:反汇编器
最常见的用法也很直接。面对一个 example.pyc,直接跑:
./pycdc example.pyc
它会尝试识别字节码版本并输出源码。对于普通函数、类定义、装饰器这类结构,效果通常够用;但如果代码里有比较绕的异步流程或者复杂跳转,就别指望完全'无损'了,至少要拿 pycdas 看一眼底层指令。
pycdas 和 pycdc 怎么配合
这两个工具最好一起用。pycdas 更像放大镜,能看到字节码指令和操作数;pycdc 则负责把结果尽量拼回源码。
pycdas:适合看虚拟机层面的执行细节pycdc:适合拿到可读代码,再做人工确认
如果你在处理不同 Python 版本的字节码,最好把版本参数带上。仓库里不同版本的实现文件放在 bytes/ 目录下,Python 2.x 和 3.x 都有对应的解析逻辑。
./pycdc -v 2.7 legacy_code.pyc
./pycdc -v 3.9 modern_app.pyc
这个参数别省。版本猜错了,输出就可能看着像'能跑',实际上细节全偏。
常见场景
恢复丢失的源码时,pycdc 的价值最直接。哪怕不能 100% 还原,函数结构、类继承、装饰器这些大框架通常还能保住,后续补代码也有抓手。

