mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1828 字
5 分钟
.nbpf 的秘密——一个插件格式,为什么要搞五层加密
2026-05-11
NOTE

这篇很长。看不完可以收藏,以后需要的时候再看。

.nbpf 是什么#

.nbpf(Nebula Plugin File)是 NebulaShell 的二进制插件打包格式。

全称 “Nebula Plugin File”,本质上是一个经过多重加密、多重签名、多层嵌套的 ZIP 容器

跟普通的 ZIP 或 JAR 不一样——普通 ZIP 一解压就全看见了,.nbpf 从设计之初就把代码保护防篡改发布者身份验证作为核心目标。

你看不到里面有什么#

一个 .nbpf 文件,用普通的解压软件是打不开的。

不是因为格式特殊,是因为它被加密了。你看到的是一堆二进制乱码。

理论上它内部是一个标准 ZIP 归档,布局是这样的:

  • META-INF/ — 元数据和加密信息区
    • MANIFEST.MF:完整元数据,加密存储
    • SIGNATURE:外层 Ed25519 签名
    • SIGNER.PEM:签名者的公钥
    • ENCRYPTION:RSA-OAEP 加密的外层 AES 密钥
    • INNER_SIGNATURE:中层 RSA-4096 签名
    • INNER_ENCRYPTION:RSA-OAEP 加密的中层 AES 密钥
    • MODULE_SIGS:内层 HMAC 签名列表
    • PLUGIN.MF:明文公开的四个字段(name、version、author、description),只用于索引发现
  • NIR/ — 编译后的中间表示目录
    • 所有 Python 源码被编译为序列化 code object(NIR),经过两层 AES-256-GCM 加密存储
  • RES/ — 资源文件目录
    • 非脚本文件(图片、配置等)以明文存储
CAUTION

这是内部结构。普通用户看不到,也不需要看到。

五层安全体系#

从外到内,一共五层。层层递进,每一层解决不同的问题。

第一层:外层 Ed25519 签名

验证整个包的签名,确保包没有被中间人篡改。验签公钥由包内提供,同时支持本地信任列表校验。这是最外层的完整性检查。

第二层:外层 AES-256-GCM 加密

使用随机生成的 key1 加密 META-INF 区域。key1 本身通过 RSA-OAEP-4096 封装。只有持有对应 RSA 私钥的加载者才能解开。没有私钥,连 META-INF 里的内容都看不到。

第三层:中层 RSA-4096-PSS 签名

对 NIR 密文摘要进行签名,验证插件作者的合法身份。这个签名存储在加密后的 META-INF 中,外部无法读取。只有先解开第二层加密,才能看到这个签名。

第四层:中层 AES-256-GCM 加密

使用 key2 加密 NIR 数据(插件代码的编译结果)。key2 同样通过 RSA-OAEP 封装。两层密钥独立生成,互不依赖。即使有人破解了外层,代码还是加密的。

第五层:内层 HMAC-SHA256 签名

对每个解密后的 NIR 模块逐一签名,防止模块被替换或重排。HMAC 密钥由 key1 和 key2 通过 HKDF-SHA256 派生。这一层确保每个模块的完整性。

每一层用不同的密钥,每一层有独立的作用。外层负责传输安全,中层负责身份验证和代码安全,内层负责模块完整性。

NIR 编译系统#

NIR 全称 Nebula Intermediate Representation,是 .nbpf 独有的中间表示层。

插件的所有 .py 源码在打包时,被 NIRCompiler 编译成 Python 原生的 code object,再通过 marshal 序列化成字节流。

编译过程中会执行静态安全检查

  • 拒绝 C 扩展(.so、.pyd 等二进制扩展)
  • 禁止导入 ossyssubprocess 等危险模块
  • 禁止使用 __import__execevalcompile 等动态执行函数

此外,NIRCompiler 还会在 code object 中插入无意义的花指令(junk code),增加逆向分析的难度。

TIP

NIR 与平台无关。任何 Python 3.10+ 环境都可以执行编译后的插件,不需要重新编译。

打包流程#

打包器做了这些事情:

  1. 读取 manifest.json
  2. 编译所有 .py 为 NIR
  3. 收集资源文件
  4. 生成随机 AES 密钥
  5. 中层加密/签名 NIR
  6. 内层 HMAC 签名
  7. 构建 META-INF
  8. 外层加密/签名
  9. 写入 ZIP

加载流程#

加载器做了这些事情:

  1. 打开 ZIP
  2. 外层验签(Ed25519)
  3. 外层解密(RSA 解密 key1 → AES-GCM 解密 META-INF)
  4. 中层验签(RSA-4096)
  5. 中层解密(RSA 解密 key2 → AES-GCM 解密 NIR)
  6. 内层验签(HMAC)
  7. 反序列化 NIR
  8. 在受限沙箱中 exec
  9. 调用 New() 创建插件实例

内存安全#

解密完成后,所有密钥立即从内存中擦除。

擦除方式是三次覆写:全0 → 全0xFF → 全0。

不是简单的 del——Python 的 del 只是删除引用,内存里的数据可能还在。三次覆写是真正的清除。

信任模型#

.nbpf 没有中心化的证书颁发机构。

系统维护一个本地信任公钥目录。当加载一个未被信任的作者签名的插件时,CLI 会展示:

  • 作者名称
  • 版本
  • 公钥指纹

由用户决定是否信任。一旦信任,公钥被持久化到本地信任目录,下次加载同一作者的插件时自动放行。

NOTE

没有中心服务器,没有在线验证。完全的离线、去中心化信任。

完整性验证#

CLI 提供了 nebula nbpf verify 命令。

这个命令可以在不加载插件(不解密完整内容)的情况下,验证外层签名和读取公开元数据。

对于插件市场的服务端审核很有价值:服务器可以在不持有任何私钥的情况下,确认包的来源和完整性。

代码保护手段#

除了加密和签名,NBPCrypto 模块还实施了一系列抗逆向措施:

  • 所有 cryptography 库的导入路径通过字符串拼接动态构造
  • 关键常量通过运行时计算,不硬编码
  • 解密函数分散在多处,不是集中在一个地方
  • 反调试检测:检测 sys.gettrace() 和调试环境变量

现状#

目前 .nbpf 是 NebulaShell 插件系统的唯一打包与分发格式。

整个实现分布在 oss/core/nbpf/ 目录下:

  • 5 个模块
  • 约 1300 行 Python 代码
  • 测试在 tests/test_nbpf.py
CAUTION

.nbpf 不追求与外部生态的兼容性。它是一个为 NebulaShell 量身定制的封闭包格式。

所以你没法用其它工具打开它。

总结#

五层安全体系,从外到内:

层级加密/签名作用
1Ed25519外层签名,防止篡改
2AES-256-GCM + RSA加密 META-INF
3RSA-4096-PSS中层签名,验证作者
4AES-256-GCM + RSA加密 NIR 代码
5HMAC-SHA256内层签名,模块完整性

NIR 编译系统做静态检查和花指令注入。

加载完后密钥三次覆写擦除。

没有中心化证书,离线信任。


这篇写完了。

如果你能完整看完——不管看懂没看懂,都说明你对这个项目是真的感兴趣。

谢谢。

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

.nbpf 的秘密——一个插件格式,为什么要搞五层加密
https://www.starlight-apk.cn/posts/project/nebulashell/nbpf-secrets/
作者
Starlight-apk
发布于
2026-05-11
许可协议
Apache License 2.0

部分信息可能已经过时

目录