QQ音乐sign参数逆向:从混淆代码到算法还原的实战解析

张开发
2026/4/7 3:04:55 15 分钟阅读

分享文章

QQ音乐sign参数逆向:从混淆代码到算法还原的实战解析
1. 逆向工程入门理解QQ音乐sign参数的作用在分析QQ音乐sign参数之前我们需要先理解这个参数的作用。sign参数是QQ音乐API请求中的一个关键加密参数它用于验证请求的合法性。每次向QQ音乐服务器发送请求时都需要携带这个经过特定算法生成的签名值。我刚开始研究这个参数时发现它有几个明显特征长度通常为40个字符左右以zzc开头对相同的输入参数每次生成的sign值都不同这让我意识到sign参数很可能是通过对请求参数进行某种哈希计算再经过特定变换得到的。在实际抓包分析中我发现QQ音乐的API请求大多采用POST方式请求体中会包含一个JSON格式的数据而sign参数就出现在请求URL中。2. 定位关键代码如何找到sign生成位置要逆向sign算法首先需要找到生成这个参数的代码位置。这里我分享几个实用技巧2.1 使用浏览器开发者工具打开QQ音乐网页版按F12调出开发者工具切换到Network面板。在过滤器中输入musics.fcg这是QQ音乐主要的API接口。观察请求URL会发现sign参数就包含在其中。2.2 搜索关键代码在Sources面板中搜索sign:这个关键词。经过多次尝试我发现在vendor.chunk.js文件中有两处相关代码// 第一处 if (-1 ! t.url.indexOf(cgi-bin/musics.fcg)) { var i, o n(350).default; i GET t.type.toUpperCase() ? o(t.data.data) : o(t.data), t.url B({sign: i}, t.url) } // 第二处 if (-1 ! t.url.indexOf(cgi-bin/musics.fcg)) { var i, o n(360).default; i GET t.type.toUpperCase() ? o(t.data.data) : o(t.data), t.url T({sign: i}, t.url) }这两处代码结构相似主要区别在于调用的模块不同n(350)和n(360)。通过断点调试可以确认sign参数是由o()函数生成的。3. 突破代码混淆理解核心逻辑QQ音乐的JavaScript代码经过了严重的混淆处理这给逆向工作带来了很大挑战。我总结了几种应对混淆代码的方法3.1 动态调试技巧在关键函数处设置断点观察输入输出。比如在o()函数入口处打断点然后触发一个API请求就能看到传入的参数和返回的sign值。3.2 日志注入法我编写了一个简单的日志记录函数可以注入到混淆代码中window.add_json_str function(param_name, param) { var log_str param_name JSON.stringify(param) \n\n; console.log(log_str); // 还可以将日志保存到本地文件 };把这个函数注入后在关键位置调用它就能记录下运行时的各种变量值。3.3 反混淆策略混淆代码虽然难以阅读但通常有固定模式。比如常见的控制流扁平化可以通过分析switch-case结构来理清逻辑。我发现在sign生成代码中有一个巨大的switch语句包含了70多个case分支。4. 算法还原拆解sign生成过程经过多次调试和分析我逐步还原出了sign参数的生成算法。整个过程可以分为以下几个步骤4.1 SHA1哈希计算首先将请求参数JSON字符串进行SHA1哈希计算。例如对于参数{ comm: { cv: 4747474, ct: 24, format: json }, req_1: { module: music.musicsearch.HotkeyService, method: GetHotkeyForQQMusicMobile } }计算其SHA1哈希值得到40位的十六进制字符串如DD69685AD37B71DB3E870E35FB14EFE3CC465405。4.2 字节数组转换接下来将这个SHA1哈希值转换为字节数组并与一个固定的xorlist进行异或运算var xorlist [89,39,179,150,218,82,58,252,177,52,186,123,120,64,242,133,143,161,121,179]; var bytes []; for(var i0; i20; i) { var high parseInt(hex_hash[i*2], 16); var low parseInt(hex_hash[i*21], 16); bytes.push((high*16 low) ^ xorlist[i]); }4.3 Base64编码变换然后对处理后的字节数组进行一种特殊的Base64编码var base64chars ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789; var sign_mid ; for(var i0; i20; i3) { var a base64chars[bytes[i] 2]; var b base64chars[((bytes[i] 3) 4) | (bytes[i1] 4)]; var c base64chars[((bytes[i1] 15) 2) | (bytes[i2] 6)]; var d base64chars[bytes[i2] 63]; sign_mid a b c d; }4.4 组合最终sign最后从原始SHA1哈希值中提取特定位置的字符与中间部分组合形成最终的sign值function get_sign_head(hex_hash) { var positions [23,14,6,36,16,40,7,19]; var head ; for(var i0; i8; i) { head hex_hash[positions[i]]; } return head; } function get_sign_tail(hex_hash) { var positions [16,1,32,12,19,27,8,5]; var tail ; for(var i0; i8; i) { tail hex_hash[positions[i]]; } return tail; } var sign zzc get_sign_head(hex_hash) sign_mid get_sign_tail(hex_hash);5. 完整实现Python代码示例根据上述分析我用Python实现了sign参数的生成算法import hashlib def qqmusic_sign(params): # 固定xor列表 xorlist [89,39,179,150,218,82,58,252,177,52,186,123,120,64,242,133,143,161,121,179] base64chars ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 # 步骤1计算SHA1 param_str json.dumps(params, separators(,, :), ensure_asciiFalse) sha1 hashlib.sha1(param_str.encode(utf-8)).hexdigest().upper() # 步骤2异或处理 bytes_array [] for i in range(20): high int(sha1[i*2], 16) low int(sha1[i*21], 16) bytes_array.append((high*16 low) ^ xorlist[i]) # 步骤3特殊Base64编码 sign_mid for i in range(0, 20, 3): a base64chars[bytes_array[i] 2] b base64chars[((bytes_array[i] 3) 4) | (bytes_array[i1] 4)] c base64chars[((bytes_array[i1] 15) 2) | (bytes_array[i2] 6)] d base64chars[bytes_array[i2] 63] sign_mid a b c d # 步骤4提取头尾 head_positions [23,14,6,36,16,40,7,19] tail_positions [16,1,32,12,19,27,8,5] sign_head .join([sha1[pos] for pos in head_positions]) sign_tail .join([sha1[pos] for pos in tail_positions]) # 组合最终sign return zzc sign_head sign_mid sign_tail6. 验证与调试实现算法后需要进行验证。我通过以下步骤确保生成的sign正确使用浏览器正常访问QQ音乐抓取一个API请求记录参数和sign值用相同的参数调用自己的sign生成函数对比两个sign值是否一致在实际测试中我发现有几个容易出错的地方参数JSON的序列化方式必须完全一致包括空格、键顺序等SHA1计算前要确保字符串编码正确字节数组处理时要注意大端小端问题7. 实际应用与注意事项成功逆向出sign算法后可以用于开发第三方QQ音乐客户端或爬虫。但在实际使用中需要注意不要频繁请求避免被封IP这个算法可能会随着QQ音乐版本更新而变化需要定期验证仅用于学习和研究目的不要用于商业用途我在实际项目中使用这个算法时还添加了缓存机制对相同的请求参数缓存sign值避免重复计算。同时建议设置合理的请求间隔模拟正常用户行为。

更多文章