引言
兄弟们,上篇文章《JS逆向实战系列一 |某头条a_bogus参数逆向分析与算法还原》详细讲解了a_bogus的整个”JS逆向实战”过程。但事情还没完!/api/pc/list/feed接口除了a_bogus参数,还包含一个msToken参数。本章就带着大家详细解密msToken参数的过程。
本文目录
1. 数据抓包实战
老规矩,先打开F12 Network面板,刷新页面,找到那个熟悉的/api/pc/list/feed请求。
仔细查看Query String Parameters(查询字符串参数),除了上回解决的a_bogus,这次重点关注另一个参数——msToken。它通常是一长串看似无规律的字符,同样每次请求都会变化。

在请求URL中,可以清晰看到我们需要msToken参数(图中红色标注部分)。这就是我们的目标。
2. 参数搜索大法
首先尝试在源代码中搜索msToken参数。与上篇文章不同,这次搜索出现了大量结果!
大部分结果都指向/web/common接口,其Response Headers中的set-cookie指令包含msToken=xxxxx。这表明msToken参数是通过请求/web/common接口获取的。这就是第一步:找到参数来源。

3. 接口分析与思考
既然msToken来自/web/common接口,我们需要将注意力转向这个接口。通过数据抓包分析,发现:
- 接口使用POST请求方式
- 请求链接需要传递msToken参数
- 请求主体包含加密的staData参数
- 响应主体不包含msToken参数
有趣的是:/web/common接口本身也需要msToken参数,但尚未获取到msToken如何传递?

通过火狐浏览器的”编辑并重发”功能测试发现,不传递msToken参数也可行,但必须传递主体的strData参数。于是重点转向解决strData加密参数。

【补充内容】
请看上图,在/web/common接口的响应头(Response Headers)中,红色框选部分下面 有一个名为x-ms-token的字段。这个字段的值,正是我们整个逆向流程的终极目标!我们后续在Python代码中,就是要提取这个响应头字段的值,来作为主接口所需的msToken参数。请务必理解这一点,这是连接“加密参数生成”和“最终结果获取”的桥梁。
4. XHR断点定位
直接搜索strData无果,说明参数没有在源代码中明文赋值。于是使用更高级的XHR断点功能,直接拦截包含/web/common的请求。

刷新页面后,代码执行在请求发出前成功暂停。通过Call Stack堆栈分析和单步调试(F10/F11),最终将生成位置锁定在代码d = s.apply(b, u)。此时变量d的值即为生成的strData。


步入函数深入分析,发现关键变量s指向了一个复杂的匿名函数u,这就是我们要找的加密函数本体!这就是成功关键。

关键代码结构如下:
javascript
(u = function e() { // ... 复杂的加密逻辑 ... })._v = [s, o, v], u._u = e, p[++l] = u
5. 扣取加密代码
将bdms.js文件拷贝到本地,找到s指向的u函数。将u函数赋值给window.msToken,这样在外部就可以通过window.msToken调用这个加密函数了。

6. 补全运行环境
创建env.js环境补全文件:
javascript
window = global delete global delete Buffer XMLHttpRequest = function(){} window.requestAnimationFrame = function(){} document ={}
在断点处查看参数u的值,复制参数内容用于后续调用。这是环境补全的重要步骤。

创建main.js主入口文件:
javascript
require('./env'); require('./bdms'); const args = [{"battery":..., ...}]; // 具体参数省略 const result = window.msToken.apply(null, args); console.log(result);
7. 运行结果验证
在终端中运行node main.js命令。如果一切顺利,将成功生成strData参数的值!这就是最终成果。

msToken生成逻辑的特别补充
首先,非常感谢这位111兄弟的尖锐评论,您说得非常对!确实,文章在从strData跳转到最终msToken的衔接上交代不清,让初学者困惑,在此致歉。现将核心逻辑梳理如下:
完整逻辑链:
我们的目标不是strData本身,而是用它作为“钥匙”去请求/web/common接口,该接口会在响应头中返回真正的msToken。
- 逆向目标: 生成合法的
strData(POST请求体)。 - 关键请求: 用
strData去请求/web/common接口。 - 最终获取: 从接口的响应头(Headers) 中提取
x-ms-token的值。
核心Python代码示意(获取msToken的关键步骤):
import execjs
from requests import request
def LoadJs(path='mian.js'):
# 加载脚本
with open(path, "r", encoding='utf-8') as file:
js_code = file.read()
return execjs.compile(js_code)
def get_msToken(url: str, js=None, cookie=None):
url = "https://mssdk.bytedance.com/web/common"
params = {
"ms_appid": 24,
"msToken": '0mHpz_Jq0qsGpC7bm7xC7G6Ve-ktB3cz587rUx3Q2L23tSM4LC-brY4EXzHjBuogzMrplTKdhDW1X0T-d0MBa9Cbu9OMg5tRRR0JD61rOT5IUGnDHoULUxru7rlrRCXY'
}
# 修正:使用 call 方法调用 JavaScript 函数
str_data = js.call('get_msToken', url)
data = {
"magic": 538969122,
"version": 1,
"dataType": 8,
"strData": str_data,
"tspFromClient": 1718114084818,
"ulr": 0
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko/20100101 Firefox/142.0",
"Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Cookie": cookie or "",
"Content-Type": "text/plain;charset=UTF-8",
"Referer": url or "",
"Origin": url or "",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "cross-site",
"Connection": "keep-alive",
"Priority": "u=4",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
}
# 发送POST请求
try:
response = request(method="POST",
url=url,
json=data,
params=params,
headers=headers)
if response.status_code == 200 and 'resultCode' not in response.text:
ms_token = response.headers.get('x-ms-token')
return ms_token
else:
return None
except Exception as e:
print(f"请求异常: {e}")
return None
if __name__ == '__main__':
Obj = LoadJs()
msToken = get_msToken('填写视频入口地址', Obj)
print(f"msToken: {msToken}")
(建议在此处插入图片:展示Python代码成功运行后打印出的msToken值)
简单总结:扣代码 → 生成strData → 请求接口 → 提取响应头x-ms-token → 得到msToken。希望这个说明能解开大家的疑惑。

简单总结:扣JS代码 → 生成strData → 请求/web/common接口 → 从响应头提取x-ms-token → 得到最终的msToken。希望这个解释能让大家豁然开朗。
8. 常见问题与解决方案(FAQ)
Q1: 为什么搜索msToken能找到结果,而strData找不到?
A: msToken在set-cookie指令中明文出现,而strData是加密参数,在代码中经过混淆处理。这是中常见的混淆技术。
Q2: 补环境后运行还是报错怎么办?
A: 根据报错信息继续补全缺失的环境变量,这是一个迭代过程。需要耐心和细心。
Q3: 生成的strData参数无效如何解决?
A: 检查参数是否与浏览器中完全一致,特别是时间戳、随机数等动态参数。这是常见问题。
Q4: 过段时间方法失效了怎么办?
A: 这是正常现象,需要重新分析新的加密逻辑,但本文提供的方法论是通用的。
9. 获取完整课件
关注公众号:孤狼网络科技,回复:msToken,即可获取本文涉及的完整代码课件(包含详细调试截图、补全后的环境文件、可运行代码示例)。如果你想深入学习JS逆向,这些资料将非常有帮助。
总结
msToken的逆向过程与a_bogus类似,但需要多一层接口分析。掌握从抓包到补环境的完整方法论,就能应对各种JS逆向挑战。如果在实践过程中遇到问题,
下期预览
以上就是本次破解 “msToken” 实战的全部内容。希望本篇JS逆向教程对您有所帮助。林石工作室下期将为您带来《JS逆向实战系列三 | 某头条_signature签名破解与完整实现》的解析,感谢关注。


你这写的有屌用啊,最后获取到的是strData也不是msToken值啊,看了好几遍也没看懂你的思路。
只能靠自己debug了,没办法。
有时staData,有时strData的~
感谢反馈,以修改
是抖音更新了吗,现在照您的方法找不到了