☰
PyArmor 项目(Project)机制完全指南:用 `.pyarmor_config` 高效管理混淆脚本
2026/10/13 7:49:45 网站建设 项目流程
  • 开发工具
  • 应用安全

【免费下载链接】pyarmor

A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.

项目地址:https://gitcode.com/gh_mirrors/py/pyarmor
点击查看免费下载

PyArmor 的 Project(项目)机制把"源目录 + 配置文件 + 输出路径"封装成一个可重复执行的混淆工作单元,让你不再每次手工挑选脚本、重复敲参数,而是通过init、config、build、info四个命令完成从初始化到增量构建的全流程。本文基于仓库文档 docs.7/project.rst 展开,并结合源码 src/project.py、src/pyarmor.py 与 src/cli/project.py 深入讲解项目配置文件中每个属性的含义、默认值与底层行为,读完即可上手用项目方式管理你的混淆脚本。

Project 是什么

Project 是一个包含自身配置文件的文件夹,用于统一管理一批待混淆的 Python 脚本。它的本质是"目录 + 一份 JSON 配置",配置文件默认名为.pyarmor_config(见 src/config.py 中的config_filename = '.pyarmor_config'),存放在项目路径下。

使用 Project 管理混淆脚本有四个显著优势:

  • 增量构建:只有自上次构建以来发生变更的脚本才会被重新混淆,无需每次全量处理;
  • 过滤脚本:可以在项目中精确筛选待混淆的脚本,排除某些脚本或目录;
  • 不同混淆模式:可以为同一批脚本配置并使用不同的混淆模式;
  • 管理更便捷:所有脚本的混淆状态与构建记录集中在项目维度统一维护。

从源码角度看,项目对象在 src/project.py 中实现为Project(dict)类,它维护了从version、name到build_time等一系列默认属性,并用build_time记录最后一次构建时间——这正是增量构建判定的依据:get_build_files()会比较每个脚本的mtime与build_time,仅收集更新过的文件(src/project.py)。

注意:本文以 PyArmor 7.x 的经典 Project 机制为主进行讲解(与 docs.7/project.rst 对应)。在 9.x 的新版 CLI 中,项目信息改由本地配置文件([project]节)承载,相关实现见 src/cli/project.py,本文会在相应位置给出对照说明。

创建项目:init 命令

在当前目录创建项目

在源代码目录下执行:

cd examples/pybench pyarmor init --entry=pybench.py

这会在当前路径生成项目配置文件.pyarmor_config。源码中_init的实现(src/pyarmor.py)做了如下工作:

  1. 若目标路径已存在.pyarmor_config,直接报错A project already exists in "...",防止重复初始化;
  2. 将--src解析为绝对路径写入配置(未指定时默认为当前目录的绝对路径);
  3. 根据--type(app/pkg/auto)与入口脚本是否以__init__.py结尾,决定项目是"独立应用"还是"包"(is_package=1);
  4. 以项目目录的 basename 作为name与title,调用project.save()写出 JSON 配置。

在指定路径创建项目

如果想把项目配置保存在其他位置,可以使用--src显式指定源码路径:

pyarmor init --src=examples/pybench --entry=pybench.py projects/pybench

此时会创建projects/pybench目录,并在其中保存.pyarmor_config。注意src与项目路径是相对关系:配置中记录的是从项目文件夹出发的相对路径(当src为相对路径时),这样整个项目目录迁移后配置依然可用。

init还支持以下参数(见 src/pyarmor.py):

参数说明
-t, --typeauto(默认)/app/pkg;pkg或 auto 且入口为__init__.py时自动视为包
-e, --entry项目入口脚本,可多个(逗号分隔)
-s, --src项目源码基准路径,默认为空(当前目录)
project项目路径,默认为空(当前目录)

项目日常操作:info / build / config

项目的常规用法是"进入项目路径后执行一切操作":

cd projects/pybench

查看项目信息:pyarmor info

pyarmor info

_info实现(src/pyarmor.py)打开项目配置后调用Project.info(),后者会把全部配置属性(含build_time,格式化为可读时间)逐行输出(src/project.py)。

构建项目:pyarmor build

pyarmor build

构建是项目的核心动作,源码中_build的执行流程(src/pyarmor.py)大致如下:

  1. 打开项目并做一致性检查(project.check()),包括:项目路径存在、src存在且为绝对路径、src与output不得相同、license 文件合法等(src/project.py);
  2. 通过 manifest 模板在src下匹配待混淆文件(get_build_files());
  3. 为每个入口脚本生成运行时文件与引导(bootstrap)代码;
  4. 逐个脚本加密混淆,输出到output路径;
  5. 将当前时间写入build_time并保存配置,作为下次增量构建的基准。

修改项目配置:pyarmor config

pyarmor config --manifest "include *.py, prune dist, prune test"

config命令(_config,src/pyarmor.py)用于更新项目配置:读取现有配置 → 将参数归一化(相对路径基于项目路径换算)→ 调用project._update()只更新显式传入的属性 → 保存回.pyarmor_config。

例如,排除dist、test目录中的.py文件:

pyarmor config --manifest "include *.py, prune dist, prune test"

manifest 中还可以列出数据文件,构建时会一并拷贝到输出路径:

pyarmor config --manifest "include *.py, include config.json" pyarmor build

通过--manifest可以精确选择项目脚本,其模板语法与规则详见下文manifest属性。

强制全量重建

pyarmor build --force

build的-B, --force选项(src/pyarmor.py)会跳过增量判断,混淆全部脚本。源码中get_build_files(force=True)直接返回完整文件列表,而不比较mtime与build_time(src/project.py)。

运行混淆后的脚本

cd dist python pybench.py

构建产物输出到output(默认dist),其中包含混淆后的脚本与运行时文件;入口脚本已自动插入引导代码(from pytransform import pyarmor_runtime; pyarmor_runtime()),可直接运行。

修改源码后重新构建

cd projects/pybench pyarmor build

由于项目记住了上次构建时间(build_time),再次构建只混淆"变更过的脚本"——这正是"增量构建"优势的落地体现。

用不同模式混淆脚本

先配置不同的混淆模式,再重新构建:

pyarmor config --obf-mod=1 --obf-code=0 pyarmor build -B

这里-B(即--force)确保所有脚本都以新模式全量重建。obf_mod与obf_code的语义见下文配置文件属性说明。另外在 9.x 中目标选择改为--rft、--mini、--vmc、--ecc等构建目标(src/cli/command.py),这是版本演进带来的差异。

用子项目混淆特殊脚本

场景:项目绝大多数脚本用 restrict mode 3 混淆,但个别脚本需要 restrict mode 2。子项目(child project)就是为此设计的,它通过复制并修改配置文件实现同一源码树下的差异化混淆。

# 1. 在源码路径创建项目并设置 restrict 3 cd /path/to/src pyarmor init --entry foo.py pyarmor config --restrict 3 # 2. 复制配置文件创建子项目 .pyarmor_config-1 cp .pyarmor_config .pyarmor_config-1 # 3. 配置子项目:指定特殊脚本、无入口、restrict 2 pyarmor config --entry "" \ --manifest "include a.py other/path/sa*.py" \ --restrict 2 \ .pyarmor_config-1 # 4. 分别构建主项目与子项目 pyarmor build -B pyarmor build --no-runtime -B .pyarmor_config-1

要点解读:

  • 子项目就是一份独立的.pyarmor_config-1配置文件,build命令可以直接接受"项目配置文件名"作为参数(build的project位置参数:Project path, or project configuration file,见 src/pyarmor.py);
  • 子项目不设入口脚本(--entry ""),避免引导代码重复插入;
  • 用--manifest精确圈定"少数特殊脚本",与主项目的 manifest 互补;
  • 主项目构建时已生成运行时文件,因此子项目用--no-runtime跳过运行时生成,避免重复输出;--force确保子项目脚本无论是否变更都被重新混淆。

项目配置文件详解

每个项目都有一份 JSON 配置文件,即项目路径下的.pyarmor_config。以下属性均与 docs.7/project.rst 及 src/project.py 中的默认值对应。

基础属性:name / title / src / output

  • name:项目名称。
  • title:项目标题。init时默认与项目目录 basename 相同。
  • src:manifest 模板匹配文件的基准路径。可以是绝对路径,也可以是相对项目文件夹的相对路径。_check()强制要求构建时src解析后为绝对路径且必须存在。
  • output:构建输出的保存路径,相对项目路径计算,默认dist(default_output_path,见 src/config.py)。校验中明确禁止output与src相同,防止混淆产物覆盖源码。

manifest:精确选择要混淆的文件

manifest是一个字符串,指定哪些文件会被混淆,语法与 Python Distutils 的MANIFEST.in一致。默认值为:

global-include *.py

即匹配src树中任意位置的.py文件。多个模板指令用逗号分隔,例如:

global-include *.py, exclude __mainfest__.py, prune test
  • include/exclude:按路径匹配单个模式;
  • global-include/global-exclude:在整个src树中匹配;
  • prune:排除整个目录树;
  • recursive-include等其余 Distutils 指令同样可用。

数据文件也可以写入 manifest,构建时会被拷贝到输出路径(例如前面的include config.json)。源码层面,Project.build_manifest()借助distutils.filelist.FileList逐条处理模板行并返回文件集合(src/project.py);get_build_files()则在 manifest 基础上追加自动排除项(例如输出路径自身),再按增量策略过滤(src/project.py)。

is_package:按包结构输出

可选值0、1、None。设为1时,src的 basename 会被追加到output作为最终保存路径,但运行时文件仍直接放在output下(src/pyarmor.py)。init时若未指定--type:入口为__init__.py则自动设为1,否则为None。

restrict_mode:限制模式

可选值0、1、2、3、4,默认1。控制混淆脚本的运行限制强度(0 表示不限制;1 为基础限制,防止直接反编译运行;更高数值增强对源码、导入与调用的校验)。注意:若同时使用外部 license,restrict 0与外部 license 冲突(源码会在_check()及构建时抛出'--restrict 0" is conflicted with outer license'异常,src/project.py)。

entry:入口脚本与引导代码

entry是包含一个或多个入口脚本的字符串,入口名相对于src,也支持绝对路径;多入口用逗号分隔:

main.py, another/main.py, /usr/local/myapp/main.py

构建时,会为每个入口插入如下引导代码:

from pytransform import pyarmor_runtime pyarmor_runtime()

该引导模板定义在 src/config.py。注意:如果 manifest 没有包含某个入口,则该入口可能不被混淆,因此请确保入口脚本在 manifest 匹配范围内。入口脚本还会获得额外的交叉保护代码插入(见cross_protection)。

capsule:项目专用加密钥(已移除)

自 v5.9.0 起移除。早期版本中它表示项目专用 capsule 文件名,相对项目路径解析;新版本统一使用默认 capsule,config --capsule传入时会被忽略并告警(src/pyarmor.py)。

obf_code:代码对象混淆方式

控制**每个代码对象(code object)**如何混淆:

  • 0:不混淆;
  • 1(默认):用默认算法混淆每个代码对象;
  • 2:用更复杂的算法混淆每个代码对象。

源码将obf_code、obf_mod与wrap_mode组合映射为最终混淆模式,映射逻辑见Project.map_obfuscate_mode()(src/project.py)。

wrap_mode:代码对象包裹模式

可选值0、1、None,默认1。决定是否用try..finally块包裹代码对象,用于增强反调试与反篡改能力。

obf_mod:模块级混淆方式

控制整个模块代码对象如何混淆:

  • 0:不混淆;
  • 1(默认):用 DES 算法混淆模块字节码。

cross_protection:动态库保护

控制混淆脚本中动态库(_pytransform)的保护方式:

  • 0:不保护;
  • 1:按默认模板插入保护代码;
  • 文件名:从指定文件读取保护代码模板,替代默认模板。

--no-runtime构建时若开启保护会告警并自动降级为 0(src/pyarmor.py)。

runtime_path:动态库搜索路径

None或任意路径。运行混淆脚本时去哪里找动态库_pytransform。默认None,表示位于运行时包内或与pytransform.py同目录。典型场景:把混淆脚本打进 zip(如用 py2exe 打包)时,将runtime_path设为空字符串,并把运行时文件拷贝到 zip 同目录即可解决动态库定位问题。该值最终通过encrypt_script(..., rpath=project.runtime_path, ...)写入产物(src/pyarmor.py)。

plugins:扩展 license 类型

None或字符串列表,用于扩展混淆脚本的 license 类型,支持多插件:

plugins: ["check_ntp_time", "show_license_info"]

仓库 plugins 目录提供check_ntp_time.py、check_gpu.py、check_docker.py、check_multiple_machine.py等参考插件。

package_runtime:运行时文件组织形式

  • 0:运行时文件与混淆脚本保存在同一路径;
  • 1(默认):保存在子路径pytransform中,作为包发布。

enable_suffix:运行时包后缀

v5.8.7 新增。

  • 0(默认):运行时包(模块)名无后缀;
  • 1:运行时包(模块)名带后缀,例如pytransform_vax_00001。

用于支持"导入由不同开发者混淆的脚本"时避免运行时包命名冲突。

platform:交叉编译目标平台

v5.9.0 新增。

一个包含一个或多个平台的字符串,多平台用逗号分隔。不进行跨平台混淆时留空。构建时按逗号切分并交给compatible_platform_names()与check_cross_platform()处理(src/pyarmor.py)。

license_file:自定义 license 文件

v5.9.0 新增。

指定除默认 license 之外使用的 license 文件;留空使用默认 license。校验规则要求文件以license.lic结尾或为特殊值outer/no(src/project.py)。

bootstrap_code:引导代码插入方式

v5.9.0 新增。

控制入口脚本引导代码的生成方式:

  • 0:不向入口脚本插入引导代码;
  • 1(默认):插入引导代码;若脚本名为__init__.py则用带前导点的相对导入,否则用绝对导入;
  • 2:始终在入口脚本中使用不带前导点的绝对导入;
  • 3:始终在入口脚本中使用带前导点的相对导入。

源码据此计算relative标志并传给运行时生成与make_entry()(src/pyarmor.py、src/pyarmor.py)。

与新版(PyArmor 9)的对照

仓库同时包含 9.x 的新架构实现(当前仓库版本为 9.2.7,见 src/config.py):

  • 新版本仍以"项目"为核心概念,但项目信息改由本地配置文件承载([project]节),pyarmor init通过ConfigParser写入src、scripts、modules、packages、excludes、recursive等字段(src/cli/command.py);
  • 新版本引入Project/Module/Package/Namespace四类概念模型,将项目拆分为脚本、模块、包与命名空间四类组件(src/cli/project.py);
  • 构建目标从"模式参数"演变为--rft、--mini、--vmc、--ecc等目标参数(src/cli/command.py),并新增pyarmor env交互式环境/项目配置命令。

小结与建议

以 Project 方式管理混淆脚本的核心收益在于:一份.pyarmor_config+ 四条命令(init/config/build/info)= 可重复、可增量、可差异化配置的完整混淆工作流。实践建议:

  1. 优先为每个待交付的应用/包建立独立项目,让manifest精确圈定交付范围,避免误混淆无关文件;
  2. 善用--force做全量重建,配合info确认配置后再切换混淆模式;
  3. 需要对少数脚本特殊处理时,复制配置文件创建子项目,主项目负责运行时生成、子项目用--no-runtime补齐差异化脚本;
  4. 打包进 zip 或需跨平台交付时,重点关注runtime_path、platform、enable_suffix三个属性。

如需进一步了解混淆模式与限制模式的详细语义,可继续阅读仓库文档 docs.7/mode.rst;运行时与引导代码的实现可参考 src/pytransform.py 与 src/cli/core/runtime.py。

  • 开发工具
  • 应用安全

【免费下载链接】pyarmor

A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.

项目地址:https://gitcode.com/gh_mirrors/py/pyarmor
点击查看免费下载

相关推荐

上一篇:txAdmin服务器管理平台技术解析与部署实践
下一篇:从Gray-Scott到FitzHugh-Nagumo:Ready中的经典反应扩散模型实现指南 🧪

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询