QQ音乐 sign 值逆向实战:破解 Webpack 打包的签名算法
🎯 实战目标:抓取 QQ音乐 PC 端 TOP榜单页面(https://y.qq.com/n/ryqq/toplist/62)中,接口请求携带的
sign参数,并还原其生成流程。
🧩 适用场景:使用 Webpack 等模块化打包工具的前端应用,隐藏核心逻辑的通用逆向分析方法。
1. 初步分析:寻找加密入口
1.1 网络请求定位
打开 Chrome DevTools 的 Network 面板,刷新榜单页面。在过滤框中输入 musics.fcg 快速筛选请求,可以看到这个接口返回了榜单数据。点开请求详情,查看 Payload 标签,会发现几个关键参数:
显然,sign 是一个动态生成的校验值,我们的目标就是找到它的生成函数并模拟出来。
1.2 全局变量搜索初探索
传统逆向通常会直接在 Sources 面板全局搜索 sign,或尝试在 Console 中打印可能的全局变量。先试一把:
window.ddd 存在,且是一个函数,但 _P 却找不到。这暗示着 QQ音乐使用了模块化打包,核心函数被封装在内部了。
💡 实战提示:现代前端框架的逆向难点往往不在于算法本身,而在于如何从 Webpack 打包的“黑盒”中提取出目标函数。
2. Webpack 架构的通用识别与分析
2.1 Webpack 特征快速判断
QQ音乐采用的正是极其常见的 Webpack 模块化打包。可以通过这几个特征快速识别:
- 打开页面加载的 JS 文件(通常体积很大,几百 KB 到几 MB),搜索
__webpack_require__或旧版的关键字webpackJsonp; - 在 Console 中输入
window.webpackJsonp,如果返回数组/函数,基本可以确定是 Webpack 打包; - 如果以上都没搜到,注意观察是否有类似
window.ddd(0)这种自定义暴露的加载入口。
2.2 自定义暴露入口的 Webpack 结构
QQ音乐没有使用默认的 webpackJsonp 全局数组,而是暴露了 window.ddd 作为加载器。经过还原,它的核心结构大致如下(这是逆向时提炼的简化版,不是原始压缩代码):
看懂这个结构后,我们就知道:只要 Hook 这个加载器,就能在模块被导出时“偷看”里面都有什么。
3. 逆向定位 _P 签名函数的步骤
3.1 找到并触发模块加载
先确认 window.ddd 的实际用法。在 Network 面板中对 musics.fcg 发起之前的位置打一个 XHR 断点(Sources > XHR/fetch Breakpoints 添加 /cgi-bin/musics.fcg),页面刷新后会停在请求发出前。观察调用栈,可以发现类似这样的调用:
也就是说,整个模块系统需要先加载 ID 为 0 的模块进行初始化,之后才能使用其他模块。
3.2 Hook 加载器,追踪导出的模块
现在,我们在 Console 中写一段简易的 Hook 脚本,让 window.ddd 每次加载模块时都打印日志,并检查导出中是否含有我们心心念念的 _P:
运行后,如果控制台出现 ✅ 找到 _P 签名函数所在模块! 的警告,就说明定位成功了。此时可以直接查看该模块的导出对象,里面就包含了 _P 方法。接下来只需要把相关代码抠出来,分析算法逻辑即可。
4. 常见问题与解决思路
4.1 环境补全不完整
当你试图把 _P 函数拿到 Node.js 中模拟调用时,大概率会遇到 xxx is not defined 的报错。这是因为模块里用到了浏览器环境下的全局对象(如 window、navigator、document 等)。
解决办法分两步:
- 定位缺失项:根据报错信息,逐一找出缺少的浏览器对象或方法;
- 构造模拟对象:在脚本顶部补上对应的模拟代码。例如:
💡 进阶技巧:可以用
Proxy代理一个空对象,拦截对未知属性的访问,这样就能快速知道代码到底读了什么属性,避免写一堆无用补全。
5. 总结
本次逆向实战的核心并不是某个加密算法有多复杂,而是演示了一套针对 Webpack 打包架构的通用逆向流程:
- 通过 Network 面板定位到核心接口和加密参数;
- 全局搜索找到自定义的模块加载器(这里是
window.ddd); - Hook 加载器,在模块导出时检查是否包含目标函数(
_P); - 提取模块代码,补全必要的浏览器环境,最终在任意 JS 环境下复现签名。
只要掌握了这个思路,无论是 QQ音乐 还是其他同样采用 Webpack 打包、只暴露出自定义加载入口的前端应用,你都可以从容应对。祝你在逆向的路上越走越顺!

