Pyarmor 是一个用于加密和保护 Python 源代码的小工具。它能够在运行时刻保护 Python 脚本的二进制代码不被泄露,设置加密后 Python 源代码的有效期限,绑定加密后的Python 源代码到硬盘、网卡等硬件设备。它的保障机制主要包括
- 加密编译后的代码块,保护模块中的字符串和常量
- 在脚本运行时候动态加密和解密代码块的二进制代码
- 代码块执行完成之后清空堆栈局部变量
- 通过授权文件限制加密后脚本的有效期和设备环境
让我们看看一个普通的 Python 脚本 foo.py
加密之后是什么样子。下面是加
密脚本所在的目录 dist
下的所有文件列表
foo.py
pytransform.py
_pytransform.so, or _pytransform.dll in Windows, _pytransform.dylib in MacOS
pyshield.key
pyshield.lic
product.key
license.lic
dist/foo.py
是加密后的脚本,它的内容如下
from pytransfrom import pyarmor_runtime
pyarmor_runtime()
__pyarmor__(__name__, __file__, b'\x06\x0f...')
所有其他文件叫做 运行依赖文件
,它们是运行加密脚本所必须的。并且只要这里面的模块pytransform.py
能被正常导入进来,加密脚本 dist/foo.py
就可以像正常脚本一样被运行。这是 Pyarmor 的一个重要特征: 加密脚本无缝替换 Python 源代码
加密 Python 源代码
Pyarmor 是怎么加密 Python 源代码呢?
首先把源代码编译成代码块 Code Object
char *filename = "foo.py";
char *source = read_file( filename );
PyCodeObject *co = Py_CompileString( source, "<frozen foo>", Py_file_input );
接着对这个代码块进行如下处理
- 使用
try...finally
语句把代码块的代码段co_code
包裹起来
新添加一个头部,对应于 try 语句:
LOAD_GLOBALS N (__armor_enter__) N = length of co_consts
CALL_FUNCTION 0
POP_TOP
SETUP_FINALLY X (jump to wrap footer) X = size of original byte code
接着是处理过的原始代码段:
对于所有的绝对跳转指令,操作