PyObfuscator代码混淆总结
介绍
首先说重点,需要python3.9+版本才行,只能混淆单个文件,对有调用关系的两个python文件无法同时进行混淆,个人非商业使用还是推荐pyarmor。通过PyObfuscator -h查询详细的参数信息如下:
-h, --help: 显示帮助信息并退出。
--output-filename OUTPUT_FILENAME, --output OUTPUT_FILENAME, -o OUTPUT_FILENAME: 指定混淆后的代码输出文件名。
--level LEVEL, -l LEVEL: 指定混淆级别,LEVEL 可以是某个数字或描述,表示混淆的强度。
--names NAMES [NAMES ...], -n NAMES [NAMES ...]: 预定义要使用的名称(语法:原名:混淆名)。
--deobfuscate, -d: 保存配置和混淆与默认名称之间的映射。
--password PASSWORD, -w PASSWORD: 加密密钥,用于加密代码。
--file-encoding FILE_ENCODING, -e FILE_ENCODING: 打开 Python 文件时使用的编码。
--names-size NAMES_SIZE, -s NAMES_SIZE: 指定混淆名称的大小。
--print, -p: 在控制台打印混淆后的代码。
--log-level LOG_LEVEL, -g LOG_LEVEL: 指定日志级别。
--log-filename LOG_FILENAME, -f LOG_FILENAME: 指定日志文件名。
我测试发现-l默认的混淆级别是6,及时设置7等以上的数字跟6的效果一样,具体的各混淆级别信息可以查阅原代码PyObfuscator.py
文件可以找到,下面总结如下(ai辅助):
混淆级别 1
- 变量名变更:使用
Obfuscator.change_variables_name
函数改变变量名,使变量名变得不那么直观。 - 删除文档和签名:删除函数和类的文档字符串(docstrings)以及签名,这使得代码的意图和结构更难以理解。
混淆级别 2
- 包含级别 1 的所有混淆。
- 字符串加密:使用
Obfuscator.crypt_strings
函数加密字符串,使字符串变得不可读,但可能会增加代码的执行时间。
混淆级别 3
- 包含级别 2 的所有混淆。
- 代码压缩:使用 GZIP 压缩代码,使代码结构变得不可见,但同样可能会增加执行时间。
混淆级别 4
- 包含级别 3 的所有混淆。
- 代码加密:对代码进行加密,这会进一步增加执行时间。
混淆级别 5
- 包含级别 4 的所有混淆。
- 使用 base85 编码代码:将代码编码为 base85,这会导致文件大小增大,并且执行时间更长。
混淆级别 6
- 包含级别 5 的所有混淆。
- 十六进制转义编码:将代码编码为十六进制转义字符(例如,字符 ‘a’ 变为 ‘\x061’),这会导致文件大小增加到原来的四倍。
总结来说,随着混淆级别的提高,PyObfuscator
采取了更复杂的混淆策略,包括变量名变更、字符串加密、代码压缩、代码加密以及不同的编码方式。这些策略不仅增加了代码的复杂性,也可能会影响代码的执行效率。每个级别的混淆都会包含前一个级别的所有混淆措施,并在其基础上增加新的混淆技术。因此,选择合适的混淆级别需要在代码安全性和执行效率之间做出权衡。
示例
混淆单个文件
这里展示常用的命令,根据需要进行选择。
PyObfuscator -o ./demo/demo_obfu.py ^
-w "123456" ^
-l 6 ^
./demo/demo.py
批量混淆目录下所有py文件
import os
import subprocess
# 设定项目目录和输出目录
project_dir = './demo_dir'
output_dir = './demo_dir_obfuscated'
os.makedirs(output_dir, exist_ok=True)
# 遍历项目目录中的所有 Python 文件
for root, dirs, files in os.walk(project_dir):
for filename in files:
if filename.endswith('.py'):
# 构建输入和输出文件的完整路径
input_file = os.path.join(root, filename)
output_file = os.path.join(output_dir, filename)
# 构建PyObfuscator命令
command = [
'PyObfuscator',
'-o', output_file,
input_file
]
# 执行命令
subprocess.run(command, check=True)