抖音a_bogus参数逆向实战:JSVMP环境模拟与Hook技术(2025最新)
本文为技术摘要版,完整教程(含完整代码、bdms提取方法、调试技巧)已发布在 道满PythonAI,建议搭配阅读。
为什么需要逆向 a_bogus?
抖音Web端在所有核心API(视频列表、用户主页、搜索接口等)中都强制校验 a_bogus 签名参数。没有这个参数,请求直接被服务器拒绝。
做过抖音数据采集的同学一定遇到过这个问题:
bash
# 不带 a_bogus 的请求
GET /aweme/v1/web/aweme/post/?device_platform=webapp&aid=6383&...
→ 403 Forbidden
# 带正确 a_bogus 的请求
GET /aweme/v1/web/aweme/post/?...&a_bogus=XXXX
→ 200 OK (返回JSON数据)
a_bogus 本质上是字节跳动安全SDK(bdms)在浏览器端动态生成的校验值,它绑定了你当前的浏览器指纹、请求参数和时间戳。
核心难点
a_bogus 逆向最大的挑战不在于算法本身,而在于运行环境的模拟:
- JSVMP保护 :
bdms的核心逻辑被 JSVMP 虚拟机包裹,直接阅读代码几乎不可能 - 环境检测 :SDK 会检测
Function.prototype.toString是否为[native code]、navigator属性是否存在、document是否可创建元素等 - 动态属性访问:SDK 运行时会访问大量浏览器全局对象属性,遗漏任何一个都会导致签名错误
技术路线:环境补全 + 动态代理
我们采用「环境补全优先 + 动态代理兜底」的策略:
javascript
┌────────────────────────────────────┐
│ 技术路线全景图 │
├─────────────────────────────────────┤
│ │
│ 1. 函数 Native 伪装 │
│ └─ 重写 Function.toString │
│ └─ 随机 Symbol 标记原生函数 │
│ │
│ 2. 全局环境补全 │
│ └─ window/document/navigator │
│ └─ screen/location/history │
│ └─ 第三方SDK存根(CefSharp等) │
│ │
│ 3. toStringTag 伪装 │
│ └─ 绕过 Object.toString.call │
│ │
│ 4. 动态 Proxy 监控 │
│ └─ 实时发现缺失属性 │
│ └─ 按需补全,避免一次性写死 │
│ │
│ 5. SDK 注入 + XHR 模拟 │
│ └─ 加载 bdms 代码 │
│ └─ 模拟 XHR.send 触发加密 │
│ └─ 从 window.a_bogus 获取结果 │
│ │
└─────────────────────────────────────┘
关键代码片段
1. 函数 Native 伪装
bdms 会通过 fn.toString() 检查函数是否为原生。我们用随机 Symbol 存储伪造标记:
javascript
const $toString = Function.toString;
const fakeNativeTag = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)));
const myToString = function() {
return (typeof this === 'function' && this[fakeNativeTag]) || $toString.call(this);
};
// 替换原型方法并自伪装
delete Function.prototype['toString'];
Object.defineProperty(Function.prototype, 'toString', {
enumerable: false, configurable: true, writable: true, value: myToString
});
// 给任意函数打上"原生"标记
globalThis.safefunction = (func) => {
Object.defineProperty(func, fakeNativeTag, {
enumerable: false, configurable: true, writable: true,
value: `function ${func.name || ''}() { [native code] }`
});
};
2. 动态代理监控
用 Proxy 监听 SDK 对环境对象的属性访问,实时发现需要补全的属性:
javascript
function createProxy(objName) {
return new Proxy(window[objName] || {}, {
get(target, prop) {
console.log(`[GET] ${objName}.${String(prop)}`);
return Reflect.get(target, prop);
},
set(target, prop, val) {
console.log(`[SET] ${objName}.${String(prop)} = ${JSON.stringify(val)}`);
return Reflect.set(target, prop, val);
}
});
}
['window', 'document', 'location', 'navigator', 'screen'].forEach(name => {
window[name] = createProxy(name);
});
3. 模拟 XHR 触发加密
bdms 通过劫持 XMLHttpRequest 来拦截请求并添加签名。我们模拟这个过程来触发加密:
javascript
function get_ab(fullUrlWithParams) {
const xhr = new XMLHttpRequest();
xhr.bdmsInvokeList = [
{ args: ['GET', fullUrlWithParams, true] },
{ args: ['Accept', 'application/json, text/plain, */*'] }
];
xhr.invokeList = [
{ name: 'addEventListener', args: ['load', null] },
{ name: 'addEventListener', args: ['error', null] }
];
xhr.send(null);
return window.a_bogus; // SDK 生成的签名值
}
4. Python 端调用
python
import execjs
from urllib.parse import urlencode
# 编译 JS 环境并调用
ctx = execjs.compile(open('env.js', 'r', encoding='utf-8').read())
a_bogus = ctx.call("get_ab", full_url)
# 携带签名发起请求
params['a_bogus'] = a_bogus
response = requests.get(url, headers=headers, cookies=cookies, params=params)
技术难点与解决方案总结
| 难点 | 解决方案 |
|---|---|
Function.toString 被检测 |
重写原型方法 + 随机 Symbol 标记 |
Object.toString.call 类型检测 |
伪装 Symbol.toStringTag |
| SDK 访问未定义属性 | Proxy 动态监控 + f��需补全 |
| 加密逻辑封装在 JSVMP 内部 | 模拟 XHR 触发,无需理解算法 |
注意事项
- bdms 版本会更新:抖音不定期升级安全 SDK,签名失效时需重新提取代码
- Cookie 有效性 :
s_v_web_id、ttwid等 Cookie 有有效期,过期需重新获取 - WebID 一致性 :
env.js中的 User-Agent 必须与生成 webid 时的浏览器一致 - 请求频率控制:即使签名正确,过快请求仍会触发风控
完整教程
本文只展示了核心思路和关键代码片段。完整的教程包含:
- bdms 代码的完整提取方法(从 Chrome Sources 面板操作)
- 完整的
env.js环境模拟脚本(7个步骤,200+行代码) - 完整的 Python 调用脚本
- 调试过程中常见报错的排查方法
- WebID 生成与指纹一致性校验
👉 完整教程地址 :抖音a_bogus参数加密逆向实战
相关推荐
- 小红书X-S签名参数逆向实战 --- 同类签名逆向,mnsv2算法还原
- 验证码识别实战:YOLO+孪生网络 --- 深度学习方案破解点选验证码
- JS逆向案例合集 --- 更多逆向实战教程
作者:道满PythonAI
原文链接:www.daomanpy.com/docs/spider...
更多 Python + AI 教程请访问 daomanpy.com