1.目標
網址:https://y.qq.com/n/ryqq/toplist/26
我們知道了 sign= P(n.data)
,其中n.data
是明文的請求參數
2.webpack生成data加密參數
那么 L(n.data)
就是密文的請求參數
。返回一個Promise {<pending>}
,所以L(n.data)
是一個異步函數。
L(n.data).then(result => {console.log('結果是:', result);
}).catch(error => {console.error('發生錯誤:', error);
});
window.shark(0).cgiEncrypt(data).then(result => {console.log('結果是:', result);
}).catch(error => {console.error('發生錯誤:', error);
});
運行之后報錯
p[r[++h]] = p[r[++h]].call(p[r[++h]], p[r[++h]]);
TypeError: Cannot read properties of undefined (reading 'call')
因為請求參數是用了AES-GCM
加密,且使用了隨機iv
AES-GCM
是一種高級加密標準(AES)與伽羅瓦 / 計數器模式(GCM)結合的加密方式
在瀏覽器環境中,window.crypto
對象是 Web Crypto API 的入口,用于實現加密相關的功能。window.crypto.subtle
是 SubtleCrypto
接口的實例,它提供了更底層、更強大的加密功能。
SubtleCrypto
的所有方法均返回 Promise
,需通過 then/catch
或 async/await
處理異步結果(例如密鑰生成、加密解密等操作)。
所以我們只需要導入
window = globalThis;;
window.crypto = require('crypto');
就可以正常生成結果
3.逆向還原data加密參數
密鑰就是vTBfEND/dLbvVNq4NbXhzw==
這樣生成的結果長度為448,而網頁長度是464,少了16位,而這16位正是iv
AES-GCM
通常需要將 IV 和密文一起傳輸,接收方才能正確解密
這樣就沒有問題
4.響應數據解密
返回的數據是二進制
數據解密是用j.__cgiDecrypt
,當然也是AES-GCM
解密
搜JSON.parse(N(
可快速定位
5.繞過加密驗證
我們請求攜帶了"encoding": "ag-1"
,正是告訴QQ音樂服務器要采用某種加密方式
請求不要攜帶這個,同時data
參數保持明文傳輸
import requests
import jsonheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36","Accept": "application/octet-stream","accept-language": "zh-CN,zh;q=0.9","cache-control": "no-cache","content-type": "text/plain","origin": "https://y.qq.com","pragma": "no-cache","priority": "u=1, i","referer": "https://y.qq.com/","sec-ch-ua": "\"Chromium\";v=\"136\", \"Google Chrome\";v=\"136\", \"Not.A/Brand\";v=\"99\"","sec-ch-ua-mobile": "?0","sec-ch-ua-platform": "\"Windows\"","sec-fetch-dest": "empty","sec-fetch-mode": "cors","sec-fetch-site": "same-site"
}url = "https://u6.y.qq.com/cgi-bin/musics.fcg"
params = {"sign": "zzc308f0fefeuogbgecps0gpzosg6fnvxujyw0474ee6d"
}
data = {"comm": {"cv": 4747474,"ct": 24,"format": "json","inCharset": "utf-8","outCharset": "utf-8","notice": 0,"platform": "yqq.json","needNewCode": 1,"uin": 0,"g_tk_new_20200303": 5381,"g_tk": 5381},"req_1": {"module": "musicToplist.ToplistInfoServer","method": "GetDetail","param": {"topid": 27,"offset": 0,"num": 20,"period": "2025-05-29"}}
}
data = json.dumps(data, separators=(',', ':'))
response = requests.post(url, headers=headers, params=params, data=data)print(response)
print(response.text)
也就是說只需要分析sign
即可