如何给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搭建虚拟环境的步骤详解
Sep 27 Python
Python使用PIL模块生成随机验证码
Nov 21 Python
TensorFlow实现AutoEncoder自编码器
Mar 09 Python
Flask之flask-script模块使用
Jul 26 Python
python基于itchat模块实现微信防撤回
Apr 29 Python
python操作小程序云数据库实现简单的增删改查功能
Jun 06 Python
PIL图像处理模块paste方法简单使用详解
Jul 17 Python
pygame实现俄罗斯方块游戏(基础篇2)
Oct 29 Python
python实现井字棋小游戏
Mar 04 Python
详解Python牛顿插值法
May 11 Python
Python 如何解决稀疏矩阵运算
May 26 Python
实操Python爬取觅知网素材图片示例
Nov 27 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编写一个简单的路由类
2011/04/13 PHP
ThinkPHP数据操作方法总结
2015/09/28 PHP
微信公众号模板消息群发php代码示例
2016/12/29 PHP
thinkPHP简单导入和使用阿里云OSSsdk的方法
2017/03/15 PHP
php开发最强大的IDE编辑的phpstorm 2020.2配置Xdebug调试的详细教程
2020/08/17 PHP
浅谈javascript 迭代方法
2015/01/21 Javascript
JavaScript中5种调用函数的方法
2015/03/12 Javascript
javascript实现根据iphone屏幕方向调用不同样式表的方法
2015/07/13 Javascript
JS实现不规则TAB选项卡效果代码
2015/09/16 Javascript
jQuery实现的简单分页示例
2016/06/01 Javascript
Vue.js实现拖放效果的实例
2016/09/30 Javascript
JavaScript基于对象去除数组重复项的方法
2016/10/09 Javascript
node.js实现的装饰者模式示例
2017/09/06 Javascript
微信小程序实战篇之购物车的实现代码示例
2017/11/30 Javascript
基于JavaScript实现抽奖系统
2018/01/16 Javascript
JavaScript遍历DOM元素的常见方式示例
2019/02/16 Javascript
Vue 前端实现登陆拦截及axios 拦截器的使用
2019/07/17 Javascript
JS中锚点链接点击平滑滚动并自由调整到顶部位置
2021/02/06 Javascript
[00:52]DOTA2第二届亚洲邀请赛预选赛宣传片
2017/01/13 DOTA
python下10个简单实例代码
2017/11/15 Python
python实现求两个字符串的最长公共子串方法
2018/07/20 Python
Python编写通讯录通过数据库存储实现模糊查询功能
2019/07/18 Python
python虚拟环境的安装和配置(virtualenv,virtualenvwrapper)
2019/08/09 Python
python集合的创建、添加及删除操作示例
2019/10/08 Python
浅谈python元素如何去重,去重后如何保持原来元素的顺序不变
2020/02/28 Python
python开发实例之Python的Twisted框架中Deferred对象的详细用法与实例
2020/03/19 Python
如何在keras中添加自己的优化器(如adam等)
2020/06/19 Python
css3边框_动力节点Java学院整理
2017/07/11 HTML / CSS
电影T恤、80年代T恤和80年代服装:TV Store Online
2020/01/05 全球购物
市级绿色学校申报材料
2014/08/25 职场文书
感恩教师节演讲稿
2014/09/03 职场文书
公司授权委托书
2014/10/17 职场文书
2015医院个人工作总结范文
2015/05/21 职场文书
初中化学教学反思
2016/02/22 职场文书
解决MySQL存储时间出现不一致的问题
2021/04/28 MySQL
Python 实现定积分与二重定积分的操作
2021/05/26 Python