复现创客re-pyc题,理解python编译原理
pyc文件产生
- Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。;
- Python是解释型语言,没有严格意义上的编译和汇编过程。但是一般编写好的.py源文件,由python解释器翻译成以.pyc为结尾的字节码文件,该文件可由python虚拟机直接运行;
3.pyc的内容,是跟python的版本相关的,不同版本编译后的pyc文件是不同的,2.5编译的pyc文件,2.4版本的python是无法执行的; - 根据python源码中提供的opcode,可以根据pyc文件反编译出py文件源码;
- 加载模块时,如果同时存在.py和.pyc,Python会尝试使用.pyc,如果.pyc的编译时间早于.py的修改时间,则重新编译.py并更新.pyc;
PyCodeObject结构
Python代码的编译结果就是PyCodeObject对象。PyCodeObject对象可以由虚拟机加载后直接运行,而pyc文件就是PyCodeObject对象在硬盘上的保存形式。
PyCodeObject对象一般包含的属性名称及数据类型如下,每个属性在虚拟机执行pyc文件时都有其作用。
typedef struct {
PyObject_HEAD
int co_argcount; /* 位置参数个数 */
int co_nlocals; /* 局部变量个数 */
int co_stacksize; /* 栈大小 */
int co_flags;
PyObject *co_code; /* 字节码指令序列 */
PyObject *co_consts; /* 所有常量集合 */
PyObject *co_names; /* 所有符号名称集合 */
PyObject *co_varnames; /* 局部变量名称集合 */
PyObject *co_freevars; /* 闭包用的的变量名集合 */
PyObject *co_cellvars; /* 内部嵌套函数引用的变量名集合 */
/* The rest doesn’t count for hash/cmp */
PyObject *co_filename; /* 代码所在文件名 */
PyObject *co_name; /* 模块名|函数名|类名 */
int co_firstlineno; /* 代码块在文件中的起始行号 */
PyObject *co_lnotab; /* 字节码指令和行号的对应关系 */
void *co_zombieframe; /* for optimization only (see frameobject.c) */
} PyCodeObject;
python中使用marshal.dump的方法将PyCodeObject对象转化为对应的二进制文件结构。PyCodeObject对象中的每一个属性及值都会按照一定的顺序表示在二进制文件里。
PyCodeObject每个字段在二进制文件中的结构如图1:
byte表示占用1个字节,long表示占用4个字节,bytes表示该字段可能占用1到多个字节。
pyc文件结构主要包括两部分:pyc文件头部表示和PyCodeObject对象部分。上述即PyCodeObject对象的二进制部分,pyc文件头部较简单,在python2中只占用4个字节包含两个字段magic和mtime,完整的pyc文件结构见图2:
python提供内置的类库实现把py文件编译为pyc文件, py_compile 模块。
```javascript
# -*- coding: cp936 -*-
#python 27
#办法一:IDLE(实现见图3)
import py_compile #加r前缀进行转义
py_compile.compile(r'D:\test.py') #py文件完整的路径.
办法二:#cmd命令符下操作步骤
1、打开cmd,切换到 cd c:\\python34
2、运行
1)python -m py_compile D:\test.py #跟随完整路径
2)python -m py_compile /root/src/{file1,file2}.py #这是同时转换多个文件
3、会在需转译文件的目录下生成一个“__pycache__”目录/test.cpython-34.pyc文件
#-m 相当于脚本中的import,这里的-m py_compile 相当于上面的 import py_compile
解题
打开题目pyc文件,依照上述分析文件结构,找到PyCodeObjectData
>>> f = open('8.pyc','rb')
>>> b_data = f.read()
>>> PyCodeObjectData = b_data[8:]
>>> b_data
'\x03\xf3\r\n[9\xd6_c\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00@\x00\x00\x00s)\x00\x00\x00q\x06\x00d\x90\x00d\x00\x00\x84\x00\x00Z\x00\x00e\x01\x00d\x01\x00k\x02\x00r\x1f\x00e\x00\x00\x83\x00\x00\x01n\x00\x00d\x02\x00S(\x03\x00\x00\x00c\x00\x00\x00\x00\x04\x00\x00\x00+\x00\x00\x00C\x00\x00\x00sD\x01\x00\x00t\x00\x00d\x01\x00\x83\x01\x00}\x00\x00d\x02\x00g\x01\x00d\x03\x00\x14}\x01\x00d\x04\x00d\x05\x00d\x06\x00d\x07\x00d\x08\x00d\t\x00d\n\x00d\x0b\x00d\x0b\x00d\x0c\x00d\r\x00d\x0e\x00d\x0c\x00d\x0f\x00d\x10\x00d\x11\x00d\x0f\x00d\x12\x00d\r\x00d\x10\x00d\n\x00d\x0e\x00d\x13\x00d\x0e\x00d\x10\x00d\x13\x00d\r\x00d\x14\x00d\x0c\x00d\x10\x00d\x15\x00d\n\x00d\x12\x00d\x14\x00d\x11\x00d\x16\x00d\x17\x00d\x18\x00d\x14\x00d\x14\x00d\x17\x00d\x0b\x00d\x19\x00g+\x00}\x02\x00t\x01\x00|\x00\x00\x83\x01\x00d\x03\x00k\x03\x00r\xc1\x00d\x1a\x00GHt\x02\x00\x83\x00\x00\x01n\x00\x00xw\x00t\x03\x00t\x01\x00|\x00\x00\x83\x01\x00\x83\x01\x00D]c\x00}\x03\x00t\x04\x00|\x00\x00|\x03\x00\x19\x83\x01\x00d\x1b\x00A|\x01\x00|\x03\x00<|\x01\x00|\x03\x00\x19d\x1c\x00?|\x01\x00|\x03\x00\x19d\x1c\x00>Ad\x1d\x00@|\x01\x00|\x03\x00<|\x01\x00|\x03\x00\x19|\x02\x00|\x03\x00\x19k\x03\x00r\xd4\x00d\x1e\x00GHt\x02\x00\x83\x00\x00\x01q\xd4\x00q\xd4\x00Wd\x1f\x00GHd\x00\x00S( \x00\x00\x00Ns\x14\x00\x00\x00plz input your flag:i\x00\x00\x00\x00i+\x00\x00\x00i\x87\x00\x00\x00i\x97\x00\x00\x00i\x17\x00\x00\x00if\x00\x00\x00iG\x00\x00\x00i\x94\x00\x00\x00i`\x00\x00\x00iP\x00\x00\x00i \x00\x00\x00i\x10\x00\x00\x00i\x05\x00\x00\x00ie\x00\x00\x00i\xf1\x00\x00\x00i\xa0\x00\x00\x00ip\x00\x00\x00i\xb0\x00\x00\x00iE\x00\x00\x00i5\x00\x00\x00i\x15\x00\x00\x00iu\x00\x00\x00i0\x00\x00\x00i\xf4\x00\x00\x00t\x05\x00\x00\x00errori2\x00\x00\x00i\x04\x00\x00\x00i\xff\x00\x00\x00t\x05\x00\x00\x00wrongt\x04\x00\x00\x00true(\x05\x00\x00\x00t\t\x00\x00\x00raw_inputt\x03\x00\x00\x00lent\x04\x00\x00\x00exitt\x05\x00\x00\x00ranget\x03\x00\x00\x00ord(\x04\x00\x00\x00t\x01\x00\x00\x00at\x04\x00\x00\x00tempt\x06\x00\x00\x00resultt\x01