Python js逆向某音乐网音乐
大家好,我是March,一位热爱Python的程序员,最近学习JS逆向,爬取了有些网站的数据,在此想记录以下自己JS逆向某音乐网站的过程,这是我第一次写这种类型的文章,如果有问题,欢迎大家提出意见,感谢
我用自己很喜爱的一首歌心墙来做讲解,这也是内少的专属bgm哈哈
首先先打开F12,点击播放按钮进行抓包,抓包请求如下图,然后我们要通过查看各个请求来找到数据存储在哪个数据包中
通过分析我们发现我们需要的歌曲链接在下图标记的url请求中 aac是一种音乐格式
但是我们查看它的请求我们会发现,请求参数是加密的,我们要想拿到数据,就得先把这两个加密的参数搞清楚,加密参数红线标记如下图
那我们该怎么去找这两个参数的加密位置呢,此时方案比较多,我们可以用全局搜索变量,也可以设置xhr断点,这里我使用的是devtools的发起程序,如下图,我们可以看到这个url请求的整个堆栈,越下面的就是越早的,我们可以点一个进去打上断点,然后刷新页面,看数据最早在哪进行加密的
通过打断点我们发现,现在的数据已经是加密的了,我们需要向上跟栈,定位到数据发生加密的位置
具体怎么定位,我们可以跟断点,在一个函数的开始位置结束位置打上断点,如果进入开始位置参数就是加密的,那么我们就不需要看这个栈里面的方法了,直接去下一个栈方法
通过分析,我最终定位到加密的代码为
var bVc6W = window.asrsea(JSON.stringify(i7b), bsF5K(["流泪", "强"]), bsF5K(St9k.md), bsF5K(["爱心", "女孩", "惊恐", "大笑"]));
这个方法有要传入四个参数,通过在控制台打印,我们发现这四个参数有三个是不变的,通过多次打印来确认可以
既然我们已经定位到了方法window.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
}
打上断点进行单步调试,最终可以分析到 a,b, c方法
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 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 c(a, b, c) {
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),
h.encText = b(h.encText, i),
h.encSecKey = c(i, e, f),
h
}
分析代码我们可以发现使用的是AES和RSA加密算法 encText经历两次AES加密 ,encSecKey经历一次RSA加密
到此,我们就知道了参数加密的相关逻辑,接下来就是扣js代码了
-
准备参数
// 准备参数 arg1 = '{"ids":"[247936]","level":"standard","encodeType":"aac","csrf_token":""}' arg2 = '010001' arg3 = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7' arg4 = '0CoJUm6Qyw8W8jud'
-
把d方法拿过来,并且调用,看控制台的错误提示信息,缺什么就去扣什么,到最终不报错拿到参数为止
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 } // 完成一个完整的调用逻辑 let ret = d(arg1, arg2, arg3, arg4) // 如果没错就能得到结果 console.log(ret)
-
最终扣下来的完整代码
let 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) } function twoDigit(a) { return (10 > a ? "0" : "") + String(a) } 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 decryptedString(a, b) { var e, f, g, h, c = b.split(" "), d = ""; for (e = 0; e < c.length; ++e) for (h = 16 == a.radix ? biFromHex(c[e]) : biFromString(c[e], a.radix), g = a.barrett.powMod(h, a.d), f = 0; f <= biHighIndex(g); ++f) d += String.fromCharCode(255 & g.digits[f], g.digits[f] >> 8); return 0 == d.charCodeAt(d.length - 1) && (d = d.substring(0, d.length - 1)), d } 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 BigInt(a) { this.digits = "boolean" == typeof a && 1 == a ? null : ZERO_ARRAY.slice(0), this.isNeg = !1 } function biFromDecimal(a) { for (var d, e, f, b = "-" == a.charAt(0), c = b ? 1 : 0; c < a.length && "0" == a.charAt(c);) ++c; if (c == a.length) d = new BigInt; else { for (e = a.length - c, f = e % dpl10, 0 == f && (f = dpl10), d = biFromNumber(Number(a.substr(c, f))), c += f; c < a.length;) d = biAdd(biMultiply(d, lr10), biFromNumber(Number(a.substr(c, dpl10)))), c += dpl10; d.isNeg = b } return d } function biCopy(a) { var b = new BigInt(!0); return b.digits = a.digits.slice(0), b.isNeg = a.isNeg, b } 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 } function reverseStr(a) { var c, b = ""; for (c = a.length - 1; c > -1; --c) b += a.charAt(c); return b } function biToString(a, b) { var d, e, c = new BigInt; for (c.digits[0] = b, d = biDivideModulo(a, c), e = hexatrigesimalToChar[d[1].digits[0]]; 1 == biCompare(d[0], bigZero);) d = biDivideModulo(d[0], c), digit = d[1].digits[0], e += hexatrigesimalToChar[d[1].digits[0]]; return (a.isNeg ? "-" : "") + reverseStr(e) } function biToDecimal(a) { var c, d, b = new BigInt; for (b.digits[0] = 10, c = biDivideModulo(a, b), d = String(c[1].digits[0]); 1 == biCompare(c[0], bigZero);) c = biDivideModulo(c[0], b), d += String(c[1].digits[0]); return (a.isNeg ? "-" : "") + reverseStr(d) } 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 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 biFromString(a, b) { var g, h, i, j, c = "-" == a.charAt(0), d = c ? 1 : 0, e = new BigInt, f = new BigInt; for (f.digits[0] = 1, g = a.length - 1; g >= d; g--) h = a.charCodeAt(g), i = charToHex(h), j = biMultiplyDigit(f, i), e = biAdd(e, j), f = biMultiplyDigit(f, b); return e.isNeg = c, e } function biDump(a) { return (a.isNeg ? "-" : "") + a.digits.join(" ") } function biAdd(a, b) { var c, d, e, f; if (a.isNeg != b.isNeg) b.isNeg = !b.isNeg, c = biSubtract(a, b), b.isNeg = !b.isNeg; else { for (c = new BigInt, d = 0, f = 0; f < a.digits.length; ++f) e = a.digits[f] + b.digits[f] + d, c.digits[f] = 65535 & e, d = Number(e >= biRadix); c.isNeg = a.isNeg } return c } 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 biHighIndex(a) { for (var b = a.digits.length - 1; b > 0 && 0 == a.digits[b];) --b; return b } 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 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 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 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 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 biMultiplyByRadixPower(a, b) { var c = new BigInt; return arrayCopy(a.digits, 0, c.digits, b, c.digits.length - b), c } function biDivideByRadixPower(a, b) { var c = new BigInt; return arrayCopy(a.digits, b, c.digits, 0, c.digits.length - b), c } function biModuloByRadixPower(a, b) { var c = new BigInt; return arrayCopy(a.digits, 0, c.digits, 0, b), 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 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 biDivide(a, b) { return biDivideModulo(a, b)[0] } function biModulo(a, b) { return biDivideModulo(a, b)[1] } function biMultiplyMod(a, b, c) { return biModulo(biMultiply(a, b), c) } function biPow(a, b) { for (var c = bigOne, d = a; ;) { if (0 != (1 & b) && (c = biMultiply(c, d)), b >>= 1, 0 == b) break; d = biMultiply(d, d) } return c } function biPowMod(a, b, c) { for (var d = bigOne, e = a, f = b; ;) { if (0 != (1 & f.digits[0]) && (d = biMultiplyMod(d, e, c)), f = biShiftRight(f, 1), 0 == f.digits[0] && 0 == biHighIndex(f)) break; e = biMultiplyMod(e, e, c) } return d } 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 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 BarrettMu_multiplyMod(a, b) { var c = biMultiply(a, b); return this.modulo(c) } 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 } 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 c(a, b, c) { var d, e; return setMaxDigits(131), d = new RSAKeyPair(b, "", c), e = encryptedString(d, a) } 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 } // 出现CryptoJS ,JSEncrypt 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 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 } // 准备参数 arg1 = '{"ids":"[247936]","level":"standard","encodeType":"aac","csrf_token":""}' arg2 = '010001' arg3 = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7' arg4 = '0CoJUm6Qyw8W8jud' function getData(arg1){ return d(arg1, arg2, arg3, arg4) }
在扣js代码的过程中,很繁琐,我们可以扣整个模块,通过分析可以看到很多类似bi的,我们就把bi这整个模块给他拿下来,找到前后分隔的地方就行了
最后就是写我们的Python程序来拿到歌曲进行下载了,这里给大家分享一个简化开发的网站,我们只要右键请求复制为cURL,
然后去Convert curl commands to code (curlconverter.com)这个网址粘贴下,就可以拿到requests请求的爬虫代码
完整的python代码如下
from functools import partial
import subprocess
import json
import requests
# 这行代码防止出现牛马gbk编码错误问题
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
import execjs
data = {
"csrf_token": "",
"ids": f"[{input('请输入你喜爱的歌曲id:')}]",
"level": "standard",
"encodeType": "aac"
}
js = execjs.compile(open('wangyi.js', 'r', encoding='utf-8').read())
s = json.dumps(data)
dic = js.call('getData', s)
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
}
data = {
'params': dic['encText'],
'encSecKey': dic['encSecKey'],
}
response = requests.post(
'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=',
headers=headers,
data=data,
)
datas = response.json()
music_url = datas['data'][0]['url']
filename = music_url.split('/')[-1]
with open(filename,mode="wb") as f:
f.write(requests.get(url=music_url).content)
这次就分享到这,写的确实不太好,大家有看不懂的欢迎留言,感谢