python代码编译总结用于代码加密

  基于一个自废武功式的决定,服务需要做成标准件在客户服务器上运行,因此调研了python代码加密的相关内容。py的代码混淆没有被采用,而是采用cython编译成二进制文件进而掩盖源码的方式对代码加密。

  准备工作:

    1.安装cython ,pip install cython

    2.Linux上安装gcc ,Win需要准备vc的环境,建议安装vs2019以上,自带部分vc环境

  setup脚本,请根据需要自行添加module_list:

from distutils.core import setup
from Cython.Build import cythonize
import setuptools
from distutils.extension import Extension

setup(ext_modules=cythonize(module_list = [Extension('server', ['server.py'])]))

  module_list 中的Extension,每个文件根据路径和名称确定模块名。__init__.py不建议编译,因为模块名跟文件一一对应,将模块名指定为文件夹名称编译后运行时会找不到模块。可以使用os.walk()来遍历,批量处理文件路径和模块名称。

  Setup脚本使用当前的开发环境,终端命令如下:python setup.py build_ext --inplace

  build_ext 会创建build文件夹产生编译中间产物  --inplace 最终的编译结果(如.so文件)生成在原路径下。linux下会生成so文件,win下生成的是pyd文件,都是二进制文件,原调用方式不变。

目录结构如下图:

 完整的setup.py代码如下:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
import os

filelist = []
ex_list = []
for r, d, f in os.walk('onmt'):
    if '__' in r: continue 
    if 'templates' in r: continue # 不需要加密的文件夹    
    for ff in f:
        if ff.endswith('.c') or ff.endswith('.so'):
            os.remove(os.path.join(r, ff))
            continue
        if '__' in ff: continue
        filelist.append(os.path.join(r, ff))

if __name__ == '__main__':
    for f in filelist:
        if '__' in f:
            continue
            #  不可以将__init__.py文件放入待加密列表
        else:
            ex_list.append(Extension(f.split('.py')[0].replace('/', '.'), [f])) # 详见说明1
        # ex_list.append(Extension(f.split('.py')[0].replace('/', '.').split('.')[-1], [f])) # 详见说明2 
    setup(ext_modules=cythonize(ex_list, compiler_directives={'language_level': 3}
)) for f in filelist: os.remove(f) #删除源文件来验证编译是否成功,请一定要提前备份好代码

说明:

  1. 将源文件路径中/转换为. 编译后再次读取时模块可能会出现找不到的情况。

        以onmt/bin/ server.py文件为例,此行代码执行的编译结果中.c临时文件里的模块名字为onmt.bin.server。注意此时so文件与原py文件在同一路径下。此时在server_run中使用onmt.bin.server引用so文件时可能会出错,so文件可能被python识别为onmt.bin.server.onmt.bin.server,导致模块找不到。

         2. 模块名称与文件名一致,不再包含原文件路径。

            以onmt/bin/server.py文件为例,此行代码执行的编译结果中.c临时文件里的模块名字是server。注意此时so文件与setup.py在同一路径下,需要人为将so文件移动到原文件对应路径下。此时在server_run中使用onmt.bin.server引用so文件也有无法找到模块的可能。

         鉴于以上两种情况皆有成功和失败的情况出现,较为稳妥的办法是使用原虚拟环境进行编译,在确认编译后so文件可以使用的情况下,导出原虚拟环境与编译后so文件一起使用。

*********************************************************************************************************************************************

参考资料:Python 2.7 cython cythonize py 编译成 pyd 谈谈那些坑 - ibingshan - 博客园 (cnblogs.com)

原文地址:https://www.cnblogs.com/cnDqf/p/15693700.html