首页 > 编程知识 正文

如何把pyc反编译成py,python引入模块中的函数

时间:2023-05-05 19:04:43 阅读:22607 作者:4611

创建pyc文件的具体步骤

如上所述,Python在通过import或from xxx import xxx时动态加载模块,如果找不到相应的pyc或dll文件,则基于py文件创建pyc文件。 如上所述,pyc文件包含PyCodeObject对象

import.c

静态语音识别

write _ compiled _ module (pycodeobject * co,char *cpathname,time_t mtime ) )。

{

FILE *fp

//独占打开文件

FP=open_exclusive(cpathname;

//1写入python的幻灯片编号

py marshal _ writelongtofile (pyc _ magic,fp,Py_MARSHAL_VERSION );

//2写入pycodeobject对象

py marshal _ writeobject to file ((py object * ) co,fp,Py_MARSHAL_VERSION );

//3写入时间信息

py marshal _ writelongtofile ((long ) mtime,fp,Py_MARSHAL_VERSION );

闪存(FP;

流量(FP );

}

write_compiled_module的代码稍微缩小了一些,只留下了最值得注意的部分。 请注意,pyc文件实际上包含三个单独的信息: Python幻灯片编号、PyCodeObject对象和pyc文件的创建时间

在1中,Python将名为pyc_magic的值写入文件的开头。 pyc_magic是整数值,根据版本定义不同的magic number。 将pyc文件加载到Python时,首先检查pyc文件中的pyc_magic和当前pyc,因为不同版本的Python字节码指令可能不同。 一些旧指令会被新指令取代或添加新指令,这是导致Python不兼容的问题

在import.c中,源代码注释中可以找到从Python1.5到Python2.5的所有版本的幻灯片编号。 让我们看看Python2.5中定义的幻灯片编号:

import.c

#definemagic(62131|) (long )r'16 )|() long ) (n'24 ) )

静态long pyc _ magic=magic;

在pyc中,在3个位置向pyc文件写入时刻信息的动作完成了。 在pyc文件中包含时间信息后,Python会将pyc与最新的py文件进行比较,如果发现pyc的生成时间早于py文件的修改时间,则会修改py文件并重新编译pyc文件

在上面的代码的两个位置中,Python调用PyMarshal_WriteObjectToFile方法,将内存中的PyCodeObject对象写入pyc文件,然后将write _ compiled _ moded

现在,让我们来看看名为PyMarshal_WriteObjectToFile的方法

marshal.c

voidpymarshal _ writeobject to file (py object * x,FILE *fp,int version ) )。

{

WFILE wf;

wf.fp=fp;

wf.error=0;

wf.depth=0;

wf.strings=(版本0? pydict_new(:null;

wf.version=version;

w_object(x,wf );

py_xdecref(wf.strings;

}

在名为PyMarshal_WriteObjectToFile的方法中调用名为w_object的方法,将对象实际写入文件

marshal.c

staticvoidw_object(pyobject*v,WFILE *p ) )。

{

.

elseif(pytuple_check ) v ) }

.

}

elseif(pylist_check(v ) ) ) )

.

}

else if (PyDict_Check(v)) {

……

}

……

else if (PyCode_Check(v)) {

PyCodeObject *co = (PyCodeObject *)v;

w_byte(TYPE_CODE, p);

w_long(co->co_argcount, p);

w_long(co->co_nlocals, p);

w_long(co->co_stacksize, p);

w_long(co->co_flags, p);

w_object(co->co_code, p);

w_object(co->co_consts, p);

w_object(co->co_names, p);

w_object(co->co_varnames, p);

w_object(co->co_freevars, p);

w_object(co->co_cellvars, p);

w_object(co->co_filename, p);

w_object(co->co_name, p);

w_long(co->co_firstlineno, p);

w_object(co->co_lnotab, p);

}

……

}

从上面的代码我们可以看到,在w_object中,会遍历PyCodeObject中的各个域,将这些域一次写入。

当w_object面对一个PyListObject对象时,会有什么动作?

marshal.c

else if (PyList_Check(v)) {

w_byte(TYPE_LIST, p);

n = PyList_GET_SIZE(v);

w_long((long)n, p);

for (i = 0; i < n; i++) {

w_object(PyList_GET_ITEM(v, i), p);

}

}

如同前面对PyCodeObject一样,w_object还是遍历,将PyListObject对象中的每一个元素一次写入到pyc文件中

我们稍微浏览一遍w_object这个方法,会发现在写入任何一个对象之前,,都会先写入一个TYPE_LIST或者TYPE_CODE这样的类型标识,这些标识对于pyc文件再次加载具有至关重要的作用。如果我们仅仅是将对象中数值和字符串信息写入到pyc文件,如果没有对应的类型信息,我们很难将这些数值或者字符串恢复到以前在内存中所对应的对象。而在Python加载pyc文件时,发现了类型信息,就预示着上一个对象结束,新的对象开始,而且也知道新对象是什么类型的对象。这样,当Python加载pyc文件时,加载器才能知道在什么时候应该进行什么样的加载操作

类型标识在Python中的定义:

marshal.c

#define TYPE_NULL'0'

#define TYPE_NONE'N'

#define TYPE_FALSE'F'

#define TYPE_TRUE'T'

#define TYPE_STOPITER'S'

#define TYPE_ELLIPSIS '.'

#define TYPE_INT'i'

#define TYPE_INT64'I'

#define TYPE_FLOAT'f'

#define TYPE_BINARY_FLOAT'g'

#define TYPE_COMPLEX'x'

#define TYPE_BINARY_COMPLEX'y'

#define TYPE_LONG'l'

#define TYPE_STRING's'

#define TYPE_INTERNED't'

#define TYPE_STRINGREF'R'

#define TYPE_TUPLE'('

#define TYPE_LIST'['

#define TYPE_DICT'{'

#define TYPE_CODE'c'

#define TYPE_UNICODE'u'

#define TYPE_UNKNOWN'?'

#define TYPE_SET'

#define TYPE_FROZENSET '>'

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。