抖音a_bogus参数加密逆向#
#概述
本技术文档详细记录了针对抖音Web端反爬机制中a_bogus参数的逆向工程过程。该参数是抖音API请求中的关键加密参数,用于验证请求的合法性。通过完整的环境模拟和Hook技术,我们成功实现了该参数的本地生成。
#网页分析









#技术背景
#2.1 抖音反爬机制特点
- 基于浏览器指纹的深度检测
- 动态加密参数
a_bogus验证 - 函数调用链混淆与保护
- 环境完整性检查
#2.2 破解技术路线
- 环境模拟:完整构建浏览器运行环境
- 函数Hook:拦截关键函数调用
- 原型链保护:防止检测代码识别环境差异
- 动态代理:监控对象属性访问
#核心实现技术
#3.1 环境模拟系统
#3.1.1 全局对象初始化
window = global;
window.requestAnimationFrame = function(){}
window.HTMLSpanElement = function(){}
// 窗口属性配置
window.outerWidth = 1773
window.outerHeight = 293
window.innerWidth = 293
window.innerHeight = 293#3.1.2 SDK版本信息模拟
window._sdkGlueVersionMap = {
"sdkGlueVersion": "1.0.0.64-fix.01",
"bdmsVersion": "1.0.1.19-fix.01",
"captchaVersion": "4.0.10"
}#3.2 函数保护机制
#3.2.1 安全函数包装器
const $toString = Function.toString
const myFunction_toString_symbol = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)))
const myToString = function() {
return ((typeof this === 'function' && this[myFunction_toString_symbol]) || $toString.call(this))
}
function set_native(func, key, value) {
Object.defineProperty(func, key, {
enumerable: false,
configurable: true,
writable: true,
value: value
})
}
// 重写Function.prototype.toString
delete Function.prototype['toString']
set_native(Function.prototype, 'toString', myToString)#3.2.2 关键函数保护
globalThis.safefunction = (func) => {
set_native(func, myFunction_toString_symbol, `function ${func.name || ''}() { [native code] }`)
}
// 保护定时器函数
setInterval = function setInterval(){}; safefunction(setInterval);
setTimeout = function setTimeout(){}; safefunction(setTimeout);#3.3 DOM环境模拟
#3.3.1 文档对象模型
document = {
createElement: function(tag) {
if (tag == 'span') return span
if (tag == 'canvas') return canvas
return {}
},
documentElement: {},
createEvent: function(){},
addEventListener: function(){},
all: {}
}#3.3.2 自定义元素实现
span = {classList: {}}
canvas = {
getContext: function(){}
}
safefunction(canvas.getContext)#3.4 浏览器特性模拟
#3.4.1 导航对象
navigator = {
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...",
platform: 'Win32',
storage: {}
}#3.4.2 屏幕属性
screen = {
availWidth: 1920,
availHeight: 1040,
width: 1920,
height: 1080,
colorDepth: 24,
availLeft: 0
}#反检测技术实现
#4.1 Symbol.toStringTag 伪装
Object.defineProperty(document, Symbol.toStringTag, {
value: 'HTMLDocument',
configurable: true,
writable: true
});
Object.defineProperty(navigator, Symbol.toStringTag, {
value: 'Navigator',
configurable: true,
writable: true
});#4.2 第三方SDK模拟
window.CefSharp = {
isMock: true,
BindObjectAsync: function() { return Promise.resolve(); }
};
window.eoapi = {
mock: true,
invoke: function() { console.log('eoapi mock called'); }
};#动态代理监控系统
#5.1 代理处理器实现
function get_environment(proxy_array) {
const createProxyHandler = (objName) => ({
get(target, property, receiver) {
const value = Reflect.get(target, property, receiver)
console.log(`[GET] 对象: ${objName}, 属性: ${String(property)}`)
return value
},
set(target, property, value, receiver) {
console.log(`[SET] 对象: ${objName}, 属性: ${String(property)}`)
return Reflect.set(target, property, value, receiver)
}
})
proxy_array.forEach((objName) => {
try {
let obj = objName in window ? window[objName] : {}
window[objName] = new Proxy(obj, createProxyHandler(objName))
} catch (e) {
console.error(`处理 ${objName} 时出错:`, e)
}
})
}#5.2 监控对象配置
proxy_array = [
'window',
'document',
'location',
'navigator',
'history',
'screen',
'localStorage',
'sessionStorage',
'span',
'canvas'
]
get_environment(proxy_array)#加密参数生成流程
#6.1 bdms初始化
require('./bdms')
window.bdms.init({
aid: 6383,
pageId: 6241,
paths: ['^/webcast/', '^/aweme/v1/'],
boe: false,
ddrt: 8.5,
ic: 8.5
})#6.2 a_bogus生成函数
function get_ab(params) {
xhr = new XMLHttpRequest()
xhr.bdmsInvokeList = [
{ args: ['GET', params, 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
}#完整代码
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.douyin.com/user/MS4wLjABAAAAPs96_XYppoAye-VK57HhjucNZfR_mTyR4KKqDBHdt5k?from_tab_name=main&vid=7521300075331456256",
"sec-ch-ua": "\"Google Chrome\";v=\"137\", \"Chromium\";v=\"137\", \"Not/A)Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"uifid": "2eb4f745f9fe6544447c1d68cb43a44931f67e23b1951fd9ca8b76ce94a622365d5383cfffac86a6f5d9f4a996c6515de06c474d5bc145dbf8585b9de15cac9a709982e71e6779405f6a51c415bdcdb57c7efe5d11d9657d7e4f163276f1e3a551eb7337a5493c4c969bd7434a32cd5b5a9f5c0db12d2e64408a381b39018f7ae415d4210d1f59164ebb59fe54ad4412f2860dfd832192820486bf3a1e82c9b4",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"
}
cookies = {
"UIFID_TEMP": "2eb4f745f9fe6544447c1d68cb43a44931f67e23b1951fd9ca8b76ce94a622364c348c7d9a916f9d339d7226513c0350e401a1f04298a7806a492f0514d7a280aefc4e2f7ed9420e360d6daea7d56025",
"hevc_supported": "true",
"fpk1": "U2FsdGVkX19LuXWdPdoJUwJDGa9OvlhMpTQMqy5yGra6L9p9CAjJlysDiTli1bQFd62TBekPMQJ+G3CSFdDWyw==",
"fpk2": "3fa31b52dd6ebc517e5492d43d77e61c",
"bd_ticket_guard_client_web_domain": "2",
"UIFID": "2eb4f745f9fe6544447c1d68cb43a44931f67e23b1951fd9ca8b76ce94a622365d5383cfffac86a6f5d9f4a996c6515de06c474d5bc145dbf8585b9de15cac9a709982e71e6779405f6a51c415bdcdb57c7efe5d11d9657d7e4f163276f1e3a551eb7337a5493c4c969bd7434a32cd5b5a9f5c0db12d2e64408a381b39018f7ae415d4210d1f59164ebb59fe54ad4412f2860dfd832192820486bf3a1e82c9b4",
"SearchMultiColumnLandingAbVer": "2",
"SEARCH_RESULT_LIST_TYPE": "%22multi%22",
"xgplayer_device_id": "32342470011",
"xgplayer_user_id": "990979576172",
"live_use_vvc": "%22false%22",
"passport_mfa_token": "CjfZsPUesQxijJk50MyNG2G5kRbK2Sqj%2BwRXLRcPX%2B8HkPG31O2%2FfMnENwQ%2B5ncNCODjbEAXdyJhGkoKPOHQKWNZxI8TUlFBC0qlRyGDldo0IwYm80lswgkKk%2F3yxskR4MWHEZpuvf%2Bv9zBMBmT2quATvI2g5%2F7y5hChlvENGPax0WwgAiIBA78fYR4%3D",
"d_ticket": "f2640363d320cf41c637d73d8ed24baac436c",
"n_mh": "9-mIeuD4wZnlYrrOvfzG3MuT6aQmCUtmr8FxV8Kl8xY",
"SelfTabRedDotControl": "%5B%5D",
"__security_mc_1_s_sdk_cert_key": "8acbdf1b-4c3b-8b22",
"__security_server_data_status": "1",
"my_rd": "2",
"__security_mc_1_s_sdk_crypt_sdk": "6f3b610c-4cb2-ae51",
"s_v_web_id": "verify_mb67kwnm_HcU0pVSA_nv07_4Q2k_BD6N_5GthzfviapYA",
"passport_csrf_token": "9d8eadc10a526d72a353a20d2cd7b202",
"passport_csrf_token_default": "9d8eadc10a526d72a353a20d2cd7b202",
"volume_info": "%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.591%7D",
"enter_pc_once": "1",
"dy_swidth": "1920",
"dy_sheight": "1080",
"is_dash_user": "1",
"publish_badge_show_info": "%220%2C0%2C0%2C1751375097755%22",
"h265ErrorNum": "-1",
"stream_player_status_params": "%22%7B%5C%22is_auto_play%5C%22%3A0%2C%5C%22is_full_screen%5C%22%3A0%2C%5C%22is_full_webscreen%5C%22%3A0%2C%5C%22is_mute%5C%22%3A0%2C%5C%22is_speed%5C%22%3A1%2C%5C%22is_visible%5C%22%3A0%7D%22",
"__live_version__": "%221.1.3.5120%22",
"__security_mc_1_s_sdk_sign_data_key_sso": "38985a08-417a-89e5",
"passport_auth_status": "9311c93531036fc76d78cbb011b7b817%2C",
"passport_auth_status_ss": "9311c93531036fc76d78cbb011b7b817%2C",
"session_tlb_tag": "sttt%7C5%7ClNh4zgz_nEZz5hkc3NEbL__________HQVGGG2mTTjFRYRf0RURdgymoaJudXvRNcyg6RKd0EaI%3D",
"_bd_ticket_crypt_doamin": "2",
"_bd_ticket_crypt_cookie": "d6b6f0072e8c691c4f816d25127d1981",
"__security_mc_1_s_sdk_sign_data_key_web_protect": "a5bdc8a1-4c79-904d",
"FOLLOW_LIVE_POINT_INFO": "%22MS4wLjABAAAAAVg2eDB7F5WcELvRy7KwgfZCCZzeoxk0YXunQ7vgEa1UpFHvLMeQnebGco8NAh-8%2F1751644800000%2F0%2F0%2F1751639923707%22",
"FOLLOW_NUMBER_YELLOW_POINT_INFO": "%22MS4wLjABAAAAAVg2eDB7F5WcELvRy7KwgfZCCZzeoxk0YXunQ7vgEa1UpFHvLMeQnebGco8NAh-8%2F1751817600000%2F0%2F1751778336164%2F0%22",
"login_time": "1751778820338",
"odin_tt": "0966ab51948e2b573ad57290c70f9b4aa6290deedbc3029a45e4c2a2c4d96d58575b79ddf77f3a3a251a1955359176ac7948557567a5a8797c9801994555de52b741c97387f5d5135d70006841214837",
"pwa2": "%220%7C0%7C2%7C0%22",
"download_guide": "%223%2F20250704%2F1%22",
"WallpaperGuide": "%7B%22showTime%22%3A1751779112350%2C%22closeTime%22%3A0%2C%22showCount%22%3A1%2C%22cursor1%22%3A64%2C%22cursor2%22%3A20%2C%22hoverTime%22%3A1751548108048%7D",
"live_can_add_dy_2_desktop": "%221%22",
"strategyABtestKey": "%221751868942.104%22",
"biz_trace_id": "83ad859c",
"ttwid": "1%7CGwV7OJwoKkpTbMetbdx2z4VlKSlkI1BsZlPtvBdsiKQ%7C1751868972%7Cdfd602d3d7530e48172eccf839f9a378e759a74fc7c278f93074bf5af54b249e",
"bd_ticket_guard_client_data": "eyJiZC10aWNrZXQtZ3VhcmQtdmVyc2lvbiI6MiwiYmQtdGlja2V0LWd1YXJkLWl0ZXJhdGlvbi12ZXJzaW9uIjoxLCJiZC10aWNrZXQtZ3VhcmQtcmVlLXB1YmxpYy1rZXkiOiJCS0JRR2NFemxKeTNnQmJJek9YaFdkTjA3bDh2NnVVTytadmdlUWNJSWp2STVFYUVOc3BIVmdjN2JtNk8yT2VZcW8xK2psMHVucFFGQTJ6RzRYbS9VeU09IiwiYmQtdGlja2V0LWd1YXJkLXdlYi12ZXJzaW9uIjoyfQ%3D%3D",
"__ac_nonce": "0686b6f48004aeb3f1fd9",
"__ac_signature": "_02B4Z6wo00f01W0ZveAAAIDBWj15vpURIyVtOblAADMwe7",
"IsDouyinActive": "true",
"home_can_add_dy_2_desktop": "%220%22",
"stream_recommend_feed_params": "%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A1920%2C%5C%22screen_height%5C%22%3A1080%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A16%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A10%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A100%7D%22"
}
url = "https://www.douyin.com/aweme/v1/web/aweme/post/"
params = {
"device_platform": "webapp",
"aid": "6383",
"channel": "channel_pc_web",
"sec_user_id": "MS4wLjABAAAAPs96_XYppoAye-VK57HhjucNZfR_mTyR4KKqDBHdt5k",
"max_cursor": "0",
"locate_item_id": "7521300075331456256",
"locate_query": "false",
"show_live_replay_strategy": "1",
"need_time_list": "1",
"time_list_query": "0",
"whale_cut_token": "",
"cut_version": "1",
"count": "18",
"publish_video_strategy_type": "2",
"from_user_page": "1",
"update_version_code": "170400",
"pc_client_type": "1",
"pc_libra_divert": "Windows",
"support_h265": "1",
"support_dash": "1",
"cpu_core_num": "16",
"version_code": "290100",
"version_name": "29.1.0",
"cookie_enabled": "true",
"screen_width": "1920",
"screen_height": "1080",
"browser_language": "zh-CN",
"browser_platform": "Win32",
"browser_name": "Chrome",
"browser_version": "137.0.0.0",
"browser_online": "true",
"engine_name": "Blink",
"engine_version": "137.0.0.0",
"os_name": "Windows",
"os_version": "10",
"device_memory": "8",
"platform": "PC",
"downlink": "10",
"effective_type": "4g",
"round_trip_time": "100",
"webid": "7486005262718158363",
"uifid": "2eb4f745f9fe6544447c1d68cb43a44931f67e23b1951fd9ca8b76ce94a622365d5383cfffac86a6f5d9f4a996c6515de06c474d5bc145dbf8585b9de15cac9a709982e71e6779405f6a51c415bdcdb57c7efe5d11d9657d7e4f163276f1e3a551eb7337a5493c4c969bd7434a32cd5b5a9f5c0db12d2e64408a381b39018f7ae415d4210d1f59164ebb59fe54ad4412f2860dfd832192820486bf3a1e82c9b4",
"msToken": "fW2gW_DXSzbPKlMKipT8DBHbFIKeS94CZOZeAj0sFqmVavAISD9ZhcHefhK7IWiyKYswFy12SW3VAD-wby1eNVWYszNMnpQ0ARAxDR7cjoZDfAfcne3xZvbqbLVt4jR_Z8Ki_liwIW4OQdSboTeBHghHMQkzieN6hlbss-k1PumR81rQOX8nba0=",
"verifyFp": "verify_mb67kwnm_HcU0pVSA_nv07_4Q2k_BD6N_5GthzfviapYA",
"fp": "verify_mb67kwnm_HcU0pVSA_nv07_4Q2k_BD6N_5GthzfviapYA"
}
url_params = url + "?" + urlencode(params)
# print(url_params)
ctx = execjs.compile(open('env.js', 'r', encoding='utf-8').read()).call("get_ab", url_params)
# print(ctx)
params['a_bogus'] = ctx
response = requests.get(url, headers=headers, cookies=cookies, params=params)
print(response.text)
print(response)
window = global;
console_log = console.log
;(() => {
'use strict'
// 取原型链上的toString
const $toString = Function.toString
// 取方法名 reload
const myFunction_toString_symbol = Symbol(
'('.concat('', ')_', (Math.random() + '').toString(36))
)
const myToString = function () {
return (
(typeof this === 'function' && this[myFunction_toString_symbol]) ||
$toString.call(this)
)
}
function set_native(func, key, value) {
Object.defineProperty(func, key, {
enumerable: false, // 不可枚举
configurable: true, // 可配置
writable: true, // 可写
value: value
})
}
// 删除原型链上的toString
delete Function.prototype['toString']
// 自定义一个getter方法,其实就是一个hook
set_native(Function.prototype, 'toString', myToString)
// 套个娃,保护一下我们定义的toString:避免对toString再次toString
set_native(
Function.prototype.toString,
myFunction_toString_symbol,
'function toString() { [native code] }'
)
globalThis.safefunction = (func) => {
set_native(
func,
myFunction_toString_symbol,
`function ${func.name || ''}() { [native code] }`
)
}
// 导出函数到globalThis,更改原型上的toString为自己的toString
// 这个方法相当于过掉func的toString检测点
}).call(globalThis)
setInterval = function setInterval(){};safefunction(setInterval);
setTimeout = function setTimeout(){};safefunction(setTimeout);
window.requestAnimationFrame = function requestAnimationFrame(){};safefunction(window.requestAnimationFrame)
window.EventSource = function EventSource(){};safefunction(window.EventSource)
window.addEventListener = function addEventListener(){};safefunction(window.addEventListener)
window.OfflineAudioContext = function OfflineAudioContext(){};safefunction(window.OfflineAudioContext)
window.outerWidth = 1773
window.outerHeight = 293
window.innerWidth = 293
window.innerHeight = 293
window._sdkGlueVersionMap = {
"sdkGlueVersion": "1.0.0.64-fix.01",
"bdmsVersion": "1.0.1.19-fix.01",
"captchaVersion": "4.0.10"
}
window.indexedDB = {
}
span = {classList:{}}
canvas = {getContext:function getContext(){}}
safefunction(canvas.getContext)
document = {
createElement: function (tag) {
if (tag == 'span'){
return span
}
if (tag == 'canvas'){
return canvas
}
console_log('createElement:::', tag)
return {}
},
documentElement: {},
createEvent: function createEvent() {},
addEventListener: function addEventListener(){},
}
// 模拟这些属性避免检测
window.CefSharp = {
isMock: true,
BindObjectAsync: function() { return Promise.resolve(); }
};
window.eoapi = {
mock: true,
invoke: function() { console.log('eoapi mock called'); }
};
window.eoWebBrowserDispatcher = {
mock: true,
dispatch: function() {}
};
safefunction(document.createElement)
safefunction(document.createEvent)
safefunction(document.addEventListener)
document.all = {}
document.location = {
"ancestorOrigins": {},
"href": "https://www.douyin.com/user/MS4wLjABAAAAPs96_XYppoAye-VK57HhjucNZfR_mTyR4KKqDBHdt5k?from_tab_name=main&vid=7521300075331456256",
"origin": "https://www.douyin.com",
"protocol": "https:",
"host": "www.douyin.com",
"hostname": "www.douyin.com",
"port": "",
"pathname": "/user/MS4wLjABAAAAPs96_XYppoAye-VK57HhjucNZfR_mTyR4KKqDBHdt5k",
"search": "?from_tab_name=main&vid=7521300075331456256",
"hash": ""
}
location = {
"ancestorOrigins": {},
"href": "https://www.douyin.com/user/MS4wLjABAAAAPs96_XYppoAye-VK57HhjucNZfR_mTyR4KKqDBHdt5k?from_tab_name=main",
"origin": "https://www.douyin.com",
"protocol": "https:",
"host": "www.douyin.com",
"hostname": "www.douyin.com",
"port": "",
"pathname": "/user/MS4wLjABAAAAPs96_XYppoAye-VK57HhjucNZfR_mTyR4KKqDBHdt5k",
"search": "?from_tab_name=main",
"hash": ""
}
navigator = {"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36"}
navigator.storage = {}
navigator.platform = 'Win32'
history = {}
screen = {availWidth: 1920, availHeight: 1040, width: 1920, height: 1080, colorDepth: 24, availLeft: 0}
localStorage = {}
localStorage.getItem = function getItem(){};safefunction(localStorage.getItem)
sessionStorage = {}
Object.defineProperty(document, Symbol.toStringTag, {
value: 'HTMLDocument',
configurable: true,
writable: true
});
Object.defineProperty(location, Symbol.toStringTag, {
value: 'Location',
configurable: true,
writable: true
});
Object.defineProperty(navigator, Symbol.toStringTag, {
value: 'Navigator',
configurable: true,
writable: true
});
Object.defineProperty(history, Symbol.toStringTag, {
value: 'History',
configurable: true,
writable: true
});
Object.defineProperty(screen, Symbol.toStringTag, {
value: 'Screen',
configurable: true,
writable: true
});
Object.defineProperty(localStorage, Symbol.toStringTag, {
value: 'Storage',
configurable: true,
writable: true
});
Object.defineProperty(sessionStorage, Symbol.toStringTag, {
value: 'Storage',
configurable: true,
writable: true
});
XMLHttpRequest = function XMLHttpRequest() {}
safefunction(XMLHttpRequest)
XMLHttpRequest.prototype.send = function send() {}
safefunction(XMLHttpRequest.prototype.send)
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))
}
})
}
proxy_array = [
'window',
'document',
'location',
'navigator',
'history',
'screen',
'localStorage',
'sessionStorage',
'span',
'canvas'
]
get_environment(proxy_array)
require('./bdms')
t = {
aid: 6383,
pageId: 6241,
paths: [
'^/webcast/',
'^/aweme/v1/',
'^/aweme/v2/',
'/v1/message/send',
'^/live/',
'^/captcha/',
'^/ecom/'
],
boe: false,
ddrt: 8.5,
ic: 8.5
}
window.bdms.init(t)
function get_ab(params) {
xhr = new XMLHttpRequest()
xhr.bdmsInvokeList = [
{
args: [
'GET',
params,
true
]
},
{
args: ['Accept', 'application/json, text/plain, */*']
},
{
args: [
'uifid',
'2eb4f745f9fe6544447c1d68cb43a44931f67e23b1951fd9ca8b76ce94a622365d5383cfffac86a6f5d9f4a996c6515de06c474d5bc145dbf8585b9de15cac9a709982e71e6779405f6a51c415bdcdb57c7efe5d11d9657d7e4f163276f1e3a551eb7337a5493c4c969bd7434a32cd5b5a9f5c0db12d2e64408a381b39018f7ae415d4210d1f59164ebb59fe54ad4412f2860dfd832192820486bf3a1e82c9b4'
]
}
]
xhr.invokeList = [
{
name: 'addEventListener',
args: ['load', null]
},
{
name: 'addEventListener',
args: ['error', null]
}
]
xhr.send(null)
return window.a_bogus
}
get_ab()
#完整工作流程
- 环境初始化:构建完整的浏览器运行环境
- 函数保护:Hook关键函数防止检测
- 代理监控:设置属性访问监控
- 加密模块加载:引入bdms加密模块
- 参数生成:通过模拟XHR调用触发加密流程
- 结果获取:从全局变量提取生成的a_bogus
#技术难点与解决方案
| 难点 | 解决方案 | 实现效果 |
|---|---|---|
| 函数toString检测 | 重写Function.prototype.toString | 完美绕过函数类型检测 |
| 环境完整性检查 | 完整模拟浏览器对象结构 | 通过抖音的环境验证 |
| 动态加密逻辑 | 代理监控+XHR调用模拟 | 准确生成有效参数 |
| 第三方SDK依赖 | 模拟CefSharp等对象 | 消除SDK检测异常 |

