> 技术文档 > 使用pyarmor对python项目进行licence加密

使用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

使用pyarmor对python项目进行licence加密
(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项目目录

使用pyarmor对python项目进行licence加密

  • serverMain.py 为启动脚本,启动成功如下:

使用pyarmor对python项目进行licence加密
使用pyarmor对python项目进行licence加密

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

使用pyarmor对python项目进行licence加密

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.

使用pyarmor对python项目进行licence加密
调用接口测试
使用pyarmor对python项目进行licence加密

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 下
运行看结果
使用pyarmor对python项目进行licence加密
等5分钟后运行看结果
使用pyarmor对python项目进行licence加密
已经提醒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.

使用pyarmor对python项目进行licence加密
一个小时后重新调用

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