基于Cython和内置distutils库,实现python源码加密(非混淆模式)

起因

python本身只能做混淆,不能加密,多年的商业软件开发经验导致有某种“洁癖”欲望,将py编译打包

尝试

  • pyinstaller原理是freeze打包pyc文件,利用工具可完美逆行出源码
  • 各种混淆脚本,版本兼容很差,配置繁琐
  • cython 常规使用只能编译单个特殊模块

解决

反复尝试摸索后,还是利用了cython和distutils库,自动化识别并转换py到c源码并编译,放出源码供大家参考

"""
利用cython和distutils编译py到pyd[so] 注意安装cython及本地平台对应编译器
http://flywuya.cnblogs.com/
 """
import os
import shutil
from distutils.core import setup
from distutils.command.build_ext import build_ext
from Cython.Build import cythonize

BUILD_CONFIG = {
    'SupportExt': ['.py', '.pyx'],
    'CopyOnlyFile': ['__main__.py', '__init__.py'],
    'CopyOnlyDir': ['assets'],
    'IgnoreDir': ['dist', 'build', '__pycache__'],
}

def copy_tree(src, dst):
    """ not like shutil.copytree, dst can be exists  """
    assert os.path.exists(src)
    assert os.path.isdir(src)
    os.makedirs(dst, exist_ok=True)

    for fn in os.listdir(src):
        s = os.path.join(src, fn)
        t = os.path.join(dst, fn)
        if os.path.isfile(s):
            shutil.copy2(s, t)
        elif os.path.isdir(s):
            copy_tree(s, t)

def build_module(source_file, dst_dir, tmp_dir):
    """ cythonize && build ext """
    assert os.path.isfile(source_file)
    assert not os.path.isabs(source_file)
    assert os.path.exists(dst_dir)
    os.makedirs(tmp_dir, exist_ok=True)

    build_cython = os.path.join(tmp_dir, 'build.cython')
    build_temp = os.path.join(tmp_dir, 'build.temp')
    build_lib = dst_dir

    ext_modules = cythonize(
        source_file,
        build_dir=build_cython,
        language_level=3,
    )

    class build_here(build_ext):
        def initialize_options(self):
            super().initialize_options()
            self.build_temp = build_temp
            self.build_lib = build_lib
    setup(
        ext_modules=ext_modules,
        script_args=['build_ext'],
        cmdclass=dict(build_ext=build_here)
    )

def build_modules(source_dir, dst_dir, tmp_dir):
    """ scan && build modules in source_dir """
    assert os.path.exists(source_dir)
    assert not os.path.isabs(source_dir)
    assert not os.path.isabs(dst_dir)
    os.makedirs(dst_dir, exist_ok=True)

    for root, dirs, files in os.walk(source_dir):
        rel_pth = root[len(source_dir)+1:]

        for ignore in BUILD_CONFIG['IgnoreDir']:
            if ignore in dirs:
                dirs.remove(ignore)

        for dn in dirs:
            if dn in BUILD_CONFIG['CopyOnlyDir']:
                copy_tree(
                    os.path.join(root, dn),
                    os.path.join(dst_dir, rel_pth, dn)
                )
                dirs.remove(dn)

        for fn in files:
            _, ext = os.path.splitext(fn)
            os.makedirs(
                os.path.join(dst_dir, rel_pth),
                exist_ok=True
            )
            if fn in BUILD_CONFIG['CopyOnlyFile']:
                shutil.copy2(
                    os.path.join(root, fn),
                    os.path.join(dst_dir, rel_pth, fn)
                )
            elif ext.lower() in BUILD_CONFIG['SupportExt']:
                build_module(
                    os.path.join(root, fn),
                    dst_dir,
                    os.path.join(tmp_dir, rel_pth),
                )
            else:
                shutil.copy2(
                    os.path.join(root, fn),
                    os.path.join(dst_dir, rel_pth, fn)
                )

if __name__ == "__main__":

    # 这里填写要编译的目录
    tasks = [
        'app',
    ]

    others = [
        'requirements.txt',
        'packages',
    ]

    BUILD_CONFIG['CopyOnlyFile'].extend(['settings.py'])

    for task in tasks:
        build_modules(
            task,
            os.path.join('dist', task),
            os.path.join('build', task),
        )

    for other in others:
        if os.path.isfile(other):
            bn = os.path.basename(other)
            shutil.copy2(other, os.path.join('dist', bn))
        elif os.path.isdir(other):
            bn = os.path.basename(other)
            copy_tree(other, os.path.join('dist', bn))

原文地址:https://www.cnblogs.com/flywuya/p/10774094.html

时间: 2024-10-10 15:39:09

基于Cython和内置distutils库,实现python源码加密(非混淆模式)的相关文章

基于Docker的TensorFlow机器学习框架搭建和实例源码解读

概述:基于Docker的TensorFlow机器学习框架搭建和实例源码解读,TensorFlow作为最火热的机器学习框架之一,Docker是的容器,可以很好的结合起来,为机器学习或者科研人员提供便捷的机器学习开发环境,探索人工智能的奥秘,容器随开随用方便快捷.源码解析TensorFlow容器创建和示例程序运行,为热爱机器学者降低学习难度. 默认机器已经装好了Docker(Docker安装和使用可以看我另一篇博文:Ubuntu16.04安装Docker1.12+开发实例+hello world+w

基于Zlib算法的流压缩、字符串压缩源码

原文:基于Zlib算法的流压缩.字符串压缩源码 Zlib.net官方源码demo中提供了压缩文件的源码算法.处于项目研发的需要,我需要对内存流进行压缩,由于zlib.net并无相关文字帮助只能自己看源码解决.通过对SharpZipLib的demo研究,写出了Zlib.net的流压缩算法. 中间花费了不少的时间,应为通过Stream压缩出来的数据全是空的,呵呵,主要原因就是忽略了ZOutputStream.flush()和ZOutPutStream.close()方法.大家自己看吧.关于字符串压缩

一个基于php+mysql的外卖订餐网站(带源码)

订饭组 一个基于php+mysql的外卖订餐网站,包括前端和后台.源码地址 源码演示地址:http://dingfanzu.com 商家后台系统:http://dingfanzu.com/admin 测试账号:admin 密码:admin 运行环境:Apache+PHP+Mysql 代码说明 htaccess Rewrite配置文件,需要放入到项目根目录 configs.php 需要配置数据库连接信息(主机.用户名.密码),系统常量等 data.sql 位于data目录中,是数据库备份文件,需要

基于Java NIO的多人在线聊天工具源码实现(登录,单聊,群聊)

近来在学习Java NIO网络开发知识,写了一个基于Java NIO的多人在线聊天工具练练手.源码公开在Coding上: https://coding.net/u/hust_wsh/p/MyChat/git ,开发环境是Ubuntu14.04+Eclipse Mars+JDK1.8. 要想编写一个基于Java NIO的多人在线聊天工具,我总结需要以下几方面的地址:客户端服务器模型,Java NIO中的Selector,SocketChannel,ByteBuffer,Collections以及序

【Python笔记】图片处理库PIL的源码安装步骤

前段时间项目需要对某些图片打水印,用到Python的PIL库,本文以Imaging-1.1.7为例,记录PIL库的源码编译/安装步骤. PIL全称Python Image Library,它支持多种图片格式的处理,能为我们的应用程序代理强大的图像处理能力,如裁剪.旋转.打水印等. 从官网下载v1.1.7版本源码并解压后,cd至解压目录,读README可知,若想在应用中处理jpeg图片,需要预先安装jpeg库,否则使用时会报错. 1. 编译安装jpeg库 1.1 编译源码 从jpeg库官网下载st

用c#开发微信(3)基于Senparc.Weixin框架的接收普通消息处理 (源码下载)

本文讲述使用Senparc.Weixin框架来快速处理各种接收的普通消息.这里的消息指的是传统的微信公众平台消息交互,微信用户向公众号发送消息后,公众号回复消息给微信用户.包括以下7种类型: 1 文本消息 2 图片消息 3 语音消息 4 视频消息 5 小视频消息 6 地理位置消息 7 链接消息 实现非常简单,自定义一个继承MessageHandler的类,重写这7种类型的方法即可.注意:DefaultResponseMessage必须重写,用于返回没有处理过的消息类型(也可以用于默认消息,如帮助

图片懒加载库echo.js源码学习

最近不是在学习设计模式吗,然后就看到了代理模式加载图片的样例,然后自己实现了一下,就发现,自己写的这货每次就只能加载一张图片,而且图片要放在哪也是个很严重的问题 然后就去了 gayhub 找了找了找流行的图片懒加载库,这一找,就找到了一个echo.j是,打开一看,源码只有100多行吧,震惊..,看完源码,哎,木有上代理模式呀 仔细学习了下源码:觉得这种做法比较适合图片位置确定场景的吧,比如文章啊,一篇文章老长了,里面有蛮多图片散落在不同的地方,这样就比较合适,有可能有很多图片读者都不会翻到哪里,

python语言线程标准库threading.local源码解读

本段源码可以学习的地方: 1. 考虑到效率问题,可以通过上下文的机制,在属性被访问的时候临时构建: 2. 可以重写一些魔术方法,比如 __new__ 方法,在调用 object.__new__(cls) 前后进行属性的一些小设置: 3. 在本库中使用的重写魔术方法,上下文这两种基础之上,我们可以想到函数装饰器,类装饰器,异常捕获,以及两种上下文的结构: 灵活运用这些手法,可以让我们在代码架构上更上一层,能够更加省时省力. 1 from weakref import ref # ref用在了构造大

requests库核心API源码分析

requests库是python爬虫使用频率最高的库,在网络请求中发挥着重要的作用,这边文章浅析requests的API源码. 该库文件结构如图: 提供的核心接口在__init__文件中,如下: from . import utils from . import packages from .models import Request, Response, PreparedRequest from .api import request, get, head, post, patch, put,