某音乐爬热评签名计算
同文地址: https://wiki.shikangsi.com/post/3846/
微信文章: https://mp.weixin.qq.com/s/L7fYw8k-Lx8ZT7mApPzQ
本文将从 0 开始教你怎么解决某音乐的签名问题,实现爬取热评的功能,我们的目标是搞明白 params 和 encSecKey 的生成过程。(文中没有插入广告,请放心阅读)
首先搜索 encSecKey。

可以看到这个参数在 core 文件中,然后我们转到 Sources

直接搜索,有三个结果,第二和第三处可以看到这两个参数的取值,我们先定位第一处。

由上图可知,params 由 b 方法得来,encSecKey 由 c 方法得来,可以直接在这里下断点,也可以直接向上找,就在上面就有。

a、b、c、d 方法都在上下文中。
function b(a, b) {
var c = CryptoJS.enc.Utf8.parse(b)
, d = CryptoJS.enc.Utf8.parse("0102030405060708")
, e = CryptoJS.enc.Utf8.parse(a)
, f = CryptoJS.AES.encrypt(e, c, {
iv: d,
mode: CryptoJS.mode.CBC
});
return f.toString()
}
function c(a, b, c) {
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b,"",c),
e = encryptedString(d, a)
}
先抠出 b、c 方法,其实这里很清楚了,b 是 AES,c 是 RSA,然后我们下断点来看入参从哪来的。
function d(d, e, f, g) {
var h = {}
, i = a(16);
return h.encText = b(d, g),
h.encText = b(h.encText, i),
h.encSecKey = c(i, e, f),
h
}
首先我们看一下 params,这个就是 encText 变量,这里可以看到,其实很简单,就是调了 b 方法即 AES,入参两个,一个明文一个密钥,我们在下面下断点来调试。

这里放一下入参
d:{"rid":"R_SO_4_2102785224","threadId":"R_SO_4_2102785224","pageNo":"2","pageSize":"20","cursor":"1703117062380","offset":"0","orderType":"1","csrf_token":"9ad1ccb7e4ac0d59178520cd842b951d"}
e:010001
f:00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7
g:0CoJUm6Qyw8W8jud
上面是 d 方法的入参,可以看到 d 实际是就是明文,e 是 RSA 的公钥指数 e,是公钥,g 是 AES 的密钥。
这里可以看到 encText 进行了两次 AES,第一次用的 key 是 g,然后第二次是调用 a 方法。
function a(a) {
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
for (d = 0; a > d; d += 1)
e = Math.random() * b.length,
e = Math.floor(e),
c += b.charAt(e);
return c
}
由上文可知,a 方法就是随机数,入参就是长度,这里的 AES 是调用了 a 方法获取 16 位随机数,然后用这个随机数把 g 作为密钥加密后的密文进行二次加密。
我们来验证一下

先把明文加密,这里的 vi 在上面的 b 方法中有,因为断点处已经调用了两次 b 方法,根据流程,我们用生成的随机数:xaCvZqDUWfbkAK0y(上图有)再把密文进行加密。

可以看到结果跟上面的断点处是一样的:VQUaeNYAiiO2v......
为了节省篇幅,这里的 g 参数就不赘述了,这个参数是不变的,一直是:0CoJUm6Qyw8W8jud,读者可以自行操作,会发现这个值不会变化。
那么这里我们已经解决了 params 参数,下面看 encSecKey 的生成过程。
根据上文已经知道 encSecKey 是调用的 c 方法,c(i,e,f)

i 就是 16 位随机数,然后 e 是指数,f 是公钥,所以我们只需要对这个随机数进行 RSA 加密,得到的密文就是 encSecKey。
下面我们尝试一下

这里我引用了 js 实现 RSA 的库,对随机数进行加密,然后我们放开断点看看我们算的和网站的是否一致。
正文长度超出限制,一楼接上
下面是我们算的
看看网站请求的
可以看到是一样的,我们可以尝试重发一下请求。
成功获得数据。
既然是从 0 开始,那还要解决 d 参数的问题
这里面最主要的是 rid、threadId、cursor,这里前两个是一样的,而第三个实际是一样就能看出来是时间戳。
那么我们看看 rid 怎么来的。
很明显 rid 后面的数字就是 songId,那么我们一样搜索 R_S0_4_
其实还是在 core 文件里面,这里已经不需要再继续看了,其实已经定义了歌曲的前缀就是固定的。
上图是最终的效果,中间还有实现的过程,这个下次有空再说吧。
推荐阅读:QQ 音乐 Sign 签名算法的 VMP 分析
https://wiki.shikangsi.com/post/3753/