Python爬虫逆向分析某云音乐加密参数的实例分析

(编辑:jimmy 日期: 2024/12/29 浏览:2)

本文转自:https://blog.csdn.net/qq_42730750/article/details/108415551

前言

Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析
"text-align: left">"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

Python爬虫逆向分析某云音乐加密参数的实例分析

1. 请求分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"htmlcode">

var bVZ8R = window.asrsea(JSON.stringify(i0x), bqN0x(["流泪", "强"]), bqN0x(Wx5C.md), bqN0x(["爱心", "女孩", "惊恐", "大笑"]));
e0x.data = j0x.cs1x({
 params: bVZ8R.encText,
 encSecKey: bVZ8R.encSecKey
})

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"htmlcode">

>JSON.stringify(i0x)
<"{"csrf_token":""}"
>bqN0x(["流泪", "强"])
<"010001"
>bqN0x(Wx5C.md)
<"00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
>bqN0x(["爱心", "女孩", "惊恐", "大笑"])
<"0CoJUm6Qyw8W8jud"

"{"csrf_token":""}"、"010001""00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7""0CoJUm6Qyw8W8jud",如果没有猜错的话第三个参数是十六进制的形式,其实也就是如此。通过几次刷新,这几个值不变。

3. 加密分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"htmlcode">

d = "{\"csrf_token\":\"\"}"
	e = "010001"
	f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
	g = "0CoJUm6Qyw8W8jud"

"htmlcode">

 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
 }

"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"中随机生成长度为a的字符串。

 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()
 }

"htmlcode">

function c(a, b, c) {
  var d, e;
  return setMaxDigits(131),
  d = new RSAKeyPair(b,"",c),
  e = encryptedString(d, a)
 }

"htmlcode">

 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
 }

"htmlcode">

class EncryptText:
 def __init__(self):
  self.character = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
  self.iv = '0102030405060708'
  self.public_key = '010001'
  self.modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b'       '5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417'       '629ec4ee341f56135fccf695280104e0312ecbda92557c93'       '870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b'       '424d813cfe4875d3e82047b97ddef52741d546b8e289dc69'       '35b3ece0462db0a22b8e7'
  self.nonce = '0CoJUm6Qyw8W8jud'

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"mEXyqHtNW5dxT5IK"。
"htmlcode">

def create16RandomBytes(self):
  """
  # 产生16位随机字符, 对应函数a
  :return:
  """
  generated_string = get_random_bytes(16)
  return generated_string

"htmlcode">

 def create16RandomBytes(self):
  """
  # 产生16位随机字符, 对应函数a
  :return:
  """
  generate_string = random.sample(self.character, 16)
  generated_string = ''.join(generate_string)
  return generated_string

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析"text-align: left">程序执行到函数b处,传入的参数dg的值我们已经知道,看一下加密后的结果:

Python爬虫逆向分析某云音乐加密参数的实例分析

"eHhjXckqrtZkqcwCalCMx0QuU6Lj9L7Wxouw1iMCnB4=",下面来用官方的API来模拟一下:

 def AESEncrypt(self, clear_text, key):
  """
  AES加密, 对应函数b
  :param clear_text: 需要加密的数据
  :return:
  """
  # 数据填充
  clear_text = pad(data_to_pad=clear_text.encode(), block_size=AES.block_size)
  key = key.encode()
  iv = self.iv.encode()
  aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
  cipher_text = aes.encrypt(plaintext=clear_text)
  # 字节串转为字符串
  cipher_texts = base64.b64encode(cipher_text).decode()
  return cipher_texts

"{"csrf_token":""}"传入到该函数中,看一下模拟的结果:

Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"JWuA4mdNsTdrLdDkD9UWs8ShPCZNK0n4BLpdQEDSAaD/kFKKih8XQp8W/mICYPlN",然后对比一下自己模拟的结果:

Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"d58e873a2e908c0599b497456f1842d1734e1d17e834a221ed84d828b06b149d0bac2ddd449e38b7e5e9ce53dcb1aa43a241742a2b273434b67825743fbca6371aa143a4460477704ba3fd33b517619386daf8da4c7fe8d67a604ea0e461aedee5ae2698400a6c7340ab250c97622aa221d871b7352d81ea09262978facf5480"
"htmlcode">

 def RSAEncrypt(self, session_key):
  """
  RSA加密的结果每次都不一样
  :param session_key:
  :return:
  """
  # n和e构成公钥
  # (n, e)
  # key = RSA.RsaKey(n=int(self.modulus, 16), e=int(self.public_key, 16))
  key = RSA.construct(rsa_components=(int(self.modulus, 16), int(self.public_key, 16)))
  public_key = key.publickey()
  rsa = PKCS1_OAEP.new(key=public_key)
  cipher_text = rsa.encrypt(message=session_key).hex()
  return cipher_text

Python爬虫逆向分析某云音乐加密参数的实例分析

"htmlcode">

 def RSAEncrypt(self, i, e, n):
  """
  RSA加密, 对应函数c
  :param i:
  :return:
  """
  # num = pow(x, y) % z
  # 加密C=M^e mod n
  num = pow(int(i[::-1].encode().hex(), 16), int(e, 16), int(n, 16))
  result = format(num, 'x')
  return result

Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"{"ids":"[35440198]","level":"standard","encodeType":"aac","csrf_token":""}",最后我们看一下最终的结果:

Python爬虫逆向分析某云音乐加密参数的实例分析

Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析"text-align: left">歌曲的文件对应的 u r l url url 我们已经找到,根据结果可知,它是一个字符串,准确来说是个json格式的,而且里面只有一条数据是我们需要的,所以直接提取:

Python爬虫逆向分析某云音乐加密参数的实例分析"text-align: left">然后再去用代码请求该 u r l url url,将请求到的内容以二进制形式进行保存,文件名后缀为.mp3

5. 获取ID

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"{"hlpretag":"<span class=\"s-fc7\">","hlposttag":"</span>","s":"本兮","type":"1","offset":"0","total":"true","limit":"30","csrf_token":""}"

Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析

"text-align: center">Python爬虫逆向分析某云音乐加密参数的实例分析"text-align: left">这里简单分析一下参数d,关键字s表示你要搜索的内容,关键字type表示搜索的类型(见下面的表格),如果需要下载其他歌手的歌曲,只需要将参数d中的关键字s的值改一下即可,为了方便,可以用input()方法传递这个值。

type 含义 1 单曲 100 歌手 10 专辑 1014 视频 1006 歌词 1000 歌单 1009 主播电台 1002 用户

6. 代码框架

# -*- coding: utf-8 -*-
# @Time : 2020/9/2 11:23
# @Author : XiaYouRan
# @Email : youran.xia@foxmail.com
# @File : wangyiyun_music2.py
# @Software: PyCharm

import requests
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Util.Padding import pad
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
import random
import base64
import json
import os


class EncryptText:
 def __init__(self):
  self.character = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
  self.iv = '0102030405060708'
  self.public_key = '010001'
  self.modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b'       '5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417'       '629ec4ee341f56135fccf695280104e0312ecbda92557c93'       '870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b'       '424d813cfe4875d3e82047b97ddef52741d546b8e289dc69'       '35b3ece0462db0a22b8e7'
  self.nonce = '0CoJUm6Qyw8W8jud'

 def create16RandomBytes(self):


 def AESEncrypt(self, clear_text, key):


 def RSAEncrypt(self, i, e, n):


 def resultEncrypt(self, input_text):
  """
  对应函数d
  :param input_text:
  :return:
  """
  i = self.create16RandomBytes()
  encText = self.AESEncrypt(input_text, self.nonce)
  encText = self.AESEncrypt(encText, i)
  encSecKey = self.RSAEncrypt(i, self.public_key, self.modulus)
  from_data = {
   'params': encText,
   'encSecKey': encSecKey
  }
  return from_data


class WangYiYunMusic(object):
 def __init__(self):
  self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
          'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}

 def get_html(self, url, method='GET', from_data=None):
  try:
   if method == 'GET':
    response = requests.get(url, headers=self.headers)
   else:
    response = requests.post(url, from_data, headers=self.headers)
   response.raise_for_status()
   response.encoding = 'utf-8'
   return response.text
  except Exception as err:
   print(err)
   return '请求异常'

 def parse_text(self, text):
  ids_list = json.loads(text)['result']['songs']
  count = 0
  info_list = []
  print('{:*^80}'.format('搜索结果如下'))
  print('{0:{5}<5}{1:{5}<20}{2:{5}<10}{3:{5}<10}{4:{5}<20}'.format('序号', '歌名', '歌手', '时长(s)', '专辑', chr(12288)))
  print('{:-^84}'.format('-'))
  for id_info in ids_list:
   song_name = id_info['name']
   id = id_info['id']
   time = id_info['dt'] // 1000
   album_name = id_info['al']['name']
   picture_url = id_info['al']['picUrl']
   singer = id_info['ar'][0]['name']
   info_list.append([id, song_name, singer])
   print('{0:{5}<5}{1:{5}<20}{2:{5}<10}{3:{5}<10}{4:{5}<20}'.format(count, song_name, singer, time, album_name, chr(12288)))
   count += 1
   if count == 8:
    # 为了测试方便, 这里只显示了9条数据
    break
  print('{:*^80}'.format('*'))
  return info_list

 def save_file(self, song_text, download_info):
  filepath = './download'
  if not os.path.exists(filepath):
   os.mkdir(filepath)
  filename = download_info[1] + '-' + download_info[2]
  music_url = json.loads(song_text)['data'][0]['url']
  response = requests.get(music_url, headers=self.headers)
  with open(os.path.join(filepath, filename) + '.mp3', 'wb') as f:
   f.write(response.content)
   print("下载完毕!")


if __name__ == '__main__':
 id_url = 'https://music.163.com/weapi/cloudsearch/get/web"hlpretag": "<span class=\"s-fc7\">",
  "hlposttag": "</span>",
  "s": input("请输入歌名或歌手: "),
  "type": "1",
  "offset": "0",
  "total": "true",
  "limit": "30",
  "csrf_token": ""
 }

 encrypt = EncryptText()
 id_from_data = encrypt.resultEncrypt(str(id_d))

 wyy = WangYiYunMusic()
 id_text = wyy.get_html(id_url, method='POST', from_data=id_from_data)
 info_list = wyy.parse_text(id_text)

 while True:
  input_index = eval(input("请输入要下载歌曲的序号(-1退出): "))
  if input_index == -1:
   break
  download_info = info_list[input_index]
  song_d = {
   "ids": str([download_info[0]]),
   "level": "standard",
   "encodeType": "aac",
   "csrf_token": ""
  }
  song_from_data = encrypt.resultEncrypt(str(song_d))

  song_text = wyy.get_html(song_url, method='POST', from_data=song_from_data)
  wyy.save_file(song_text, download_info)

"在这里插入图片描述" src="/UploadFiles/2021-04-08/2020120410130464.png">
Python爬虫逆向分析某云音乐加密参数的实例分析

结束语

",“hlposttag”:"",“s”:"你要搜索的信息",“type”:"1",“offset”:“0”,“total”:“true”,“limit”:“30”,“csrf_token”:""}" https://music.xxx.com/weapi/cloudsearch/get/web",“level”:"standard",“encodeType”:“aac”,“csrf_token”:""}" https://music.xxx.com/weapi/song/enhance/player/url/v1",“lv”:-1,“tv”:-1,“csrf_token”:""}" https://music.xxx.com/weapi/song/lyric",“offset”:“0”,“orderType”:“1”,“csrf_token”:""}" https://music.xxx.com/weapi/comment/resource/comments/get"external nofollow" target="_blank" href="https://github.com/xiayouran/Musicer">GitHub仓库点个Star哦!ヾ(≧∇≦*)ヾ

一句话新闻

Windows上运行安卓你用过了吗
在去年的5月23日,借助Intel Bridge Technology以及Intel Celadon两项技术的驱动,Intel为PC用户带来了Android On Windows(AOW)平台,并携手国内软件公司腾讯共同推出了腾讯应用宝电脑版,将Windows与安卓两大生态进行了融合,PC的使用体验随即被带入到了一个全新的阶段。