今日头条a_bogus参数加密逆向#
#概述
今日头条作为国内主流新闻资讯平台,其API请求中使用了名为a_bogus的加密参数进行反爬防护。本笔记记录如何通过补全浏览器环境和逆向分析来生成该参数。
#网页分析











#技术要点
#2.1 核心难点
a_bogus是动态生成的加密参数- 加密逻辑依赖浏览器环境指纹
- 使用混淆的JavaScript代码(bdms.js)实现加密
#2.2 解决方案
- 补全浏览器环境对象
- 逆向分析加密调用链
- 代理关键对象监控调用过程
#环境补全实现
#3.1 基础环境配置
// 全局对象初始化
window = global;
window.requestAnimationFrame = function(){}
window.HTMLSpanElement = function(){}
// 窗口属性模拟
window.innerWidth = 1920
window.innerHeight = 331
window.outerWidth = 1920
window.outerHeight = 1040
window.screenX = 0
window.screenY = 0
window.pageYOffset = 0
// SDK版本信息
window._sdkGlueVersionMap = {
"sdkGlueVersion": "1.0.0.55",
"bdmsVersion": "1.0.1.7",
"captchaVersion": "4.0.2"
}#3.2 存储对象模拟
// localStorage模拟
localStorage = {
"__tea_cache_first_2018": "1",
"__tea_cache_tokens_2018": "{\"web_id\":\"7530833203905971739\"}",
// 其他缓存数据...
getItem: function(){},
removeItem: function(){}
}
// sessionStorage模拟
sessionStorage = {
"__tea_session_id_24": "{\"sessionId\":\"ea368e47-fcc8...\"}",
getItem: function(){},
removeItem: function(){}
}#3.3 DOM对象模拟
// document对象
document = {
cookie: 'ttcid=7ddaeb4ae85c4ad3...',
createElement: function(tag){
if (tag === 'span') return span
},
referrer: 'https://www.toutiao.com/',
// 其他DOM属性...
}
// navigator对象
navigator = {
userAgent: 'Mozilla/5.0 (Windows NT 10.0...)'
}#代理监控系统
#4.1 代理实现函数
function setProxy(proxyObjArr) {
for (let i = 0; i < proxyObjArr.length; i++) {
const handler = `{
get: function(target, property, receiver) {
console.log("方法:", "get ", "对象:", "${proxyObjArr[i]}",
" 属性:", property, " 属性类型:", typeof property,
", 属性值:", target[property],
", 属性值类型:", typeof target[property]);
return target[property];
},
set: function(target, property, value, receiver) {
console.log("方法:", "set ", "对象:", "${proxyObjArr[i]}",
" 属性:", property, " 属性类型:", typeof property,
", 属性值:", value,
", 属性值类型:", typeof target[property]);
return Reflect.set(...arguments);
}
}`;
eval(`try {
${proxyObjArr[i]};
${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler});
} catch (e) {
${proxyObjArr[i]} = {};
${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler});
}`);
}
}#4.2 代理对象配置
proxy_array = [
'window',
'canvas'
// 可根据需要添加其他对象
]
setProxy(proxy_array)#加密参数生成
#5.1 加密函数调用
function get_a_bogus(arg){
args_1 = [
0, // 固定参数1
1, // 固定参数2
14, // 固定参数3
arg, // 请求参数
"", // 空字符串
navigator.userAgent // 浏览器UA
]
// 获取加密所需的基础参数
var r = window._U._v;
// 调用核心加密函数
a_bogus = window._U._u(
r[0], // 参数1
args_1, // 参数数组
r[1], // 参数2
r[2], // 参数3
null // 上下文
)
return a_bogus
}#5.2 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
| r[0] | Number | 基础参数1(通常为1897) |
| args_1 | Array | 包含请求参数的数组 |
| r[1] | Object | 基础参数2(通常为空对象) |
| r[2] | Number | 基础参数3(通常为6) |
#完整调用流程
- 初始化浏览器环境
- 加载加密JS文件(bdms.js)
- 设置代理监控
- 构造请求参数
- 生成a_bogus参数
- 发送API请求
// 1. 加载加密逻辑
require("./bdms")
// 2. 构造请求参数
const params = {
offset: "0",
channel_id: "94349549395",
max_behot_time: "0",
category: "pc_profile_channel",
aid: "24",
app_name: "toutiao_web"
}
// 3. 生成a_bogus
const a_bogus = get_a_bogus(urlencode(params))
// 4. 添加到请求参数
params.a_bogus = a_bogus
// 5. 发送请求
// const response = requests.get(url, params=params)#完整代码
import requests
import execjs
from urllib.parse import urlencode
headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "no-cache",
"pragma": "no-cache",
"priority": "u=1, i",
"referer": "https://www.toutiao.com/?wid=1753408727185",
"sec-ch-ua": "\"Not;A=Brand\";v=\"99\", \"Google Chrome\";v=\"139\", \"Chromium\";v=\"139\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
}
cookies = {
"tt_webid": "7530833195744642610",
"ttcid": "7ddaeb4ae85c4ad3a97a1f5a20f3128a13",
"local_city_cache": "%E9%95%BF%E6%B2%99",
"_ga": "GA1.1.152252405.1753408751",
"csrftoken": "d50380b8fd876691377e1784f520d987",
"s_v_web_id": "verify_mdi6arfb_JhCmehzG_uZlV_4Uni_95YM_SHlmdFBh8evy",
"gfkadpd": "24,6457",
"_ga_QEHZPBE5HH": "GS2.1.s1755501167$o10$g1$t1755501179$j48$l0$h0",
"tt_scid": "IZYk7N4czkWBONK2CXhKEaMTAU9mHQsId8eTpHoGU.x2iaxnzaAU7tS2yjtoKlS2932d",
"ttwid": "1%7CBXcBsVkKaGJhR8z2otQMXZQ5KyemAE5rZCYmMW7X7Yo%7C1755501182%7C4f426bea4b4347b5a88ccf4f952936fe836cf82bc83a9357735980f36356d1ae"
}
url = "https://www.toutiao.com/api/pc/list/feed"
params = {
"offset": "0",
"channel_id": "94349549395",
"max_behot_time": "0",
"category": "pc_profile_channel",
"disable_raw_data": "true",
"aid": "24",
"app_name": "toutiao_web",
"msToken": "rbgPJm26nRNMyXMIjHJoEN2mBaX7RApOkC9YcHYHGSprXqztmiSBt7y7Du9SXXLIrPg3UDzjloBJzp8sSNWZbHPDXzz2qjyc3Dryr0WO07LhQf8qRHyCre0=",
# "a_bogus": "E68ZMDzkDk2Nvf6d53xLfY3qVll3YM770t9bMDhqbn31rL39HMPu9exoQ77vkoWjis/mIeyjy4hbYpn2rQInM1wfH8iN/2CZs6s0el1Mso0j53iruyRkrzDF-vG-SaBBRk-lrOX0w7lHFbYgAnAJ-7C4bfebYrtswnuYt9/bKf=="
}
url_params = "" + urlencode(params)
ctx = execjs.compile(open('env.js', 'r', encoding='utf-8').read()).call("get_a_bogus", url_params)
params['a_bogus'] = ctx
print(params['a_bogus'])
response = requests.get(url, headers=headers, cookies=cookies, params=params)
print(response.text)
print(response)
window = global;
window.requestAnimationFrame = function (){}
window.HTMLSpanElement = function (){}
window = global;
window.requestAnimationFrame = function (){}
window.onwheelx = {
"_Ax": "0X21"
}
window.innerWidth = 1920
window.innerHeight = 331
window.outerWidth = 1920
window.outerHeight = 1040
window.screenX = 0
window.screenY = 0
window.pageYOffset = 0
window._sdkGlueVersionMap = {
"sdkGlueVersion": "1.0.0.55",
"bdmsVersion": "1.0.1.7",
"captchaVersion": "4.0.2"
}
window.EventSource = function (){}
span = {
classList: {}
}
localStorage = {
"__tea_cache_first_2018": "1",
"__PRE_CACHE__KEYS": "",
"__pwa_push_show_count": "3",
"__tea_cache_first_24": "1",
"__tea_cache_tokens_2018": "{\"web_id\":\"7530833203905971739\",\"user_unique_id\":\"verify_mdi6arfb_JhCmehzG_uZlV_4Uni_95YM_SHlmdFBh8evy\",\"timestamp\":1755420203978,\"_type_\":\"default\"}",
"xmst": "qdgaz2YbD0bYbuSAHX82t4nPpmXOLOJ-3WB0JYY2AKt3AvzhiX9YxwQtosoldnfPjbYlLihGE3W0z03xcvvjyBoh_TderM9TH3gHKZ2-oeC6u1wKhC5AzUG6XUP4Mrw=",
"__tea_cache_tokens_1300": "{\"web_id\":\"7530833195744642610\",\"user_unique_id\":\"7530833195744642610\",\"timestamp\":1753672463960,\"_type_\":\"default\"}",
"__tea_cache_tokens_24": "{\"web_id\":\"7530833195744642610\",\"user_unique_id\":\"7530833195744642610\",\"timestamp\":1755422052831,\"_type_\":\"default\"}",
"__pwa_push_show_time": "1755417098928",
"__tea_cache_refer_24": "{\"refer_key\":\"\",\"refer_title\":\"今日头条\",\"refer_manual_key\":\"\",\"routeChange\":false}",
"__is_visited_home": "1",
"loglevel": "SILENT",
"__click_close_download_panel_ts__": "1753429771457",
"tt_scid": "QqnVBu5PLTT5IYFV0LBt6D0i8IEcZ17Aebn86VJcNa3TruYKbChQ7VMnJCqf4e3-2205",
"__tea_cache_first_1300": "1",
"show_player_gesture_tips": "0",
"_byted_param_sw": "KIcozisJHmcff1wheN4=",
"web_runtime_security_uid": "fb35592c-8202-4de2-b6da-e0957145bacf",
"SLARDARtoutiao_web_pc": "JTdCJTIydXNlcklkJTIyOiUyMjc1MzA4MzMxOTU3NDQ2NDI2MTAlMjIsJTIyZGV2aWNlSWQlMjI6JTIyNzUzMDgzMzE5NTc0NDY0MjYxMCUyMiwlMjJleHBpcmVzJTIyOjE3NjMxOTgwNTMwMDklN0Q=",
"ttcid": "7ddaeb4ae85c4ad3a97a1f5a20f3128a13"
}
localStorage.getItem = function (){}
localStorage.removeItem = function (){}
sessionStorage = {
"__tea_session_id_24": "{\"sessionId\":\"ea368e47-fcc8-4784-b10c-cc8bfe4b1072\",\"timestamp\":1755422548963}",
"tt_scid": "QqnVBu5PLTT5IYFV0LBt6D0i8IEcZ17Aebn86VJcNa3TruYKbChQ7VMnJCqf4e3-2205",
"_tea_cache_duration": "{\"duration\":90935,\"page_title\":\"今日头条\"}",
"_byted_param_sw": "KIcozisJHmcff1wheN4=",
"/": "1",
"__tea_session_id_2018": "{\"sessionId\":\"2db0d03c-d1c2-49f8-a2b4-fda228db67d1\",\"timestamp\":1755420203981}"
}
sessionStorage.getItem = function (){}
sessionStorage.removeItem = function (){}
document = {
cookie: 'ttcid=7ddaeb4ae85c4ad3a97a1f5a20f3128a13; local_city_cache=%E9%95%BF%E6%B2%99; _ga=GA1.1.152252405.1753408751; csrftoken=d50380b8fd876691377e1784f520d987; s_v_web_id=verify_mdi6arfb_JhCmehzG_uZlV_4Uni_95YM_SHlmdFBh8evy; gfkadpd=24,6457; _ga_QEHZPBE5HH=GS2.1.s1755420185$o6$g1$t1755422181$j60$l0$h0; tt_scid=QqnVBu5PLTT5IYFV0LBt6D0i8IEcZ17Aebn86VJcNa3TruYKbChQ7VMnJCqf4e3-2205',
createElement: function (tag){
if (tag === 'span'){
return span
}
},
documentElement: {},
createEvent: function (){}
}
document.referrer = 'https://www.toutiao.com/?wid=1753408727185'
document.all = {}
location = {}
navigator = {}
navigator.userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36'
screen = {}
history = {}
XMLHttpRequest = function (){}
function get_environment(proxy_array) {
if (!Array.isArray(proxy_array)) {
console.error('Expected an array of property names')
return
}
const createProxyHandler = (objName) => ({
get(target, property, receiver) {
const value = Reflect.get(target, property, receiver)
console.log(
`[GET] 对象: ${objName}, 属性: ${String(property)}, ` +
`类型: ${typeof property}, 值类型: ${typeof value}, ` +
`值: ${typeof value === 'function' ? 'function' : JSON.stringify(value)}`
)
return value
},
set(target, property, value, receiver) {
console.log(
`[SET] 对象: ${objName}, 属性: ${String(property)}, ` +
`类型: ${typeof property}, 值类型: ${typeof value}, ` +
`值: ${typeof value === 'function' ? 'function' : JSON.stringify(value)}`
)
return Reflect.set(target, property, value, receiver)
},
apply(target, thisArg, argumentsList) {
console.log(
`[CALL] 函数: ${objName}, ` + `参数: ${JSON.stringify(argumentsList)}`
)
return Reflect.apply(target, thisArg, argumentsList)
}
})
proxy_array.forEach((objName) => {
try {
// 尝试获取全局对象
let obj
if (objName in window) {
obj = window[objName]
} else {
obj = {}
// 如果是特殊对象需要初始化
if (objName === 'localStorage' || objName === 'sessionStorage') {
obj = {
getItem: () => {},
setItem: () => {},
removeItem: () => {},
clear: () => {},
length: 0,
key: () => null
}
}
window[objName] = obj
}
// 创建代理
window[objName] = new Proxy(obj, createProxyHandler(objName))
} catch (e) {
console.error(`处理 ${objName} 时出错:`, e)
window[objName] = new Proxy({}, createProxyHandler(objName))
}
})
}
function setProxy(proxyObjArr) {
for (let i = 0; i < proxyObjArr.length; i++) {
const handler = `{
get: function(target, property, receiver) {
console.log("方法:", "get ", "对象:", "${proxyObjArr[i]}", " 属性:", property, " 属性类型:", typeof property, ", 属性值:", target[property], ", 属性值类型:", typeof target[property]);
return target[property];
},
set: function(target, property, value, receiver) {
console.log("方法:", "set ", "对象:", "${proxyObjArr[i]}", " 属性:", property, " 属性类型:", typeof property, ", 属性值:", value, ", 属性值类型:", typeof target[property]);
return Reflect.set(...arguments);
}
}`;
eval(`try {
${proxyObjArr[i]};
${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler});
} catch (e) {
${proxyObjArr[i]} = {};
${proxyObjArr[i]} = new Proxy(${proxyObjArr[i]}, ${handler});
}`);
}
}
proxy_array = [
'window',
// 'document',
// 'location',
// 'navigator',
// 'history',
// 'screen',
// 'localStorage',
// 'sessionStorage',
// 'span',
'canvas'
]
setProxy(proxy_array)
require("./bdms")
function get_a_bogus(arg){
args_1 = [
0,
1,
14,
arg,
"",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
]
var r = window._U._v;
a_bogus = window._U._u(r[0], args_1, r[1], r[2], null)
return a_bogus
}
// console.log(get_a_bogus())
补环境的另一种实现思路
插件安装包


#常见问题解决
#7.1 环境补全不完整
现象:报错提示某些属性未定义\ 解决:
- 检查报错信息中缺失的对象/属性
- 在环境初始化部分添加对应的模拟代码
- 使用代理监控确认属性访问情况
#7.2 加密结果不一致
现象:生成的a_bogus与服务端验证不匹配\ 解决:
- 检查所有环境参数是否与真实浏览器一致
- 确认请求参数的顺序和格式
- 检查时间戳等动态参数的影响

