开发工具应用安全【免费下载链接】pyarmorA tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.项目地址https://gitcode.com/gh_mirrors/py/pyarmor点击查看免费下载导读本文以 PyArmor 仓库官方文档 wheel.rst 为主体讲解如何将经 PyArmor 混淆后的 Python 包用 setuptools 构建成可分发的 Wheel 包。你将掌握完整的示例工程结构、pyarmor gen混淆命令与python -m build构建命令的配合方式、pyarmor cfg模块级配置的精确用法深入理解attr:版本读取与StaticModule导致构建失败的原理及两种解决方案并学会用插件自动修补混淆脚本。文中的每一条命令与参数均有 src/cli 下的源码实现作为佐证。为什么需要构建混淆后的 WheelPyArmor 的常规用法是把脚本混淆到某个输出目录默认dist/后直接分发该目录。但在发布正式 Python 库时更标准、更利于用户pip install的方式是构建成 Wheel 包。Wheel 是 Python 的二进制发布格式安装速度快、与pip集成紧密而混淆后的产物.py字节码文件 运行时扩展pyarmor_runtime_*.so恰好也属于源码 二进制的混合体非常适合封装进 Wheel。这条路径要解决三个核心问题混淆后源码的目录迁移PyArmor 输出目录dist/需要重新映射为 Python 包的根目录版本号读取冲突setuptools 的version attr: ...依赖ast.parse直接读取源码 AST而混淆代码无法被其解析构建会失败运行时包的打包与重命名pyarmor_runtime_00xxxx运行时扩展必须随包一起分发且可以按需重命名、换位置存放。下文以官方文档中的test-project示例为主线完整演示这一过程。第一步准备测试工程结构文档给出的示例工程层级如下完整代码见 docs/how-to/wheel.rsttest-project ├── MANIFEST.in ├── pyproject.toml ├── setup.cfg └── src └── parent ├── child │ └── __init__.py └── __init__.py其中src/是 setuptools 推荐的源码目录布局src layoutparent/child是两层嵌套子包。三个配置文件的职责如下。pyproject.toml声明构建后端[build-system] requires [ setuptools66.1.1, wheel ] build-backend setuptools.build_meta这里显式要求setuptools66.1.1该版本开始对version attr:采用基于StaticModule的 AST 静态读取机制下文会详述wheel则用于生成 Wheel 格式产物。setup.cfg声明包结构与版本来源[metadata] name parent.child version attr: parent.child.VERSION [options] package_dir dist/ packages parent parent.child parent.pyarmor_runtime_00xxxx include_package_data True关键点version attr: parent.child.VERSION让 setuptools 从模块属性parent.child.VERSION动态读取版本号package_dir dist/把包的根目录重定向到混淆输出目录dist/这样parent和parent.child直接取自混淆产物packages中显式列出parent.pyarmor_runtime_00xxxx把 PyArmor 生成的运行时扩展作为普通子包一并打包00xxxx是随每次混淆生成的运行时后缀include_package_data True配合MANIFEST.in把.so二进制文件收进 wheel。MANIFEST.in收录运行时动态库recursive-include dist/parent/pyarmor_runtime_00xxxx *.sorecursive-include会把dist/parent/pyarmor_runtime_00xxxx/下所有.so文件Linux 下运行时扩展名Windows 下对应.pyd递归纳入源码包与 wheel 包。src/parent/__init__.py与src/parent/child/__init__.py的内容一致均为版本常量VERSION 0.0.1第二步混淆源码包进入工程目录后执行递归混淆$ cd test-project $ pyarmor gen --recursive -i src/parent参数说明--recursive等价-r以递归模式搜索并混淆子目录下的所有.py脚本默认仅处理指定目录对应命令行定义见 src/cli/main.py默认配置项finder.recursive 0见 src/cli/default.cfg-i即--prefix的短选项形式表示把运行时文件存放在包内部import_prefix其与--prefix PREFIX的处理逻辑见 src/cli/main.py 和 src/cli/main.py。成功执行后dist/目录结构如下dist └── parent ├── child │ ├── __init__.py │ └── __pycache__ │ └── __init__.cpython-311.pyc ├── __init__.py └── pyarmor_runtime_00xxxx ├── __init__.py └── pyarmor_runtime.so可以看到混淆后的parent/child/__init__.py与运行时扩展pyarmor_runtime_00xxxx/pyarmor_runtime.so都被生成在dist/parent下与setup.cfg中package_dir dist/的布局完全吻合。其中pyarmor_runtime_00xxxx这个包名的默认格式由配置项runtime.package_name_format pyarmor_runtime_{suffix}决定{suffix}会替换为实际运行时后缀见 src/cli/default.cfg 与 src/cli/context.py。第三步构建 Wheel 并复现版本号读取异常执行构建$ python -m build --skip-dependency-check --no-isolation--no-isolation表示直接用当前环境构建、跳过创建隔离虚拟环境避免每次构建都重新下载构建依赖--skip-dependency-check跳过依赖完整性检查。若未安装build需先pip install build。文档中的预期结果是构建失败错误栈如下* Building sdist... Traceback (most recent call last): File /usr/lib/python3/dist-packages/setuptools/config/expand.py, line 81, in __getattr__ return next( ^^^^^ StopIteration The above exception was the direct cause of the following exception: Traceback (most recent call last): File /usr/lib/python3/dist-packages/setuptools/config/expand.py, line 191, in read_attr return getattr(StaticModule(module_name, spec), attr_name)异常根因StaticModule 无法解析混淆源码从回溯可以看出setuptools 在展开version attr: parent.child.VERSION时走到了expand.py中的read_attr进而实例化StaticModule。StaticModule的实现方式是用ast.parse对源码文件做静态语法分析、直接提取局部变量而非真正import模块。PyArmor 混淆后的脚本是可运行但不可静态解析的密文形态它不再包含普通的VERSION 0.0.1字面量赋值语句模块级的VERSION常量已被重写/保护ast.parse无法从中读出该属性于是触发StopIteration异常。解决方案手工恢复版本属性解决思路是在混淆产物中补回一个可供ast.parse读取的版本语句。编辑dist/parent/child/__init__.py在文件头部追加from pyarmor_runtime_00xxxx import __pyarmor__ VERSION 0.0.1 ...其中from pyarmor_runtime_00xxxx import __pyarmor__保持混淆产物原有的运行时引导导入追加的VERSION 0.0.1则让 setuptools 的 AST 解析能够取到版本值。解除 PyArmor 的防修改限制默认情况下 PyArmor 会校验混淆脚本的完整性不允许用户改动混淆产物防止篡改。因此直接手工编辑dist/下的文件前必须先用pyarmor cfg对特定模块关闭这一限制$ pyarmor cfg -p parent.child.__init__ restrict_module 0 $ pyarmor gen --recursive -i src/parent这条命令的语义值得拆解pyarmor cfg是运行时配置命令-p指定某个模块或包的私有配置-p parent.child.__init__表示本次设置只对parent/child/__init__.py生效而不会影响其它模块的默认防篡改行为——这正是文档强调仅对该文件关闭限制的原因restrict_module 0关闭该模块的 restrict 模式即允许修改混淆产物配置语法模块路径 选项名 值的处理逻辑见 src/cli/config.py 的run方法-p参数在 src/cli/main.py 中定义为special module or package 的 private settings修改配置后需重新执行pyarmor gen让配置生效并重新生成混淆产物。关于restrict_module的取值从 src/cli/main.py 的命令行选项可进一步确认--private对应取值 2私密模式--restrict对应取值 3包的 restrict 模式设为 0 即关闭该模块的 restrict 限制。另外默认配置中builder.exclude_restrict_modules __init__见 src/cli/default.cfg表示__init__模块默认本就不在 restrict 之列但parent.child.__init__之所以仍需显式关闭是因为版本属性场景下模块被当作需要保护的对象处理。修改完成后重新构建$ python -m build --skip-dependency-check --no-isolation此时attr: parent.child.VERSION能在混淆后的__init__.py中静态读取到VERSIONsdist 与 wheel 均可成功生成。第四步重命名运行时包并放入子包默认方案把pyarmor_runtime_00xxxx作为parent下的平级子包存放。如果你希望运行时包改名为libruntime并把它放入parent.child子包内部需要同时调整三处。修改 MANIFEST.inrecursive-include dist/parent/child/libruntime *.so修改 setup.cfg[options] ... packages parent parent.child parent.child.libruntime ...重新配置并混淆$ pyarmor cfg package_name_format libruntime $ pyarmor gen --recursive --prefix parent.child src/parent两个命令的含义pyarmor cfg package_name_format libruntime把运行时包名从默认的pyarmor_runtime_{suffix}改为固定的libruntime不再带随机后缀pyarmor gen --recursive --prefix parent.child src/parent注意此处使用的是长选项--prefix parent.child而非短选项-i。--prefix的语义是把运行时包以parent.child作为导入前缀即运行时包最终出现在parent/child/libruntime/目录下与之对应导入语句为from parent.child.libruntime import __pyarmor__--prefix参数定义见 src/cli/main.py。完成后仍需手工把VERSION 0.0.1补进dist/parent/child/__init__.py因为--prefix只改变运行时包的位置不改变版本属性的静态读取问题再构建$ python -m build --skip-dependency-check --no-isolation第五步用插件自动修补版本属性手工编辑混淆产物既繁琐又易错尤其每次重新混淆后都要重做一遍。PyArmor 的插件机制提供了在构建后自动修补的能力把修补逻辑写进插件脚本每次pyarmor gen结束后由post_build钩子自动执行。编写插件脚本在工程根目录创建.pyarmor/myplugin.py__all__ [VersionPlugin] class VersionPlugin: staticmethod def post_build(ctx, inputs, outputs, pack): script os.path.join(outputs[0], parent, child, __init__.py) with open(script, a) as f: f.write(\nVERSION 0.0.1)要点插件模块位于.pyarmor/目录下PyArmor 会把该目录作为本地插件搜索路径之一__all__声明插件导出的类名PyArmor 会加载其中所有成员作为插件实例加载逻辑见 src/cli/plugin.pypost_build是构建完成后回调的钩子PyArmor 在构建流程末尾以plugin.post_build(ctx, inputs, outputs, packpack)形式调用所有注册了post_build的插件见 src/cli/plugin.pyoutputs[0]是本次构建的输出根目录即dist/inputs为输入路径列表pack在打包模式下为打包参数用追加写方式把VERSION 0.0.1补到__init__.py末尾。注意本示例中类内直接引用了os实际使用时需在插件文件顶部import os文档为省略写法在此补全以保持可运行。启用插件$ pyarmor cfg plugins mypluginplugins是builder节下的配置项表示向现有插件列表追加而不是覆盖、、-、^四种操作符的处理见 src/cli/config.py其中表示覆盖、表示追加。默认配置为plugins CodesignPlugin DarwinUniversalPlugin见 src/cli/default.cfg执行上述命令后列表变为CodesignPlugin DarwinUniversalPlugin myplugin。一键化构建启用插件后每次发布只需两条命令$ pyarmor gen --recursive --prefix parent.child src/parent $ python -m build --skip-dependency-check --no-isolationpyarmor gen会自动完成混淆、生成运行时包、并触发post_build修补版本属性python -m build随即读取到完整可解析的混淆产物并产出 Wheel。整个流程无需再手工编辑任何混淆文件。附配置命令与插件机制的源码对应为便于读者在仓库中继续深入本文涉及的关键实现位置汇总如下能力源码位置说明gen命令选项解析src/cli/main.py--recursive、-i/--prefix、--output、--restrict/--private等-i/--prefix转import_prefixsrc/cli/main.py运行时包前缀写入构建选项restrict_module隐式升级src/cli/main.pyassert_call/assert_import会自动把restrict_module提升到 2cfg命令与-p参数src/cli/main.py-p定义 module/package 级私有配置配置读写与操作符src/cli/config.py追加、覆盖、-移除、^换行追加插件加载与post_build回调src/cli/plugin.py.pyarmor/目录、__all__导出、post_build(ctx, inputs, outputs, pack)运行时包名格式src/cli/default.cfgpackage_name_format pyarmor_runtime_{suffix}默认插件与 restrict 排除项src/cli/default.cfg 、src/cli/default.cfgexclude_restrict_modules __init__、plugins CodesignPlugin DarwinUniversalPlugin总结与适用前提本文完整演示了混淆 → 配置 → 构建 → 排错 → 自动化的整条 wheel 打包链路先理解attr:版本读取为何与混淆产物冲突再用pyarmor cfg -p ... restrict_module 0精确解除单模块限制并手工补回版本常量最后用pyarmor cfg plugins 挂载自定义插件把修补动作自动化。适用于需要把混淆库以标准 wheel 形式发布到 PyPI 或内部私有源的场景。几点前提与限制需要注意文中命令基于 PyArmor 8.x 命令行pyarmor gen、pyarmor cfg与 setuptools 构建链混淆与构建均在 Linux 环境演示*.so在 Windows 下对应*.pydMANIFEST.in的匹配模式需相应调整--prefix parent.child方案会把运行时包嵌入子包最终目录结构、导入路径与默认方案不同需与setup.cfg的packages列表保持一致关闭restrict_module意味着该模块的混淆产物允许被改写请仅在确有版本修补需求时按模块粒度启用避免放宽整个包的防篡改保护。赞分享开发工具应用安全【免费下载链接】pyarmorA tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.项目地址https://gitcode.com/gh_mirrors/py/pyarmor点击查看免费下载相关推荐PyArmor 使用完全指南从脚本混淆、License 绑定到打包发布PyArmor 使用完全指南从脚本混淆、License 绑定到打包发布 导读 PyArmor 是一款用于混淆 Python 脚本的命令行工具核心能力是混淆开发工具应用安全Pyarmor混淆实战从单个脚本到复杂包的完整保护方案Pyarmor混淆实战从单个脚本到复杂包的完整保护方案 Pyarmor是Python开发者保护代码安全的终极利器这款强大的 Python代码混淆工具 能够将开发工具应用安全BentoPDF 部署到 Netlify从构建配置到 SharedArrayBuffer 排错的完整指南BentoPDF 部署到 Netlify从构建配置到 SharedArrayBuffer 排错的完整指南 BentoPDF 是一个隐私优先Privacy F前端上一篇Windows Cleaner终极指南三步解决C盘爆红让Windows系统重获新生下一篇MikroORM 自定义数据库驱动开发指南从 Platform 到 Driver 的四层架构与完整实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考