1.目标
切换榜单出现请求,可以看到sign
和data
是加密的
2.逆向分析
搜索sign:
可以看到sign = P(n.data)
,而n.data
就是请求的加密data
参数
javascript
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-27"}}}'
3.webpack分析

这是Webpack
打包后的模块加载代码
在这里打上断点找加载器n
,然后刷新页面
可以看到加载器的name
是"f"
,数组m
里面390个模块
点击进入就是加载器
可以看到是以列表的方式存储模块的,
然后将获取sign
的模块,就是含有下面内容的模块,放进去
javascript
var P = G._getSecuritySign;
var L = j.__cgiEncrypt
, N = j.__cgiDecrypt;

G._getSecuritySign
- 获取sign
j.__cgiEncrypt
- 加密请求参数data
j.__cgiDecrypt
- 解密响应二进制数据
javascript
window = global;
!function(e) {
function r() {
for (var e, t = 0; t < d.length; t++) {
for (var r = d[t], a = !0, n = 1; n < r.length; n++) {
var c = r[n];
0 !== o[c] && (a = !1)
}
a && (d.splice(t--, 1),
e = f(f.s = r[0]))
}
return e
}
var a = {}
, n = {
21: 0
}
, o = {
21: 0
}
, d = [];
function f(t) {
if (a[t])
return a[t].exports;
var r = a[t] = {
i: t,
l: !1,
exports: {}
};
console.log(t)
return e[t].call(r.exports, r, r.exports, f),
r.l = !0,
r.exports
}
f.m = e,
f.c = a,
f.d = function(e, t, r) {
f.o(e, t) || Object.defineProperty(e, t, {
enumerable: !0,
get: r
})
}
,
f.r = function(e) {
"undefined" !== typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}),
Object.defineProperty(e, "__esModule", {
value: !0
})
}
,
f.t = function(e, t) {
if (1 & t && (e = f(e)),
8 & t)
return e;
if (4 & t && "object" === typeof e && e && e.__esModule)
return e;
var r = Object.create(null);
if (f.r(r),
Object.defineProperty(r, "default", {
enumerable: !0,
value: e
}),
2 & t && "string" != typeof e)
for (var a in e)
f.d(r, a, function(t) {
return e[t]
}
.bind(null, a));
return r
}
,
f.o = function(e, t) {
return Object.prototype.hasOwnProperty.call(e, t)
}
r()
window.shark = f;
}([]);
console.log(window.shark);
先删除一些无用的代码,然后将模块放进去
如果这么运行的话,毫无疑问是会报错的
javascript
return e[t].call(r.exports, r, r.exports, f),
^
TypeError: Cannot read properties of undefined (reading 'call')
很明显缺少的是下标为81
的模块,然后我们去浏览器取该模块
然后这里也不是导入81
模块,在这里我们是导入自己的下标为1
的模块
然后接下来就是导出全局函数了
打印方法没有问题
4.sign验证
javascript
get_sign = (data) => window.shark(0).getSign(data);
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-28"}}}'
console.log(get_sign(data))
写个箭头函数验证能否生成sign
运行代码可以生成sign
但是和浏览器的sign
不一样,而且data是一样的,这就是缺少必要的环境
javascript
window = global;
document = {
cookie: 'pgv_pvid=592785550; fqm_pvqid=75e53579-6875-45e3-9bfa-8c3634fd8b23; fqm_sessionid=4742d993-b7c2-4148-b070-67c2ac322bc7; pgv_info=ssid=s6945372512; ts_last=y.qq.com/n/ryqq/toplist/26; ts_refer=cn.bing.com/; ts_uid=4872983500',
createElement: function(res){
if(res == 'a') return {}
},
}
navigator = {
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
}
location = {
"href": "https://y.qq.com/",
"host": "y.qq.com",
}

补充环境之后发现和浏览器的一致
sign
算法逆向参见:https://blog.csdn.net/2406_83321119/article/details/146435985