前言:对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.0
INFO Pyarmor 9.1.7 (trial), 000000, non-profits
INFO Platform windows.x86_64
INFO search inputs ...
INFO find script hello.py
INFO find 1 top resources
INFO start to generate runtime files
INFO target platforms {'windows.amd64'}
INFO write dist\pyarmor_runtime_000000\pyarmor_runtime.pyd
INFO generate runtime files OK
INFO start to obfuscate scripts
INFO process resource "hello"
INFO obfuscating file hello.py
INFO write dist\hello.py
INFO obfuscate scripts OK
(4)运行加密后的文件
python dist/hello.py
(smart_campus) E:\zhx\workspace_2025\DaBao\module_Read>python dist/hello.py
0 run success
1 run success
2 run success
3 run success
4 run success
5 run success
6 run success
7 run success
8 run success
9 run success
(5)日期时间过了之后运行结果
python dist/hello.py
(smart_campus) E:\zhx\workspace_2025\DaBao\module_Read>python dist/hello.py
Traceback (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.0
INFO Pyarmor 9.1.7 (trial), 000000, non-profits
INFO Platform windows.x86_64
INFO search inputs ...
INFO find script hello.py
INFO find 1 top resources
INFO start to generate runtime files
INFO target platforms {'windows.amd64'}
INFO write dist\pyarmor_runtime_000000\pyarmor_runtime.pyd
INFO generate runtime files OK
INFO start to obfuscate scripts
INFO process resource "hello"
INFO obfuscating file hello.py
INFO write dist\hello.py
INFO obfuscate scripts OK
(2)运行加密的文件
python dist/hello.py
(smart_campus) E:\zhx\workspace_2025\DaBao\module_Read>python dist/hello.py
Traceback (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.0
INFO Pyarmor 9.1.7 (trial), 000000, non-profits
INFO Platform windows.x86_64
INFO start to generate outer runtime key "pyarmor.rkey"
INFO write dist/key111\pyarmor.rkey
INFO 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.py
0 run success
1 run success
2 run success
3 run success
4 run success
5 run success
6 run success
7 run success
8 run success
9 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.py
Traceback (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.serverMain
Traceback (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 "<frozen __main__>", line 3, in <module>
File "<frozen DaBao.serverMain>", 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 tet
INFO Python 3.10.0
INFO Pyarmor 9.1.7 (trial), 000000, non-profits
INFO Platform windows.x86_64
INFO search inputs ...
INFO find package at module_Read
INFO find package at configs
INFO find package at module_Logging
INFO find package at tet
INFO find 4 top resources
INFO start to generate runtime files
INFO target platforms {'windows.amd64'}
INFO write dist\module_Read\pyarmor_runtime_000000\pyarmor_runtime.pyd
INFO generate runtime files OK
INFO start to obfuscate scripts
INFO process resource "module_Read"
INFO obfuscating file readExcel.py
INFO write dist\module_Read\readExcel.py
INFO obfuscating file read_document.py
INFO write dist\module_Read\read_document.py
INFO obfuscating file read_excel.py
INFO write dist\module_Read\read_excel.py
INFO obfuscating file Router_Read.py
INFO write dist\module_Read\Router_Read.py
INFO obfuscating file toolRead.py
INFO write dist\module_Read\toolRead.py
INFO obfuscating file __init__.py
INFO write dist\module_Read\__init__.py
INFO obfuscating file __init__.py
INFO write dist\module_Read\data\__init__.py
INFO obfuscating file __init__.py
INFO write dist\module_Read\static\__init__.py
INFO obfuscating file __init__.py
INFO write dist\module_Read\static\111\__init__.py
INFO obfuscating file __init__.py
INFO write dist\module_Read\static\documents\__init__.py
INFO obfuscating file __init__.py
INFO write dist\module_Read\static\file_img\__init__.py
INFO process resource "configs"
INFO obfuscating file config.py
INFO write dist\configs\config.py
INFO obfuscating file __init__.py
INFO write dist\configs\__init__.py
INFO process resource "module_Logging"
INFO obfuscating file loggingD1.py
INFO write dist\module_Logging\loggingD1.py
INFO obfuscating file __init__.py
INFO write dist\module_Logging\__init__.py
INFO process resource "tet"
INFO obfuscating file dd.py
INFO write dist\tet\dd.py
INFO obfuscating file hello.py
INFO write dist\tet\hello.py
INFO obfuscating file hh.py
INFO write dist\tet\hh.py
INFO obfuscating file __init__.py
INFO write dist\tet\__init__.py
INFO 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.0
INFO Pyarmor 9.1.7 (trial), 000000, non-profits
INFO Platform windows.x86_64
INFO search inputs ...
INFO find script serverMain.py
INFO find 1 top resources
INFO start to generate runtime files
INFO target platforms {'windows.amd64'}
INFO write dist\pyarmor_runtime_000000\pyarmor_runtime.pyd
INFO generate runtime files OK
INFO start to obfuscate scripts
INFO process resource "serverMain"
INFO obfuscating file serverMain.py
INFO write dist\serverMain.py
INFO obfuscate scripts OK
3.1.5 运行加密文件
python dist/serverMain.py
(smart_campus) E:\zhx\workspace_2025\DaBao>python dist/serverMain.py
INFO: 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.py
pyarmor gen --outer serverMain.py
运行测试报不存在licence
(smart_campus) E:\zhx\workspace_2025\DaBao>python dist/serverMain.py
Traceback (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.py
INFO: 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 OK
INFO: 192.168.1.155:63661 - "POST /Reader/DocumentReader HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (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 "<frozen module_Read.Router_Read>", line 23, in DocumentReader
RuntimeError: 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