ZemerTeam/zemer-cipher
GitHub: ZemerTeam/zemer-cipher
一个独立的 Kotlin Android 库,用于 YouTube signature cipher 反混淆、n-parameter 转换与 PoToken 生成,并通过远程配置实现 player 轮换后的应用自愈。
Stars: 1 | Forks: 1
# zemer-cipher
用于 YouTube cipher 反混淆和 PoToken 生成的 Android 库。
## 来源与采用
此处的 WebView signature-cipher / n-transform 解密代码(`CipherDeobfuscator`、`CipherWebView`,
以及注入的 `window._cipherSigFunc`)最初由我
([alltechdev](https://github.com/alltechdev))编写 —— 首次于 **2026-02-12** 在 Zemer 应用中实现
([`f905d49`](https://github.com/ZemerTeam/zemer-app/commit/f905d49da8b4486b659fa32d68e2f45f939fb56a)),
随后于两天后的 **2026-02-14** 添加到了 [Metrolist](https://github.com/MetrolistGroup/Metrolist)
([`0750a63d`](https://github.com/MetrolistGroup/Metrolist/commit/0750a63d74d69082b81ae8868b06edab51fb3875))。
此仓库即为同一套代码,并已提取为独立的 Android 库
(`com.zemer:cipher`)。
**远程配置:** Zemer 应用和 Metrolist 在运行时(通过 `PlayerConfigStore`)从该仓库的 `master`
分支获取 `player_configs.json`,以实现在无需应用更新的情况下自愈 YouTube player 轮换。
**代码复用:** 该解密代码也被复制到了许多其他项目中 —— 这些项目仅打包了
代码,且不会从这里拉取配置更新。已验证的示例包括:
- [Echo-Music](https://github.com/EchoMusicApp/Echo-Music)
- [Flow](https://github.com/A-EDev/Flow)
- [vivi-music](https://github.com/vivizzz007/vivi-music)
- [Kreate](https://github.com/knighthat/Kreate)
- [Meld](https://github.com/FrancescoGrazioso/Meld)
……以及数十个其他分支和衍生应用。
## 功能
- 用于 YouTube 流媒体 URL 的 Signature cipher 反混淆
- 用于避免限流的 N-parameter 转换
- 使用 BotGuard 生成 PoToken
- **远程可更新的 player 配置** —— 推送到此仓库 `master` 分支的配置可在几分钟内修复已部署的应用,无需发布 APK
## Player 配置 (`library/src/main/assets/player_configs.json`)
YouTube 会频繁轮换其 `player_ias` JS;每次轮换都需要一个针对特定 player 的配置
(sig 调用表达式、n-transform URL 类、signatureTimestamp)。所有配置都存在于
**同一个 JSON 文件**中,该文件是:
1. 作为离线默认配置**打包**在 APK 中,
2. 在运行时由 `PlayerConfigStore` 从该仓库的原始 `master` URL 获取
(6 小时的 TTL + ETag),并且**在未知的 player 导致解密失败时立即强制刷新** —— 因此向 `master` 推送新条目即是部署过程,
3. 由 `zemer-app` 测试工具读取 —— 应用、设备和测试之间不会产生脱节。
### 条目结构 (schemaVersion 1)
```
"445213fb": { "sig": "mP(4,155,INPUT)", "nClass": "Yx", "sts": 20613, "aliases": ["d62bd338"] }
```
- key —— 来自 player JS URL 的 8 位十六进制 player hash;`aliases` —— 前 10000 字节 md5 的后备哈希
- `sig` —— signature 反混淆调用,锁定为 `name(int,int,INPUT)`
- `nClass` —— 用于 n-transform IIFE 的 URL 类(由本地模板构建)
- `sts` —— player 的 signatureTimestamp
### 添加轮换后的 player
1. 在 `zemer-app` 中:运行 `node tests/validate-player-config.mjs ` —— 解密真实的流
并检查 CDN 是否返回 **HTTP 206**(这是唯一的真实基准;多组常量对可能都能“解密”,但只有一组会被接受)。它会打印出可直接粘贴的 JSON 条目。
2. 将该条目添加到这里的 `player_configs.json` 中。重复的 hash/alias 会导致整个
文件被拒绝 —— 请运行单元测试。
3. 推送到 `master` —— 已部署的应用会在几分钟内从该 URL 自愈。
4. 之后需在 `zemer-app` 中更新 submodule 指针(以保持打包的默认配置保持最新)。
### 安全模型
`PlayerConfigParser` 是验证边界:每个值都通过 regex 锁定,因此远程数据
永远无法向 cipher WebView 中注入自由格式的 JS。无效条目会被跳过;无效
文件(包括 hash/alias 冲突)会被整体拒绝,并且设备会保留其
最后一次有效表。**仅在**发生破坏性的结构更改时才升级 `schemaVersion` —— 较旧的应用会拒绝
较新的 schema 文件,并继续使用其最后一次的有效表运行。
使用 `./gradlew :library:testDebugUnitTest` 运行测试。`config-parity/` 固定数据(fixtures)与 `zemer-app` 工具
共享:文件级别的接受/拒绝判定(以及 n-IIFE
模板)在两个读取器之间保持逐字节一致。
## 用法
### 初始化
```
// Initialize in your Application class
ZemerCipher.initialize(
context = applicationContext,
proxy = yourProxy, // optional
debugLogging = BuildConfig.DEBUG // optional
)
```
### Cipher 反混淆
```
// Deobfuscate a signature cipher URL
val deobfuscatedUrl = CipherDeobfuscator.deobfuscateStreamUrl(signatureCipher, videoId)
// Transform n-parameter in URL
val transformedUrl = CipherDeobfuscator.transformNParamInUrl(url)
```
### PoToken 生成
```
val generator = PoTokenGenerator()
val result = generator.getWebClientPoToken(videoId, sessionId)
// result.playerRequestPoToken - for player requests
// result.streamingDataPoToken - for streaming data requests
```
## 致谢
- PoToken 生成模式基于 [BgUtils](https://github.com/LuanRT/BgUtils) (MIT License)
- Cipher 函数提取使用了标准的 YouTube 反混淆技术(如 yt-dlp、NewPipe 等所记录的)
所有其他代码(WebView 实现、运行时执行、n-parameter 转换逻辑)均为自定义实现。
## 许可证
GPL-3.0
标签:Android开发, BotGuard, Homebrew安装, Kotlin, YouTube, 云资产清单, 代码混淆, 后台面板检测, 逆向工程, 音视频解析