某音乐爬热评签名计算

3 条回复
28 次浏览

同文地址: https://wiki.shikangsi.com/post/3846/
微信文章: https://mp.weixin.qq.com/s/L7fYw8k-Lx8ZT7mApPzQ

本文将从 0 开始教你怎么解决某音乐的签名问题,实现爬取热评的功能,我们的目标是搞明白 params 和 encSecKey 的生成过程。(文中没有插入广告,请放心阅读)

首先搜索 encSecKey。

null

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

null

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

null

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

null

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,入参两个,一个明文一个密钥,我们在下面下断点来调试。

null

这里放一下入参

复制
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 作为密钥加密后的密文进行二次加密。

我们来验证一下

null

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

null

可以看到结果跟上面的断点处是一样的:VQUaeNYAiiO2v......

为了节省篇幅,这里的 g 参数就不赘述了,这个参数是不变的,一直是:0CoJUm6Qyw8W8jud,读者可以自行操作,会发现这个值不会变化。

那么这里我们已经解决了 params 参数,下面看 encSecKey 的生成过程。

根据上文已经知道 encSecKey 是调用的 c 方法,c(i,e,f)

null

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

下面我们尝试一下

null

这里我引用了 js 实现 RSA 的库,对随机数进行加密,然后我们放开断点看看我们算的和网站的是否一致。

种子用户
OP

正文长度超出限制,一楼接上

下面是我们算的

复制
params:VQUaeNYAiiO2vBViJWoEA0DB61QPUagi1X+1jKmKGj8c51JMIP6QOzNoQuYyEBzF7n3D7y1pKscTrtC+I/XBJSyzUk4GtwqDvK/+GtBI8tSHMdvusxZldr0AYDoQa0OSVg2Z3RiGYq1BB1QYwC5w92euP0X+/GC/GzpswedjhcN2J2X7wh0eET7ZpBZqxuhDFFKVdfrsnnU+AgriW8oksegaHxVnXGSmAiTWn2qACQSK1CCZG7IfCc/z5JObFFqf2QZ96PdFkOhZrwSn5NiQjV2plHdCfXlJf67ocnohv/VLCzeIBtueO4jgGIOLkBWSLk0pUJCWBrXzPoaRb25jjj60IQ59KQs/OX/+n6dgS/U=
encSecKey:1601e9c737ce7b7d65ee42c1e391cb162a030c5abe5306bf1e52e35c10ea88663bb5839571a3b79b212ffbdc583f5381ccdbd1d384ad25ff0289651aa925e319fdaa892743c360f560eb9b1282b3bc2ca209f8006f0b62e911fc0ab8b8e838329360e661e4d4f8d3b1c2ac11c9ca44ff2cee50f054eb44a7a43b1714fb625a9c

看看网站请求的

null

可以看到是一样的,我们可以尝试重发一下请求。

null

成功获得数据。

既然是从 0 开始,那还要解决 d 参数的问题

复制
{"rid":"R_SO_4_2102785224","threadId":"R_SO_4_2102785224","pageNo":"2","pageSize":"20","cursor":"1703117062380","offset":"0","orderType":"1","csrf_token":"9ad1ccb7e4ac0d59178520cd842b951d"}

这里面最主要的是 rid、threadId、cursor,这里前两个是一样的,而第三个实际是一样就能看出来是时间戳。

那么我们看看 rid 怎么来的。

复制
网址:https://music.***.com/#/song?id=2102785224
rid:R_SO_4_2102785224

很明显 rid 后面的数字就是 songId,那么我们一样搜索 R_S0_4_

null

其实还是在 core 文件里面,这里已经不需要再继续看了,其实已经定义了歌曲的前缀就是固定的。

null

上图是最终的效果,中间还有实现的过程,这个下次有空再说吧。

推荐阅读:QQ 音乐 Sign 签名算法的 VMP 分析

https://wiki.shikangsi.com/post/3753/

种子用户
OP

信息安全,什么都搞一下,渗透测试、编程开发这些。

发表一个评论

R保持