反编译导入的模块(例如使用 uncompyle2)
Decompile an imported module (e.g. with uncompyle2)
我的任务是导出从容器加载的导入(编译)模块。
我有一个导入模块的 Py.-Script。使用 print(module1) 后,我可以看到它是一个已编译的 python (pyc) 文件,从存档中加载。由于我无法访问存档,我的想法是导入模块并使用 uncompyle2 对其进行反编译。
这是我的最低代码:
import os, sys
import uncompyle2
import module1
with open("module1.py", "wb") as fileobj:
uncompyle2.uncompyle_file(module1, fileobj)
但是,这打印出我的错误。如果我将 uncompyle 参数中的 module1 替换为实际路径,则不会有任何区别。当 pyc 文件不是从容器中加载而是目录中的单个文件并且它工作时,我成功地尝试了代码片段。
错误:
Traceback (most recent call last):
File "C:\....\run.py", line 64, in <module>
uncompyle2.uncompyle_file(module1, fileobj)
File "C:\....\Python\python-2.7.6\lib\site-packages\uncompyle2\__init__.py", line 124, in uncompyle_file
version, co = _load_module(filename)
File "C:\.....\Python\python-2.7.6\lib\site-packages\uncompyle2\__init__.py", line 67, in _load_module
fp = open(filename, 'rb')
TypeError: coercing to Unicode: need string or buffer, module found
有谁知道我错在哪里?
首先传递文件名字符串,然后传递要写入的文件对象:
with open("out.txt","w") as f:
uncompyle2.uncompyle_file('path_to.pyc',f)
可以看到输出:
with open("/home/padraic/test.pyc","rb") as f:
print(f.read())
with open("out.txt","r+") as f:
uncompyle2.uncompyle_file('/home/padraic/test.pyc',f)
f.seek(0)
print(f.read())
输出:
�
d�ZdS(cCs dGHdS(Nshello world((((stest.pytfoosN(R(((stest.pyt<module>s
#Embedded file name: test.py
def foo():
print 'hello world'
你最初的假设是错误的:
As I cannot access the archive, my idea was to import the module and
have it decompiled with uncompyle2.
很遗憾,无法反编译已加载的模块。加载的 Python 模块不是 .pyc
文件在磁盘上的镜像。相反,它是 对象 的集合,作为执行 .pyc
中代码的副作用而创建。一旦代码被执行,它的字节码就被丢弃并且它(在一般情况下)不能被重建。
例如,考虑以下 Python 模块:
import gtk
w = gtk.Window(gtk.WINDOW_TOPLEVEL)
w.add(gtk.Label("A quick brown fox jumped over the lazy dog"))
w.show_all()
在碰巧 运行 一个 GTK main loop 的应用程序中导入此模块将弹出一个 window 和一些文本作为副作用。该模块将有一个包含两个条目的字典,gtk
指向 gtk
模块,w
指向一个已经创建的 GTK window。那里没有提示如何创建 another GTK window 之类的,也没有提示如何创建另一个这样的模块。 (请记住,创建的对象可能非常复杂,而且它的创建可能是一个非常复杂的过程。)
你可能会问,那么,如果是这样,那么pyc
文件的内容是什么?第一次是怎么加载的?答案是 pyc
文件包含模块中字节编译代码的磁盘再现,准备执行。创建一个 pyc
文件大致相当于做这样的事情:
import marshal
def make_pyc(source_code, filename):
compiled = compile(source_code, filename, "exec")
serialized = marshal.dumps(compiled)
with open(filename, "wb") as out:
out.write(serialized)
# for example:
make_pyc("import gtk\nw = gtk.Window(gtk.WINDOW_TOPLEVEL)...",
"somefile.pyc", "exec")
另一方面,加载已编译的模块大约等同于:
import sys, marshal, imp
def load_pyc(modname):
with open(modname + ".pyc", "rb") as in_:
serialized = in_.read()
compiled = marshal.loads(serialized)
module = sys.modules[modname] = imp.new_module(modname)
exec compiled in module.__dict__
load_pyc("somefile")
请注意,一旦使用 exec
语句执行了代码,字符串和反序列化的字节码将不再被使用,并将被垃圾收集器清除。已加载 pyc
的唯一剩余影响是存在具有活动函数的新模块 类 和其他无法序列化的对象,例如对打开文件的引用、网络连接、 OpenGL 画布或 GTK windows.
像uncompyle2
这样的模块所做的是compile
函数的反函数。您必须拥有模块的实际 code(序列化为 pyc
文件或反序列化代码对象,如上述片段中的 compiled
变量), uncompyle2
将从中产生对原始来源的相当忠实的表示。
我的任务是导出从容器加载的导入(编译)模块。
我有一个导入模块的 Py.-Script。使用 print(module1) 后,我可以看到它是一个已编译的 python (pyc) 文件,从存档中加载。由于我无法访问存档,我的想法是导入模块并使用 uncompyle2 对其进行反编译。
这是我的最低代码:
import os, sys
import uncompyle2
import module1
with open("module1.py", "wb") as fileobj:
uncompyle2.uncompyle_file(module1, fileobj)
但是,这打印出我的错误。如果我将 uncompyle 参数中的 module1 替换为实际路径,则不会有任何区别。当 pyc 文件不是从容器中加载而是目录中的单个文件并且它工作时,我成功地尝试了代码片段。
错误:
Traceback (most recent call last):
File "C:\....\run.py", line 64, in <module>
uncompyle2.uncompyle_file(module1, fileobj)
File "C:\....\Python\python-2.7.6\lib\site-packages\uncompyle2\__init__.py", line 124, in uncompyle_file
version, co = _load_module(filename)
File "C:\.....\Python\python-2.7.6\lib\site-packages\uncompyle2\__init__.py", line 67, in _load_module
fp = open(filename, 'rb')
TypeError: coercing to Unicode: need string or buffer, module found
有谁知道我错在哪里?
首先传递文件名字符串,然后传递要写入的文件对象:
with open("out.txt","w") as f:
uncompyle2.uncompyle_file('path_to.pyc',f)
可以看到输出:
with open("/home/padraic/test.pyc","rb") as f:
print(f.read())
with open("out.txt","r+") as f:
uncompyle2.uncompyle_file('/home/padraic/test.pyc',f)
f.seek(0)
print(f.read())
输出:
�
d�ZdS(cCs dGHdS(Nshello world((((stest.pytfoosN(R(((stest.pyt<module>s
#Embedded file name: test.py
def foo():
print 'hello world'
你最初的假设是错误的:
As I cannot access the archive, my idea was to import the module and have it decompiled with uncompyle2.
很遗憾,无法反编译已加载的模块。加载的 Python 模块不是 .pyc
文件在磁盘上的镜像。相反,它是 对象 的集合,作为执行 .pyc
中代码的副作用而创建。一旦代码被执行,它的字节码就被丢弃并且它(在一般情况下)不能被重建。
例如,考虑以下 Python 模块:
import gtk
w = gtk.Window(gtk.WINDOW_TOPLEVEL)
w.add(gtk.Label("A quick brown fox jumped over the lazy dog"))
w.show_all()
在碰巧 运行 一个 GTK main loop 的应用程序中导入此模块将弹出一个 window 和一些文本作为副作用。该模块将有一个包含两个条目的字典,gtk
指向 gtk
模块,w
指向一个已经创建的 GTK window。那里没有提示如何创建 another GTK window 之类的,也没有提示如何创建另一个这样的模块。 (请记住,创建的对象可能非常复杂,而且它的创建可能是一个非常复杂的过程。)
你可能会问,那么,如果是这样,那么pyc
文件的内容是什么?第一次是怎么加载的?答案是 pyc
文件包含模块中字节编译代码的磁盘再现,准备执行。创建一个 pyc
文件大致相当于做这样的事情:
import marshal
def make_pyc(source_code, filename):
compiled = compile(source_code, filename, "exec")
serialized = marshal.dumps(compiled)
with open(filename, "wb") as out:
out.write(serialized)
# for example:
make_pyc("import gtk\nw = gtk.Window(gtk.WINDOW_TOPLEVEL)...",
"somefile.pyc", "exec")
另一方面,加载已编译的模块大约等同于:
import sys, marshal, imp
def load_pyc(modname):
with open(modname + ".pyc", "rb") as in_:
serialized = in_.read()
compiled = marshal.loads(serialized)
module = sys.modules[modname] = imp.new_module(modname)
exec compiled in module.__dict__
load_pyc("somefile")
请注意,一旦使用 exec
语句执行了代码,字符串和反序列化的字节码将不再被使用,并将被垃圾收集器清除。已加载 pyc
的唯一剩余影响是存在具有活动函数的新模块 类 和其他无法序列化的对象,例如对打开文件的引用、网络连接、 OpenGL 画布或 GTK windows.
像uncompyle2
这样的模块所做的是compile
函数的反函数。您必须拥有模块的实际 code(序列化为 pyc
文件或反序列化代码对象,如上述片段中的 compiled
变量), uncompyle2
将从中产生对原始来源的相当忠实的表示。