使用pyarmor对python项目进行licence加密
前言:对python项目进行加密设置,实现 日期 + ip 的 licence 加密
一、pyarmor 介绍
PyArmor 是一款商业 Python 代码加密工具,可通过字节码转换、机器码编译等技术保护 Python 代码不被逆向工程。它主要用于保护商业软件、算法知识产权或敏感代码逻辑,防止未授权访问、修改或复制。
核心功能
- 代码加密
转换 Python 字节码为混淆格式,生成加密脚本。
支持直接运行加密代码,无需额外解密步骤。 - 多平台支持
兼容 Windows、Linux、macOS 等主流操作系统。
支持 x86、ARM 等多种硬件架构。 - 运行时保护
检测调试器、反编译工具,防止动态分析。
限制程序在特定机器、时间或环境中运行。 - 灵活部署
可选择性加密部分模块,保留纯 Python 代码兼容性。
支持加密 Python 包(Package)和应用程序。
二、单脚步加密
2.1 日期加密
2.1.1 单次设置加密方式
(1)安装包
pip install pyarmor
(2)创建测试脚本
hello.py脚本
for i in range(10): print(i, \'run success\')
(3)执行日期加密命令
pyarmor gen -e \"2025-07-02T17:20:00\" hello.py
- -e : 有效期日期,我这里设置的是运行时的20分钟之内(也可以直接填入整数,单位为天)
(smart_campus) E:\\zhx\\workspace_2025\\DaBao\\module_Read>pyarmor gen -e \"2025-07-02T17:20:00\" hello.py INFO Python 3.10.0INFO Pyarmor 9.1.7 (trial), 000000, non-profitsINFO Platform windows.x86_64INFO search inputs ...INFO find script hello.pyINFO find 1 top resourcesINFO start to generate runtime filesINFO target platforms {\'windows.amd64\'}INFO write dist\\pyarmor_runtime_000000\\pyarmor_runtime.pydINFO generate runtime files OKINFO start to obfuscate scriptsINFO process resource \"hello\"INFO obfuscating file hello.pyINFO write dist\\hello.pyINFO obfuscate scripts OK
(4)运行加密后的文件
python dist/hello.py
(smart_campus) E:\\zhx\\workspace_2025\\DaBao\\module_Read>python dist/hello.py0 run success1 run success2 run success3 run success4 run success5 run success6 run success7 run success8 run success9 run success
(5)日期时间过了之后运行结果
python dist/hello.py
(smart_campus) E:\\zhx\\workspace_2025\\DaBao\\module_Read>python dist/hello.pyTraceback (most recent call last): File \"E:\\zhx\\workspace_2025\\DaBao\\module_Read\\dist\\hello.py\", line 2, in <module> from pyarmor_runtime_000000 import __pyarmor__ File \"E:\\zhx\\workspace_2025\\DaBao\\module_Read\\dist\\pyarmor_runtime_000000\\__init__.py\", line 2, in <module> from .pyarmor_runtime import __pyarmor__RuntimeError: this license key is expired (1:11086)
提醒 licence 过期了
2.1.2 使用外部文件存放运行密钥
(1)在加密脚本的时候指定使用外部密钥
pyarmor gen --outer hello.py
(smart_campus) E:\\zhx\\workspace_2025\\DaBao\\module_Read>pyarmor gen --outer hello.py INFO Python 3.10.0INFO Pyarmor 9.1.7 (trial), 000000, non-profitsINFO Platform windows.x86_64INFO search inputs ...INFO find script hello.pyINFO find 1 top resourcesINFO start to generate runtime filesINFO target platforms {\'windows.amd64\'}INFO write dist\\pyarmor_runtime_000000\\pyarmor_runtime.pydINFO generate runtime files OKINFO start to obfuscate scriptsINFO process resource \"hello\"INFO obfuscating file hello.pyINFO write dist\\hello.pyINFO obfuscate scripts OK
(2)运行加密的文件
python dist/hello.py
(smart_campus) E:\\zhx\\workspace_2025\\DaBao\\module_Read>python dist/hello.pyTraceback (most recent call last): File \"E:\\zhx\\workspace_2025\\DaBao\\module_Read\\dist\\hello.py\", line 2, in <module> from pyarmor_runtime_000000 import __pyarmor__ File \"E:\\zhx\\workspace_2025\\DaBao\\module_Read\\dist\\pyarmor_runtime_000000\\__init__.py\", line 2, in <module> from .pyarmor_runtime import __pyarmor__RuntimeError: missing license key to run the script (1:10672)
提醒 licence 不存在
(3)生成 licence
pyarmor gen key -O dist/key111 -e 1
- -e 设置为 1 天
(smart_campus) E:\\zhx\\workspace_2025\\DaBao\\module_Read>pyarmor gen key -O dist/key111 -e 1 INFO Python 3.10.0INFO Pyarmor 9.1.7 (trial), 000000, non-profitsINFO Platform windows.x86_64INFO start to generate outer runtime key \"pyarmor.rkey\"INFO write dist/key111\\pyarmor.rkeyINFO generate outer runtime key OK
将 dist/key111//pyarmor.rkey 下的licence 拷贝到 hello的加密文件dist/pyarmor_runtime_000000/ 下
cp dist/key2/pyarmor.rkey dist/pyarmor_runtime_000000/
(4)运行查看
(smart_campus) E:\\zhx\\workspace_2025\\DaBao\\module_Read>python dist/hello.py0 run success1 run success2 run success3 run success4 run success5 run success6 run success7 run success8 run success9 run success
正常可以运行了
2.2 周期性检查运行密钥
当运行加密的服务时一直处于运行的状态时,需要设置周期性检查命令。
使用下面的命令生成的加密脚本,运行的时候会每隔一个小时对运行密钥进行一次检查
pyarmor gen --period 1 hello.py
2.3 日期+设备ip 加密
使用下面的命令绑定加密脚本到多台设备:
pyarmor gen -e 1 -b \"fe80::6172:250a:329d:3f97\" -b \"f48:tf:f2:j7:70:2f\" hello.py
- -b :物理地址 / ip / ipv4地址
- -e :日期
注意: 当我使用linux上的mac地址时是没有问题的,但是当我使用windows的物理地址是会报 “ERROR invalid device info “9C-***-44” ” ,这个时候我们只需要把windows物理地址中的 ‘-’ 改成 ‘:’ 就行了。
测试:当在其他设备上运行时
Traceback (most recent call last): File \"/home/ws/store/zhx/workspace_2024/dist/dd.py\", line 2, in <module> from pyarmor_runtime_000000 import __pyarmor__ File \"/home/ws/store/zhx/workspace_2024/dist/pyarmor_runtime_000000/__init__.py\", line 2, in <module> from .pyarmor_runtime import __pyarmor__RuntimeError: 脚本许可证不可用于当前设备 (1:10252)
三、python项目加密
3.1 使用单次加密方式
3.1.1 查看待打包的python项目目录
- serverMain.py 为启动脚本,启动成功如下:
3.1.2 命令介绍
- -r :递归搜索目录下面的 Python 脚本,否则只搜索当前目录下面的脚本
- -i :保存运行辅助文件到加密包的内部。
- -O :设置加密脚本的输出路径,默认值是 dist
3.1.3 分析
(1)在脚本互相引用的时候,需要把路径写全,如下在serverMain.py中引用:
from module_Read.Router_Read import RouterRead
(2) 如果使用直接对整个项目进行加密时
pyarmor gen -e 1 -r -i DaBao
运行加密后的文件会报错1
(smart_campus) E:\\zhx\\workspace_2025>python dist/DaBao/serverMain.pyTraceback (most recent call last): File \"E:\\zhx\\workspace_2025\\dist\\DaBao\\serverMain.py\", line 2, in <module> from .pyarmor_runtime_000000 import __pyarmor__ImportError: attempted relative import with no known parent package
报错2
(smart_campus) E:\\zhx\\workspace_2025>python -m dist.DaBao.serverMainTraceback (most recent call last): File \"F:\\anaconda3\\envs\\smart_campus\\lib\\runpy.py\", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File \"F:\\anaconda3\\envs\\smart_campus\\lib\\runpy.py\", line 86, in _run_code exec(code, run_globals) File \"\", line 3, in <module> File \"\", line 11, in <module>ModuleNotFoundError: No module named \'module_Read\'
3.1.4 正确的加密方式
因为我们的所有代码是在DaBao下,对应的在dist/下包含DaBao下所有的代码,为了名称统一,使用 -O 输出路径把dist改成DaBao。
然后对应DaBao中的代码,有configs、module_Logging、module_Read、tet4个文件夹,一个serverMain.py 脚本,所有我们需要区分开加密,文件夹的需要使用 “-r -i” 这 两个参数,对应 “serverMain.py” 则不需要。
注: 每个文件夹(不管几层,每层都需要)下都必须包含“init.py” 脚本 ,确保每个文件夹都被加载
(1)文件夹加密(需要保存为DaBao的话使用-O参数,这里使用默认的dist)
pyarmor gen -e 1 -r -i module_Read configs module_Logging tet
(smart_campus) E:\\zhx\\workspace_2025\\DaBao>pyarmor gen -e 1 -r -i module_Read configs module_Logging tetINFO Python 3.10.0INFO Pyarmor 9.1.7 (trial), 000000, non-profitsINFO Platform windows.x86_64INFO search inputs ...INFO find package at module_ReadINFO find package at configsINFO find package at module_LoggingINFO find package at tetINFO find 4 top resourcesINFO start to generate runtime filesINFO target platforms {\'windows.amd64\'}INFO write dist\\module_Read\\pyarmor_runtime_000000\\pyarmor_runtime.pydINFO generate runtime files OKINFO start to obfuscate scriptsINFO process resource \"module_Read\"INFO obfuscating file readExcel.pyINFO write dist\\module_Read\\readExcel.pyINFO obfuscating file read_document.pyINFO write dist\\module_Read\\read_document.pyINFO obfuscating file read_excel.pyINFO write dist\\module_Read\\read_excel.pyINFO obfuscating file Router_Read.pyINFO write dist\\module_Read\\Router_Read.pyINFO obfuscating file toolRead.pyINFO write dist\\module_Read\\toolRead.pyINFO obfuscating file __init__.pyINFO write dist\\module_Read\\__init__.pyINFO obfuscating file __init__.pyINFO write dist\\module_Read\\data\\__init__.pyINFO obfuscating file __init__.pyINFO write dist\\module_Read\\static\\__init__.pyINFO obfuscating file __init__.pyINFO write dist\\module_Read\\static\\111\\__init__.pyINFO obfuscating file __init__.pyINFO write dist\\module_Read\\static\\documents\\__init__.pyINFO obfuscating file __init__.pyINFO write dist\\module_Read\\static\\file_img\\__init__.pyINFO process resource \"configs\"INFO obfuscating file config.pyINFO write dist\\configs\\config.pyINFO obfuscating file __init__.pyINFO write dist\\configs\\__init__.pyINFO process resource \"module_Logging\"INFO obfuscating file loggingD1.pyINFO write dist\\module_Logging\\loggingD1.pyINFO obfuscating file __init__.pyINFO write dist\\module_Logging\\__init__.pyINFO process resource \"tet\"INFO obfuscating file dd.pyINFO write dist\\tet\\dd.pyINFO obfuscating file hello.pyINFO write dist\\tet\\hello.pyINFO obfuscating file hh.pyINFO write dist\\tet\\hh.pyINFO obfuscating file __init__.pyINFO write dist\\tet\\__init__.pyINFO obfuscate scripts OK
(2)脚本加密
pyarmor gen -e 1 serverMain.py
(smart_campus) E:\\zhx\\workspace_2025\\DaBao>pyarmor gen -e 1 serverMain.py INFO Python 3.10.0INFO Pyarmor 9.1.7 (trial), 000000, non-profitsINFO Platform windows.x86_64INFO search inputs ...INFO find script serverMain.pyINFO find 1 top resourcesINFO start to generate runtime filesINFO target platforms {\'windows.amd64\'}INFO write dist\\pyarmor_runtime_000000\\pyarmor_runtime.pydINFO generate runtime files OKINFO start to obfuscate scriptsINFO process resource \"serverMain\"INFO obfuscating file serverMain.pyINFO write dist\\serverMain.pyINFO obfuscate scripts OK
3.1.5 运行加密文件
python dist/serverMain.py
(smart_campus) E:\\zhx\\workspace_2025\\DaBao>python dist/serverMain.pyINFO: Uvicorn running on http://0.0.0.0:8208 (Press CTRL+C to quit)INFO: Started parent process [36260]INFO: Started server process [36624]INFO: Waiting for application startup.INFO: Started server process [34520]INFO: Waiting for application startup.INFO: Application startup complete.INFO: Application startup complete.
调用接口测试
3.2 使用外部文件存放运行密钥
3.2.1 外部加密
pyarmor gen --outer -r -i configs module_Logging module_Read tet serverMain.pypyarmor gen --outer serverMain.py
运行测试报不存在licence
(smart_campus) E:\\zhx\\workspace_2025\\DaBao>python dist/serverMain.pyTraceback (most recent call last): File \"E:\\zhx\\workspace_2025\\DaBao\\dist\\serverMain.py\", line 2, in <module> from pyarmor_runtime_000000 import __pyarmor__ File \"E:\\zhx\\workspace_2025\\DaBao\\dist\\pyarmor_runtime_000000\\__init__.py\", line 2, in <module> from .pyarmor_runtime import __pyarmor__RuntimeError: missing license key to run the script (1:10672)
3.2.2 生成licence
时效为5分钟之内
pyarmor gen key -O key222 -e \"2025-07-03T11:55:00\"
将这个licence粘贴到每个 pyarmor_runtime_000000 下
运行看结果
等5分钟后运行看结果
已经提醒licence过期了
3.2.3 周期性检查
由于当前代码运行之后是一个服务,只要启动的时候licence没有过期则可以一直运行着,可以使用 --period 参数对正在运行的服务进行周期性的检查
pyarmor gen key --period 1 -O key222 -e \"2025-07-03T12:30:00\"
然后把服务起来,1小时之后会进行自动检查
(smart_campus) E:\\zhx\\workspace_2025\\DaBao>python dist/serverMain.pyINFO: Uvicorn running on http://0.0.0.0:8208 (Press CTRL+C to quit)INFO: Started parent process [34736]INFO: Started server process [8884]INFO: Started server process [15508]INFO: Waiting for application startup.INFO: Waiting for application startup.INFO: Application startup complete.INFO: Application startup complete.
一个小时后重新调用
INFO: 192.168.1.155:52219 - \"POST /Reader/DocumentReader HTTP/1.1\" 200 OKINFO: 192.168.1.155:63661 - \"POST /Reader/DocumentReader HTTP/1.1\" 500 Internal Server ErrorERROR: Exception in ASGI applicationTraceback (most recent call last): File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\uvicorn\\protocols\\http\\h11_impl.py\", line 403, in run_asgi result = await app( # type: ignore[func-returns-value] File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\uvicorn\\middleware\\proxy_headers.py\", line 60, in __call__ return await self.app(scope, receive, send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\fastapi\\applications.py\", line 1054, in __call__ await super().__call__(scope, receive, send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\applications.py\", line 112, in __call__ await self.middleware_stack(scope, receive, send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\middleware\\errors.py\", line 187, in __call__ raise exc File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\middleware\\errors.py\", line 165, in __call__ await self.app(scope, receive, _send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\middleware\\exceptions.py\", line 62, in __call__ await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\_exception_handler.py\", line 53, in wrapped_app raise exc File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\_exception_handler.py\", line 42, in wrapped_app await app(scope, receive, sender) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\routing.py\", line 715, in __call__ await self.middleware_stack(scope, receive, send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\routing.py\", line 735, in app await route.handle(scope, receive, send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\routing.py\", line 288, in handle await self.app(scope, receive, send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\routing.py\", line 76, in app await wrap_app_handling_exceptions(app, request)(scope, receive, send) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\_exception_handler.py\", line 53, in wrapped_app raise exc File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\_exception_handler.py\", line 42, in wrapped_app await app(scope, receive, sender) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\starlette\\routing.py\", line 73, in app response = await f(request) File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\fastapi\\routing.py\", line 301, in app raw_response = await run_endpoint_function( File \"F:\\anaconda3\\envs\\smart_campus\\lib\\site-packages\\fastapi\\routing.py\", line 212, in run_endpoint_function return await dependant.call(**values) File \"\", line 23, in DocumentReaderRuntimeError: this license key is expired (1:11086)
看到提醒licence过期了。
四、绑定平台
- –platform
用于跨平台加密脚本指定运行加密脚本的目标平台
这个选项可以使用多次,也可以使用逗号把多个平台名称分开
平台名称必须是 Pyarmor 定义的 运行平台 名称
- Windows
- windows.x86_64
- windows.x86
- Many Linuxs
- linux.x86_64
- linux.x86
- linux.aarch64
- linux.armv7
- Apple Intel and Silicon
- darwin.x86_64
- darwin.aarch64 or darwin.arm64
- FreeBSD
- freebsd.x86_64
- Alpine Linux (musl-c)
- alpine.x86_64
- alpine.aarch64
- Android
- android.x86_64
- android.x86
- android.aarch64
- android.armv7