目标接口:/api/post/item_list
签名参数:X-Gnarly(332 字符)
SDK 版本:webmssdk 5.2.1
方法与工具:fast-spider skills 工作流 + GLM-5.2 辅助分析 + 语义级插桩
在 TikTok Web 端中,访问 /api/post/item_list 等核心接口通常需要两个关键的签名参数:
X-Gnarly 参数由 webmssdk.js(byted_acrawler SDK)动态计算生成。由于该 SDK 采用了 JSVMP(JavaScript VM Protection)混淆技术,其实际执行算法被编译为约 44KB 的字节码,源码中仅包含解释器内核,静态分析难以直观还原其明文逻辑。
本篇报告记录了如何利用 fast-spider skills 工作流,在 GLM-5.2 的辅助推理下,从 trace 日志中逐步还原出 X-Gnarly 的完整生成链路,并完成纯 JavaScript 算法复现的过程。
传统的补环境方案(如 FakeEnv 或 Node vm 模拟)在面对该级别的混淆时,往往因为大量未知的浏览器特征检测而难以推进。因此,本方案采用语义级插桩思路:
通过这一方法,单次流程可稳定产出约 28 万行语义日志,为后续算法推导提供了坚实的数据支撑。
X-Gnarly 的生成可以划分为以下 4 个阶段:
算法首先在内存中收集并构建一个包含 17 个元素的混合数组:
在进行洗牌前,需要计算数组中的两个校验和:
num15 (tag16):
num15=73⊕14⊕num3⊕num4⊕num5⊕ts⊕A⊕B⊕num9⊕num10⊕1⊕T12⊕T13⊕M1⊕M2
注:其中 num3, num4, num5, num9, num10 是对应字符串字段前 4 字节转换而成的大端 uint32 整数。
num0 (tag0):
num0=∑⊕arr(仅对数组中数值类型的元素进行异或运算,非数值类型不参与)
基于线性同余生成器(LCG)生成的伪随机数对上述数组进行倒序洗牌:
洗牌完成后的数组将被转化为 TLV(Type-Length-Value)二进制流:
最终输出:200 字节明文字节数组。
加密状态矩阵的 16 个 32位 Word 布局如下:
轮数由初始 key48 决定。由于本方案中 key48 采用提取自真机环境的静态常量,其推导轮数亦维持不变:
rounds=(∑i=011(keyWord[i] & 15))& 15+5
QR 结构与标准 ChaCha 保持一致,保留了经典移位常数:
这是 webmssdk 对经典 ChaCha 算法做出的核心修改。对比标准对角线变换索引,本版本进行了如下替换:
该修改打破了标准 ChaCha 算法原有的对称扩散特性,需在重构时严格遵循变种索引。
分块对 200 字节明文执行流加密(每块 64 字节):
最终输出:200 字节密文数组。
分割索引依据密文及 key48 数据之和求模动态计算:
splitIndex=(∑i=0199ciphertext[i]+∑j=047key48[j])mod201
将 48 字节的 key48 插入到密文字节流的分割点处,构建合成数组 W:
W=ciphertext[0…splitIndex]∥key48[0…47]∥ciphertext[splitIndex…199]
最终输出:248 字节的数据块。
在数据块头部附加固定标识 0x4B(字符 'K'):
input=[0x4B]∥W(总长度为 249 字节)
使用指定的自定义字母表进行标准的 3 字节至 4 字符转换(转换过程中无填充字符 =):
自定义字母表(64 字符):
编码转换逻辑:
Group=(b0≪16)∣(b1≪8)∣b2
char1=alphabet[(Group≫18) & 63],…char4=alphabet[Group & 63]
最终输出:332 字符长度的有效 X-Gnarly 签名。
为保持长期调用的稳定性,算法实现中明确区分了动态变量与静态常量:
面对包含数百个虚拟机操作码分支及复杂分发循环的 JSVMP 保护,完全依赖静态反汇编分析极易陷入迷局。此时,借助 GLM-5.2 的代码分析与逻辑整合能力,配合同步插桩方案,是定位真实解密链路的高效途径。
通过自动向执行单元添加插桩,能够避开虚拟机内部繁琐的操作码转换,直接将寄存器数值与函数交互以自然语言级别记录下来。这不仅极大地缩短了逆向周期,而且保证了底层逻辑还原的准确性。
| 变换组别 |
标准 ChaCha 索引 |
webmssdk 5.2.1 变种索引 |
差异说明 |
| 第一组 |
(0, 5, 10, 15) |
(0, 5, 10, 15) |
无变化 |
| 第二组 |
(1, 6, 11, 12) |
(1, 6, 11, 12) |
无变化 |
| 第三组 |
(2, 7, 8, 13) |
(2, 7, x, 13) |
索引 8 被替换为 x |
| 第四组 |
(3, 4, 9, 14) |
(3, 4, y, 14) |
索引 9 被替换为 y |
| 参数类型 |
字段明细 |
处置策略 |
| 动态输入 |
queryString (URL 查询参数), userAgent (浏览器 UA), ts (当前时间戳) |
随每次请求实时生成,用于计算数组中的 Tag 字段 |
| 固定参数 |
状态矩阵 OT, 加密密钥 key48, rounds, 变量 A, B, M1, M2, T12, T13 |
采用从真机 trace 日志中分析固定的静态数值,降低运行时的环境依赖风险 |
| 测试批次 |
key48 摘要 |
加密轮数 |
变量 B |
splitIndex |
复现结果一致性 |
| trace4 |
e0671fe6... |
17 |
354945180 |
38 |
✅ 一致 |
| trace6 |
098bf137... |
11 |
1316161044 |
194 |
✅ 一致 |
初始化环境 (init) → 捕获 SDK (capture) → 制定运行策略 (runbook) → 采集 trace → 逻辑分析 (analyze) → 制定方案 (plan) → 补全算法 (fill) → 对拍校验 (verify)
[内核课程]《Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于 2026-7-14 10:06
被红皮西瓜编辑
,原因: 数值脱敏