1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > xx云音乐 encSecKey参数逆向分析

xx云音乐 encSecKey参数逆向分析

时间:2021-02-06 10:52:10

相关推荐

xx云音乐 encSecKey参数逆向分析

网易云音乐唯一的加密地方在每个音乐的评论数据上,一些做自然语言nlp的同学可能会需要这部分的数据。本篇文章将带着大家逐步分析网易云音乐paramsencSecKey参数的加密方法,以及如何逆向得出加密参数。

我们先随便进入一首歌的页面当中,然后打开浏览器抓包,找到这首音乐下面的评论区数据。

为了方便查找,我直接把接口的url 地址放出来,大家也可以自己动动手通过浏览器F12抓包获取,/weapi/comment/resource/comments/get?csrf_token=。该url的请求格式为post请求,所以我们需要提交正确的表单参数服务器才会给我返回正确的数据,点击playload就能看到浏览器在请求该url的时候提交了paramsencSecKey这两个参数,这两个参数就是我们本篇文章所需要逆向分析的关键参数。

点击Initiator开始跟栈分析,大家都知道web端如果post表单中存在着加密参数,一般都是通过该网站所加载的js文件进行加密的,跟栈的目的就是为了在js文件当中找到加密的最初位置以及加密部分的代码,可以理解为从最后一步一直向上一步跟进。点击最上面的一个栈进入 浏览器会自己跟到最后一处地方,我们在当前的位置打上断点,然后刷新当前页面,刷新过后浏览器会自动断在当前的断点处,此处有一个send发送了个名为gC9t.data的数据,用鼠标括住gC9t把光标放在gC9t上可以看到,gC9t内部有许多参数,其中的data就包含paramsencSecKey这两个参数,这就能够确定数据是从上一个栈传过来的,在右边的Call Stack可以向上一个栈跟进。

进入上一个栈,自动跳转到this.ci8a(d7e)其中的d7e就是往下一个栈传的参数,鼠标放上去看看里面有啥。能够看到其中的requestdata包含着我们需要的参数params,encSeckey

此时我们需要注意查看当前断点函数的内部是否重新定义了d7e,如果没有重新定义则往函数头部查看d7e是否为上一个栈传进来的参数。虽然当前的函数内部定义了d7e( var d7e = xxxx),但是任何加密方法生成新的参数。我们往头部查看可以发现传进来的ib7为一串字符串,其中包含着params,encSecKey,这就可以断定我们需要的参数还是从上一个栈中传进来的,接着往上一个栈跟,发现传入的数据变成ed7.data,往头部查看发现ed7为传入的参数,继续往上一个栈跟。

进到上一个栈后,发现向下一个栈传递的数据为Y8Q, e7d还是老方法看当前函数内部有没有重新定义e7d, 向上看第一眼就看到了e7d.data = j7c.cr8j(括号内跟着一个字典类型的数据)

看到有重新定义e7d.data我们就需要注意,需要在e7d.data当前这一行下断点查看是否有重新生成新的参数。我们找到的这个地方很明显就是一个加密的入口,已经可以看到我们想找的paramsencSecKey

e7d.data = j7c.cr8j({params: bMr5w.encText,encSecKey: bMr5w.encSecKey})

params=bMr5wencTextencSecKey=bMr5wencSecKey,现在我们需要搞明白bMr5W是什么东西,把它括住进到内部查看发现就在上一面一行定义了一个bMr5w

var bMr5w = window.asrsea(JSON.stringify(i7b), bsg1x(["流泪", "强"]), bsg1x(TH2x.md), bsg1x(["爱心", "女孩", "惊恐", "大笑"]));

bMr5w是通过了window.asrsea这个方法,传入四个参数进行的加密,分别括住四个参数查看。第一个参数跟我们当前的url有关(url 上的音乐id),传入的第二个参数则是一串固定的数字,第三个参数是取TH2x这个列表进行了一个加密的操作,然后取加密后返回的结构(也是固定的),第四个参数对一个字符串列表进行加密取返回的结果(固定的)。很明显,现在的思路基本可以定下来,我们可以把后三个参数直接写死,但是我们还需要分析window.asrsea这个方法的加密原理,直接进到内部查看。

进到内部就会自动跳到这一行,可以看到d这个方法里头return了h.encTexth.encSecKey这俩个数据。其中的h.encText就对应着我们的params。现在开始分析d这个方法的内部是怎么实现的,首先是 var 了一个 h,然后是 var 了一个 i 而i又等于a(16)【 a(16)这是生成一串长度固定的随机数】​​​​​​,返回的h.encText先经过b方法进行加密,传入的d与 当前歌曲的id有关,g则是固定值。然后将已经加密过的h.encText再一次传入b这个方法中加密,i为我们上面提到的一串长度固定的随机数,简单理解为就是h.encText经过同一个方法加密了两次。我们进到b这个方法中看看。

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,一目了然b这个方法就是调用了CryptoJS做了一个AES的加密,我们能看到最后 return 了f.toString(),而f是经过AES加密的来,其中传入的esalt(固定值)和c(数组),大致了解此处的加密方法之后我们就可以开始扣js代码了。

Advanced Encryption Standard是一种分组加密标注,每个加密数据块大小固定为128位(16个字节),最终生成的加密密钥长度有128位、192位和256位。AES 加密主要有五种加密模式(还有更多):CBC(Cipher-block chaining,密码分组链接),CFB (Cipher feedback,密文反馈),OFB (Output feedback,输出反馈),PCBC (Propagating cipher-block chaining,增强型密码分组链接),ECB (Electroniccodebook,电子密码本)

第一部分主要是扣b这个方法,然后两次加密得到h.encText(这个其实对应的就是我们想要的params参数),如下图所示,我们把b方法扣下来,用encryption重新命名,第一次运行这段代码会报CryptoJS不存在这个错误,解决的两种方法:第一种方法就是在js文件当中找到CryptoJS扣下来(一般都会很大串很大条:));第二种方法也是我用的方法,就是用nodejs提供的CryptoJS(能少扣不少代码)

const CryptoJS = require('crypto-js');

扣下来后,我们模拟h.encText的生成方法,先来第一次的加密,这里我们需要把传入的参数拿出来单独讲讲(就是之前说的和音乐id有关的参数),该参数的格式如下ridthreadId里头的一串数字对应着就是我们的音乐id 前面的R_SO_4_则不用动。传入的第二个参数是固定的,直接写死,生成的结果如下图所示:

// 传入的参数1如下所示{"rid":"R_SO_4_865632948","threadId":"R_SO_4_865632948","pageNo":"1","pageSize":"20","cursor":"-1","offset":"0","orderType":"1","csrf_token":""}

接着就是params的第二次加密,在第二次加密中我们之前提到了一个重要的参数 i ,i 参数是一串长度固定且随机生成的参数,在上面我们能够看到 i 其实是等于a(16),将 a 这个方法扣下来就能够模拟生成出i这个重要的参数了!我们直接进到a这个方法查看,内部的原理其实就是用random做了一个随机数,然后通过charAt取出特定位置的字符进行拼接,直接把这段代码扣下来,生成结果如下图所示。

得到生成的i值,接下来就能够把生成出的i值与第一次加密出来的结果传入我们定义的encryption中进行加密,最后加密出来就是我们想要的params,结果如下图:

搞定params参数后,我们接着来看encSecKey参数,我们已经知道h.encSecKey = c(i, e, f)i值我们已经搞定 ,传入的e值为固定值(010001),f值是一串很长的数据(其实也是固定值,直接定死),现在只需要把c这个方法扣出来就能够得到需要的encSecKey,进入c方法看看,进入后断在此处,不难看出encSecKey其实是通过RSA加密出来的,setMaxDigits(131)是一个空值(不用管),重点在下面的 d 和 e。

dnew了一个新的方法名为RSAKeyPair,可以理解为d生成了RSA加密所需要的密钥publickey,然后将da传入encryptedString方法中加密,最后得到我们想要的encSecKey,直接把c这个方法扣出来,然后将RSA的加密方法补上以及下面的encryptedString方法(具体操作和扣params加密方法一样),随后运行,缺少什么函数就在当前的js文件中寻找然后补上,补完所有函数后我们想要的encSecKey也就生成了!(过程很简单我就不细说了,就是找到然后扣出来),最后扣完的代码一共390来行,扣完的代码在下面。

const CryptoJS = require('crypto-js');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 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 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 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 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 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 biHighIndex(a) {for (var b = a.digits.length - 1; b > 0 && 0 == a.digits[b]; )--b;return 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 biCopy(a) {var b = new BigInt(!0);return b.digits = a.digits.slice(0),b.isNeg = a.isNeg,b}function biDivide(a, b) {return biDivideModulo(a, b)[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 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 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 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 biMultiplyByRadixPower(a, b) {var c = new BigInt;return arrayCopy(a.digits, 0, c.digits, b, c.digits.length - 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 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} elsec.isNeg = a.isNeg}return 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 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 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}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 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 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 biToHex(a) {var d, b = "";for (biHighIndex(a),d = biHighIndex(a); d > -1; --d)b += digitToHex(a.digits[d]);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 reverseStr(a) {var c, b = "";for (c = a.length - 1; c > -1; --c)b += a.charAt(c);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;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 i(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}// paramsfunction encryption(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()}// encSecKeyfunction encSecKeyEncryption(a, b, c) {var d, e;return setMaxDigits(131),d = new RSAKeyPair(b, "", c),e = encryptedString(d, a)}// 生成i值var i_data = i(16);// encSecKey固定参数1var encSecKeyParameterOne = '010001';// encSecKey固定参数2var encSecKeyParameterTwo = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7';// 生成paramsvar params = encryption(encryption('{"rid":"R_SO_4_865632948","threadId":"R_SO_4_865632948","pageNo":"1","pageSize":"20","cursor":"-1","offset":"0","orderType":"1","csrf_token":""}', '0CoJUm6Qyw8W8jud'), i_data)// 生成encSecKeyvar encSecKey = encSecKeyEncryption(i_data, encSecKeyParameterOne, encSecKeyParameterTwo)function data() {return {'params': params,'encSecKey': encSecKey}}console.log(data())

运行一下看看生成的结果,如下图所示:

接着我们写一个简单的爬虫测试一下,注意大家自行修改当前的音乐id哦!

# -*- coding: utf-8 -*-import execjsimport requestsurl = '/weapi/comment/resource/comments/get?csrf_token='def get_response():''' 请求 '''JsFile = open('parameter.js', encoding='utf-8')JsCode = JsFile.read()compile_JsCode = pile(JsCode)ParameterData = compile_JsCode.call('data')data = {'params': ParameterData['params'],'encSecKey': ParameterData['encSecKey']}print(data, '\n')response = requests.post(url=url, data=data).textprint(response)get_response()

可以看到服务器已经给我们返回正确的数据,证明加密的结果没有问题。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。