pyc是编译py之后生成的二进制文件。当我们发布系统的时候不想让别人看到源代码,就需要将py文件编译生成pyc文件,对外只提供pyc文件。同样,如果拿到一个python程序,只有pyc文件,我们就无法看到源码,希望有办法反编译pyc文件以获得源码。

既然有反编译的需求,为了保护pyc文件不被反编译,我们又希望找到一个方法来防止pyc文件被反编译。

本文介绍了如何将py文件编译成pyc和pyo文件,也介绍了如何反编译pyc文件, 又给出了一种字节码混淆方法来防止pyc文件被反编译。

1 编译py文件到pyc和pyo

pyc是编译py之后生成的二进制文件,由python虚拟机来执行的。当我们发布系统的时候不想让别人看到源代码,就需要将py文件编译生成pyc文件,对外只提供pyc文件。

同时,在模块被加载时,.pyc文件比.py文件更快

但是pyc的内容跟python的版本相关,不同的版本编译后的pyc文件不同,2.5编译的pyc文件不能到3.5上执行.

发布python软件的过程为:

1. 生产pyc文件: python -m compileall .

2. 删除py文件: find . -name “*.py” |xargs rm -rf

3. 删除pycache目录: find . -name “pycache” |xargs rm -rf

1.1 Python2 编译

命令:

python -m py_compile file.py

python -m py_compile {file1,file2}.py

编译完成后,生成的 .pyc文件在当前目录。

可以使用-O或者-OO转换python命令来减少编译模块的大小

-O转换会帮你去掉assert语句

-OO转换会帮你去掉assert语句和__doc__文档字符串

由于一些程序可能依赖于assert语句或文档字符串,应该在确认需要的情况下使用这些选项。

例如 python –O -m py_compile file.py 会在本目录生成 file.pyo

1.2 python3 编译

Python3的编译和python2一样,只是在python3之后编译后的文件在pycache目录下,而不是与源文件同一目录。

那么如何让python3实现生成的pyc与源代码在同一目录呢?可以加上-b参数,例如

Python3 -m py_compile -b file.py

1.3 批量编译

python -m compileall DIR

python3 -m compileall –b DIR

DIR为需要编译的目录

例如: python -m compileall .

参数说明:

usage: python compileall.py [-l] [-f] [-q] [-d destdir] [-x regexp] [-i list] [directory|file ...]

arguments: zero or more file and directory names to compile; if no arguments given,

defaults to the equivalent of -l sys.path

options:

-l: don't recurse into subdirectories

-f: force rebuild even if timestamps are up-to-date

-q: output only error messages

-d destdir: directory to prepend to file paths for use in compile-time tracebacks and in

runtime tracebacks in cases where the source file is unavailable

-x regexp: skip files matching the regular expression regexp; the regexp is searched for

in the full path of each file considered for compilation

-i file: add all the files and directories listed in file to the list considered for

compilation; if "-", names are read from stdin

1.4 代码实现

单文件编译:

import py_compile
py_compile.compile('path') //path是包括.py文件名的路径

批量编译:

import compileall

compileall.compile_dir('$dir')

2反编译pyc

如果只有pyc文件,我们是无法直接查看内容的,这时,就需要反编译工具将pyc文件反编译成py源程序。 这里介绍uncompyle6反编译工具。Pyc文件能够反编译的前提是文件没有被加密或者代码混淆。

2.1 Uncompyle6安装

> git clone https://github.com/rocky/python-uncompyle6.git

> git checkout python-2.4

> sudo python setup.py install

如果没有报错,则安装成功了。

2.2反编译

执行命令:

>uncompyle6 -o . *.pyc

这时会在当前目录生成.py源文件。

3 防止反编译pyc文件

如何防止pyc文件被反编译呢? 这里介绍字节码混淆的方法,此方法能够抵挡低端的反编译手段,例如第2章的方法,但是,要到高手,还是抵挡不住。

字节码混淆可以非常容易的欺骗通常的反汇编器和反编译器,同时不影响代码的正常执行。下面这个例子展示了如何欺骗Uncompyle6反编译器以及dis反汇编器:

#一个简单的Python应用 sample1.py

print 'Hello World'

对其进行编译:

python -m py_compile sample1.py

对编译后的sample1.pyc使用Python内置dis模块反汇编:

>>> import marshal,dis

>>> fd = open('sample1.pyc', 'rb')

>>> fd.seek(8)

>>> sample1_code_obj = marshal.load(fd)

>>> fd.close()

>>> dis.dis(sample1_code_obj)

1           0 LOAD_CONST               0 ('Hello World')

3 PRINT_ITEM

4 PRINT_NEWLINE

5 LOAD_CONST               1 (None)

8 RETURN_VALUE

>>>

以上的汇编代码笔者肉眼反汇编的结果如下:

0 LOAD_CONST     0 ('Hello World') #加载co_consts[0]到栈顶,co_consts[0]存储着常量字符串'Hello World'

3 PRINT_ITEM                       #打印栈顶到sys.stdout,即print 'Hello World'

4 PRINT_NEWLINE                    #打印新行到sys.stdout,此指令因print语句而由编译器自动生成

5 LOAD_CONST     1 (None)          #加载co_consts[1]到栈顶,co_consts[1]存储着None

8 RETURN_VALUE                     #将栈顶返回给调用者,此两条指令为编译器自动生成

现在我们修改sample1.pyc,在程序入口增加一条绝对跳转指令(可以使用UltraEdit 16进制插入功能修改pyc文件,”JUMP_ABSOLUTE 3”在Python 2.7中对应的字节码为 0x71 0x03 0x00。修改code string内容的同时应修改code string的长度,此处增加了一个3字节指令),使用内置dis模块反汇编的结果如下:

1           0 JUMP_ABSOLUTE            3                 #自行添加

>>    3 LOAD_CONST               0 ('Hello World')

6 PRINT_ITEM

7 PRINT_NEWLINE

8 LOAD_CONST               1 (None)

11 RETURN_VALUE

如果读者对汇编代码有一定认识,就会明白此处的绝对跳转对Python虚拟机执行此程序基本没有影响(除了增加一个指令执行周期),然而这个绝对跳转将成功欺骗反编译器。使用Uncompyle6反编译的结果如下:

<<< Error: Decompiling stopped due to <class 'uncompyle6.semantics.pysource.ParserError'>

如果一个pyc文件无法被反编译,初级的破解者可能就会止步于此了,但对于有经验的工程师来说这还远远不够。同样的,我们还要让通常的反汇编器也无法工作才行。按下面的汇编代码继续加工上面的sample1.pyc。

|   1           0 JUMP_ABSOLUTE        [71 06 00]     6

|               3 LOAD_CONST           [64 FF FF] 65535 (FAKE!)

|         >>    6 LOAD_CONST           [64 00 00]     0 (Hello World)

|               9 PRINT_ITEM           [47 -- --]

|              10 PRINT_NEWLINE        [48 -- --]

|              11 LOAD_CONST           [64 01 00]     1 (None)

|              14 RETURN_VALUE         [53 -- --]

以上第二条指令的意思是加载code object常量表的第65535项到栈顶。在上述sample1.pyc中,常量表的长度为2,下标65535已超出常量表的范围,所以这是条非法指令。但由于第一条绝对跳转的存在,第二条指令永远都不会被执行。通常的反汇编器如dis会尽全力列举有用的信息,但并不能理解实际执行的控制流,当反汇编器尝试反汇编第二条指令时,会试着去读取code object常量表的第65535项并且抛出一个’tuple index out of range’的意外。Python内置dis模块的出错信息如下:

>>> fd = open('sample1.pyc', 'rb')

>>> fd.seek(8)

>>> import marshal,dis

>>> sample1_code_obj = marshal.load(fd)

>>> dis.dis(sample1_code_obj)

1           0 JUMP_ABSOLUTE            6

3 LOAD_CONST           65535

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

File "C:\Python27\lib\dis.py", line 43, in dis

disassemble(x)

File "C:\Python27\lib\dis.py", line 96, in disassemble

print '(' + repr(co.co_consts[oparg]) + ')',

IndexError: tuple index out of range

>>>

现在Uncompyle6和dis都被欺骗了,代码得到了有效的保护。

4 Reference

https://blog.csdn.net/ir0nf1st/article/details/61650984

https://www.cnblogs.com/nickchen121/p/10802465.html

https://www.cnblogs.com/dkblog/archive/2009/04/16/1980757.html

python文件编译与pyc反编译相关推荐

  1. python pyc文件解析_如何反编译pyc文件

    如何将.pyc和.pyo文件反编译为.py文件 pyc大约在python2刚出的时候有.后来就很少找得到了.有一次,不小心把.py删除了,通过pyc还把代码还原了. 你搜索uncompyle2, de ...

  2. python代码封装加密_对Python源码加密及反编译前后对比

    关于python的加密 目前软件开发商对 Python 加密时可能会有两种形式,一种是对python转成的exe进行 保护,另一种是直接对.py或者.pyc文件进行保护,下面将列举两种形式的保护流程. ...

  3. 【反编译系列】反编译so文件(IDA_Pro)

    概述 安卓应用程序的开发语言是java,但是由于java层的代码很容易被反编译,而反编译c/c++程序的难度比较大,所以现在很多安卓应用程序的核心部分都使用NDK进行开发.使用NDK开发能够编译c/c ...

  4. Python攻防-APK批量自动反编译与数据分析

    文章目录 前言 Pull APK 1.1 根据包名列表 1.2 根据手机路径 逆向APK 2.1 自动化反编译 2.2 数据快速检索 数据分析 3.1 txt文本的比较 3.2 txt转换为xlsx ...

  5. python脚本转换成apk_apktool反编译apk并回编译

    apktool反编译apk并回编译 下载apktool工具: apktool官方网站:https://ibotpeaches.github.io/Apktool/ 安装apktool并配置apktoo ...

  6. ipa文件反编译_iOS class-dump 反编译ipa包

    最近上传AppStore,总是说包含第三方支付而被拒. 如何反编译ipa包,查看所有的头文件和方法名(包括私有方法名)? 1.找到ipa包所在位置(这里的ipa包是通过archive后,export导 ...

  7. 配置python查看网易模拟器app反编译函数hook

    配置python查看网易模拟器app反编译函数hook 一.电脑终端安装:frida # 方法一 pip install frida pip install frida-tools ## 方法一 镜像 ...

  8. 如何反编译,防止反编译,常见问题总结

    本文对如何反编译,防止反编译,和常遇到的问题做了个总结,并略有修改. 资源来自:http://blog.csdn.net/sunboy_2050/article/details/6727581 htt ...

  9. Android反编译工具与反编译步骤及常见问题

    Android代码混淆很大程度上就是为了别人反编译我们的代码,用反编译工具也可以测试我们的代码是否混淆成功. "工欲善其事,必先利其器",先介绍一下反编译的工具: apktool. ...

最新文章

  1. java获取真实ip
  2. jupyter % 符号用法
  3. layui 键盘选中行
  4. c# ef报错_C#中Entity Framework常见报错汇总
  5. linux 调优篇 :硬件调优(BIOS配置)* 壹
  6. VSCode + git 代码托管【当前没有源代码管理提供程序注册】(没有‘+’加法号) - 解决篇
  7. 【面试篇】Java多线程并发-Java中的CAS机制算法
  8. ActiveMQ 即时通讯服务 浅析
  9. 配置eclipse,创建类/方法时自动生成作者、创建日期、方法功能等注释
  10. 使用Context和Hooks来管理状态
  11. 常用Docker 镜像命令(二)
  12. sis地址发布器_【一起练翻译-9.1】关于提词器、真实、川普和演讲
  13. 回车键为什么叫做回车键?
  14. Excel键盘快捷键大全
  15. 8b/10b编码技术系列(二):Disparity、RD、8b/10b编码
  16. deepin更新失败_更新失败
  17. 电子商务数据分析的认识
  18. VUE3.0——组件传值
  19. 在不同的库存情况下,亚马逊CPC广告的投放策略会有什么改变呢?
  20. Linux 虚拟文件系统(一)概述

热门文章

  1. 完美解决PowerPoint 2007无法输入汉字及Office自动调用输入法的问题
  2. 如何使用mac自带录屏截图功能?
  3. 2015融博面试总结
  4. 解决Android11上分享图片失败
  5. tomcatservlet入门
  6. 计算机网络--http和https
  7. 运营小白如何选择靠谱的运营工作
  8. 交通标志结构计算软件开发进程
  9. Android11激活冰箱
  10. 超平面的法向量与距离公式