如何保护你写的 Python 代码?
选自《编程小记》
作者:Prodesire
https://zhuanlan.zhihu.com/p/54296517
去年11月在PyCon China 2018 杭州站分享了 Python 源码加密,讲述了如何通过修改 Python 解释器达到加解密 Python 代码的目的。然而因为笔者拖延症发作,一直没有及时整理成文字版,现在终于战胜了它,才有了本文。
本系列将首先介绍下现有源码加密方案的思路、方法、优点与不足,进而介绍如何通过定制 Python 解释器来达到更好地加解密源码的目的。
由于 Python 的动态特性和开源特点,导致 Python 代码很难做到很好的加密。社区中的一些声音认为这样的限制是事实,应该通过法律手段而不是加密源码达到商业保护的目的;而还有一些声音则是不论如何都希望能有一种手段来加密。于是乎,人们想出了各种或加密、或混淆的方案,借此来达到保护源码的目的。
常见的源码保护手段有如下几种:
发行
.pyc
文件代码混淆
使用
py2exe
使用
Cython
下面来简单说说这些方案。
01. 发行 .pyc 文件
思路
大家都知道,Python 解释器在执行代码的过程中会首先生成.pyc
文件,然后解释执行.pyc
文件中的内容。当然了,Python 解释器也能够直接执行.pyc
文件。而.pyc
文件是二进制文件,无法直接看出源码内容。如果发行代码到客户环境时都是.pyc
而非.py
文件的话,那岂不是能达到保护 Python 代码的目的?
方法
把.py
文件编译为.pyc
文件,是件非常轻松地事情,可不需要把所有代码跑一遍,然后去捞生成的.pyc
文件。
事实上,Python 标准库中提供了一个名为 compileall 的库,可以轻松地进行编译。
执行如下命令能够将遍历<src>
目录下的所有.py
文件,将之编译为.pyc
文件:
python -m compileall<src>
然后删除<src>
目录下所有.py
文件就可以打包发布了:
$ find <src> -name '*.py' -type f -print -exec rm {} \;
优点
简单方便,提高了一点源码破解门槛
平台兼容性好,
.py
能在哪里运行,.pyc
就能在哪里运行
不足
解释器兼容性差,
.pyc
只能在特定版本的解释器上运行有现成的反编译工具,破解成本低
python-uncompyle6 就是这样一款反编译工具,效果出众。
执行如下命令,即可将.pyc
文件反编译为.py
文件:
$ uncompyle6 *compiled-python-file-pyc-or-pyo*
02. 代码混淆
如果代码被混淆到一定程度,连作者看着都费劲的话,是不是也能达到保护源码的目的呢?
思路
既然我们的目的是混淆,就是通过一系列的转换,让代码逐渐不让人那么容易明白,那就可以这样下手:- 移除注释和文档。没有这些说明,在一些关键逻辑上就没那么容易明白了。- 改变缩进。完美的缩进看着才舒服,如果缩进忽长忽短,看着也一定闹心。- 在tokens中间加入一定空格。这就和改变缩进的效果差不多。- 重命名函数、类、变量。命名直接影响了可读性,乱七八糟的名字可是阅读理解的一大障碍。- 在空白行插入无效代码。这就是障眼法,用无关代码来打乱阅读节奏。
方法
方法一:使用 oxyry 进行混淆
http://pyob.oxyry.com/ 是一个在线混淆 Python 代码的网站,使用它可以方便地进行混淆。
假定我们有这样一段 Python 代码,涉及到了类、函数、参数等内容:
# coding: utf-8class A(object):"""Description"""def __init__(self, x, y, default=None):self.z = x + yself.default = defaultdef name(self):return 'No Name'def always():return Truenum = 1
a = A(num, 999, 100)
a.name()
always()
经过Oxyry
的混淆,得到如下代码:
class A (object ):#line:4""#line:7def __init__ (O0O0O0OO00OO000O0 ,OO0O0OOOO0000O0OO ,OO0OO00O00OO00OOO ,OO000OOO0O000OOO0 =None ):#line:9O0O0O0OO00OO000O0 .z =OO0O0OOOO0000O0OO +OO0OO00O00OO00OOO #line:10O0O0O0OO00OO000O0 .default =OO000OOO0O000OOO0 #line:11def name (O000O0O0O00O0O0OO ):#line:13return 'No Name'#line:14
def always ():#line:17return 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 . oOooOoO0Oo0Oif 10 - 10: IIiI1I11i11if 54 - 54: i11iIi1 - oOo0O0Oooif 2 - 2: o0 * i1 * ii1IiI1i % OOooOOo / I11i / Ii1Idef __init__ ( self , x , y , default = None ) :self . z = x + yself . default = defaultif 48 - 48: iII111i % IiII + I1Ii111 / ooOoO0o * Ii1Idef name ( self ) :return 'No Name'if 46 - 46: ooOoO0o * I11i - OoooooooOOif 30 - 30: o0 - O0 % o0 - OoooooooOO * O0 * OoooooooOO
def Oo0o ( ) :return Trueif 60 - 60: i1 + I1Ii111 - I11i / i1IIiif 40 - 40: oOooOoO0Oo0O / O0 % ooOoO0o + O0 * i1IIi
I1Ii11I1Ii1i = 1
Ooo = o0OO00 ( I1Ii11I1Ii1i , 999 , 100 )
Ooo . name ( )
Oo0o ( ) # dd678faae9ac167bc83abf78e5cb2f3f0688d3a3
相比于方法一,方法二的效果看起来更好些。除了类和函数进行了重命名、加入了一些空格,最明显的是插入了若干段无关的代码,变得更加难读了。
优点
简单方便,提高了一点源码破解门槛
不足
只能对单个文件混淆,无法做到多个互相有联系的源码文件的联动混淆
03. 使用 py2exe
思路
py2exe 是一款将 Python 脚本转换为 Windows 平台上的可执行文件的工具。其原理是将源码编译为.pyc
文件,加之必要的依赖文件,一起打包成一个可执行文件。
如果最终发行由py2exe
打包出的二进制文件,那岂不是达到了保护源码的目的?
方法
使用py2exe
进行打包的步骤较为简便。
1)编写入口文件。本示例中取名为hello.py
:
print 'Hello World'
2)编写setup.py
:
from distutils.core import setup
import py2exesetup(console=['hello.py'])
3)生成可执行文件
python setup.py py2exe
生成的可执行文件位于dist\hello.exe
。
优点
能够直接打包成 exe,方便分发和执行
破解门槛比 .pyc 更高一些
不足
兼容性差,只能运行在 Windows 系统上
生成的可执行文件内的布局是明确、公开的,可以找到源码对应的
.pyc
文件,进而反编译出源码
04. 使用 Cython
思路
虽说Cython
的主要目的是带来性能的提升,但是基于它的原理:将.py
/.pyx
编译为.c
文件,再将.c
文件编译为.so
(Unix) 或.pyd
(Windows),其带来的另一个好处就是难以破解。
方法
使用Cython
进行开发的步骤也不复杂。
1)编写文件hello.pyx
或hello.py
:
def hello():print('hello')
2)编写setup.py
:
from distutils.core import setup
from Cython.Build import cythonizesetup(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()
函数。
优点
生成的二进制 .so 或 .pyd 文件难以破解
同时带来了性能提升
不足
兼容性稍差,对于不同版本的操作系统,可能需要重新编译
虽然支持大多数 Python 代码,但如果一旦发现部分代码不支持,完善成本较高
推荐阅读
在看?
如何保护你写的 Python 代码?相关推荐
- python实现tomasulo算法_手写算法-python代码实现KNN
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 原理解析 KNN-全称K-Nearest Neighbor,最近邻算法,可以做分类任务,也可以做回归 ...
- 多元线性回归算法python实现_手写算法-Python代码推广多元线性回归
1.梯度下降-矩阵形式 上篇文章介绍了一元线性回归,包括Python实现和sklearn实现的实例.对比,以及一些问题点,详情可以看这里: 链接: 手写算法-Python代码实现一元线性回归 里面封装 ...
- python函数的组成要素_python函数要素有哪些?这7点是你写好python代码的关键
[摘要]对于python小白来说,写好一个python代码并不容易,不过你知道python函数要素有哪些?这7点是你写好python代码的关键,如果你想学好python,那么本文内容一定要自己试试,毕 ...
- 手写算法-python代码实现Ridge(L2正则项)回归
手写算法-python代码实现Ridge回归 Ridge简介 Ridge回归分析与python代码实现 方法一:梯度下降法求解Ridge回归参数 方法二:标准方程法实现Ridge回归 调用sklear ...
- 写好 Python 代码的几条原则
程序设计的好与坏,早在我们青葱岁月时就接触过了,只是那是并不知道这竟如此重要.能够立即改善程序设计.写出"好"代码的知识有以下几点: •面向对象五个基本原则: •常见的三种架构: ...
- 你写的Python代码规范吗?
总第141篇/张俊红 1.什么是PEP8 PEP 是 Python Enhancement Proposals 的缩写,直译过来就是「Python增强建议书」也可叫做「Python改进建议书」,说的直 ...
- python代码规范方面的书_你写的Python代码规范吗?
# 不建议这样importpandas,numpy 且导入模块的代码总是位于代码的最开始部分,在模块注释和文档字符串之后,在模块的全局变量与常量之前. 2.8命名规范 在 Python 里面会涉及到很 ...
- python多元非线性拟合csdn_手写算法-Python代码实现非线性回归
生成非线性数据集 前面我们介绍了Python代码实现线性回归,今天,我们来聊一聊当数据呈现非线性时,这时我们继续用线性表达式去拟合,显然效果会很差,那我们该怎么处理?继续上实例(我们的代码里用到的数据 ...
- 10年老司机,写好 Python 代码的几条重要技巧!
来源:NightTeam-韦世东 程序设计的好与坏,早在我们青葱岁月时就接触过了,只是那是并不知道这竟如此重要.能够立即改善程序设计.写出"好"代码的知识有以下几点: •面向对象五 ...
最新文章
- spring junit 测试
- spring beans源码解读之--Bean的注解(annotation)
- 阿里云配置负载均衡实例
- GDCM:转储一个DICOM文件,显示DICOM中的结构和值的测试程序
- 最新的INTEL FPGA时序分析资料
- netty的编解码、粘包拆包问题、心跳检测机制原理
- linux 容器_Linux容器的幕后花絮
- 特斯拉为什么要“干掉”保险丝和继电器?
- python练习-华氏转摄氏
- 年薪60w的程序员与年薪6w的极品程序员,差距怎么这么大呢?
- CSS的压缩 方法与解压
- 佟鑫 PHP,【盖佟鑫】姓名测试打分,起名字测试打分盖佟鑫,盖佟鑫名字打分测试,盖佟鑫测名字打分,【盖佟鑫】名字测分,姓名测试网...
- @keyup.enter.native
- 【新书推荐】【2019.07】第二曲线创新(混沌大学首部创新必修教科书 混沌大学创办人李善友八年磨一剑全新力作)...
- 10种靠谱又收益不错的在家就可以做的网赚兼职平台介绍
- ASP.NET + adminLTE (一)
- 从实例出发,让你一文实现Floyd算法
- 标签打印机是什么?标签打印机的应用特点有哪些
- 将十进制数转换成二进制、八进制、十六进制数算法
- C语言知识学习归纳总结(逐梦篇专栏合集)
热门文章
- 【MATLAB】将向量表示的多项式用字符串输出的通用函数示例
- 英特尔公布新技术路线图,将为 AWS、高通代工芯片
- 百度飞桨成为北京市首个AI产业方向创新应用平台
- EMNLP 2019 | 大规模利用单语数据提升神经机器翻译
- 测试工程师的好日子来啦?Testin发布AI测试产品,提升易用性和自动化效率
- 吴甘沙:天外飞“厕”、红绿灯消失,未来无人驾驶将被重新定义
- 免费公开课 | 基于定制数据流技术的AI计算加速
- 雷军的100亿计划:不服就干,生死看淡
- 双十一报名截止,决赛在即!AI Challenger2018极客峰会免费抢票!
- Alphabet旗下自驾公司Waymo入华,变身“慧摩”!