美文网首页python
浅谈Python的编译与反编译

浅谈Python的编译与反编译

作者: 我爱学python | 来源:发表于2020-04-20 20:28 被阅读0次

    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文件。

    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函数

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    import py_compile  # 相当于命令行中的“-m py_compile”
    py_compile.compile('py file path')
    

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

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

    生成pyc文件示例:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    anliven@DESKTOP-68OFQFP 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
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test
    $ cat sample.py
    # -*- coding: utf-8 -*-
    print("Hello Python !")
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test
    $ cat sample2.py
    # -*- coding: utf-8 -*-
    print("Hello World !")
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test
    $ python -m compileall ./
    Listing './'...
    Compiling './sample.py'...
    Compiling './sample2.py'...
    
    anliven@DESKTOP-68OFQFP 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
    
    anliven@DESKTOP-68OFQFP 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文件

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test
    $ python -O -m compileall ./
    Listing './'...
    Compiling './sample.py'...
    Compiling './sample2.py'...
    
    anliven@DESKTOP-68OFQFP 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文件

    anliven@DESKTOP-68OFQFP 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
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test
    $ py -2 -O -m compileall ./
    Listing ./ ...
    Listing ./__pycache__ ...
    Compiling ./sample.py ...
    Compiling ./sample2.py ...
    
    anliven@DESKTOP-68OFQFP 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文件

    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
    $ python sample.cpython-36.pyc
    Hello Python !
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
    $ python sample2.cpython-36.pyc
    Hello World !
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
    $ python sample.cpython-36.opt-1.pyc
    Hello Python !
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
    $ python sample2.cpython-36.opt-1.pyc
    Hello World !
    

    运行pyo文件

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    anliven@DESKTOP-68OFQFP 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
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test
    $ py -2 sample.pyo
    Hello Python !
    
    anliven@DESKTOP-68OFQFP 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: rb@dustyfeet.com
    License: MIT
    Location: c:\python36\lib\site-packages
    Requires: xdis, spark-parser, six
    

    示例:反编译pyc文件

    anliven@DESKTOP-68OFQFP 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
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
    $
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
    $ uncompyle6 sample.cpython-36.pyc > s1.py
    
    anliven@DESKTOP-68OFQFP 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
    
    anliven@DESKTOP-68OFQFP 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
    
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test/__pycache__
    $
    

    示例:反编译pyo文件

    anliven@DESKTOP-68OFQFP 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                                            
                                                                                                        
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test                                        
    $                                                                                                   
                                                                                                        
    anliven@DESKTOP-68OFQFP MINGW64 /d/Anliven/Anliven-Code/Test                                        
    $ uncompyle6 sample2.pyo > s2.py                                                                    
                                                                                                        
    anliven@DESKTOP-68OFQFP 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                                                                      
                                                                                                        
    anliven@DESKTOP-68OFQFP 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)
    

    相关文章

      网友评论

        本文标题:浅谈Python的编译与反编译

        本文链接:https://www.haomeiwen.com/subject/ftndihtx.html