如何给Python代码进行加密


Posted in Python onJanuary 10, 2020

这篇文章主要介绍了如何给Python代码进行加密,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

去年11月在PyCon China 2018 杭州站分享了 Python 源码加密,讲述了如何通过修改 Python 解释器达到加解密 Python 代码的目的。然而因为笔者拖延症发作,一直没有及时整理成文字版,现在终于战胜了它,才有了本文。

本系列将首先介绍下现有源码加密方案的思路、方法、优点与不足,进而介绍如何通过定制 Python 解释器来达到更好地加解密源码的目的。

由于 Python 的动态特性和开源特点,导致 Python 代码很难做到很好的加密。社区中的一些声音认为这样的限制是事实,应该通过法律手段而不是加密源码达到商业保护的目的;而还有一些声音则是不论如何都希望能有一种手段来加密。于是乎,人们想出了各种或加密、或混淆的方案,借此来达到保护源码的目的。

常见的源码保护手段有如下几种:

  • 发行 .pyc 文件
  • 代码混淆
  • 使用 py2exe
  • 使用 Cython

下面来简单说说这些方案。

1 发行 .pyc 文件

1.1 思路

大家都知道,Python 解释器在执行代码的过程中会首先生成 .pyc 文件,然后解释执行 .pyc文件中的内容。当然了,Python 解释器也能够直接执行 .pyc 文件。而 .pyc 文件是二进制文件,无法直接看出源码内容。如果发行代码到客户环境时都是 .pyc 而非 .py文件的话,那岂不是能达到保护 Python 代码的目的?

1.2 方法

把 .py 文件编译为 .pyc 文件,是件非常轻松地事情,可不需要把所有代码跑一遍,然后去捞生成的 .pyc 文件。

事实上,Python 标准库中提供了一个名为 compileall 的库,可以轻松地进行编译。

执行如下命令能够将遍历 <src> 目录下的所有 .py 文件,将之编译为 .pyc 文件:

python -m compileall <src> 然后删除 <src> 目录下所有 .py 文件就可以打包发布了:

$ find <src> -name '*.py' -type f -print -exec rm {} \;

1.3 优点

简单方便,提高了一点源码破解门槛

平台兼容性好,.py 能在哪里运行,.pyc 就能在哪里运行

1.4 不足

解释器兼容性差,.pyc 只能在特定版本的解释器上运行

有现成的反编译工具,破解成本低
python-uncompyle6 就是这样一款反编译工具,效果出众。

执行如下命令,即可将 .pyc 文件反编译为 .py 文件:

$ uncompyle6 *compiled-python-file-pyc-or-pyo*

2 代码混淆

如果代码被混淆到一定程度,连作者看着都费劲的话,是不是也能达到保护源码的目的呢?

2.1 思路

既然我们的目的是混淆,就是通过一系列的转换,让代码逐渐不让人那么容易明白,那就可以这样下手:- 移除注释和文档。没有这些说明,在一些关键逻辑上就没那么容易明白了。- 改变缩进。完美的缩进看着才舒服,如果缩进忽长忽短,看着也一定闹心。- 在tokens中间加入一定空格。这就和改变缩进的效果差不多。- 重命名函数、类、变量。命名直接影响了可读性,乱七八糟的名字可是阅读理解的一大障碍。- 在空白行插入无效代码。这就是障眼法,用无关代码来打乱阅读节奏。

2.2 方法

方法一:使用 oxyry 进行混淆

http://pyob.oxyry.com/ 是一个在线混淆 Python 代码的网站,使用它可以方便地进行混淆。

假定我们有这样一段 Python 代码,涉及到了类、函数、参数等内容:

# coding: utf-8
 
class A(object):
  """
  Description
  """
 
  def __init__(self, x, y, default=None):
    self.z = x + y
    self.default = default
 
  def name(self):
    return 'No Name'
def always():
  return True
num = 1
a = A(num, 999, 100)
a.name()
always()

经过 Oxyry 的混淆,得到如下代码:

class A (object ):#line:4
  ""#line:7
  def __init__ (O0O0O0OO00OO000O0 ,OO0O0OOOO0000O0OO ,OO0OO00O00OO00OOO ,OO000OOO0O000OOO0 =None ):#line:9
    O0O0O0OO00OO000O0 .z =OO0O0OOOO0000O0OO +OO0OO00O00OO00OOO #line:10
    O0O0O0OO00OO000O0 .default =OO000OOO0O000OOO0 #line:11
  def name (O000O0O0O00O0O0OO ):#line:13
    return 'No Name'#line:14
def always ():#line:17
  return True #line:18
num =1 #line:21
a =A (num ,999 ,100 )#line:22
a .name ()#line:23
always ()

混淆后的代码主要在注释、参数名称和空格上做了些调整,稍微带来了点阅读上的障碍。

方法二:使用 pyobfuscate 库进行混淆

pyobfuscate 算是一个颇具年头的 Python 代码混淆库了,但却是“老当益壮”了。

对上述同样一段 Python 代码,经 pyobfuscate 混淆后效果如下:

# coding: utf-8
if 64 - 64: i11iIiiIii
if 65 - 65: O0 / iIii1I11I1II1 % OoooooooOO - i1IIi
class o0OO00 ( object ) :
 if 78 - 78: i11i . oOooOoO0Oo0O
 if 10 - 10: IIiI1I11i11
 if 54 - 54: i11iIi1 - oOo0O0Ooo
 if 2 - 2: o0 * i1 * ii1IiI1i % OOooOOo / I11i / Ii1I
 def __init__ ( self , x , y , default = None ) :
 self . z = x + y
 self . default = default
 if 48 - 48: iII111i % IiII + I1Ii111 / ooOoO0o * Ii1I
 def name ( self ) :
 return 'No Name'
 if 46 - 46: ooOoO0o * I11i - OoooooooOO
 if 30 - 30: o0 - O0 % o0 - OoooooooOO * O0 * OoooooooOO
def Oo0o ( ) :
 return True
 if 60 - 60: i1 + I1Ii111 - I11i / i1IIi
 if 40 - 40: oOooOoO0Oo0O / O0 % ooOoO0o + O0 * i1IIi
I1Ii11I1Ii1i = 1
Ooo = o0OO00 ( I1Ii11I1Ii1i , 999 , 100 )
Ooo . name ( )
Oo0o ( ) # dd678faae9ac167bc83abf78e5cb2f3f0688d3a3

Oo0o ( ) # dd678faae9ac167bc83abf78e5cb2f3f0688d3a3
相比于方法一,方法二的效果看起来更好些。除了类和函数进行了重命名、加入了一些空格,最明显的是插入了若干段无关的代码,变得更加难读了。

2.3 优点

简单方便,提高了一点源码破解门槛

兼容性好,只要源码逻辑能做到兼容,混淆代码亦能

2.4 不足

只能对单个文件混淆,无法做到多个互相有联系的源码文件的联动混淆

代码结构未发生变化,也能获取字节码,破解难度不大

3 使用 py2exe

3.1 思路

py2exe 是一款将 Python 脚本转换为 Windows 平台上的可执行文件的工具。其原理是将源码编译为 .pyc 文件,加之必要的依赖文件,一起打包成一个可执行文件。

如果最终发行由 py2exe 打包出的二进制文件,那岂不是达到了保护源码的目的?

3.2 方法

使用 py2exe 进行打包的步骤较为简便。

1)编写入口文件。本示例中取名为 hello.py:

print 'Hello World'

2)编写 setup.py:

from distutils.core import setup
import py2exe
setup(console=['hello.py'])

3)生成可执行文件

python setup.py py2exe

生成的可执行文件位于 dist\hello.exe。

3.3 优点

能够直接打包成 exe,方便分发和执行

破解门槛比 .pyc 更高一些

3.4 不足

兼容性差,只能运行在 Windows 系统上

生成的可执行文件内的布局是明确、公开的,可以找到源码对应的 .pyc 文件,进而反编译出源码

4 使用 Cython

4.1 思路

虽说 Cython 的主要目的是带来性能的提升,但是基于它的原理:将 .py/.pyx 编译为 .c 文件,再将 .c 文件编译为 .so(Unix) 或 .pyd(Windows),其带来的另一个好处就是难以破解。

4.2 方法

使用 Cython 进行开发的步骤也不复杂。

1)编写文件 hello.pyx 或 hello.py:

def hello():
  print('hello')

2)编写 setup.py:

from distutils.core import setup
from Cython.Build import cythonize
setup(name='Hello World app',
   ext_modules=cythonize('hello.pyx'))

3)编译为 .c,再进一步编译为 .so 或 .pyd:

python setup.py build_ext --inplace

执行 python -c "from hello import hello;hello()" 即可直接引用生成的二进制文件中的 hello() 函数。

4.3 优点

生成的二进制 .so 或 .pyd 文件难以破解

同时带来了性能提升

4.4 不足

兼容性稍差,对于不同版本的操作系统,可能需要重新编译

虽然支持大多数 Python 代码,但如果一旦发现部分代码不支持,完善成本较高

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中使用copy模块实现列表(list)拷贝
Apr 14 Python
python实现搜索本地文件信息写入文件的方法
Feb 22 Python
python使用arcpy.mapping模块批量出图
Mar 06 Python
python交互式图形编程实例(一)
Nov 17 Python
NetworkX之Prim算法(实例讲解)
Dec 22 Python
pandas.DataFrame 根据条件新建列并赋值的方法
Apr 08 Python
解决Python print 输出文本显示 gbk 编码错误问题
Jul 13 Python
基于wxPython的GUI实现输入对话框(2)
Feb 27 Python
python虚拟环境完美部署教程
Aug 06 Python
Django中提示消息messages的设置方式
Nov 15 Python
Python IDLE或shell中切换路径的操作
Mar 09 Python
Django权限控制的使用
Jan 07 Python
pytorch如何冻结某层参数的实现
Jan 10 #Python
python标识符命名规范原理解析
Jan 10 #Python
pytorch1.0中torch.nn.Conv2d用法详解
Jan 10 #Python
pytorch 利用lstm做mnist手写数字识别分类的实例
Jan 10 #Python
Tensorflow Summary用法学习笔记
Jan 10 #Python
TENSORFLOW变量作用域(VARIABLE SCOPE)
Jan 10 #Python
python numpy数组复制使用实例解析
Jan 10 #Python
You might like
PHP调用三种数据库的方法(2)
2006/10/09 PHP
phpmyadmin里面导入sql语句格式的大量数据的方法
2010/06/05 PHP
PHP学习笔记之数组篇
2011/06/28 PHP
PHP正则表达式之定界符和原子介绍
2012/10/05 PHP
php curl获取网页内容(IPV6下超时)的解决办法
2013/07/16 PHP
PHP基于session.upload_progress 实现文件上传进度显示功能详解
2019/08/09 PHP
Javascript 原型和继承(Prototypes and Inheritance)
2009/04/01 Javascript
innerhtml用法 innertext用法 以及innerHTML与innertext的区别
2009/10/26 Javascript
document.all的一个比较完整的总结及案例
2013/01/31 Javascript
JQuery.Ajax()的data参数类型实例详解
2015/11/20 Javascript
jquery显示隐藏元素的实现代码
2016/05/19 Javascript
Javascript OOP之面向对象
2016/07/31 Javascript
Javascript中内建函数reduce的应用详解
2016/10/20 Javascript
jquery配合.NET实现点击指定绑定数据并且能够一键下载
2016/10/28 Javascript
利用JavaScript实现拖拽改变元素大小
2016/12/14 Javascript
快速入门Vue
2016/12/19 Javascript
jQuery实现两列等高并自适应高度
2016/12/22 Javascript
Vue.js实现开发购物车功能的方法详解
2019/02/22 Javascript
JS操作Fckeditor的一些常用方法(获取、插入等)
2020/02/19 Javascript
简单的通用表达式求10乘阶示例
2014/03/03 Python
python简单实现刷新智联简历
2016/03/30 Python
Python 判断文件或目录是否存在的实例代码
2018/07/19 Python
Face++ API实现手势识别系统设计
2018/11/21 Python
python+numpy按行求一个二维数组的最大值方法
2019/07/09 Python
python实现简易版学生成绩管理系统
2020/06/22 Python
美国最受欢迎的度假租赁网站:VRBO
2016/08/02 全球购物
Electric官网:美国高级眼镜和配件品牌
2020/06/04 全球购物
学前教育求职自荐信范文
2013/12/25 职场文书
求职信的七个关键技巧
2014/02/05 职场文书
打架检讨书2000字
2014/02/22 职场文书
学生党员一帮一活动总结
2014/07/08 职场文书
审查起诉阶段律师意见书
2015/05/19 职场文书
导游词之韩国济州岛
2019/10/28 职场文书
一劳永逸彻底解决pip install慢的办法
2021/05/24 Python
常用的Python代码调试工具总结
2021/06/23 Python
为什么代码规范要求SQL语句不要过多的join
2021/06/23 MySQL