Python - 浅谈Python的编译与反编译

1 - Python编译过程涉及的文件

py

源代码文件,由python.exe解释,可在控制台下运行,可用文本编辑器进行编辑;

pyc

源代码文件经过编译后生成的二进制文件,无法用文本编辑器进行编辑;
执行一个.py文件后,并不会自动生成对应的.pyc文件,需要指定触发Python来创建pyc文件;
- pyc是由py文件经过编译后生成的二进制字节码(byte code)文件;
- pyc文件的加载速度比py文件快;
- pyc文件是一种跨平台的字节码,由python的虚拟机来执行;
- pyc文件的内容跟python版本相关,不同的python版本编译生成不同的pyc文件,只能在相同版本环境下执行;

pyo

源代码文件经过优化编译后生成的文件,无法用文本编辑器进行编辑;
Python3.5之后,不再使用.pyo文件名,而是使用类似“xxx.opt-n.pyc的文件名;

pyd

是python的动态链接库;
动态链接库(DLL)文件是一种可执行文件,允许程序共享执行特殊任务所必需的代码和其他资源;
pyd文件虽然是作为python的动态模块,但实质上还是DLL文件,只是后缀改为pyd;
一般是用C、C++、D语言按照一定的格式编写;
参考信息:https://docs.python.org/3/faq/windows.html?highlight=pyd#is-a-pyd-file-the-same-as-a-dll

pyz

从Python 3.5开始,定义了.pyz和.pyzw分别作为“Python Zip应用”和“Windows下Python Zip应用”的扩展名。
新增了内置zipapp模块来进行简单的管理,可以用Zip打包Python程序到一个可执行.pyz文件。
- zipapp — Manage executable python zip archives
- https://docs.python.org/3/library/zipapp.html
详细内容请见PEP441(https://www.python.org/dev/peps/pep-0441/)

2 - 生成pyc文件

执行一个.py文件后,并不会自动生成对应的.pyc文件,需要指定触发Python来创建pyc文件。

可以利用Python的import机制创建pyc文件:

  • 内置的py_compile模块可以把py文件编译为pyc或pyo文件;
  • 内置的compileall模块可以把整个目录中的py文件编译为pyc或pyo文件;

生成pyc文件的过程:

Python在执行import语句时(例如“import abc”),将会到已设定的path中寻找abc.pyc或abc.dll文件。
如果只是发现了abc.py,那么Python会首先将abc.py编译成相应的PyCodeObject中间结果,然后创建abc.pyc文件,并将中间结果写入该文件。
然后,Python会import这个abc.pyc文件,实际上也就是将abc.pyc文件中的PyCodeObject重新在内存中复制出来。

生成pyc文件的方法:

命令形式:

python -m py_compile file.py  # 生成单个pyc文件
python -m py_compile /dir/{file1,file2}.py  # 生成多个pyc文件
python -m compileall /dir/  # 生成目录下所有py文件对应的pyc文件

脚本形式:compile模块的compile函数

import py_compile  # 相当于命令行中的“-m py_compile”
py_compile.compile(‘py file path‘)

脚本形式:compileall模块的compile_dir函数

import compileall
compileall.compile_dir("py files dir")

生成pyc文件示例:

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ ls -l
total 2
-rw-r--r-- 1 anliven 197121 50 3月   7 22:55 sample.py
-rw-r--r-- 1 anliven 197121 49 3月   7 23:40 sample2.py

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ cat sample.py
# -*- coding: utf-8 -*-
print("Hello Python !")

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ cat sample2.py
# -*- coding: utf-8 -*-
print("Hello World !")

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ python -m compileall ./
Listing ‘./‘...
Compiling ‘./sample.py‘...
Compiling ‘./sample2.py‘...

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ ls -l
total 6
drwxr-xr-x 1 anliven 197121  0 3月   7 23:42 __pycache__/
-rw-r--r-- 1 anliven 197121 50 3月   7 22:55 sample.py
-rw-r--r-- 1 anliven 197121 49 3月   7 23:40 sample2.py

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ ls -l __pycache__/
total 2
-rw-r--r-- 1 anliven 197121 122 3月   7 23:41 sample.cpython-36.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:41 sample2.cpython-36.pyc

3 - 生成pyo文件

与生成pyc文件类似,但要额外使用-O和-OO选项来生成pyo文件。

但在Python3.5之后,不再使用.pyo文件名,而是生成文件名类似“xxx.opt-n.pyc的文件。

命令示例:

python -O -m py_compile file.py
python -O -m py_compile /dir/{file1,file2}.py
python -O -m compileall /dir/

示例:python3.6生成pyo文件

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ python -O -m compileall ./
Listing ‘./‘...
Compiling ‘./sample.py‘...
Compiling ‘./sample2.py‘...

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ ls -l __pycache__/
total 4
-rw-r--r-- 1 anliven 197121 122 3月   7 23:42 sample.cpython-36.opt-1.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:41 sample.cpython-36.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:42 sample2.cpython-36.opt-1.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:41 sample2.cpython-36.pyc

示例:python2.7生成pyo文件

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ ls -l
total 6
drwxr-xr-x 1 anliven 197121  0 3月   7 23:42 __pycache__/
-rw-r--r-- 1 anliven 197121 50 3月   7 22:55 sample.py
-rw-r--r-- 1 anliven 197121 49 3月   7 23:40 sample2.py

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ py -2 -O -m compileall ./
Listing ./ ...
Listing ./__pycache__ ...
Compiling ./sample.py ...
Compiling ./sample2.py ...

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ ls -l
total 8
drwxr-xr-x 1 anliven 197121   0 3月   7 23:42 __pycache__/
-rw-r--r-- 1 anliven 197121  50 3月   7 22:55 sample.py
-rw-r--r-- 1 anliven 197121 122 3月   7 23:45 sample.pyo
-rw-r--r-- 1 anliven 197121  49 3月   7 23:40 sample2.py
-rw-r--r-- 1 anliven 197121 122 3月   7 23:45 sample2.pyo

4 - 运行pyc或pyo文件

运行pyc文件

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$ python sample.cpython-36.pyc
Hello Python !

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$ python sample2.cpython-36.pyc
Hello World !

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$ python sample.cpython-36.opt-1.pyc
Hello Python !

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$ python sample2.cpython-36.opt-1.pyc
Hello World !

运行pyo文件

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ ls -l
total 8
drwxr-xr-x 1 anliven 197121   0 3月   7 23:42 __pycache__/
-rw-r--r-- 1 anliven 197121  50 3月   7 22:55 sample.py
-rw-r--r-- 1 anliven 197121 122 3月   7 23:45 sample.pyo
-rw-r--r-- 1 anliven 197121  49 3月   7 23:40 sample2.py
-rw-r--r-- 1 anliven 197121 122 3月   7 23:45 sample2.pyo

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ py -2 sample.pyo
Hello Python !

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ py -2 sample2.pyo
Hello World !

5 - 利用uncompyle6进行Python反编译

uncompyle6

安装uncompyle6

$ pip3 install --proxy="10.144.1.10:8080" uncompyle6
Collecting uncompyle6
  Downloading uncompyle6-3.0.0-py36-none-any.whl (195kB)
    100% |████████████████████████████████| 204kB 321kB/s
Requirement already satisfied: six in c:\python36\lib\site-packages (from uncompyle6)
Collecting spark-parser<1.9.0,>=1.8.5 (from uncompyle6)
  Downloading spark_parser-1.8.5-py36-none-any.whl
Collecting xdis<3.7.0,>=3.6.9 (from uncompyle6)
  Downloading xdis-3.6.11-py36-none-any.whl (74kB)
    100% |████████████████████████████████| 81kB 153kB/s
Collecting click (from spark-parser<1.9.0,>=1.8.5->uncompyle6)
  Using cached click-6.7-py2.py3-none-any.whl
Installing collected packages: click, spark-parser, xdis, uncompyle6
Successfully installed click-6.7 spark-parser-1.8.5 uncompyle6-3.0.0 xdis-3.6.11

$ pip3 show uncompyle6
Name: uncompyle6
Version: 3.0.0
Summary: Python cross-version byte-code decompiler
Home-page: https://github.com/rocky/python-uncompyle6/
Author: Rocky Bernstein, Hartmut Goebel, John Aycock, and others
Author-email: [email protected]
License: MIT
Location: c:\python36\lib\site-packages
Requires: xdis, spark-parser, six

示例:反编译pyc文件

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$ ls -l
total 4
-rw-r--r-- 1 anliven 197121 122 3月   7 23:42 sample.cpython-36.opt-1.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:41 sample.cpython-36.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:42 sample2.cpython-36.opt-1.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:41 sample2.cpython-36.pyc

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$ uncompyle6 sample.cpython-36.pyc > s1.py

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$ ls -l
total 5
-rw-r--r-- 1 anliven 197121 335 3月   8 00:01 s1.py
-rw-r--r-- 1 anliven 197121 122 3月   7 23:42 sample.cpython-36.opt-1.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:41 sample.cpython-36.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:42 sample2.cpython-36.opt-1.pyc
-rw-r--r-- 1 anliven 197121 122 3月   7 23:41 sample2.cpython-36.pyc

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$ cat s1.py
# uncompyle6 version 3.0.1
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.2 (v3.6.2:5fd33b5, Jul  8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)]
# Embedded file name: ./sample.py
# Compiled at: 2018-03-07 22:55:30
# Size of source mod 2**32: 50 bytes
print(‘Hello Python !‘)
# okay decompiling sample.cpython-36.pyc

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
$

示例:反编译pyo文件

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ ls -l
total 8
drwxr-xr-x 1 anliven 197121   0 3月   8 00:01 __pycache__/
-rw-r--r-- 1 anliven 197121  50 3月   7 22:55 sample.py
-rw-r--r-- 1 anliven 197121 122 3月   7 23:45 sample.pyo
-rw-r--r-- 1 anliven 197121  49 3月   7 23:40 sample2.py
-rw-r--r-- 1 anliven 197121 122 3月   7 23:45 sample2.pyo                                            

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$                                                                                                   

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ uncompyle6 sample2.pyo > s2.py                                                                    

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$ cat s2.py
# uncompyle6 version 3.0.1
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.6.2 (v3.6.2:5fd33b5, Jul  8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)]
# Embedded file name: ./sample2.py
# Compiled at: 2018-03-07 23:40:22
print ‘Hello World !‘
# okay decompiling sample2.pyo                                                                      

[email protected] MINGW64 /d/Anliven/Anliven-Code/Test
$                                                                                                   

uncompyle6的帮助信息

$ uncompyle6 --help

Usage:
  uncompyle6 [OPTIONS]... [ FILE | DIR]...
  uncompyle6 [--help | -h | --V | --version]

Examples:
  uncompyle6      foo.pyc bar.pyc       # decompile foo.pyc, bar.pyc to stdout
  uncompyle6 -o . foo.pyc bar.pyc       # decompile to ./foo.pyc_dis and ./bar.pyc_dis
  uncompyle6 -o /tmp /usr/lib/python1.5 # decompile whole library

Options:
  -o <path>     output decompiled files to this path:
                if multiple input files are decompiled, the common prefix
                is stripped from these names and the remainder appended to
                <path>
                  uncompyle6 -o /tmp bla/fasel.pyc bla/foo.pyc
                    -> /tmp/fasel.pyc_dis, /tmp/foo.pyc_dis
                  uncompyle6 -o /tmp bla/fasel.pyc bar/foo.pyc
                    -> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
                  uncompyle6 -o /tmp /usr/lib/python1.5
                    -> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis
  -c <file>     attempts a disassembly after compiling <file>
  -d            print timestamps
  -p <integer>  use <integer> number of processes
  -r            recurse directories looking for .pyc and .pyo files
  --fragments   use fragments deparser
  --verify      compare generated source with input byte-code
  --verify-run  compile generated source, run it and check exit code
  --weak-verify compile generated source
  --linemaps    generated line number correspondencies between byte-code
                and generated source output
  --help        show this message

Debugging Options:
  --asm     -a  include byte-code         (disables --verify)
  --grammar -g  show matching grammar
  --tree    -t  include syntax tree       (disables --verify)

Extensions of generated files:
  ‘.pyc_dis‘ ‘.pyo_dis‘   successfully decompiled (and verified if --verify)
    + ‘_unverified‘       successfully decompile but --verify failed
    + ‘_failed‘           decompile failed (contact author for enhancement)

6 - 其他Python反编译工具

Decompyle++

A Python Byte-code Disassembler/Decompiler

https://github.com/zrax/pycdc

Easy Python Decompiler

https://sourceforge.net/projects/easypythondecompiler/

Easy Python Decompiler is python bytecode decompiler, decompiles pyc & pyo files.

原文地址:https://www.cnblogs.com/anliven/p/9185549.html

时间: 2024-07-31 00:51:25

Python - 浅谈Python的编译与反编译的相关文章

浅谈 Python 程序和 C 程序的整合

源地址:http://www.ibm.com/developerworks/cn/linux/l-cn-pythonandc/ 概览 Python 是一种用于快速开发软件的编程语言,它的语法比较简单,易于掌握,但存在执行速度慢的问题,并且在处理某些问题时存在不足,如对计算机硬件系统的访问,对媒体文件的访问等.而作为软件开发的传统编程语言—— C 语言,却能在这些问题上很好地弥补 Python 语言的不足.因此,本文通过实例研究如何在 Python 程序中整合既有的 C 语言模块,包括用 C 语言

开发技术--浅谈Python函数

开发|浅谈Python函数 函数在实际使用中有很多不一样的小九九,我将从最基础的函数内容,延伸出函数的高级用法.此文非科普片~~ 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点的描述.力求不含任何的自我感情色彩. 情感:用我自己的方式,解读知识点.力求通俗易懂,完美透析知识. 正文 首先介绍函数是什么,接着走进函数,并且发现函数的高级使用方法,最后列出常用的Python的内置函数. 函数是什么? 1.函数,在代码执行的是不执行,只有在调用函数的时候才会执行. 2.函数使用

python浅谈正则的常用方法

python浅谈正则的常用方法覆盖范围70%以上 上一次很多朋友写文字屏蔽说到要用正则表达,其实不是我不想用(我正则用得不是很多,看过我之前爬虫的都知道,我直接用BeautifulSoup的网页标签去找内容,因为容易理解也方便,),而是正则用好用精通的很难(看过正则表的应该都知道,里面符号对应的方法规则有很多,很灵活),对于接触编程不久的朋友们来说很可能在编程的过程上浪费很多时间,今天我把经常会用到正则简单介绍下,如果不是很特殊基本都覆盖使用. 1.正则的简单介绍 首先你得导入正则方法 impo

浅谈python字符串存储形式

http://blog.csdn.net/zhonghuan1992 钟桓 2014年8月31日 浅谈python字符串存储形式 记录一下自己今的天发现疑问并且给出自己现有知识有的回答.长话短说,用过python的人对于 == 和 is 应该不陌生,但是这里我还是介绍一下. ==是用来判断两个东西是否相等,比如: a = 10: b = 10: print(a == b): 输出是true: 再看一个例子: a = [1,2,3]; b = [1,2,3]; c = [1,2,4]; print

浅谈 Python 的 with 语句

浅谈 Python 的 with 语句 王 生辉 和 李 骅宸2011 年 12 月 02 日发布 WeiboGoogle+用电子邮件发送本页面 3 引言 with 语句是从 Python 2.5 开始引入的一种与异常处理相关的功能(2.5 版本中要通过 from __future__ import with_statement 导入后才可以使用),从 2.6 版本开始缺省可用(参考 What's new in Python 2.6? 中 with 语句相关部分介绍).with 语句适用于对资源

浅谈python中的递归

python 浅谈 递归函数 最近在自学一些python,找了些资料.自己慢慢研究到了递归函数这一章,碰到个很经典的例子.汉诺塔的移动.一开始尝试自己写的时候发现,这东西怎么可能写的出来.但是看到别人写出来以后发现,这东西真的能写出来. 本着借鉴的目的想去分析一下别人写的东西.觉得很有意思想给大家分享一下,如果有误请大家指正首先大家可以先自己想想如何能写出来. 先说一下:所谓的递归,我认为就是不断重复调用.直到return 出当前的递归循环.在我拆分的过程中,大家不妨先自己想一下结果,然后看一下

浅谈 Python 的模块导入

浅谈 Python 的模块导入 本文不讨论 Python 的导入机制(底层实现细节),仅讨论模块与包,以及导入语句相关的概念.通常,导入模块都是使用如下语句: import ... import ... as ... from ... import ... from ... import ... as ... 一般情况下,使用以上语句导入模块已经够用的.但是在一些特殊场景中,可能还需要其他的导入方式.例如 Python 还提供了 __import__ 内建函数和 importlib 模块来实现动

开发技术--浅谈python数据类型

开发|浅谈python数据类型 在回顾Python基础的时候,遇到最大的问题就是内容很多,而我的目的是回顾自己之前学习的内容,进行相应的总结,所以我就不玩基础了,很多在我实际生活中使用的东西,我会在文章中提一下.并且我自己会根据这些内容进行相应的补充与扩展. 文章定位:不是科普文,是自己对于自己学习的总结. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点的描述.力求不含任何的自我感情色彩. 情感:用我自己的方式,解读知识点.力求通俗易懂,完美透析知识. 正文 正文的主要内

Java代码的编译与反编译那些事儿

编程语言 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language).编程语言(Programming Language)分为低级语言(Low-level Language)和高级语言(High-level Language). 机器语言(Machine Language)和汇编语言(Assembly Language)属于低级语言,直接用计算机指令编写程序. 而C.C++.Java.Python等属于高级语言,用语句(Statement)编写程序,语句是计算