如何玩转中国电信「爱音乐」,记一次有趣的折腾过程,解密彩铃ID及相关参数

146次阅读

共计 9661 个字符,预计需要花费 25 分钟才能阅读完成。


起因

之前购买的一首彩铃,很喜欢,但众所周知,电信的系统就是那么难用,还经常改版开倒车,所以怎么都找不到了。

当然也不能说是找不到,可能是工作人员失误,能搜索到,能在列表中看到,但是参数错误,播放出来的彩铃并不匹配罢了。

我要找的一首彩铃叫:我崩溃了崩溃了(男人专用),列表在这:https://www.imusic.cn/#/singer/detail/2078n-23-15。

点击跳转后,我们可以看到,列表中有两首,而如果点击播放的话,两首都是女生版,是存在明显错误的。

折腾

第一直觉是研究歌曲 ID,看看每次点击播放,发送的是什么,返回的是什么,播放的是什么,应该能找到规律,找到突破口。

请求

如何玩转中国电信「爱音乐」,记一次有趣的折腾过程,解密彩铃 ID 及相关参数

如上图,每次点击,所有的 Network 都在这里,他们分别是什么呢?

两个 post 请求

这里的两个 post 请求,分别以 contentId 和 contentId 向 https://www.imusic.cn/content/getSongContent.html,发送请求,两个请求分别给与了不同的值,但返回的内容是一致的。

如何玩转中国电信「爱音乐」,记一次有趣的折腾过程,解密彩铃 ID 及相关参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[{songId: “54839”, newSongId: 36844, qqPrice: “0”, isVipFree: “1”,}]
0: {songId: “54839”, newSongId: 36844, qqPrice: “0”, isVipFree: “1”,}
collected: 0
crbtMdmcId: “810036104184”
cring: “imusic://QUFodHRwOi8vbXVzaWMuY3RtdXMuY24vYXVkaW8ucmVzLnYyL211c2ljLzEwNjEvbXAzLzAwLzEzLzUyLzEwNjEwMDEzNTIwNDA4MDAubXAzP3BhcmFtPVNUJmRldmljZWlkPTEwMDAwJnRpbWVzdGFtcD0xNjE2ODUzNDk0JnNpZ24xPTRhNjE2YTNlOTQ2NmM3OGQwYTE5ZmFmMzA1MjA4MDM4JnBvc2l0aW9uPTAmc2lnbjI9NWYzNmVhZTM1NmE0ZDE4ZWExOTNkYTQyODE2MGM3ZGEmY2M9NTI4MiZyZXNpZD0xMDYxMDAxMzUyWlo=”
feeMode: “0”
free: 0
haspay: 0
isNewSongId: 0
isVipFree: “1”
lyric: “[00:00.92]工作总是特别累    崩溃崩溃
↵[00:01.75]票子总是不够好    崩溃崩溃
↵[00:02.13]车子总是不够好    崩溃崩溃
↵[00:02.51]房子总是不够大    崩溃崩溃
↵[00:02.89]崩溃啊
↵[00:03.00]十年前我开开心心走路有风
↵[00:03.41]十年后我无金打睬若不惊风
↵[00:03.82]从前看到朋友找个地方喝酒
↵[00:04.24]如今见面点个头他就算招呼
↵[00:04.65]客户越来越多 朋友越来越少
↵[00:05.07]年龄越来越大 工作越来越忙
↵[00:05.48]如今手机上他不停的想
↵[00:05.82]有哪一个电话是来捞了家长
↵[00:06.24]工作总是特别累    崩溃崩溃
↵[00:06.62]票子总是不够好    崩溃崩溃
↵[00:07.00]车子总是不够好    崩溃崩溃
↵[00:07.38]房子总是不够大    崩溃崩溃
↵[00:07.76]崩溃啊
↵”
member: “NONE”
mp3: “imusic://QUFodHRwOi8vbXVzaWMuY3RtdXMuY24vYXVkaW8ucmVzLnY2L211c2ljLzEwNjEvbXAzLzAwLzEzLzUyLzEwNjEwMDEzNTIwMDA4MDAubXAzP3BhcmFtPVNUJmRldmljZWlkPTEwMDAwJnRpbWVzdGFtcD0xNjE2ODUzNDk0JnNpZ24xPTRiMjRkOWEwM2FmNzRiMGM5OWYxNGRkYmIyZWFlMWVmJnBvc2l0aW9uPTAmc2lnbjI9ZWYyZmI1N2M5NDlhMzc1ZmZlM2YxOGYyYzE3NWFhNzQmY2M9NTI4MiZyZXNpZD0xMDYxMDAxMzUyWlo=”
newSongId: 36844
orderStatu: 2
qqMdmcId: “106100135100”
qqPrice: “0”
resourceId: “1061001352”
singerName: “ 酷兔兔 ”
songId: “54839”
songImg: “//pic.ctmus.cn/pic.nets.v1/nets/upfile/singer/1/cb/3f05c3a4-5b9a-487d-ba2a-3a38a5af9e33.jpg?param=150y150”
songName: “ 我崩溃了崩溃了(男人专用)”

当然,我们也可以通过第三方工具,看看这个传递与返回。

postman

如何玩转中国电信「爱音乐」,记一次有趣的折腾过程,解密彩铃 ID 及相关参数

看了一下这首彩铃上下的 post 参数,并没有发现什么有价值有规律的事情,但直觉告诉我,可以通过遍历的形式,尝试前后 ID 是否能找到。

一个小型遍历 POST

于是我尝试按照页面的两种请求,尝试获取前后 ID 的歌曲信息。

PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public function post()
    {
        for ($x=36800; $x<=46800; $x++) {
        $post_data = array(
 
            ‘contentId’ => $x.‘n’
          
          );
 
          $url = ‘https://www.imusic.cn/content/getSongContent.html’;
        
        $postdata = http_build_query($post_data);
 
            $options = array(
 
                ‘http’ => array(
 
                ‘method’ => ‘POST’,
 
                ‘header’ => ‘Content-type:application/x-www-form-urlencoded’,
 
                ‘content’ => $postdata,
 
                ‘timeout’ => 15 * 60 // 超时时间(单位:s)
 
                )
 
            );
 
            $context = stream_context_create($options);
 
            $result = file_get_contents($url, false, $context);
            echo PHP_EOL;
            echo $result;
        }
    }

形式大概就是这样,很好理解,就是不断的更新 ID,不断的 post 并且 echo。

这样的效率不会很高,1 秒钟大概能 post100 个地址。

但是主要是方便,我要查询的量不是很大,并不是要把整个 爱音乐“爬”下来。

如果大的话,自然用别的方法比较好。

我前后遍历了几万条数据,很遗憾,我并没有找到有用的信息。

音乐是怎么播放的

播放的音乐是怎么来的?刚开始不知道怎么也找不到两个很关键的参数,sign1 和 sign2,如果没有这两个参数,是没办法播放音乐的,请求会被直接拒绝。

那么这个参数是怎么来的呢?

难道是后端处理?但是前端也没有看到任何痕迹表明向后台请求了这个东西。

请求方法

查看播放器 JS 代码,https://www.imusic.cn/res/js/player/musicPlayer.js

可以看到在一开始就定义了请求接口:

1
var musicSingleUrl = ‘/content/getSongContent.html’, // 单曲接口

请求方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 根据歌曲 id 查找歌曲信息
$.ajax({
url: musicSingleUrl,
async: false,
type: ‘POST’,
data: {“contentId” : songId},
dataType: “json”,
success: function(data){
                            if(data && data.length==0){
                                base.alert(0,“ 无法试听!”);
                                return;
                            }
if(data){
songInfo.mp3 = data[0].mp3;
songInfo.cring = data[0].cring;
songInfo.songImg = data[0].songImg;
songInfo.lyric = data[0].lyric;
songInfo.collected = data[0].collected;
songInfo.free = data[0].free;
songInfo.feeMode = data[0].feeMode;
songInfo.haspay = data[0].haspay;
songInfo.crbtMdmcId = data[0].crbtMdmcId;
songInfo.newSongId = data[0].newSongId;
_this.playNow(songInfo, quanqu, songPriority);
 
}
},
error: function(){
songName.text(‘ 歌曲加载失败 ’);
setTimeout(function(){if(list_content.children().length > 1) playerMap.next();}, 2000);
}
});

对应的,从返回数据中取值,但是,在这里任然没有看到任何签名的操作。

反思

既然没有向后台请求,那么肯定是浏览器端进行的签名,再找找看是怎么对音乐进行签名的。

我注意到一个参数,中英文混写果然是国内开发者显著特点:

1
playerACR.src = playerUI.jiemi(data[0].cring);

播放器的播放地址,进行了解密,解密数据是返回数据的 cring 字段,再看看 cring 是什么内容,上文我们已经通过 post 查看过这个内容,他就是:

1
imusic://QUFodHRwOi8vbXVzaWMuY3RtdXMuY24vYXVkaW8ucmVzLnY2L211c2ljLzEwNjEvbXAzLzAwLzEzLzUyLzEwNjEwMDEzNTIwMDA4MDAubXAzP3BhcmFtPVNUJmRldmljZWlkPTEwMDAwJnRpbWVzdGFtcD0xNjE2ODUzNDk0JnNpZ24xPTRiMjRkOWEwM2FmNzRiMGM5OWYxNGRkYmIyZWFlMWVmJnBvc2l0aW9uPTAmc2lnbjI9ZWYyZmI1N2M5NDlhMzc1ZmZlM2YxOGYyYzE3NWFhNzQmY2M9NTI4MiZyZXNpZD0xMDYxMDAxMzUyWlo=

是不是咋一看很神奇,其实不然,这种加密方式防君子不防我这样的小人,直接在前端就能看到解密过程,当然,哪怕隐藏了解密过程,也很好破解。

前端 JS 中有这样一段代码:

1
2
3
4
5
6
7
jiemi:function(str) {
if (str.search(/^imusic/i)!=1) {
str=str.replace(“imusic://”,“”);
str=playerUI.base64decode(str).replace(/^AA|ZZ$/gi,“”);
return str
}  
}

翻译过来就,把 imusic:// 删掉,把 AA|ZZ 也删掉,然后通过 base64decode 的方式,对字符串解密。

就得到这样的地址:http://music.ctmus.cn/audio.res.v2/music/1061/mp3/00/13/52/1061001352040800.mp3?param=ST&deviceid=10000&timestamp=1616777942&sign1=b7c45a083c6bac69637ec0ba8a940384&position=0&sign2=d2a6d03edbd8409fec34740407af8f5d&cc=5282&resid=1061001352

至此,很明显,sign 并没有在前端完成,而且后台给定,所以,哪怕我知道 resid,也没有办法去获取资源。

好玩的小技巧

分页

在前面的分页列表中,我们能看到,每页的分页数据是 15,这个时候,如果我们改变一下 URL 的值,就能看到更多数据,更方便搜索。

把 15 改成 50 即可,通过尝试,发现这里最大值就是 50。

https://www.imusic.cn/#/singer/detail/2078n-23-50

播放自定义歌曲

如果想要播放自定义歌曲或订购指定彩铃,可以通过修改 DOM 对象实现。

1
<a href=“javascript:;” class=“audition” title=“ 试听铃声 ” songid=“2457672” datanewsongid=“1376400n” ptype=“1”></a>

songid=”2457672″ 改成自己知道的 ID,点一下播放或者订购,可以看到效果。

最后的推断

在前面的返回值中的,resourceId1061001352

上一首歌是 1061001353,而 1061001352 出现了两次,接着就是 1061001350。

而我们已经得知,解密后的音乐参数中,传递的一个重要值,就是 resourceId, 将其替换到链接中,可以看到是这样的:

http://music.ctmus.cn/audio.res.v2/music/1061/mp3/00/13/52/resourceId040800.mp3?param=ST&deviceid=10000&timestamp=1616777942&sign1=b7c45a083c6bac69637ec0ba8a940384&position=0&sign2=d2a6d03edbd8409fec34740407af8f5d&cc=5282&resid=resourceId

也就是,如果有缘的情况下,我能模拟出 sign1 和 sign2,然后通过 resourceId1061001351 应该就能拿到这首彩铃。

但是想想也没用,不光需要下载,我更多的是希望知道contentId,这样我直接就能在前台订购这首彩铃!

正文完
 0