一、前言

上一节我们知道了pyc文件是python在编译过程中出现的主要中间过程文件。pyc文件是二进制的,可以由python虚拟机直接执行的程序。分析pyc文件的文件结构对于实现python编译与反编译就显得十分重要。

Python代码的编译结果就是PyCodeObject对象。PyCodeObject对象可以由虚拟机加载后直接运行,而pyc文件就是PyCodeObject对象在硬盘上的保存形式。因此我们先分析PyCodeObject对象的结构,随后再涉及pyc文件的二进制结构。

二、PyCodeObject对象结构分析

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;

上面就是PyCodeObject对象一般情况下包含的属性名称及数据类型,每个属性在虚拟机执行pyc文件时都有其作用,随后在编译与反编译的过程中我们会对上述出现的属性一一分析。

三、pyc文件生成

python中使用marshal.dump的方法将PyCodeObject对象转化为对应的二进制文件结构。每个字段在二进制文件中的结构如下图:

byte表示占用1个字节,long表示占用4个字节,bytes表示该字段可能占用1到多个字节。需要说明的是,PyCodeObject对象中的每一个属性及值都会按照一定的顺序表示在二进制文件里。

pyc文件结构主要包括两部分:pyc文件头部表示和PyCodeObject对象部分。上面对PyCodeObject对象的二进制部分已经有了了解,pyc文件头部比较简单,在python2中只占用4个字节包含两个字段magic和mtime,完整的pyc文件结构见下图:

四、实例分析

上面我们对pyc文件结构已经有了理论上的了解,接下来通过一个实例对实际的二进制文件进行分析。

源文件test.py

s = "hello"
def func():
a = 3
print s
func()

通过执行python2 -m py_compile test.py 可以生成编译好的pyc文件test.pyc。

我们使用二进制编辑器打开test.pyc

  • pyc文件头部

    • 前4个字节:03f3 0d0a,表示python版本
    • 5-8个字节:0e6b 905d,表示pyc文件修改时间
  • PyCodeObject对象二进制编译结果
    • 第9字节:63,TYPE_CODE字段,也就是字符c,值为99,即0x63,表示接下为是一个PyCodeObject对象
  • PyCodeObject对象----全局参数:
    • 然后4个字节是0x00 0000 00,code block的位置参数个数co_argument,这里是0;
    • 再接着4个字节是0x00 0000 00, code block中的局部变量个数co_nlocals,这里是0;
    • 再接着4个字节是0x01 0000 00, code block需要的栈空间co_stacksize,这里是1;
    • 再接着4个字节是0x40 0000 00, co_flags,这里是64;
  • PyCodeObject对象----code block:
    • 1个字节0x73为TYPE_CODE字段, 表示该字段为string格式;
    • 4个字节0x1a00 0000表示code block段的数据部分占用0x1a个字节,即长度为26;
    • 接下来26个字节6400 ...... 6402 0053为该TYPE_CODE字段(数据类型string)部分,也就是pyc文件中包含的字节码指令
  • 再往下的逐个TYPE_CODE字段都是重复结构的,用来表示PyCodeObject对象中的一些其他参数

Python逆向(二)—— pyc文件结构分析的更多相关文章

  1. python中的PYC文件是什么?

    1. Python是一门解释型语言吗? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在.如果是解释型语言 ...

  2. Python逆向(四)—— Python内置模块dis.py源码详解

    一.前言 上一节我们对Python编译及反汇编做了讲解,大家知道dis模块可以将编译好的pyc文件中提取出来的PyCodeObject反汇编为可以阅读字节码形式.本节我们对dis模块中的源码进行详细的 ...

  3. Python之code对象与pyc文件(二)

    上一节:Python之code对象与pyc文件(一) 创建pyc文件的具体过程 前面我们提到,Python在通过import或from xxx import xxx时会对module进行动态加载,如果 ...

  4. Python之code对象与pyc文件(三)

    上一节:Python之code对象与pyc文件(二) 向pyc写入字符串 在了解Python如何将字符串写入到pyc文件的机制之前,我们先来了解一下结构体WFILE: marshal.c typede ...

  5. Python之code对象与pyc文件(一)

    Python程序的执行过程 我们都知道,C语言在执行之前需要将源代码编译成可执行的二进制文件,也就是将源代码翻译成机器代码,这种二进制文件一旦生成,即可用于执行.但是,Python是否一样呢?或许很多 ...

  6. 《python解释器源码剖析》第8章--python的字节码与pyc文件

    8.0 序 我们日常会写各种各样的python脚本,在运行的时候只需要输入python xxx.py程序就执行了.那么问题就来了,一个py文件是如何被python变成一系列的机器指令并执行的呢? 8. ...

  7. Python逆向(一)—— 前言及Python运行原理

    一.前言 最近在学习Python逆向相关,涉及到python字节码的阅读,编译及反汇编一些问题.经过长时间的学习有了一些眉目,为了方便大家交流,特地将学习过程整理,形成了这篇专题.专题对python逆 ...

  8. vscode 不显示指定后缀名pyc文件

    不显示python生成的pyc文件 不显示java eclipse编辑器生成的.metadata生成的文件夹 py文件执行后会生成.pyc文件,会影响侧边栏的使用,可以通过如下设置隐藏.pyc等中间文 ...

  9. py 与 pyc 文件

    本文要说明的问题 pyc 文件是什么 pyc 文件的作用 py 与 pyc 文件冲突 pyc 文件是什么 当 py 文件加载后,py 文件被二进制编码成 pyc 文件.py 文件的修改时间被记录到 p ...

随机推荐

  1. Vue传递方法给页面调用

    很多人在使用vue的时候苦于在vue中写方法,但是在外部甚至在另一个js该如何调用呢? 这个方法就是显示了vue的可以传递方法到页面使得页面任何地方都可以调用 前提得引用文件 这个方法一般多用于加载周 ...

  2. System.ArgumentException:路由集合中已存在名为“XXX”的路由。路由名称必须唯一。

    软件环境:Visual Studio 2017 + MVC4 + EF6 问题描述:System.ArgumentException:路由集合中已存在名为“XXX”的路由.路由名称必须唯一. 解决办法 ...

  3. dubbo循序渐进 - nacos安装

    1.安装docker ce yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-r ...

  4. MES应用案例 | 天博集团成功完成数字化转型

    受到智能制造观念和技术的巨大且快速的影响,使得工业特别是汽车行业必须以最快速度赶上这场企业数字化转型的浪潮,唯有实现企业转型升级才能在这场速度战中占得先机.当然关于企业的转型升级,最为重要的是需要打造 ...

  5. orcale的to_number方法

    转自:https://blog.csdn.net/tiantangdizhibuxiang/article/details/81034893 TO_NUMBER函数()是Oracle中常用的类型转换函 ...

  6. Linux-crontab定时执行脚本配置

    crontab是一个可以根据自己配置的命令定时执行脚本的服务 安装crontab(centos) yum install Vixie-cron yum install crontabs vixie-c ...

  7. Office--CVE-2017-11882【远程代码执行】

    Office远程代码执行漏洞现POC样本 最近这段时间CVE-2017-11882挺火的.关于这个漏洞可以看看这里:https://www.77169.com/html/186186.html 今天在 ...

  8. (一)Kubernetes 系统基础

    Kubernetes介绍 什么是Kubernetes? Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署.自动扩缩容.维护等功能. 使用Kubernetes可以: ...

  9. jenkiins 配置邮件发送(四)

    一.默认邮件配置的方法 Jenkins默认的插件只能发送执行失败的job 系统管理-->系统设置-->邮件通知 需要注意的是系统管理员邮箱地址必须要邮箱通知的邮箱一致,否则不会发送成功 在 ...

  10. geany写C语言,printf打印中文时显示乱码

    原因 geany设置了编码格式为utf8 运行时显示出的cmd窗口编码格式为GBK 解决方法 要么修改geany编码,要么修改cmd窗口编码. 修改geany编辑器为GBK编码格式 编辑=>首选 ...