有时,由于代码保密的要求,需要对python代码进行加密或编译,实现保密代码原理Python是一种面向对象的解释型计算机程序设计语言,其解释特性是将py编译成唯一的二进制编码*.pyc文件来解释和执行pyc中的指令,但是pyc的反编译非常简单,直接反编译成源代码即可。因为java或python等基于虚拟机(解释型语言)的编程语言很容易被逆向所以越来越多的应用使用C/C++作为核心代码的编程语言,并以*.so文件的形式提供.*.dll文件在windows环境下常见,在Linux环境下也常见。查看*.so文件,这两个都是动态库。*.so文件可以称为动态链接库或共享库。它们是ELF文件格式,也是二进制文件。它们通常由C或C++编译。虽然目前有一些反编译的方法可以反编译so文件,但是好像效果不是很好。反编译出来的是一堆乱七八糟的C语言代码。我们是用python写程序,所以我们把python代码打包成so文件,可以满足加密的要求。该技术依赖于开源项目Nuitka,使用Apache-2.0许可协议安装nuitkapip,安装方式为python-mpipinstall-Unuitka。Ubuntu22下可以成功安装Python3.10。其他操作系统或python版本如果安装失败,请详细阅读nuitka官方安装文档,里面有apt和yum形式的安装单文件。编译nuitka官方文档中的以下部分以创建hello.pydeftalk(message):return"Talk"+messagedefmain():print(talk("HelloWorld"))if__name__=="__main__":main()当前目录文件为$lltotalusage4.0K-rw-rw-r--1gonggong133September2212:52hello.py开始编译。因为nuitka之前是pip安装的,所以使用的时候需要加上python-m前缀。如果是使用apt或yum安装的,直接运行nuitka或nuitka3即可,在当前目录运行如下命令Down创建一个hello.bin文件$python-mnuitkahello.py--remove-output....参数说明--remove-output参数表示生成二进制编译文件后删除编译构建目录,即编译过程中会用到,编译完成后可以删除二进制文件运行。$./hello.binTalkHelloWorld项目级编译下面使用django项目进行演示。为了方便,使用了sqlite数据库。对于生产环境,请使用其他数据库创建演示项目。$pipinstalldjango-ihttps://pypi.doubanio.com/simple/$django-adminstartprojecthellonuitka$cdhellonuitka$pythonmanage.pymigrate$pythonmanage.pyrunserver查看初始路径树(树可以通过sudoapt/yuminstalltr??eeinstall)$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目录,11个文件开始编译在项目根目录(manage.py同级目录)开始编译,开始编译。编译时需要指定编译文件夹名$python-mnuitka--modulehellonuitka--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不生成这个文件.........importdjango.core.asgiimportpathlibimportdjango.contribiimportdjango.urlsimportdjango.{操作系统信息},这是一个二进制文件,可用于etc.有效替换hellonuitka验证编译结果移动旧的源文件夹$mvhellonuitka/tmp/hellonuitka删除不需要的*.pyi文件$rmhellonuitka.pyi删除生成的sqlite数据库,方便测试后面的migrate命令是否正常$rmdb.sqlite3终于开始验证编译项目根目录下的python源码,查看项目路径树$lltotalusage224K-rw-rw-r--1gonggong218KSeptember2215:09hellonuitka.cpython-310-x86_64-linux-gnu.so-rwxrwxr-x1gonggong667September2212:00manage.py开始执行命令,发现运行正常$pythonmanage.pymigrate$pythonmanage.pystartappapp1$pythonmanage.pyrunserver.....manage.py转换为manage.bin后可能出现的错误报错$python-mnuitkamanage.py--remove-output$mvmanage.py/tmp/manage.py查看文件$lltotalusage6.2M-rw-r--r--1gonggong128KSeptember2216:24db.sqlite3-rw-rw-r--1gonggong218KSeptember2217:16hellonuitka.cpython-310-x86_64-linux-gnu.so-rwxrwxr-x1gonggong5.8MSeptember2217:20manage.bin运行以下命令正常$./manage.binmigrate$。/manage.binstartappapp2但是./manage.binrunserver就不行了,报错如下$./manage.binrunserverSyntaxError:Non-UTF-8codestartingwith'\x80'infile/home/gong/work/hellonuitka/./manage.bin在第2行,但没有声明编码;详见https://python.org/dev/peps/pep-0263/会报错,不支持UTF-8编码,主要是manage.py通过命令包反射机制启动服务完成打包导入并启动服务。导致不支持runserver命令,其他命令依然可以正常运行。如果没有manage.py的重要信息,则不需要编译该文件。经过运行gunicornhellonuitka.wsgi以避免不必要的麻烦。这个问题在python3.10和django4.*版本都会遇到。网上其他人的教程中没有出现这个问题。稍后可能会修复。以下错误可以通过mvhellonuitka.cpython-310-x86_64-linux-gnu.sohellonuitka.soModuleNotFoundError:Nomodulenamed'hellonuitka'但我仍然遇到错误。找了一圈也没找到解决办法。如果你也遇到同样的问题,找不到解决方案,建议使用uwsgi,可以正常启动(提示:如果你使用docker环境部署服务,比如用python编译后:3.10.7-slim-bullseye镜像(其他版本的pythondocker镜像可能相同),gunicorn服务可以正常启动,不会遇到上面的Nomodulenamed'hellonuitka'错误,所以世界很神秘)undefinedsymbol:PyDescr_IsData在非docker环境编译加密后在项目根目录下执行该命令,然后删除python源码文件,只保留$(ls-d*/)中dir的so文件dopython-mnuitka--module${dir%?}--include-package=${dir%?}--remove-output--no-pyi-filedonedocker容器镜像编译加密创建一个requirements.txt并写入如下依赖gunicorndjangonuitkagevent新建一个compile.sh,因为这个脚本是用在容器构建过程中执行rm操作#!/bin/bashfordirin$(ls-d*/)dopython-mnuitka--module${dir%?}--include-package=${dir%?}--remove-output--no-pyi-filerm-rf${dir}done从python:3.10.7-slim-bullsey创建一个DockerfileeWORKDIR/work#因为需要编译python,所以需要安装gccRUNsed-i"s#http://deb.debian.org#https://mirrors.ustc.edu.cn#g"/etc/apt/来源。列出\&&aptupdate\&&aptinstall-ygcc\&&rm-rf/var/lib/apt/lists/\&&rm-rf/var/cache/apt/archivesADDrequirements.txtrequirements.txtRUNpipinstall--no-cache-dir-rrequirements.txt-ihttps://pypi.doubanio.com/simple/COPY..RUNbashcompile.sh&&rmcompile.shrequirements.txt使用dockercompose将项目部署到根目录下。dockerignore排除不需要的文件和一些重要的信息文件Dockerfilecompose.yaml.git/.idea/.dockerignore新建一个compose.yaml文件services:hellonuitka:build:。container_name:helloimage:helloports:-8000:8000restart:always命令:-/bin/sh--c-|pythonmanage.pymigrate&&gunicornhellonuitka.wsgi--bind=0.0.0.0:8000--workers=4--worker-connections=1000--worker-class=geventthis当前项目的路径树如下├──app2│├──admin.py│├──apps.py│├──__init__.py│├──迁移││└──__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验证服务是否启动成功$dockercomposeup--build#可以看到输出的最后几行如下.....hello|[2022-09-2301:35:43+0000][8][INFO]启动gunicorn20.1.0hello|[2022-09-2301:35:43+0000][8][INFO]正在收听:http://0.0.0.0:8000(8)你好|[2022-09-2301:35:43+0000][8][INFO]使用工人:geventhello|[2022-09-2301:35:43+0000][9][INFO]使用pid启动工作程序:9hello|[2022-09-2301:35:43+0000][10][INFO]使用pid启动工作程序:10hello|[2022-09-2301:35:43+0000][11][INFO]使用pid启动工作程序:11hello|[2022-09-2301:35:43+0000][12][INFO]Bootingworkerwithpid:12现在进入容器编译验证$dockerexec-ithello/bin/bashroot@f18baf3ec559:/work#ls-altotal1632drwxr-xr-x1rootroot4096Sep2301:39.drwxr-xr-x1rootroot4096Sep2301:39。.-rw-r--r--1rootroot764584Sep2301:39app2.cpython-310-x86_64-linux-gnu.so-rw-r--r--1rootroot131072Sep2208:24db.sqlite3-rw-r--r--1rootroot756264Sep2301:39hellonuitka.cpython-310-x86_64-linux-gnu.so-rwxrwxr-x1rootroot667Sep2209:34manage.py扩展理解Nuitka将python编译成C代码,然后编译成可执行文件。没有逆向分析的问题,非常安全。由于可执行文件是从C编译出来的,运行速度也会有所提升,但是在使用nuitka的过程中还是会出现一些问题。如果您在生产环境中使用它,请尝试进行完整测试。如果遇到一些编译后难以解决的复杂问题,也可以考虑pyinstaller。这个开源项目的编译操作比较简单。坑也比较少,但是编译后运行速度不如nuitka编译出来的软件,而且编译出来的软件反编译难度比nuitka低(编译成pyc,还可以使用一些加密参数来打包加密时执行代码)参考Nuitka官方项目Nuitka官方文档
