基于 Grok-4.5 的 X-Dynosaur 签名算法纯算还原分析
基于 Grok-4.5 的 X-Dynosaur 签名算法纯算还原分析版本基准webmssdk 2.0.0.507sdkVersion5.3.0,scmVersion2.0.0.507形态特征挂载于 URL Query 上的约 392 字符签名参数通常与X-Gnarly/X-Bogus配合出现。一、请求链路与分层架构在完整的 API 请求流程中SDK 通过拦截 HTTP 请求如fetch/XHR并追加签名参数。整体架构可划分为三层层级名称内容与作用还原程度L1业务输入层业务 Query、Body、User-Agent、时间戳、计数器等已知输入入口L2逻辑字段层25 个语义字段经 VMP 混淆后序列化为自定义 TLV 明文243~244 字节TLV 结构已解开部分 Value 混淆规则在 VMP 内L3外壳加密层48 字节随机密钥 ChaCha 变体 XOR 密钥动态嵌入 变异 Base64已完全纯算还原支持双向 Roundtrip[L1: 业务参数 / 环境信息] │ ▼ [L2: JSVMP 字段处理] ──► 25 段混淆字段 ──► 自定义 TLV 序列化 (243~244 B) │ ▼ [L3: 外壳加密] ───────► ChaCha-XOR 变体 ──► 嵌入 48B 动态 Key ──► 变异 Base64 ──► X-Dynosaur (~392 字符)二、L3外壳加密算法拆解X-Dynosaur的外壳加密与X-Gnarly保持同构主要分为 5 个步骤1. 动态密钥生成每次签名随机生成 48 字节密钥keyBytesrandomBytes(48)\text{keyBytes} \text{randomBytes}(48)keyBytesrandomBytes(48)拆分为 12 个 32 位小端无符号整数keyWords[0..11]\text{keyWords}[0..11]keyWords[0..11]。2. 轮次Rounds推导根据密钥低 4 位累加和动态推导 ChaCha 迭代轮次r∑i011(keyWords[i] 0xF)(mod16)r \sum_{i0}^{11} (\text{keyWords}[i] \ \ \ \text{0xF}) \pmod{16}ri0∑11(keyWords[i]0xF)(mod16)roundsr5(取值范围 [5,20])\text{rounds} r 5 \quad (\text{取值范围 } [5, 20])roundsr5(取值范围[5,20])3. ChaCha 变体流密码 XOR非标准 RFC 8439 ChaCha20 实现核心差异如下特性标准 ChaCha20WebMSSDK 变体Sigma 常量expand 32-byte k[0x475D03A6, 0x23CF0377, 0xE648A32B, 0x56891B76]Key / Nonce8 词 Key 3 词 Nonce12 词全部为动态keyWords无独立 Nonce轮次设定固定 20 轮动态推导5∼205 \sim 205∼20轮状态矩阵布局[SIGMA(4)KEY(8)注state[12]兼作 Counter每消耗 64 字节密钥流时自动111。单轮 Quarter Round 旋转位移保持为[16, 12, 8, 7]最终叠加初始状态Feed-forward。cipherplaintext⊕keystream(keyWords,rounds)\text{cipher} \text{plaintext} \oplus \text{keystream}(\text{keyWords}, \text{rounds})cipherplaintext⊕keystream(keyWords,rounds)4. 密钥校验和与交织嵌入计算校验和确定密钥在密文中的嵌入位置modlen(cipher)1\text{mod} \text{len}(\text{cipher}) 1modlen(cipher)1sum(∑i047keyBytes[i]∑j0N−1cipher[j])(modmod)\text{sum} \left( \sum_{i0}^{47} \text{keyBytes}[i] \sum_{j0}^{N-1} \text{cipher}[j] \right) \pmod{\text{mod}}sum(i0∑47keyBytes[i]j0∑N−1cipher[j])(modmod)insertPossum\text{insertPos} \text{sum}insertPossum拼接成中间二进制流wire0x4B ∥ cipher[0…insertPos−1] ∥ keyBytes[48] ∥ cipher[insertPos…N−1]\text{wire} \text{0x4B} \ \parallel \ \text{cipher}[0 \dots \text{insertPos}-1] \ \parallel \ \text{keyBytes}[48] \ \parallel \ \text{cipher}[\text{insertPos} \dots N-1]wire0x4B∥cipher[0…insertPos−1]∥keyBytes[48]∥cipher[insertPos…N−1]魔数 (Magic)固定首字节0x4B(K)。数据总长明文 244 字节时中间二进制流总长为1244482931 244 48 293124448293字节。5. 自定义 Base64 编码采用映射表置换后的 Base64 编码Alphabet: u09tbS3UvgDEe6r-ZVMXzLpsAohTn7mdINQlW412GqBjfYiyk8JORCF5/xKHwacP首字节0x4B高 6 位为18映射到索引18为M因此合法 Token 均以M开头。293 字节编码后产生 392 字符的签名字符串含填充符。三、L2TLV 明文结构分析1. 字节布局规范明文由 25 个连续的 Tag-Length-Value (TLV) 段组成Tag 范围从0x20递增至0x38无跳号Offset ──► ┌──────┬──────┬──────┬───────────────┬──────┬──────┬──────┬───────────────┐ │ Tag │ 0x00 │ Len │ Value (Len B) │ Tag1│ 0x00 │ Len │ Value (Len B) │ ... └──────┴──────┴──────┴───────────────┴──────┴──────┴──────┴───────────────┘ 1B 1B 1B len 字节 1B 1B 1B解析约束Reserved 字节必须严格为0x00。Len为 1 字节0≤Len≤2550 \le \text{Len} \le 2550≤Len≤255。25 段解析完成后偏移量必须精确等于明文总长度通常为 243 或 244 字节。2. Value 常见后缀规则部分字段包含尾部标志位Trailer格式通常为[ Payload ] [ 0x00 ] [ Code ]结尾 Code观察含义0x01/0x02/0x03整型 / 枚举类型标志0x05/0x07/0x09/0x0A字符串类型标志数值多等于前置 Payload 长度无后缀裸 4 字节 uint32大端序如0x2b/0x2e/0x30/0x383. Tag 字段映射速查Tag典型长度语义/观察0x206 B随请求路径/接口变化Trailer 常见0x02/0x030x21–0x236 B固定的模式串如...dfe000010x249 B与 SDK 版本相关如5.3.0的混淆态0x25/0x2F6 B随动态请求变化0x27/0x2C/0x3411~12 B混淆后的长特征串0x2A7 B短特征串0x2B4 BGET 请求通常固定为811c9dc4空 Body FNV 哈希占位0x2E4 B强时效/环境上下文相关Query/时间戳0x3111 B固定为混淆后的scmVersion2.0.0.507(e3a7cba7cbb7d73f3f0009)0x384 B校验/异或头字段如e207512b四、算法对比X-Gnarly vs X-Dynosaur特性维度X-GnarlyX-Dynosaur明文结构16 个字段[Count][Idx][Len_u16_BE][Val]25 个字段[Tag][0x00][Len_u8][Val]Value 混淆多为明文 MD5 Hex / 版本字符串先经 JSVMP 内部逻辑混淆再构建 TLV外壳加密ChaCha 变体 密钥交织嵌入 魔数0x4B完全相同Base64 字符表变异 Base64 表完全相同输出串长度~332 字符~392 字符