【技术深水区】抖音 WEB 端逆向:从零到一拿下 a_bogus 参数

【技术深水区】抖音 WEB 端逆向:从零到一拿下 a_bogus 参数

前言

a_bogus 相比于之前的 x-bogus,这家伙隐藏得更深,而且裹挟着 JSVMP 混淆,让很多想要抓取数据的同学头疼不已。

注意:本文仅用于技术学习与交流,请勿用于非法爬取商业数据,所有后果自负。

一、什么是 a_bogus?

在抖音的 WEB 端请求中,a_bogus 是一个必不可少的请求签名参数

它的作用类似于一张“动态身份证”,服务端会根据请求的 URL、参数、环境指纹等计算出签名,只有签名正确,服务器才返回真实数据。如果你直接复制浏览器里的请求链接,或者单纯注释掉 a_bogus,返回的数据要么是空的,要么直接是 403。

二、逆向分析环境准备

正式开始之前,你需要具备以下基础(如果你已经是大佬,请跳过):

  • 熟悉浏览器的开发者工具(Network 面板、Sources 面板)。
  • 掌握 XHR 断点条件断点日志断点的用法。
  • 了解基础的 JavaScript 语法。
  • 知道如何利用 curlconverter 将请求转换为 Python 代码。

三、实战拆解:追踪 a_bogus 的生成逻辑

1. 选取目标接口

以抖音的关键词搜索接口为例:

https://www.douyin.com/aweme/v1/web/general/search/single/

这个接口用于搜索视频内容,参数复杂且加密严密,是逆向分析的绝佳对象。

2. 接口参数分析

打开浏览器开发者工具,刷新页面,在 Network 面板中找到上述接口。

复制它的 cURL(bash),使用 curlconverter.com 转换为 Python 代码,方便我们测试。

观察请求参数,你会发现除了常规的 keyword、offset 等参数外,还有两个让人头疼的变量:msTokena_bogus

分别注释掉这两个参数进行请求,发现缺了任何一个都会导致请求失败。本文我们重点攻克 a_bogus

3. 定位加密位置

3.1 全局搜索失效

直接在 Sources 面板搜索 a_bogus,发现代码被混淆,根本搜不到明文。这说明抖音做了代码混淆,我们需要换一种思路——XHR 断点

3.2 使用 XHR 断点

在 Sources 面板右侧,找到 XHR/fetch Breakpoints,点击 +,输入接口路径的关键词 general/search/single。

设置好后刷新页面,页面会自动断在发送请求的代码处。3.3 分析堆栈调用

断下来后,查看右侧的 Call Stack(调用堆栈)。

堆栈是从下往上执行的,我们需要找到 生成 a_bogus 的那个堆栈帧。

  • 往下翻堆栈,找到 请求参数中还没有 a_bogus 的地方。
  • 往上翻,找到 请求参数中已经有了 a_bogus 的地方。

这两个位置之间的某个函数,就是加密函数。关键点:不要只找一个堆栈就停下,要逐个查看作用域(Scope)中的 params 或 data 对象,看是否有 a_bogus 字段。

4. 精细调试:日志断点与条件断点

最终,我们定位到了一个混淆很严重的 JS 文件(通常是 bdms.js 之类的),代码看起来像这样:

var result = s.apply(b, u);

这个地方很难一眼看出 s 是干什么的,但我们可以设置日志断点

在 s.apply(b, u) 这行右键,选择 Add logpoint,输出内容设为:

返回值:{result}

刷新页面,看控制台打印的日志,你会发现有很多 true、false、数字以及字符串

观察那些字符串,你会惊奇地发现:

  • 短的那一串看起来像是我们请求的 URL 参数拼接。
  • 长的那一串长度大约在 160 位左右,看起来就是我们要找的 a_bogus。

为了精准定位,我们可以设置条件断点:比如当返回值长度大于 150 时再断下来。

result.length > 150

最终,我们找到了生成 a_bogus 的核心函数,它在 e 函数内部。

四、补环境与代码封装

找到核心函数后,将 bdms.js 文件下载到本地。

1. 补环境

直接运行这段 JS 会报错,因为缺少浏览器环境(window, document, navigator 等)。我们需要模拟这些环境:

window = global; delete global; delete Buffer; window.requestAnimationFrame = function(){}; XMLHttpRequest = function() {}; document = {} navigator = {}; screen = { availHeight: 816, availLeft: 0, availTop: 0, availWidth: 1536, colorDepth: 24, height: 864 }

2. 导出加密函数

分析函数调用逻辑,发现 e 函数被调用时的参数 u 包含了很多环境信息(如 UA、屏幕宽高等)和请求参数。

我们可以将其封装成一个标准的 getSign 函数,只接收 params 字符串作为入参:

function getSign(params) { u = [ 0, 1, 14, params, "", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0" ] var r = window.sign_z._v; return (0,window.sign_z._u)(r[0], u, r[1], r[2], this) }

这样,在 Python 中调用 execjs 执行这段代码,输入参数字符串,就能得到 a_bogus 了。

五、最终测试

# 伪代码示例import execjsimport requestswithopen('douyin.js','r', encoding='utf-8')as f: ctx = execjs.compile(f.read())params_str ="device_platform=webapp&aid=6383&keyword=飞驰人生2..."a_bogus = ctx.call('getSign', params_str)print(a_bogus)# 输出类似:mXmZMdzgdDfiDDWX5VcLfY3q6WB3Y/R30CPYMD2f7dVr...

将生成的 a_bogus 塞回请求参数中,你会发现数据正常返回了。

写在最后

看到这你已经对抖音 WEB 端的加密参数 a_bogus 有了比较深的理解。

  • 但是,抖音的反爬体系是动态更新的:msToken 和 a_bogus 的算法是否会变?
  • 补环境的时候是否需要更多指纹?
  • 如果被封 IP 了怎么办?

逆向是一场无止境的博弈。

想直接拿到稳定、高并发、低延迟的解决方案,可以查看我的主页,有封装好的 API 接口和完整的 SDK。

如果你有定制需求,也欢迎直接私信我。

Read more

视频续播功能实现 - 断点续看从前端到 Spring Boot 后端

视频续播功能实现 - 断点续看从前端到 Spring Boot 后端

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Micro麦可乐的博客 🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战 🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战 🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解 🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用 🍎 《前端技术》专栏以实战为主介绍日常开发中前端应用的一些功能以及技巧,均附有完整的代码示例 ✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧 💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程 🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整 👍《Spring Security》专栏中我们将逐步深入Spring Security的各个

1Panel+Ollama+WebUI:打造本地AI模型的完整指南(附Gemini插件教程)

1Panel、Ollama与Open WebUI:构建你的私有化AI模型应用平台实战 在AI技术日益普及的今天,许多开发者和技术爱好者不再满足于仅仅调用云端API。他们渴望在本地环境中部署、管理和实验自己的AI模型,无论是出于数据隐私的考量、网络环境的限制,还是纯粹对技术探索的热爱。构建一个稳定、易用且可扩展的本地AI平台,成为了一个极具吸引力的目标。本文将为你呈现一套完整的解决方案,它并非简单的工具堆砌,而是一个经过精心设计的、以1Panel为控制中枢,Ollama为模型引擎,Open WebUI为交互前端的集成化平台。我们将深入探讨如何将它们无缝衔接,并重点解锁通过插件系统集成如Gemini等第三方模型的高级玩法,让你在本地也能拥有媲美云端服务的AI应用体验。 1. 平台基石:1Panel与OpenResty的部署与配置 构建任何复杂应用,一个稳定且管理便捷的基础环境是首要前提。1Panel作为一个现代化的Linux服务器运维管理面板,以其直观的Web界面和容器化应用管理能力,极大地简化了服务器运维工作。而OpenResty,作为Nginx的增强版本,集成了LuaJIT,为

Docker部署music-tag-web音乐标签编辑器

Docker部署music-tag-web音乐标签编辑器

Docker部署music-tag-web音乐标签编辑器 * 一、music-tag-web介绍 * 1.1 music-tag-web简介 * 1.2 主要特点 * 二、本次实践规划 * 2.1 本地环境规划 * 2.2 本次实践介绍 * 三、本地环境检查 * 3.1 检查Docker服务状态 * 3.2 检查Docker版本 * 3.3 检查docker compose 版本 * 四、下载music-tag-web镜像 * 五、部署music-tag-web应用 * 5.1 创建部署目录 * 5.2 编辑部署文件 * 5.3 创建music-tag-web容器 * 5.4 查music-tag-web容器状态 * 5.5 查看music-tag-web容器日志 * 六、

我用Claude Code + GLM4.7修前端Bug的翻车现场,1小时烧光5小时限额

本来想体验一把“vibe coding 省时间”,结果变成“vibe coding 省不了、还很贵”:折腾将近一小时,GLM 额度直接打满,Bug 还在。 背景:事情是怎么开始的 最近遇到一个前端 Bug,属于那种看起来不大、但很烦的类型:页面运行时报错,提示动态导入某个模块失败(报错里能看到类似 Failed to fetch dynamically imported module .../router/index.ts 这种信息)。 我想着正好试试工具链:Claude Code + GLM4.7。理想情况是:它读代码、跑命令、给修改方案,我负责点确认就行。 现实是另一回事。 结果:时间花了,额度没了,Bug 还没修好 简单总结一下这次的“