首先,项目必须在运行,代码必须驻留在内存中
安装GDB(pyrasite需要)
apt-get update && apt-get install gdb
安装pyrasite,它让你能够跟正在运行的进程通信
pip install pyrasite
安装uncomplyle6,它能让你获取内存中存在的对象的源代码
pip install uncompyle6
找到正在运行的进程的PID
ps aux | grep python
使用pyrasite附着一个交互提示符
pyrasite-shell <PID>
现在你在交互终端中了,导入你要恢复的代码
>>> from my_package import my_module
找出你需要恢复的函数和类
>>> dir(my_module)
['MyClass', 'my_function']
把函数源代码提取出来
>>> import uncompyle6
>>> import sys
>>> uncompyle6.main.uncompyle(
2.7, my_module.my_function.func_code, sys.stdout
)
# uncompyle6 version 2.9.10
# Python bytecode 2.7
# Decompiled from: Python 2.7.12 (default, Nov 19 2016, 06:48:10)
# [GCC 5.4.0 20160609]
# Embedded file name: /srv/my_package/my_module.py
function_body = "appears here"
对于类,你需要逐个提取每一个方法的文档
>>> uncompyle6.main.uncompyle(
2.7, my_module.MyClass.my_method.im_func.func_code, sys.stdout
)
# uncompyle6 version 2.9.10
# Python bytecode 2.7
# Decompiled from: Python 2.7.12 (default, Nov 19 2016, 06:48:10)
# [GCC 5.4.0 20160609]
# Embedded file name: /srv/my_package/my_module.py
class_method_body = "appears here"
举例说明:
假如现在已经用如下命令进入到了交互模式(注意:你要首先cd到你项目所在的目录)
pyrasite-shell <PID>
我的代码有一个xmlparser模块,这个模块代码里面有个XmParser类,我现在想恢复这个类里面的方法
>>> import xmlparser
>>> dir(xmlparser.XmlParser)
打印的结果为:
['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', 'getContentAppendStr', 'getSummarPicStr', 'handleContent', 'handleSpecialModuleActor', 'handleSpecialModuleConcert', 'handleSpecialModuleMovieAndTv', 'handleSpecialModuleMusic', 'handleSpecialModulePlot', 'handleSpecialModuleRole', 'handleSpecialModuleStaff', 'handleSpecialModuleVariety', 'handleSpecialModules', 'obtainAbstract', 'obtainAmbiTitle', 'obtainBaseinfo', 'obtainContent', 'obtainKeywords', 'obtainLemmaStatistic', 'obtainPolysemantList', 'obtainReference', 'obtainTags', 'obtainTitle', 'removeTagWithOutSup', 'retainSupAndBr']
可以看到,这是这个类里面的所有方法,接下来就可以反编译得到指定方法的代码了,比如我想得到obtainAmbiTitle的代码
uncompyle6.main.decompile(2.7, xmlparser.XmlParser.obtainAmbi.func_code, sys.stdout)
上述命令的执行结果为:
# uncompyle6 version 2.15.0
# Python bytecode 2.7
# Decompiled from: Python 2.7.5 (default, Nov 6 2016, 00:28:07)
# [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
# Embedded file name: /search/data2/dlj/work/baiduHtmlExtract-dev/xmlparser.py
ul = doc.select('ul.polysemantList-wrapper.cmn-clearfix')
if ul:
sele = ul[0].select('span.selected')
if sele:
return RuleUtils.standardHtmlEscape(sele[0].text.strip())<uncompyle6.semantics.pysource.SourceWalker object at 0x1f2d790>
ul = doc.select('ul.polysemantList-wrapper.cmn-clearfix')
if ul:
sele = ul[0].select('span.selected')
if sele:
return RuleUtils.standardHtmlEscape(sele[0].text.strip())<uncompyle6.semantics.pysource.SourceWalker object at 0x1f2d790>
如上黑体部分就是代码了
有的时候我们想得到的不是类的方法,而是某个变量,那么可以直接跟pdb的时候一样,比如我想知道xmlparser模块中的变量escapeRex的值,可以如下:
>>>import xmlparser
>>>print xmlparser.excapeRex
其实就跟我们在pdb中调试的时候获取变量的值有点类似