有些时候处于代码窃密的要求,会须要把python代码进行加密或者编译加密等来实现窃密

原理

  • Python是一种面向对象的解释型计算机程序设计语言,解释个性是将py编译为独有的二进制编码*.pyc文件,对pyc中的指令进行解释执行,然而pyc的反编译非常简单,可间接反编译为源码
  • 因为基于虚拟机(解释型语言)的编程语言比方java或者python很容易被人反编译,因而越来越多的利用将其中的外围代码以C/C++为编程语言,并且以*.so文件的模式提供
  • windows环境上面常常会看到*.dll文件,在Linux环境下常常会看到*.so文件,这两种都是动静库,*.so文件能够称为动态链接库或者共享库,是ELF文件格式,也是一种二进制文件,个别是C或者C++编译进去的

尽管目前有一些反编译伎俩能够去反编译so文件,然而如同成果都不怎么样,反编译进去的都是一堆比拟凌乱的C语言代码,咱们是用python编写的程序,所以把Python代码打包成so文件是能够达到加密的要求的

技术依赖

开源我的项目Nuitka,采纳Apache-2.0 license协定

装置nuitka

pip形式

python -m pip install -U nuitka

Ubuntu22上面应用python3.10是能够胜利装置的,其余操作系统或者python版本如果装置失败

请具体浏览官网nuitka装置文档,外面蕴含了aptyum模式的装置

单文件编译

以下局部来源于nuitka官网文档

创立一个hello.py

def talk(message):    return "Talk " + messagedef main():    print(talk("Hello World"))if __name__ == "__main__":    main()

当前目录文件为

$ ll总用量 4.0K-rw-rw-r-- 1 gong gong 133 九月   22 12:52 hello.py

开始编译

因为之前是采纳pip形式装置的nuitka,所以应用的时候须要带上python -m的前缀

如果是应用apt或者yum等装置的,间接运行nuitka或者nuitka3即可

运行如下命令能够在当前目录上面创立一个hello.bin的文件

$ python -m nuitka hello.py --remove-output....

参数解释

--remove-output参数示意在生成二进制编译文件之后移除编译构建目录,该目录是编译过程中会应用到,编译完结之后即可删除

运行二进制文件

$ ./hello.binTalk Hello World

我的项目级别编译

上面采纳django我的项目进行演示,出于不便采纳sqlite数据库,生产环境请应用其余数据库

创立示范我的项目

$ pip install django -i https://pypi.doubanio.com/simple/$ django-admin startproject hellonuitka$ cd hellonuitka$ python manage.py migrate$ python manage.py runserver

查看初始门路树

tree能够通过sudo apt/yum install tree装置)

$ tree.├── db.sqlite3├── hellonuitka│   ├── asgi.py│   ├── __init__.py│   ├── __pycache__│   │   ├── __init__.cpython-310.pyc│   │   ├── settings.cpython-310.pyc│   │   ├── urls.cpython-310.pyc│   │   └── wsgi.cpython-310.pyc│   ├── settings.py│   ├── urls.py│   └── wsgi.py└── manage.py2 directories, 11 files

开始编译

在我的项目根目录下(manage.py同级目录)开始进行编译,编译的过程当中须要指定编译的文件夹名称

$ python -m nuitka --module hellonuitka --include-package=hellonuitka --remove-output

命令执行实现之后查看目录树,发现多了一个hellonuitka.cpython-310-x86_64-linux-gnu.so文件以及hellonuitka.pyi

$ tree.├── db.sqlite3├── hellonuitka│   ├── asgi.py│   ├── __init__.py│   ├── __pycache__│   │   ├── __init__.cpython-310.pyc│   │   ├── settings.cpython-310.pyc│   │   ├── urls.cpython-310.pyc│   │   └── wsgi.cpython-310.pyc│   ├── settings.py│   ├── urls.py│   └── wsgi.py├── hellonuitka.cpython-310-x86_64-linux-gnu.so├── hellonuitka.pyi└── manage.py

生成文件解释

hellonuitka.pyi

文件内容如下,这个问价蕴含了包外面的导入信息(官网文档的形容是说是用于检测隐式导入的)

standalone模式创立的库会须要应用到这个文件,目前应用的模式不须要这个文件,能够间接删除,或者在执行命令的时候增加参数--no-pyi-file不生成这个文件

........import django.core.asgiimport pathlibimport django.contribimport django.urlsimport django.core.wsgi........

hellonuitka.cpython-310-x86_64-linux-gnu.so

由打包之前的文件夹hellonuitka组成,前面拼接的是cpython-{python版本号}-{cpu架构}-{操作系统信息},这个是一个二进制文件,能够用于等效替换hellonuitka

验证编译后果

挪动旧的源码文件夹

$ mv hellonuitka /tmp/hellonuitka

删除不必要的*.pyi文件

$ rm hellonuitka.pyi

删除生成的sqlite数据库,不便测试前面的migrate命令是否失常

$ rm db.sqlite3

最初在编译我的项目根目录下的python源码

开始进行验证,查看我的项目门路树

$ ll总用量 224K-rw-rw-r-- 1 gong gong 218K 九月   22 15:09 hellonuitka.cpython-310-x86_64-linux-gnu.so-rwxrwxr-x 1 gong gong  667 九月   22 12:00 manage.py

开始执行命令,发现都失常运行

$ python manage.py migrate$ python manage.py startapp app1$ python manage.py runserver.....

可能遇到的谬误

  • manage.py转成manage.bin之后的报错
$ python -m nuitka manage.py --remove-output$ mv manage.py /tmp/manage.py

查看文件

$ ll总用量 6.2M-rw-r--r-- 1 gong gong 128K 九月   22 16:24 db.sqlite3-rw-rw-r-- 1 gong gong 218K 九月   22 17:16 hellonuitka.cpython-310-x86_64-linux-gnu.so-rwxrwxr-x 1 gong gong 5.8M 九月   22 17:20 manage.bin

运行下列命令都是能够失常的

$ ./manage.bin migrate$ ./manage.bin startapp app2

然而./manage.bin runserver就不行了,谬误如下

$ ./manage.bin runserver SyntaxError: Non-UTF-8 code starting with '\x80' in file /home/gong/work/hellonuitka/./manage.bin on line 2, but no encoding declared; see https://python.org/dev/peps/pep-0263/ for details

会报错不反对 UTF-8编码

次要是因为manage.py启动服务是通过命令掉包反射机制实现包导入进行服务启动的,导致不反对runserver命令,其余命令还是能够失常运行的

如果对于manage.py没有什么重要信息的话就能够不必编译这个文件了,免得不必要的麻烦

  • 运行gunicorn hellonuitka.wsgi谬误

    python3.10django4.*版本会遇到这个问题,看网络上其他人的教程中没有呈现这个问题,前期可能会有修复吧

    如下谬误能够通过mv hellonuitka.cpython-310-x86_64-linux-gnu.so hellonuitka.so

    ModuleNotFoundError: No module named 'hellonuitka'

    然而还是会遇到谬误,去搜寻了一圈没找到有什么解决方案,如果也遇到了雷同的问题,并且找不到解决方案的话,倡议采纳uwsgi,该形式是能够失常启动的
    (Tips: 如果是采纳docker环境部署服务,如采纳python:3.10.7-slim-bullseye镜像进行编译之后(其余版本的python docker镜像可能也是一样的),gunicorn服务是能够失常启动的,也不会遇到下面的 No module named 'hellonuitka'谬误,所以大千世界神秘莫测)

    undefined symbol: PyDescr_IsData

docker环境编译加密

在我的项目根目录上面执行此命令,之后再删除python源代码文件即可,只保留so文件

for dir in $(ls -d */)do  python -m nuitka --module ${dir%?} --include-package=${dir%?} --remove-output --no-pyi-filedone

docker容器镜像编译加密

创立一个requirements.txt,写入如下依赖

gunicorndjangonuitkagevent

新建一个compile.sh,因为该脚本是在容器构建过程中应用,所以能够执行rm操作

#!/bin/bashfor dir in $(ls -d */)do  python -m nuitka --module ${dir%?} --include-package=${dir%?} --remove-output --no-pyi-file  rm -rf ${dir}done

创立一个Dockerfile文件

FROM python:3.10.7-slim-bullseyeWORKDIR /work# 因为须要编译python,所以须要装置gccRUN sed -i "s#http://deb.debian.org#https://mirrors.ustc.edu.cn#g" /etc/apt/sources.list \    && apt update \    && apt install -y gcc \    && rm -rf /var/lib/apt/lists/ \    && rm -rf /var/cache/apt/archivesADD requirements.txt requirements.txtRUN pip install --no-cache-dir -r requirements.txt -i https://pypi.doubanio.com/simple/COPY . .RUN bash compile.sh && rm compile.sh requirements.txt

采纳docker compose形式部署

我的项目根目录上面新建.dockerignore排除不必要的文件以及一些重要信息文件

Dockerfilecompose.yaml.git/.idea/.dockerignore

新建compose.yaml文件

services:  hellonuitka:    build: .    container_name: hello    image: hello    ports:      - 8000:8000    restart: always    command:     - /bin/sh     - -c     - |        python manage.py migrate &&        gunicorn hellonuitka.wsgi --bind=0.0.0.0:8000 --workers=4 --worker-connections=1000 --worker-class=gevent

此时我的项目的门路树如下

├── app2│   ├── admin.py│   ├── apps.py│   ├── __init__.py│   ├── migrations│   │   └── __init__.py│   ├── models.py│   ├── tests.py│   └── views.py├── compile.sh├── compose.yaml├── Dockerfile├── hellonuitka│   ├── asgi.py│   ├── __init__.py│   ├── settings.py│   ├── urls.py│   └── wsgi.py├── manage.py└── requirements.txt

开始进行构建,因为是第一次构建镜像所以须要携带--build参数,命令执行完结之后能够去拜访http://127.0.0.1:8000进行验证服务是否启动胜利

$ docker compose up --build# 能够看到输入中最初几行如下.....hello  | [2022-09-23 01:35:43 +0000] [8] [INFO] Starting gunicorn 20.1.0hello  | [2022-09-23 01:35:43 +0000] [8] [INFO] Listening at: http://0.0.0.0:8000 (8)hello  | [2022-09-23 01:35:43 +0000] [8] [INFO] Using worker: geventhello  | [2022-09-23 01:35:43 +0000] [9] [INFO] Booting worker with pid: 9hello  | [2022-09-23 01:35:43 +0000] [10] [INFO] Booting worker with pid: 10hello  | [2022-09-23 01:35:43 +0000] [11] [INFO] Booting worker with pid: 11hello  | [2022-09-23 01:35:43 +0000] [12] [INFO] Booting worker with pid: 12

当初进入容器进行编译验证

$ docker exec -it hello /bin/bash[email protected]:/work# ls -altotal 1632drwxr-xr-x 1 root root   4096 Sep 23 01:39 .drwxr-xr-x 1 root root   4096 Sep 23 01:39 ..-rw-r--r-- 1 root root 764584 Sep 23 01:39 app2.cpython-310-x86_64-linux-gnu.so-rw-r--r-- 1 root root 131072 Sep 22 08:24 db.sqlite3-rw-r--r-- 1 root root 756264 Sep 23 01:39 hellonuitka.cpython-310-x86_64-linux-gnu.so-rwxrwxr-x 1 root root    667 Sep 22 09:34 manage.py

拓展理解

Nuitka是将python编译成C代码 ,再编译成可执行文件,不存在反向解析的问题,十分平安,因为可执行文件由C编译而来,运行速度也会取得晋升,然而在应用nuitka过程当中还是会有一些问题的,生产环境应用的话尽量做到全量测试,如果遇到一些简单的编译之后很难解决的问题,也能够考虑一下pyinstaller,这个开源我的项目编译操作更简略,相对来说坑也更少一些,然而编译之后的运行速度上不如nuitka编译之后的软件,并且编译之后的软件的反编译难度比nuitka更低一些(编译成pyc,也能够应用一些加密参数在打包时候进行代码加密)

参考浏览

Nuitka官网我的项目

Nuitka官网文档