有些时候处于代码窃密的要求,会须要把 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
装置文档,外面蕴含了 apt
,yum
模式的装置
单文件编译
以下局部来源于 nuitka
官网文档
创立一个hello.py
def talk(message):
return "Talk" + message
def 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.bin
Talk 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.py
2 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.asgi
import pathlib
import django.contrib
import django.urls
import 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.10
和django4.*
版本会遇到这个问题,看网络上其他人的教程中没有呈现这个问题,前期可能会有修复吧如下谬误能够通过
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-file
done
docker
容器镜像编译加密
创立一个requirements.txt
,写入如下依赖
gunicorn
django
nuitka
gevent
新建一个 compile.sh
,因为该脚本是在容器构建过程中应用,所以能够执行rm
操作
#!/bin/bash
for 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-bullseye
WORKDIR /work
# 因为须要编译 python,所以须要装置 gcc
RUN 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/archives
ADD requirements.txt requirements.txt
RUN 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
排除不必要的文件以及一些重要信息文件
Dockerfile
compose.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.0
hello | [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: gevent
hello | [2022-09-23 01:35:43 +0000] [9] [INFO] Booting worker with pid: 9
hello | [2022-09-23 01:35:43 +0000] [10] [INFO] Booting worker with pid: 10
hello | [2022-09-23 01:35:43 +0000] [11] [INFO] Booting worker with pid: 11
hello | [2022-09-23 01:35:43 +0000] [12] [INFO] Booting worker with pid: 12
当初进入容器进行编译验证
$ docker exec -it hello /bin/bash
[email protected]:/work# ls -al
total 1632
drwxr-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
官网文档