【python】python代码加密与License控制

系统 1585 0

背景

在一些使用python的商业项目上,开发人员不想被用户看到源代码时,就需要对python代码进行加密;进一步地,如果想限制用户只能在获得授权的机器上运行你写的代码时(利益相关),就需要使用License控制。只有经过加密的代码才能进行License控制,试想一下,如果客户能拿到你的源代码,那么License控制就成为无稽之谈。

这里提供一种代码加密与License控制的思路。

先说python代码加密。

代码加密

众所周知,python是一种开源的编程语言,在开源的语言上做加密,加密效果肯定不如编译性语言的加密效果好,其逆向工程的难度会比编译性语言的逆向工程简单,按照这个思路,既然编译性语言c/c++的逆向工程难,那么为何不先把python编译成c/c++代码,然后再加密呢?根据经验这样是可行的,且这样加密的代码比那些编译成pyd文件或者打包成exe的方法就安全得多(pyd和exe的逆向工程有专门的包可以实现)。这就是这篇文章介绍的加密方法。

思路是先将py转换为c代码,然后编译c为so文件。

准备工作:

linux安装:

  • python-dev

  • gcc

    sudo apt-get install python-dev gcc

python安装第三方库

  • pycrypto (注意:在win10环境下安装这个包可能会报错,解决办法见这里 )

  • Cython

    pip install pycrypto Cython

    加密脚本``setup.py`的代码如下

            
              
                # coding:utf-8
              
              
                from
              
               distutils
              
                .
              
              core 
              
                import
              
               setup

              
                from
              
               Cython
              
                .
              
              Build 
              
                import
              
               cythonize

              
                import
              
               os


              
                '''
该文件的执行需要的在Terminal中输入  python setup.py build_ext --inplace
使用Cpython 编译python文件,关键函数编译成pyd文件(相当于dll)
'''
              
              
                # 针对多文件情况设置,单文件就只写一个就行, 文件之间用逗号隔开
              
              
key_funs 
              
                =
              
              
                [
              
              
                'test.py'
              
              
                ]
              
              

setup
              
                (
              
              
    name
              
                =
              
              
                "XX app"
              
              
                ,
              
               
    ext_modules 
              
                =
              
               cythonize
              
                (
              
              key_funs
              
                )
              
              
                ,
              
              
                )
              
              
                '''
1、将编译后的pyd文件的命名更改成与原py文件一致
2、删除编译后得到的c文件和原py文件
'''
              
              
                print
              
              
                (
              
              
                "——————"
              
              
                ,
              
               os
              
                .
              
              getcwd
              
                (
              
              
                )
              
              
                ,
              
              
                "——————"
              
              
                )
              
              

files 
              
                =
              
               os
              
                .
              
              listdir
              
                (
              
              os
              
                .
              
              getcwd
              
                (
              
              
                )
              
              
                )
              
              
                print
              
              
                (
              
              files
              
                )
              
              
                for
              
               fi 
              
                in
              
               files
              
                :
              
              
                if
              
               fi
              
                .
              
              __contains__
              
                (
              
              
                ".pyd"
              
              
                )
              
              
                :
              
              
        re_name 
              
                =
              
               fi
              
                .
              
              split
              
                (
              
              
                "."
              
              
                )
              
              
                [
              
              
                0
              
              
                ]
              
              
                +
              
              
                ".pyd"
              
              
                print
              
              
                (
              
              re_name
              
                )
              
              
        os
              
                .
              
              rename
              
                (
              
              fi
              
                ,
              
               re_name
              
                )
              
              
                elif
              
               fi
              
                .
              
              __contains__
              
                (
              
              
                ".c"
              
              
                )
              
              
                or
              
               fi 
              
                in
              
               key_funs
              
                :
              
              
        os
              
                .
              
              remove
              
                (
              
              fi
              
                )
              
            
          

为了更好的说明,这里举个简单的例子。

另外准备两个py文件, test.py main.py ,其中 test.py 是需要加密的代码, main.py 是调用加密代码的脚本,不需要加密。

test.py 的内容如下

            
              
                import
              
               datetime


              
                class
              
              
                Today
              
              
                (
              
              
                )
              
              
                :
              
              
                def
              
              
                get_time
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              datetime
              
                .
              
              datetime
              
                .
              
              now
              
                (
              
              
                )
              
              
                )
              
              
                def
              
              
                say
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'hello world'
              
              
                )
              
            
          

main.py 的内容如下

            
              
                from
              
               test 
              
                import
              
               Today

t 
              
                =
              
               Today
              
                (
              
              
                )
              
              
t
              
                .
              
              get_time
              
                (
              
              
                )
              
              
t
              
                .
              
              say
              
                (
              
              
                )
              
            
          

加密之前,测试一下运行效果,在终端执行 python main.py ,输出

            
              2019-08-30 11:38:38.419308
hello world

            
          

使用 setup.py test.py 进行加密

方法:将需要加密的代码放到列表 key_funs 里面,然后在终端运行

            
              python setup.py build_ext --inplace

            
          

运行完加密脚本 setup.py 后,会将 test.py 删掉(请备份到其他地方!),得到 test.so 文件和文件夹 build/ ,这个文件夹可以删掉。至此代码加密完成。

测试

再次在终端执行 python main.py ,输出

            
              2019-08-30 11:49:17.986503
hello world

            
          

成功!

(注意,不能直接在IDE执行main.py,会出现错误ImportError: cannot import name ‘Today’)

License控制

知道怎么加密代码之后,就可以用license控制你的代码,以防被别人滥用。

通过License可以控制你的代码,控制方式有很多种,包括限制主机、限制时间(过期则无法执行)、限制使用地点等,这里只介绍如何通过License限制主机,其他方法大同小异,做适当修改即可。

物理地址是每台计算机独一无二的身份号码,我们可以利用物理地址作为限制主机的依据。

具体思路是,用户拿到你写的代码后,如果用户的计算机未经你权授则不能运行你的代码,这时候就需要利用物理地址作为权授的载体进行授权计算机。如需要授权计算机,用户要把需权授的机器的物理地址发给你,你使用AES加密算法把这个物理地址加密后,将得到的加密文件发给用户(这个加密文件就相当于一把钥匙,只有拥有这把钥匙才能正常运行你的代码)用户把加密文件放到指定路径下并执行代码,程序读取加密文件并解密,得到你加密的物理地址,将此物理地址与当前主机的物理地址做匹配,如果这两个物理地址相同则程序能正常运行,不同则退出程序。这里将物理地址加密的目的是防止被用户篡改。

这里涉及到的加密算法不做详细介绍,需了解请移步 here

用户计算机申请授权过程

【python】python代码加密与License控制_第1张图片

License控制流程图

【python】python代码加密与License控制_第2张图片

具体代码及实现例子请移步github

(别忘了点star哦)

Reference:
  • 浅谈常见的七种加密算法及实现
  • 加密Python源代码笔记

更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论