本文转自: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哦!ヾ(≧∇≦*)ヾ

华山资源网 Design By www.eoogi.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
华山资源网 Design By www.eoogi.com

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?