在手动清除可移动 USB 驱动器上损坏的回收站后,我发现我最近执行的几个 Python 文件也损坏了;用编辑器打开它们会显示它们的全部内容都填充了空字节(所有00
s)。我不知道这是怎么发生的,但无论如何,不幸的是,我的最后一次备份要追溯到几周前,所以如果可能的话,我想尝试恢复丢失的源文件。
我在其中找到了相关的.pyc
(日期为损坏前一天)文件.\__pycache__\
,我正在尝试.py
从二进制文件中重建一个人类可读、准备执行的文件,但到目前为止我还没有取得太大的成功。
许多类似的搜索都会找到诸如uncompyle6或decompyle3 之类的工具,但这些工具都不支持 Python 3.10,并且他们的开发人员表示他们也不打算维护它们。
似乎唯一一个与字节码反编译远程相关的工具/包也支持 Python 3.10 是unpyc3 的这个分支,但它似乎在实际代码(或代码对象;我不完全确定)上运行。
希望这个工具是我恢复代码的关键,这就是我自己取得的成就:
from unpyc3 import decompile
import dis, marshal
with open("thermo.cpython-310.pyc", "rb") as f:
f.seek(16) # By all accounts this should be 8 bytes, but 16 is the only way I have successfully been able to read the bytecode
raw = f.read()
code = marshal.loads(raw)
with open("disassembly.txt", "w", encoding="utf-8") as out:
dis.dis(code, file=out)
encoding="utf-8"
因为我的一些变量是Unicode 字符(例如 α、λ、φ 等),所以在过程中的某个地方需要。
这将我认为是一系列 CPythonInstruction
实例写入disassembly.txt
,我在下面复制了其中的一个片段:
2 0 LOAD_CONST 0 (0)
2 LOAD_CONST 1 (None)
4 IMPORT_NAME 0 (Constants)
6 STORE_NAME 0 (Constants)
3 8 LOAD_CONST 0 (0)
10 LOAD_CONST 1 (None)
12 IMPORT_NAME 1 (EOS)
14 STORE_NAME 1 (EOS)
4 16 LOAD_CONST 0 (0)
18 LOAD_CONST 1 (None)
20 IMPORT_NAME 2 (ACM)
22 STORE_NAME 2 (ACM)
7 24 LOAD_CONST 0 (0)
26 LOAD_CONST 2 (('sqrt', 'exp', 'log'))
28 IMPORT_NAME 3 (math)
30 IMPORT_FROM 4 (sqrt)
32 STORE_NAME 4 (sqrt)
34 IMPORT_FROM 5 (exp)
36 STORE_NAME 5 (exp)
38 IMPORT_FROM 6 (log)
40 STORE_NAME 6 (log)
42 POP_TOP
我试图恢复的实际源文件thermo.py
将近 3000 行,所以我不会在这里重现整个输出(我也不认为我可以在任何地方复制,因为它超过了 Pastebin 的 512 kB 的免费限制)。
这似乎是正确的信息,但是一旦我们到达这个与汇编相邻的代码,我的编程经验就完全枯竭了,老实说,我对下一步感到茫然。似乎unpyc3.decompile()
接受 Python module
、 Pythonfunction
或 CPythonPyCodeObject
作为输入,但 unpyc3 的文档不是很详细。
所以我现在的问题是:
如果我上面的编组/反汇编方法是正确的,我不知道如何处理反汇编
Instruction
的 s 以提供给unpyc3.decompile()
.如果上述方法不正确,我不知道该去哪里。
如果有人知道如何解决这个问题(或者我的目标是否真的可以实现),我会很感激任何建议。