Python 脚本安全防护全攻略(二)
在上一篇文章中,我们探讨了三种常见的 Python 脚本保护方法:将脚本编译为 .pyc 文件、进行脚本级加密以及对数据文件进行加密。这些方法在一定程度上能够提供保护,但面对专业的逆向工程手段时,其安全性仍有待加强。因此,本文将继续介绍三种更具安全性的 Python 脚本保护方案,旨在帮助开发者进一步提升代码的安全防护能力,有效抵御源代码被轻易破解的风险。
读者群体
- Python 脚本开发者
- 安全领域技术研究人员
魔改 Python 解释器
魔改 Python 解释器是对之前提到的将脚本编译为 .pyc 文件的保护方法的一种高级强化手段。通过修改 Python 解释器中的字节码定义并重新编译,生成的定制化 Python 解释器能够有效抵御标准反编译工具(例如 uncompyle)对 .pyc 文件的反编译操作。本文将以 Python 3.8 为例进行说明。
实施步骤
- 从 GitHub 下载 CPython 3.8 的源代码。
- 修改
Include/opcode.h文件中的字节码定义,例如将#define POP_TOP修改为(1 ^ 0x56),对字节码进行异或操作。 - 编译 Python 项目,生成定制化的 Python 解释器。
防护效果
经过修改字节码后,尽管文件格式保持不变,但使用标准反编译工具如 uncompyle6 对 .pyc 文件进行反编译时,将无法还原出原始的源代码。例如,运行命令 uncompyle6.exe -o 1.py test.cpython-38.pyc 时,会发现反编译失败,输出如下错误信息:
-- Stacks of completed symbols:
START ::= |- stmts .
_come_froms ::= \e__come_froms . COME_FROM
_come_froms ::= \e__come_froms . COME_FROM_LOOP
while1stmt ::= \e__come_froms . l_stmts COME_FROM JUMP_BACK COME_FROM_LOOP
whileTruestmt ::= \e__come_froms . l_stmts JUMP_BACK POP_BLOCK
whileTruestmt38 ::= \e__come_froms . l_stmts JUMP_BACK
whileTruestmt38 ::= \e__come_froms . l_stmts JUMP_BACK COME_FROM_EXCEPT_CLAUSE
whileTruestmt38 ::= \e__come_froms . pass JUMP_BACK
whileTruestmt38 ::= \e__come_froms \e_pass . JUMP_BACK
whilestmt38 ::= \e__come_froms . testexpr \e_l_stmts_opt COME_FROM JUMP_BACK POP_BLOCK
whilestmt38 ::= \e__come_froms . testexpr \e_l_stmts_opt JUMP_BACK POP_BLOCK
whilestmt38 ::= \e__come_froms . testexpr \e_l_stmts_opt JUMP_BACK come_froms
whilestmt38 ::= \e__come_froms . testexpr l_stmts JUMP_BACK
whilestmt38 ::= \e__come_froms . testexpr l_stmts come_froms
whilestmt38 ::= \e__come_froms . testexpr l_stmts_opt COME_FROM JUMP_BACK POP_BLOCK
whilestmt38 ::= \e__come_froms . testexpr l_stmts_opt JUMP_BACK POP_BLOCK
whilestmt38 ::= \e__come_froms . testexpr l_stmts_opt JUMP_BACK come_froms
whilestmt38 ::= \e__come_froms . testexpr returns POP_BLOCK
Instruction context:
->
L. 1 0 GET_AITER
2 GET_AITER
4 <58>
6 UNARY_NOT
# file test.cpython-38.pyc
# Parse error at or near `GET_AITER' instruction at offset 0
test.cpython-38.pyc --
# decompile failed
潜在风险与限制
- 逆向工程人员可以通过对比标准版和魔改版字节码之间的差异,修改反编译工具来进行逆向。
- 生成的
.pyc文件只能在定制的解释器环境中运行,这给部署带来了不便。 - 每次 Python 版本更新时,都需要单独维护魔改后的解释器,这增加了维护成本。
Python 到 C 的转换
最具代表性的工具是 Cython。Cython 能够将 Python 源代码转换为等价的 C 代码,然后将其编译为 Python 的 C 扩展模块(例如 .pyd 或 .so 文件)。这种方法不仅可以有效防止 Python 源代码泄露,还能显著提升代码的执行效率。Python C 扩展模块(如 .pyd、.so 或 .dylib 文件)本质上是一个动态链接库,只是使用了 Python SDK 编写,能够与 Python 解释器进行交互。
逆向技能要求
- 熟悉 Python C API。
- 掌握 native 层的静态分析和动态调试技术。
实施步骤
- 安装 Cython:
pip install cython。 - 编写
setup.py文件。 - 编译:
python setup.py build_ext --inplace。
示例 Python 源码:
def sayhi():
print('Hello from Cython!')
示例 setup.py 文件:
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules = cythonize("test.py"))
防护效果
下图展示了使用 Cython 转换后的汇编代码反编译效果:

方案局限性
- 部分 Python 特殊语法的兼容性可能存在问题。
- 开发者需要额外学习 Cython 相关知识。
- 需要为不同的平台和架构分别进行编译。
- 对于经验丰富的逆向工程人员来说,仍有可能通过静态和动态调试了解代码逻辑。
逆向对抗思路
- 确定编译
.pyd文件所使用的 Python 版本和 Cython 版本。 - 下载对应版本,自行编译一份带有调试信息的
.pyd文件。 - 结合生成的 C 文件和 IDA 工具进行静态对比分析,了解 Cython 生成
.pyd文件的框架结构。 - 根据 Python 提供的 C API 文档分析代码逻辑。
字节码级加密
这是一种针对 Python 字节码的保护技术。该方案首先将 Python 脚本编译为代码对象(Code Object),然后对代码对象中的字节码进行加密。在脚本运行时,通过加载解密的 Python C 扩展库来动态解密和加密字节码,从而防止逆向工程人员窃取字节码。通常,还会对解密的 Python C 扩展库进行代码保护,以增强安全性。
核心优势
- 运行时动态解密,确保内存中不会暴露完整的字节码。
- 与保护前的 Python 脚本无缝替换,无需修改原有代码结构。
- 兼容主流 Python 版本,包括 Python 3.6 至 3.13。
- 结合 native 代码加固技术,提供多层防护。
逆向技能要求
- 熟悉 Python 解释器的内部结构,例如 CodeObject 等。
- 掌握 native 层的静态分析和动态调试技术。
- 具备分析混淆后的 native 代码的能力。
实施步骤
虽然实现难度较高,但目前已经有比较成熟和稳定的实现方案。具体操作可以参考深盾科技官网的《Python 程序保护最佳实践》文档。
防护效果
示例代码:
from virbox_pyruntime import virbox
virbox((b'X\xa7m\x04h\xbe \x83^\x8a\xcf\xf0\x1e\x0c.........~o\xf6\xd7\x05\x11\xebm\x83\x1c\x8e\x07v\x13Dt\rzA\xf2\x9bN-\xe5\xfb\xde\x1f\xd7`\x1bo\xa4'))
方案局限性
- 如果代码调用频率很高,可能会导致性能下降。
- 实现较为复杂,但已有成熟的第三方工具可供使用。
代码保护方案对比
| 保护方案 | 安全强度 | 性能影响 | 部署复杂度 | 适用场景 |
|---|---|---|---|---|
.pyc 文件 |
★☆☆☆☆ | 无影响 | 中 | 基础保护 |
| 脚本级混淆 | ★★☆☆☆ | 轻微影响 | 低 | 快速简易保护 |
| 数据文件加密 (DS) | ★★★☆☆ | 轻微影响 | 中 | 敏感数据和脚本保护 |
| 魔改 Python 解释器 | ★★★☆☆ | 无影响 | 高 | 封闭可控环境 |
| Python 到 C 的转换 | ★★★★☆ | 性能提升 | 中 | 性能敏感代码 |
| 字节码级加密 | ★★★★★ | 可控影响 | 低 | 商业级高安全需求 |
总结
在本文介绍的六种 Python 脚本安全防护方式中,字节码级加密方案提供了最高级别的安全性。尽管每种方案都有其自身的优缺点,但通过合理选择并组合这些保护措施,可以显著提升 Python 脚本的安全性,有效抵御各种潜在的逆向工程威胁。

浙公网安备 33010602011771号