网易云音乐在线播放接口解析(两种方法运行扣出来的js)
网易云音乐在线播放接口解析(两种方法运行扣出来的js)
目标接口:https://music.163.com/weapi/song/enhance/player/url/v1
请求该接口需要携带两个参数encparam,sencSecKey才会返回歌曲的真实地址,加密方法采用AES和RSA加密,之前看到过一篇文章是把加密过程完全逆向成python代码,并且利用漏洞跳过了RSA加密
但这篇文章就用一个不需要太透彻分析的方法,扣取网易云音乐生成encparam,sencSecKey部分的js代码
需要node.js环境和crypto-js模块和express框架
加密过程的核心JavaScript代码(163.js文件)
/* 引入crypto-js 用于aes加密 */ var CryptoJS = require('crypto-js'); function RSAKeyPair(a, b, c) { this.e = biFromHex(a), this.d = biFromHex(b), this.m = biFromHex(c), this.chunkSize = 2 * biHighIndex(this.m), this.radix = 16, this.barrett = new BarrettMu(this.m) } // 。。。。此处省略几百行(为RSA加密过程)需要扣取 /* 核心加密过程从此处开始 */ !function() { function a(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 } function b(a, b) { // 函数b AES 加密 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 //CBC工作模式 }); return f.toString() } function c(a, b, c) { // RSA加密 var d, e; return setMaxDigits(131), d = new RSAKeyPair(b,"",c), e = encryptedString(d, a) } function d(d, e, f, g) { // 核心加密函数 var h = {} , i = a(16); return h.encText = b(d, g),//"0CoJUm6Qyw8W8jud" 为密钥的AES 加密 歌曲的id等信息 h.encText = b(h.encText, i),//函数a 产生的16位字符为密钥的AES 二次加密 歌曲的id等信息 h.encSecKey = c(i, e, f),//ras 加密a 产生的16位字符(即二次AES加密的密钥) h//return 后逗号隔开顺序执行,最后只返回最后一个逗号后内容 } function e(a, b, d, e) { var f = {}; return f.encText = c(a + e, b, d), f } asrsea = d, ecnonasr = e }(); function get_params(ids) { var params = `{"ids":"${ids}","level":"standard","encodeType":"aac","csrf_token":""}","csrf_token":""}`; var result = asrsea(params, "010001", "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7", "0CoJUm6Qyw8W8jud"); return result; } // 导出get_params方便server.js使用 module.exports = { get_params } // var ids = "[1357850926,492144016,415090367]"; // var result = get_params(ids); // console.log(result); /* 请求接口https://music.163.com/weapi/song/enhance/player/url/v1 */
server.js部分代码
在本地3000端口开启一个API 响应歌曲ids返回加密后的encparam,sencSecKey
// 作者@夜幕团队 const express = require('express'); const app = express(); const encparams = require('./163'); var bodyParser = require('body-parser'); app.use(bodyParser()); app.post('/encrpt',function(req,res){ var request = req.body; console.log('收到客户端消息',request); var result = encparams.get_params(request['ids']); console.log('返回加密后的params',JSON.stringify(result)); res.send(JSON.stringify(result)); }) app.listen(3000,()=>{ console.log('开启服务,端口3000'); })
主文件163music.py
import execjs import requests class Music163: def __init__(self): self.headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' } self.nodejs_url = 'http://127.0.0.1:3000/encrpt' self.post_url = 'https://music.163.com/weapi/song/enhance/player/url/v1' def get_params(self,ids): """ execjs 执行js代码返回加密后的params 即'encText', 'encSecKey'""" with open('163.js','r',encoding='utf-8') as f: jstext = f.read() ctx = execjs.compile(jstext) params = ctx.call('get_params',ids) return params def get_from_node_server(self,ids): """ 从运行在本地的 HTTP API 获取加密后的params 通过node.js的express框架实现 """ data = { 'ids':ids } response = requests.post(self.nodejs_url,data=data) if response.status_code==200: return response.json() def get_src(self,params): data = { 'params':params['encText'], 'encSecKey':params['encSecKey'] } response = requests.post(self.post_url,data=data,headers=self.headers) if response.status_code ==200: return response.json()['data'] def run(self): # 传入一个或多个歌曲的id 打印歌曲的真实地址,传入多个id时返回的歌曲顺序可能打乱 ids = [108485,1357850926,492144016,415090367] # 用excejs 加密 # params = self.get_params(str(ids)) # 请求本地API 加密 需要先开启服务 node server.js params = self.get_from_node_server(str(ids)) srcs = self.get_src(params) for src in srcs: print('id:',src['id'],'url:',src['url']) if __name__ == "__main__": m = Music163() m.run()
execjs效果
HTTP API (node.js + express)效果
注意事项:需要node.js环境
如果可以完全逆向成python代码肯定最高效,无法逆向的,execjs,HTTP API 这种方法应该也还行
本文最后更新于2020年1月26日,若涉及的内容可能已经失效,直接留言反馈补链即可,我们会处理,谢谢