sharoon7171/vidfast-pro-stream-resolver
GitHub: sharoon7171/vidfast-pro-stream-resolver
一个逆向工具包,用于解密 VidFast 加密载荷并根据内容 ID 解析出直链 HLS 播放地址。
Stars: 0 | Forks: 1
# vidfast-pro
解密 VidFast 加密的 payload,通过 TMDB 内容 ID 解析 m3u8 URL,并通过 HTTP 将结果与用于播放的 Web 客户端一起暴露出来。
## 1. 概述
VidFast 会针对两种数据类型返回加密的 base64 blob:
| 加密输入 | 明文输出 | 用途 |
| --- | --- | --- |
| `capture/probe.b64` | 服务器列表(`name`、`data`、…) | 流媒体服务器目录 |
| Stream POST 响应体 | `{ url: "….m3u8", … }` | 直连 HLS manifest URL |
两者都使用相同的加密算法以及来自 `capture/keys.json` 的相同密钥。代码库在 `src/dec/` 中对它们进行解密,通过 `src/capture/init.js` 加载密钥和 probe,通过 `src/net/vidfast.js` 获取 stream blob,并在 `src/resolve/run.js` 中编排整个链路。
## 2. 解密
### 2.1 输入与输出
```
capture/keys.json ──► parseKeys() ──► { k1, k2, k3 }
│
capture/probe.b64 ──► decProbe() ──────────┤──► [ { name, data, description, image }, … ]
│
Stream POST body ──► decStream() ─────────┘──► "https://…/index.m3u8"
```
| 密文来源 | 磁盘上的文件 | 解密函数 | 模块 | 输出 |
| --- | --- | --- | --- | --- |
| 服务器列表 | `capture/probe.b64` | `decProbe(b64, keys)` | `src/dec/probe.js` | 服务器行数组 |
| Stream URL | VidFast POST 响应 | `decStream(b64, keys)` | `src/dec/stream.js` | m3u8 URL 字符串 |
| 任意(原始 JSON) | 任何 base64 blob | `decJson(b64, keys)` | `src/dec/aes.js` | 解析后的 JSON 对象 |
密钥永远不会嵌入到密文中。它们在启动时从磁盘加载一次:
```
capture/keys.json ──► parseKeys() ──► src/dec/keys.js ──► { k1, k2, k3 } as Buffer
```
### 2.2 加密算法
所有解密路径都会调用 `src/dec/aes.js` 中的 `decJson()`。
**实现:** Node.js `node:crypto` — `createHash('sha256')`、`createDecipheriv('aes-256-gcm')`。
**Blob 布局(base64 解码后):**
| 偏移量 | 大小 | 字段 |
| --- | --- | --- |
| 0 | 16 | Header |
| 16 | 12 | IV |
| 28 | n | Ciphertext |
| 28 + n | 16 | Auth tag |
**密钥派生:**
```
h1 = SHA256(k1 ‖ k2 ‖ k3)
key = SHA256(h1 ‖ header)
```
**解密:**
```
plain = AES-256-GCM-Decrypt(key, iv, ciphertext, tag)
json = JSON.parse(plain.subarray(8))
```
在解析 JSON 之前,明文的前 0–7 字节会被丢弃。
### 2.3 模块链
```
src/dec/keys.js parseKeys(raw) keys.json object → { k1, k2, k3 }
│
▼
src/dec/aes.js decJson(b64, keys) base64 blob → JSON
│
├──► src/dec/probe.js decProbe(b64, keys) JSON → server rows
│
└──► src/dec/stream.js decStream(b64, keys) JSON → json.url
```
`src/dec/` 不具有文件系统或网络访问权限。调用者需提供 `b64` 和 `keys`。
### 2.4 加载器
`src/capture/init.js` 读取磁盘构件并连接解密调用:
| 函数 | 读取 | 调用 | 返回 |
| --- | --- | --- | --- |
| `warm()` | `keys.json`、`probe.b64` | `parseKeys`,缓存在内存中 | — |
| `listProbe()` | 缓存的 probe + keys | `decProbe` | 服务器行 |
| `urlFromBlob(b64)` | 缓存的 keys | `decStream` | m3u8 URL |
每个进程加载一次。修改 `capture/` 后需要重启。
## 3. 解析
解析过程将内容 ID 转换为 probe 列表中每个服务器的已解密 m3u8 URL。
### 3.1 Pipeline
```
listProbe() decrypt probe.b64 → server rows
│
▼
for each row (8 workers):
postStream(row.data, pagePath) POST to VidFast → base64 body
urlFromBlob(b64) decrypt body → m3u8 URL
│
▼
yield NDJSON events meta → server → done
```
### 3.2 内容路径
| 查询 `type` | 构建的路径 |
| --- | --- |
| `movie` | `/movie/{id}` |
| `tv` | `/tv/{id}/{season}/{episode}` |
在 `src/resolve/run.js` 中根据 `URLSearchParams` 构建。在 stream POST 中用作 `Referer` 后缀。
### 3.3 Stream POST
`src/net/vidfast.js` → `postStream(data, page)`
**读取:** `capture/routes.json`
**请求:**
```
POST {origin}/{probePrefix}/{streamPrefixB}/{data}
Referer: {origin}{page}
Origin: {origin}
+ csrfHeaders, User-Agent
Timeout: 2500 ms
```
**返回:** 修剪过的 base64 密文,失败或返回 JSON 错误体时为 `null`。
该 base64 字符串是 `urlFromBlob()` → `decStream()` → `decJson()` 的输入。
### 3.4 并发
`src/resolve/pool.js` 最多并行运行 8 个 `postStream` + 解密任务。结果按完成顺序 yield。重复的 m3u8 URL 会被跳过。POST 或解密失败仅针对该服务器返回 `null`。
### 3.5 服务器结果对象
由 `src/resolve/run.js` 生成:
| 字段 | 来源 |
| --- | --- |
| `name`、`description`、`image`、`data` | Probe 行 |
| `streamUrl` | `decStream` 输出 |
| `playbackUrl` | `{origin}/api/hls?url={encodeURIComponent(streamUrl)}` |
## 4. HTTP 服务器
**入口:** `npm start` → `src/srv/http.js`
**端口:** `8787`(环境变量 `PORT`)
| 路由 | 使用的模块 | 动作 |
| --- | --- | --- |
| `GET /api/resolve` | `src/resolve/run.js` | 流式传输 NDJSON 解析事件 |
| `GET /api/hls?url=` | `src/net/hls.js` | 代理 HLS manifest 或分片 |
| `GET /` | — | 提供 `public/index.html` |
启动时会调用 `warm()` 将 `capture/` 预加载到内存中。
### 4.1 `/api/resolve`
**查询参数:** `id`(必填)、`type`(`movie`|`tv`)、`season`、`episode`
**响应:** `application/x-ndjson`
| 事件 | Payload |
| --- | --- |
| `meta` | `{ type, contentPath, total }` |
| `server` | `{ server: { name, streamUrl, playbackUrl, … } }` |
| `done` | `{ servers: [...] }` |
| `error` | `{ error }`(仅在流传输过程中) |
### 4.2 `/api/hls`
不进行解密。使用 VidFast referrer 标头获取上游 HLS。
| 响应类型 | 行为 |
| --- | --- |
| `.m3u8` manifest | 将分片 URL 重写为通过 `/api/hls` 循环 |
| 分片字节 | 如果存在 PNG 包装则剥离;返回 MPEG-TS |
## 5. Web 客户端
**文件:** `public/index.html`
| 依赖项 | 来源 |
| --- | --- |
| hls.js 1.5.15 | jsDelivr CDN |
| 动作 | 使用的 API |
| --- | --- |
| 获取流 | `GET /api/resolve` — 读取 NDJSON 流 |
| 播放视频 | 通过 `server.playbackUrl` 调用 `GET /api/hls` |
| 切换服务器 | 更改 `
标签:AES解密, GNU通用公共许可证, HLS, MITM代理, Node.js, 云资产清单, 后端开发, 流媒体解析, 逆向工程