JS逆向案例之网易云音乐逆向
JS逆向案例之网易云音乐逆向
网址:
网易云音乐真离谱哇,一直扣扣扣
在参考了好几个大神,以及自己多次犯错误之后,终于是完成了网易云音乐两个加密参数的逆向。
好耶 ヾ(✿゚▽゚)ノ
***用到的知识点:
(1)requests模块和session模块,发起请求
- 什么是session对象?
- 该对象和requests模块用法几乎一致.
- 对于在请求过程中产生了cookie的请求
- 如果该请求是使用session发起的,则cookie会被自动存储到session中.
session = requests.Session()
(2)headers头部伪装,随机UA伪装
# UA伪装之随机headers模块
from fake_useragent import UserAgent
headers = {'User-Agent': UserAgent().random,} # 这里的random方法不需要random模块支持
(3)execjs的使用
# 在cmd中调起外部程序, 阻塞的方式
os.system(command="python test.py")
# 在cmd中调起外部程序, 非阻塞的方式
import subprocess
process = subprocess.Popen(command="python test.py", stderr=subprocess.PIPE)
# 终止进程
# process.kill()
# communicate: 当前线程阻塞,直到子进程执行结束
stdout, stderr = process.communicate(timeout=172800)
# 简单理解就是为了防止 execjs 执行代码时报错
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')
# 导入Python中执行 js 代码的模块
import execjs
# 打开JS 代码文件
# 注意这里可能会报一个错误:文中出现了连‘gb18030’也无法编码的字符,可以使用‘ignore’属性进行忽略
# UnicodeDecodeError: 'gbk' codec can't decode byte 0xbc in position 405: illegal multibyte sequence
with open("js文件路径", encoding='gb18030', errors="ignore") as f:
# 将JS 代码读出来
jsCode = f.read()
# 将读出来的JS代码交给 execjs 进行编译
JS_sign_t = execjs.compile(jsCode)
# call() 运行代码中的xxx函数. 后续的参数是xxx的参数 # 后面的参数可留空
result = JS_sign_t.call("需要调用的函数名")
(4)json模块,序列化与反序列化
# 在Python中将文本数据类型转换为字典类型
dataDict = json.loads(decrypt_data)
(5)逆向改写之引入外部包
- 我们在逆向补写 JS 代码时,时常会遇到需要外部包的情况,在Python里面我们可以直接 import 但是在 JS 里面是这样引入外部包的
// const 自己定义的变量名 = require('需要导入的包名');
// 导入crypto 加密算法的包
const CryptoJS = require('crypto-js');
(6)开发者模式中 启动器 的使用了解

【一】抓包分析
- 本次逆向的网站是网易云音乐的歌曲的下载
- 这里拿一首歌曲做例子

- 打开开发者工具进行抓包

- 我们对抓到的包进行逐个分析,
- 发现在
v1?csrf_token=这个包的响应数据中存放着我们想要找的数据,即歌曲的播放链接

- 我们将这个链接复制到浏览器打开,发现其可以正常播放
- 接着分析这个包的请求参数及请求类型

- 我们可以发现,他的请求方式为post请求
- post请求一般都会携带请求参数,我们再观察其请求参数

- 我们发现是携带了两个参数
**params****encSecKey** - 那我们的目的就很明确了,就是将这两个参数加密的方式找到,并通过JS逆向生成
- 从而再发送post请求,进行获取数据
【二】加密参数的逆向思路
关于这个参数的逆向思路一共提供以下几种方案
【方案一】常规思路
- 通过搜索关键字,从而定位加密函数
- 我才用的关键字是
v1?csrf_token= - 既然这个数据是通过这个请求拿到的,那么拿数据的过程中是一定会向这个请求发送请求
- 我们将其添加到断点,只要请求过程中,经过这个参数就一定会被断掉

- 再次刷新发送请求,我们可以明显的看到,被断住了,说明我们的思路目前是正确的
- 我们在控制台,打印这个参数,进行观察

-
发现其数据是
"params=sJ8J3yBkeku7KZRInEOYTOtqjw31KTFr9Hfuces6DH1gceUdlEUhyLB%2FzbKwtNBSboTn579%2B5P%2BUK%2B8ZLlcMPznfLRcW1kw1Tf6DcCkJEvgC8sBGw8W%2BQC82oay81uuSyPdD1To%2BZ7w%2Bpf%2FrBdEwHA%3D%3D&encSecKey=47f3fb73242e1a3a7e2c8f2e4aa1b756c55eae2dcd6092001b75ce1a9985a1043b33b7811a5c70458d180ba1b36d46b5a1dddd9a81978e79153a2ab2c49f73bfe81e8f670b17767a7f44c64f22eda1407f9c4dde5075632ef919056399c03162ea41800b7fd3cc7213b664b51455befd370a3be00d203f5d886d51d52fadebb9" -
仔细观察我们发现,其携带的正是我们需要的两个加密参数
-
那既然这里的数据是已经加密过的,那我们只需要,再向前找到该数据加密的位置即可

- 我们再次向前一个调用函数发现这里依然是加密的参数
- 逐层向上寻找查看

-
在到达这个调用函数时,我们细心的查看其代码
b2x.bzu7n = function() { this.Bq1x(); u2x.be2x("/api/song/enhance/player/url/v1", { type: "json", query: { ids: JSON.stringify([this.cx3x.id]), level: DEFAULT_LEVEL, encodeType: DEFAULT_ENCODETYPE }, onload: this.bVS9J.f2x(this), onerror: this.bVS9J.f2x(this) }) } -
在这个函数中,我们可以发现,它存在一个
stringify方法 -
我们经验知道,一般遇到这个方法都会进行一次加密相关的操作

- 我们回到这个函数,通过观察上面的数据加载情况,可以看到我们传进来的数据一步步正在被加密

-
我们细心地观察这行代码时最明显的
var bMs8k = window.asrsea(JSON.stringify(i2x), bsi5n(["流泪", "强"]), bsi5n(Vx0x.md), bsi5n(["爱心", "女孩", "惊恐", "大笑"])); -
在这行代码之前都是一个params,但是在这行代码结束后就生成了我们需要的两个参数,那我们的思路就很明确了
【方案二】从启动器进入到函数的调用地方

- 开发者工具中有一个参数叫启动器
- 我们进入到启动器就会看到这一堆数据,我们分析点进去就知道这正是,生成该数据的一个个函数
【二】加密参数的逆向
- 这行代码就是关键,弄懂这行代码,我们的工作就完成了一大半
- 我们分析这行代码,发现其一共有四个参数
JSON.stringify(i2x)
bsi5n(["流泪", "强"])
bsi5n(Vx0x.md)
bsi5n(["爱心", "女孩", "惊恐", "大笑"])
-
我们通过不断调试,发现出第一个参数外,其他三个都是定值
-
那我们需要明白这第一个参数到底是什么

- 我们通过控制台不断的进行反复刷新调试,最终知道了他的数据格式是这样的
'{"ids":"[2047756673]","level":"standard","encodeType":"aac","csrf_token":""}'
-
这个结构已经很明显了,其中的参数正是我们的歌曲ID
-
其他参数是定值
bsi5n(Vx0x.md):00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7
bsi5n(["流泪", "强"]):'010001'
bsi5n(["爱心", "女孩", "惊恐", "大笑"]):'0CoJUm6Qyw8W8jud'
-
那参数我们都已经知道了
-
接下来就是找到加密函数进行逆向破解
-
我们进入到加密函数中

- 这里进入到了这个
asrsea方法中

-
我们在这里打断点,观察数据变化情况
-
其实我们从这个函数中也可以很明显的发现,他最后的两个方法正在获取我们加密过的参数
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 }

-
我们通过打断点,观察函数情况,也很明显的看到了这个加密的参数的生成过程
-
我们将这行代码扣出来放到JS文件中并且给她刚才我们已经知道的所有参数,观察其运行情况

-
这里我们运行发现,报了一个错误,错误原因是因为C函数没定义
-
那我们在原来函数的位置点c函数进去将c函数扣出来(这里先不扣c函数)
- 原因是,后面c函数还需要用到很多调用函数,同时我们通过代码也会发现他是生成我们第二个加密参数的函数
- 我们先解决第一个加密参数
- 我们先将c函数注释掉

- 它没有让我们失望,因为我们从代码中就可以发现,他是调用了好多函数来进加密的
- 这里缺少a函数,我们将a函数扣出来,他还会报b函数找不到,那我们也将b函数扣出来

- 然后我们就遇到了这个错误
- 这个错误的意思也很明显,这是我们学过的一个 Crypto方法 ,这是个加密方法,我们没有定义这个方法,所以他自然是找不到的
- 于是我们利用js 中的外部导入包的方法进行包的导入
# 下载包的方法:npm install crypto-js
const CryptoJS = require('crypto-js');
- 我们将参数补上后再次运行

-
然后我们就可以发现我们其中一个加密参数就破解完成了
-
对于C函数也是同样的道理,缺什么补什么是最稳妥点的方法
-
还有一种方法是仔细观察每一个闭包函数的作用域,也可以将这个闭包函数作用域下的相关函数和参数全都拿下来,然后根据缺啥补啥的方法尽心完善
-
以下是扣完以后,完整的JS逆向代码
const CryptoJS = require('crypto-js');
function reverseStr(a) {
var c, b = "";
for (c = a.length - 1; c > -1; --c)
b += a.charAt(c);
return b
}
function digitToHex(a) {
var b = 15
, c = "";
for (i = 0; 4 > i; ++i)
c += hexToChar[a & b],
a >>>= 4;
return reverseStr(c)
}
function biToHex(a) {
var d, b = "";
for (biHighIndex(a),
d = biHighIndex(a); d > -1; --d)
b += digitToHex(a.digits[d]);
return b
}
function biModuloByRadixPower(a, b) {
var c = new BigInt;
return arrayCopy(a.digits, 0, c.digits, 0, b),
c
}
function biMultiply(a, b) {
var d, h, i, k, c = new BigInt, e = biHighIndex(a), f = biHighIndex(b);
for (k = 0; f >= k; ++k) {
for (d = 0,
i = k,
j = 0; e >= j; ++j,
++i)
h = c.digits[i] + a.digits[j] * b.digits[k] + d,
c.digits[i] = h & maxDigitVal,
d = h >>> biRadixBits;
c.digits[k + e + 1] = d
}
return c.isNeg = a.isNeg != b.isNeg,
c
}
function encryptedString(a, b) {
for (var f, g, h, i, j, k, l, c = new Array, d = b.length, e = 0; d > e;)
c[e] = b.charCodeAt(e),
e++;
for (; 0 != c.length % a.chunkSize;)
c[e++] = 0;
for (f = c.length,
g = "",
e = 0; f > e; e += a.chunkSize) {
for (j = new BigInt,
h = 0,
i = e; i < e + a.chunkSize; ++h)
j.digits[h] = c[i++],
j.digits[h] += c[i++] << 8;
k = a.barrett.powMod(j, a.e),
l = 16 == a.radix ? biToHex(k) : biToString(k, a.radix),
g += l + " "
}
return g.substring(0, g.length - 1)
}
function BarrettMu_powMod(a, b) {
var d, e, c = new BigInt;
for (c.digits[0] = 1,
d = a,
e = b; ;) {
if (0 != (1 & e.digits[0]) && (c = this.multiplyMod(c, d)),
e = biShiftRight(e, 1),
0 == e.digits[0] && 0 == biHighIndex(e))
break;
d = this.multiplyMod(d, d)
}
return c
}
function BarrettMu_multiplyMod(a, b) {
var c = biMultiply(a, b);
return this.modulo(c)
}
function BarrettMu_modulo(a) {
var i, b = biDivideByRadixPower(a, this.k - 1), c = biMultiply(b, this.mu), d = biDivideByRadixPower(c, this.k + 1),
e = biModuloByRadixPower(a, this.k + 1), f = biMultiply(d, this.modulus),
g = biModuloByRadixPower(f, this.k + 1), h = biSubtract(e, g);
for (h.isNeg && (h = biAdd(h, this.bkplus1)),
i = biCompare(h, this.modulus) >= 0; i;)
h = biSubtract(h, this.modulus),
i = biCompare(h, this.modulus) >= 0;
return h
}
function biShiftRight(a, b) {
var e, f, g, h, c = Math.floor(b / bitsPerDigit), d = new BigInt;
for (arrayCopy(a.digits, c, d.digits, 0, a.digits.length - c),
e = b % bitsPerDigit,
f = bitsPerDigit - e,
g = 0,
h = g + 1; g < d.digits.length - 1; ++g,
++h)
d.digits[g] = d.digits[g] >>> e | (d.digits[h] & lowBitMasks[e]) << f;
return d.digits[d.digits.length - 1] >>>= e,
d.isNeg = a.isNeg,
d
}
function biMultiplyDigit(a, b) {
var c, d, e, f;
for (result = new BigInt,
c = biHighIndex(a),
d = 0,
f = 0; c >= f; ++f)
e = result.digits[f] + a.digits[f] * b + d,
result.digits[f] = e & maxDigitVal,
d = e >>> biRadixBits;
return result.digits[1 + c] = d,
result
}
function biSubtract(a, b) {
var c, d, e, f;
if (a.isNeg != b.isNeg)
b.isNeg = !b.isNeg,
c = biAdd(a, b),
b.isNeg = !b.isNeg;
else {
for (c = new BigInt,
e = 0,
f = 0; f < a.digits.length; ++f)
d = a.digits[f] - b.digits[f] + e,
c.digits[f] = 65535 & d,
c.digits[f] < 0 && (c.digits[f] += biRadix),
e = 0 - Number(0 > d);
if (-1 == e) {
for (e = 0,
f = 0; f < a.digits.length; ++f)
d = 0 - c.digits[f] + e,
c.digits[f] = 65535 & d,
c.digits[f] < 0 && (c.digits[f] += biRadix),
e = 0 - Number(0 > d);
c.isNeg = !a.isNeg
} else
c.isNeg = a.isNeg
}
return c
}
function biCompare(a, b) {
if (a.isNeg != b.isNeg)
return 1 - 2 * Number(a.isNeg);
for (var c = a.digits.length - 1; c >= 0; --c)
if (a.digits[c] != b.digits[c])
return a.isNeg ? 1 - 2 * Number(a.digits[c] > b.digits[c]) : 1 - 2 * Number(a.digits[c] < b.digits[c]);
return 0
}
function biMultiplyByRadixPower(a, b) {
var c = new BigInt;
return arrayCopy(a.digits, 0, c.digits, b, c.digits.length - b),
c
}
function arrayCopy(a, b, c, d, e) {
var g, h, f = Math.min(b + e, a.length);
for (g = b,
h = d; f > g; ++g,
++h)
c[h] = a[g]
}
function biShiftLeft(a, b) {
var e, f, g, h, c = Math.floor(b / bitsPerDigit), d = new BigInt;
for (arrayCopy(a.digits, 0, d.digits, c, d.digits.length - c),
e = b % bitsPerDigit,
f = bitsPerDigit - e,
g = d.digits.length - 1,
h = g - 1; g > 0; --g,
--h)
d.digits[g] = d.digits[g] << e & maxDigitVal | (d.digits[h] & highBitMasks[e]) >>> f;
return d.digits[0] = d.digits[g] << e & maxDigitVal,
d.isNeg = a.isNeg,
d
}
function biFromNumber(a) {
var c, b = new BigInt;
for (b.isNeg = 0 > a,
a = Math.abs(a),
c = 0; a > 0;)
b.digits[c++] = a & maxDigitVal,
a >>= biRadixBits;
return b
}
var maxDigits, ZERO_ARRAY, bigZero, bigOne, dpl10, lr10, hexatrigesimalToChar, hexToChar, highBitMasks, lowBitMasks,
biRadixBase = 2, biRadixBits = 16, bitsPerDigit = biRadixBits, biRadix = 65536, biHalfRadix = biRadix >>> 1,
biRadixSquared = biRadix * biRadix, maxDigitVal = biRadix - 1, maxInteger = 9999999999999998;
setMaxDigits(20),
dpl10 = 15,
lr10 = biFromNumber(1e15),
hexatrigesimalToChar = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"),
hexToChar = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"),
highBitMasks = new Array(0, 32768, 49152, 57344, 61440, 63488, 64512, 65024, 65280, 65408, 65472, 65504, 65520, 65528, 65532, 65534, 65535),
lowBitMasks = new Array(0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535);
function biNumBits(a) {
var e, b = biHighIndex(a), c = a.digits[b], d = (b + 1) * bitsPerDigit;
for (e = d; e > d - bitsPerDigit && 0 == (32768 & c); --e)
c <<= 1;
return e
}
function biDivideModulo(a, b) {
var f, g, h, i, j, k, l, m, n, o, p, q, r, s, c = biNumBits(a), d = biNumBits(b), e = b.isNeg;
if (d > c)
return a.isNeg ? (f = biCopy(bigOne),
f.isNeg = !b.isNeg,
a.isNeg = !1,
b.isNeg = !1,
g = biSubtract(b, a),
a.isNeg = !0,
b.isNeg = e) : (f = new BigInt,
g = biCopy(a)),
new Array(f, g);
for (f = new BigInt,
g = a,
h = Math.ceil(d / bitsPerDigit) - 1,
i = 0; b.digits[h] < biHalfRadix;)
b = biShiftLeft(b, 1),
++i,
++d,
h = Math.ceil(d / bitsPerDigit) - 1;
for (g = biShiftLeft(g, i),
c += i,
j = Math.ceil(c / bitsPerDigit) - 1,
k = biMultiplyByRadixPower(b, j - h); -1 != biCompare(g, k);)
++f.digits[j - h],
g = biSubtract(g, k);
for (l = j; l > h; --l) {
for (m = l >= g.digits.length ? 0 : g.digits[l],
n = l - 1 >= g.digits.length ? 0 : g.digits[l - 1],
o = l - 2 >= g.digits.length ? 0 : g.digits[l - 2],
p = h >= b.digits.length ? 0 : b.digits[h],
q = h - 1 >= b.digits.length ? 0 : b.digits[h - 1],
f.digits[l - h - 1] = m == p ? maxDigitVal : Math.floor((m * biRadix + n) / p),
r = f.digits[l - h - 1] * (p * biRadix + q),
s = m * biRadixSquared + (n * biRadix + o); r > s;)
--f.digits[l - h - 1],
r = f.digits[l - h - 1] * (p * biRadix | q),
s = m * biRadix * biRadix + (n * biRadix + o);
k = biMultiplyByRadixPower(b, l - h - 1),
g = biSubtract(g, biMultiplyDigit(k, f.digits[l - h - 1])),
g.isNeg && (g = biAdd(g, k),
--f.digits[l - h - 1])
}
return g = biShiftRight(g, i),
f.isNeg = a.isNeg != e,
a.isNeg && (f = e ? biAdd(f, bigOne) : biSubtract(f, bigOne),
b = biShiftRight(b, i),
g = biSubtract(b, g)),
0 == g.digits[0] && 0 == biHighIndex(g) && (g.isNeg = !1),
new Array(f, g)
}
function biDivideByRadixPower(a, b) {
var c = new BigInt;
return arrayCopy(a.digits, b, c.digits, 0, c.digits.length - b),
c
}
function biDivide(a, b) {
return biDivideModulo(a, b)[0]
}
function biCopy(a) {
var b = new BigInt(!0);
return b.digits = a.digits.slice(0),
b.isNeg = a.isNeg,
b
}
function BarrettMu(a) {
this.modulus = biCopy(a),
this.k = biHighIndex(this.modulus) + 1;
var b = new BigInt;
b.digits[2 * this.k] = 1,
this.mu = biDivide(b, this.modulus),
this.bkplus1 = new BigInt,
this.bkplus1.digits[this.k + 1] = 1,
this.modulo = BarrettMu_modulo,
this.multiplyMod = BarrettMu_multiplyMod,
this.powMod = BarrettMu_powMod
}
function biHighIndex(a) {
for (var b = a.digits.length - 1; b > 0 && 0 == a.digits[b];)
--b;
return b
}
function charToHex(a) {
var h, b = 48, c = b + 9, d = 97, e = d + 25, f = 65, g = 90;
return h = a >= b && c >= a ? a - b : a >= f && g >= a ? 10 + a - f : a >= d && e >= a ? 10 + a - d : 0
}
function hexToDigit(a) {
var d, b = 0, c = Math.min(a.length, 4);
for (d = 0; c > d; ++d)
b <<= 4,
b |= charToHex(a.charCodeAt(d));
return b
}
function biFromHex(a) {
var d, e, b = new BigInt, c = a.length;
for (d = c,
e = 0; d > 0; d -= 4,
++e)
b.digits[e] = hexToDigit(a.substr(Math.max(d - 4, 0), Math.min(d, 4)));
return b
}
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)
}
function BigInt(a) {
this.digits = "boolean" == typeof a && 1 == a ? null : ZERO_ARRAY.slice(0),
this.isNeg = !1
}
function setMaxDigits(a) {
maxDigits = a,
ZERO_ARRAY = new Array(maxDigits);
for (var b = 0; b < ZERO_ARRAY.length; b++)
ZERO_ARRAY[b] = 0;
bigZero = new BigInt,
bigOne = new BigInt,
bigOne.digits[0] = 1
}
function c(a, b, c) {
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b, "", c),
e = encryptedString(d, 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()
}
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
}
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
}
key_2 = '010001'
key_3 = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
key_4 = '0CoJUm6Qyw8W8jud'
function main(key_1) {
encrypted_params = d(key_1, key_2, key_3, key_4)
encText = encrypted_params['encText']
encSecKey = encrypted_params['encSecKey']
return [encText, encSecKey]
}
- 在这个逆向代码中,在结尾我补了一个main函数
- 主要是我们需要在Python代码中调用excejs方法运行js代码
- 需要有一个主程序入口
【三】代码的补全
【1】Python主程序
- main.py
import requests
from fake_useragent import UserAgent
# json 序列化模块
import os
#
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')
# 导入Python中执行 js 代码的模块
import execjs
def get_download_url(sound_number):
page_url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='
# 打开JS 代码文件
# 注意这里可能会报一个错误:文中出现了连‘gb18030’也无法编码的字符,可以使用‘ignore’属性进行忽略
# UnicodeDecodeError: 'gbk' codec can't decode byte 0xbc in position 405: illegal multibyte sequence
with open("encryptParams.js", encoding='gb18030', errors="ignore") as f:
# 将JS 代码读出来
jsCode = f.read()
# 将读出来的JS代码交给 execjs 进行编译
JS_sign_t = execjs.compile(jsCode)
key = '{"ids":"[%s]","level":"standard","encodeType":"aac","csrf_token":""}' % sound_number
# call() 运行代码中的xxx函数. 后续的参数是xxx的参数 # 后面的参数可留空
encryptionParams = JS_sign_t.call('main', key)
encText = encryptionParams[0]
encSecKey = encryptionParams[1]
# headers 伪装
headers = {
'User-Agent': UserAgent().random
}
params = {
'params': encText,
'encSecKey': encSecKey
}
session = requests.Session()
response = session.post(url=page_url, headers=headers, params=params)
data_json = response.json()
# print(response.text)
download_url = data_json['data'][0]['url']
return download_url
def download_sound(download_url, sound_name):
# 发起请求,获取到数据
response = requests.get(download_url)
# 转为二进制数据
data = response.content
# 文件操作,判断文件夹是否存在以及对歌曲的命名
filename = 'music'
if not os.path.exists(filename):
os.mkdir(filename)
soundName = sound_name + '.mp4'
print(soundName)
file_path = os.path.join(filename, soundName)
try:
with open(file_path, 'wb') as f:
f.write(data)
print(f'{soundName}下载成功')
except Exception as e:
print(e)
def choose():
# 加一个判断是否继续下载下一首
count = 0
chose = input('请输入是否继续下砸下一首(y/n):>>>')
if chose == 'y':
count += 1
print(f'你已经下载了{count}首歌曲了哦 (≖ᴗ≖)✧')
main()
else:
print("感谢您的使用,谢谢! (。・ω・。) ")
def main():
sound_number = input('请输入歌曲的id:>>>>')
sound_number = int(sound_number)
download_url = get_download_url(sound_number)
sound_name = input('请输入歌曲的名字:>>>>')
download_sound(download_url, sound_name)
choose()
if __name__ == '__main__':
main()
【二】JS文件
- encryptParams.js
const CryptoJS = require('crypto-js');
function reverseStr(a) {
var c, b = "";
for (c = a.length - 1; c > -1; --c)
b += a.charAt(c);
return b
}
function digitToHex(a) {
var b = 15
, c = "";
for (i = 0; 4 > i; ++i)
c += hexToChar[a & b],
a >>>= 4;
return reverseStr(c)
}
function biToHex(a) {
var d, b = "";
for (biHighIndex(a),
d = biHighIndex(a); d > -1; --d)
b += digitToHex(a.digits[d]);
return b
}
function biModuloByRadixPower(a, b) {
var c = new BigInt;
return arrayCopy(a.digits, 0, c.digits, 0, b),
c
}
function biMultiply(a, b) {
var d, h, i, k, c = new BigInt, e = biHighIndex(a), f = biHighIndex(b);
for (k = 0; f >= k; ++k) {
for (d = 0,
i = k,
j = 0; e >= j; ++j,
++i)
h = c.digits[i] + a.digits[j] * b.digits[k] + d,
c.digits[i] = h & maxDigitVal,
d = h >>> biRadixBits;
c.digits[k + e + 1] = d
}
return c.isNeg = a.isNeg != b.isNeg,
c
}
function encryptedString(a, b) {
for (var f, g, h, i, j, k, l, c = new Array, d = b.length, e = 0; d > e;)
c[e] = b.charCodeAt(e),
e++;
for (; 0 != c.length % a.chunkSize;)
c[e++] = 0;
for (f = c.length,
g = "",
e = 0; f > e; e += a.chunkSize) {
for (j = new BigInt,
h = 0,
i = e; i < e + a.chunkSize; ++h)
j.digits[h] = c[i++],
j.digits[h] += c[i++] << 8;
k = a.barrett.powMod(j, a.e),
l = 16 == a.radix ? biToHex(k) : biToString(k, a.radix),
g += l + " "
}
return g.substring(0, g.length - 1)
}
function BarrettMu_powMod(a, b) {
var d, e, c = new BigInt;
for (c.digits[0] = 1,
d = a,
e = b; ;) {
if (0 != (1 & e.digits[0]) && (c = this.multiplyMod(c, d)),
e = biShiftRight(e, 1),
0 == e.digits[0] && 0 == biHighIndex(e))
break;
d = this.multiplyMod(d, d)
}
return c
}
function BarrettMu_multiplyMod(a, b) {
var c = biMultiply(a, b);
return this.modulo(c)
}
function BarrettMu_modulo(a) {
var i, b = biDivideByRadixPower(a, this.k - 1), c = biMultiply(b, this.mu), d = biDivideByRadixPower(c, this.k + 1),
e = biModuloByRadixPower(a, this.k + 1), f = biMultiply(d, this.modulus),
g = biModuloByRadixPower(f, this.k + 1), h = biSubtract(e, g);
for (h.isNeg && (h = biAdd(h, this.bkplus1)),
i = biCompare(h, this.modulus) >= 0; i;)
h = biSubtract(h, this.modulus),
i = biCompare(h, this.modulus) >= 0;
return h
}
function biShiftRight(a, b) {
var e, f, g, h, c = Math.floor(b / bitsPerDigit), d = new BigInt;
for (arrayCopy(a.digits, c, d.digits, 0, a.digits.length - c),
e = b % bitsPerDigit,
f = bitsPerDigit - e,
g = 0,
h = g + 1; g < d.digits.length - 1; ++g,
++h)
d.digits[g] = d.digits[g] >>> e | (d.digits[h] & lowBitMasks[e]) << f;
return d.digits[d.digits.length - 1] >>>= e,
d.isNeg = a.isNeg,
d
}
function biMultiplyDigit(a, b) {
var c, d, e, f;
for (result = new BigInt,
c = biHighIndex(a),
d = 0,
f = 0; c >= f; ++f)
e = result.digits[f] + a.digits[f] * b + d,
result.digits[f] = e & maxDigitVal,
d = e >>> biRadixBits;
return result.digits[1 + c] = d,
result
}
function biSubtract(a, b) {
var c, d, e, f;
if (a.isNeg != b.isNeg)
b.isNeg = !b.isNeg,
c = biAdd(a, b),
b.isNeg = !b.isNeg;
else {
for (c = new BigInt,
e = 0,
f = 0; f < a.digits.length; ++f)
d = a.digits[f] - b.digits[f] + e,
c.digits[f] = 65535 & d,
c.digits[f] < 0 && (c.digits[f] += biRadix),
e = 0 - Number(0 > d);
if (-1 == e) {
for (e = 0,
f = 0; f < a.digits.length; ++f)
d = 0 - c.digits[f] + e,
c.digits[f] = 65535 & d,
c.digits[f] < 0 && (c.digits[f] += biRadix),
e = 0 - Number(0 > d);
c.isNeg = !a.isNeg
} else
c.isNeg = a.isNeg
}
return c
}
function biCompare(a, b) {
if (a.isNeg != b.isNeg)
return 1 - 2 * Number(a.isNeg);
for (var c = a.digits.length - 1; c >= 0; --c)
if (a.digits[c] != b.digits[c])
return a.isNeg ? 1 - 2 * Number(a.digits[c] > b.digits[c]) : 1 - 2 * Number(a.digits[c] < b.digits[c]);
return 0
}
function biMultiplyByRadixPower(a, b) {
var c = new BigInt;
return arrayCopy(a.digits, 0, c.digits, b, c.digits.length - b),
c
}
function arrayCopy(a, b, c, d, e) {
var g, h, f = Math.min(b + e, a.length);
for (g = b,
h = d; f > g; ++g,
++h)
c[h] = a[g]
}
function biShiftLeft(a, b) {
var e, f, g, h, c = Math.floor(b / bitsPerDigit), d = new BigInt;
for (arrayCopy(a.digits, 0, d.digits, c, d.digits.length - c),
e = b % bitsPerDigit,
f = bitsPerDigit - e,
g = d.digits.length - 1,
h = g - 1; g > 0; --g,
--h)
d.digits[g] = d.digits[g] << e & maxDigitVal | (d.digits[h] & highBitMasks[e]) >>> f;
return d.digits[0] = d.digits[g] << e & maxDigitVal,
d.isNeg = a.isNeg,
d
}
function biFromNumber(a) {
var c, b = new BigInt;
for (b.isNeg = 0 > a,
a = Math.abs(a),
c = 0; a > 0;)
b.digits[c++] = a & maxDigitVal,
a >>= biRadixBits;
return b
}
var maxDigits, ZERO_ARRAY, bigZero, bigOne, dpl10, lr10, hexatrigesimalToChar, hexToChar, highBitMasks, lowBitMasks,
biRadixBase = 2, biRadixBits = 16, bitsPerDigit = biRadixBits, biRadix = 65536, biHalfRadix = biRadix >>> 1,
biRadixSquared = biRadix * biRadix, maxDigitVal = biRadix - 1, maxInteger = 9999999999999998;
setMaxDigits(20),
dpl10 = 15,
lr10 = biFromNumber(1e15),
hexatrigesimalToChar = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"),
hexToChar = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"),
highBitMasks = new Array(0, 32768, 49152, 57344, 61440, 63488, 64512, 65024, 65280, 65408, 65472, 65504, 65520, 65528, 65532, 65534, 65535),
lowBitMasks = new Array(0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535);
function biNumBits(a) {
var e, b = biHighIndex(a), c = a.digits[b], d = (b + 1) * bitsPerDigit;
for (e = d; e > d - bitsPerDigit && 0 == (32768 & c); --e)
c <<= 1;
return e
}
function biDivideModulo(a, b) {
var f, g, h, i, j, k, l, m, n, o, p, q, r, s, c = biNumBits(a), d = biNumBits(b), e = b.isNeg;
if (d > c)
return a.isNeg ? (f = biCopy(bigOne),
f.isNeg = !b.isNeg,
a.isNeg = !1,
b.isNeg = !1,
g = biSubtract(b, a),
a.isNeg = !0,
b.isNeg = e) : (f = new BigInt,
g = biCopy(a)),
new Array(f, g);
for (f = new BigInt,
g = a,
h = Math.ceil(d / bitsPerDigit) - 1,
i = 0; b.digits[h] < biHalfRadix;)
b = biShiftLeft(b, 1),
++i,
++d,
h = Math.ceil(d / bitsPerDigit) - 1;
for (g = biShiftLeft(g, i),
c += i,
j = Math.ceil(c / bitsPerDigit) - 1,
k = biMultiplyByRadixPower(b, j - h); -1 != biCompare(g, k);)
++f.digits[j - h],
g = biSubtract(g, k);
for (l = j; l > h; --l) {
for (m = l >= g.digits.length ? 0 : g.digits[l],
n = l - 1 >= g.digits.length ? 0 : g.digits[l - 1],
o = l - 2 >= g.digits.length ? 0 : g.digits[l - 2],
p = h >= b.digits.length ? 0 : b.digits[h],
q = h - 1 >= b.digits.length ? 0 : b.digits[h - 1],
f.digits[l - h - 1] = m == p ? maxDigitVal : Math.floor((m * biRadix + n) / p),
r = f.digits[l - h - 1] * (p * biRadix + q),
s = m * biRadixSquared + (n * biRadix + o); r > s;)
--f.digits[l - h - 1],
r = f.digits[l - h - 1] * (p * biRadix | q),
s = m * biRadix * biRadix + (n * biRadix + o);
k = biMultiplyByRadixPower(b, l - h - 1),
g = biSubtract(g, biMultiplyDigit(k, f.digits[l - h - 1])),
g.isNeg && (g = biAdd(g, k),
--f.digits[l - h - 1])
}
return g = biShiftRight(g, i),
f.isNeg = a.isNeg != e,
a.isNeg && (f = e ? biAdd(f, bigOne) : biSubtract(f, bigOne),
b = biShiftRight(b, i),
g = biSubtract(b, g)),
0 == g.digits[0] && 0 == biHighIndex(g) && (g.isNeg = !1),
new Array(f, g)
}
function biDivideByRadixPower(a, b) {
var c = new BigInt;
return arrayCopy(a.digits, b, c.digits, 0, c.digits.length - b),
c
}
function biDivide(a, b) {
return biDivideModulo(a, b)[0]
}
function biCopy(a) {
var b = new BigInt(!0);
return b.digits = a.digits.slice(0),
b.isNeg = a.isNeg,
b
}
function BarrettMu(a) {
this.modulus = biCopy(a),
this.k = biHighIndex(this.modulus) + 1;
var b = new BigInt;
b.digits[2 * this.k] = 1,
this.mu = biDivide(b, this.modulus),
this.bkplus1 = new BigInt,
this.bkplus1.digits[this.k + 1] = 1,
this.modulo = BarrettMu_modulo,
this.multiplyMod = BarrettMu_multiplyMod,
this.powMod = BarrettMu_powMod
}
function biHighIndex(a) {
for (var b = a.digits.length - 1; b > 0 && 0 == a.digits[b];)
--b;
return b
}
function charToHex(a) {
var h, b = 48, c = b + 9, d = 97, e = d + 25, f = 65, g = 90;
return h = a >= b && c >= a ? a - b : a >= f && g >= a ? 10 + a - f : a >= d && e >= a ? 10 + a - d : 0
}
function hexToDigit(a) {
var d, b = 0, c = Math.min(a.length, 4);
for (d = 0; c > d; ++d)
b <<= 4,
b |= charToHex(a.charCodeAt(d));
return b
}
function biFromHex(a) {
var d, e, b = new BigInt, c = a.length;
for (d = c,
e = 0; d > 0; d -= 4,
++e)
b.digits[e] = hexToDigit(a.substr(Math.max(d - 4, 0), Math.min(d, 4)));
return b
}
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)
}
function BigInt(a) {
this.digits = "boolean" == typeof a && 1 == a ? null : ZERO_ARRAY.slice(0),
this.isNeg = !1
}
function setMaxDigits(a) {
maxDigits = a,
ZERO_ARRAY = new Array(maxDigits);
for (var b = 0; b < ZERO_ARRAY.length; b++)
ZERO_ARRAY[b] = 0;
bigZero = new BigInt,
bigOne = new BigInt,
bigOne.digits[0] = 1
}
function c(a, b, c) {
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b, "", c),
e = encryptedString(d, 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()
}
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
}
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
}
key_2 = '010001'
key_3 = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
key_4 = '0CoJUm6Qyw8W8jud'
function main(key_1) {
encrypted_params = d(key_1, key_2, key_3, key_4)
encText = encrypted_params['encText']
encSecKey = encrypted_params['encSecKey']
return [encText, encSecKey]
}
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17409249.html

浙公网安备 33010602011771号