文章目录

前言

一、JS逆向以及PyExecJS模块介绍

1、JS逆向

2、PyEecJS

二、使用步骤

1、环境安装

安装PyExecJS模块

安装node.js开发环境(官网链接 https://nodejs.org/en/)

若无法访问官网,可从该网盘下载

检查是否安装成功:

验证execjs的JS引擎是否正确

2.PyExecJS使用步骤

三、网易云逆向思路分析

1、首先要打开你浏览器的无痕窗口

2、关于两种JS逆向思路

3、方案一、缺啥补啥型(比较万能的方案,适合绝大多数网站)

具体操作方案如下

(1)定位数据包

(2)分析数据包

(3)分析栈结构

(4)分析t6n.be7X文件,还原算法过程

(5)开始编写逆向JS代码

(6)此时我们来编写python代码

下节预告

网易云逆向的第二种思维--全局搜索法

总结


前言

逆向是学习爬虫必不可少的一个部分,JS逆向的掌握可以解决绝大多数网站加密机制,以下就从一个小案例中入手JS逆向吧。


一、JS逆向以及PyExecJS模块介绍

1、JS逆向

在数据加密的情况下,我们通过目标网站的JS数据加密算法,反向推导出该算法的加密过程,这个过程我们称之为JS逆向。

2、PyEecJS

在python中能够运行JS代码的模块。


二、使用步骤

1、环境安装

安装PyExecJS模块

安装成功后,最好重启下cmd终端和pycharm,或者重启电脑

pip install PyExecJS

安装node.js开发环境(官网链接 https://nodejs.org/en/)

安装node.js是为了让程序有一个比较良好的JS运行引擎

若无法访问官网,可从该网盘下载

链接:https://pan.baidu.com/s/15dJnead7mxmc6dhtMXz2Kg
        提取码:zw01

选择LTS版本下载(LTS为长期支持版,版本稳定)

以下是安装步骤,一步一部照着来就可以

检查是否安装成功:

在CMD里面输入如下指令

node -v
npm -v

显示版本号及说明安装成功! (安装好了之后,记得重启电脑)

验证execjs的JS引擎是否正确

打开PyCharm,新建一个.py文件

在代码界面输入以下代码,

import execjs
print(execjs.get().name)

显示如下,则证明正确

Node.js (V8)

2.PyExecJS使用步骤

1、导入模块

2、创建node对象

3、打开JS文件

4、使用compile命令把JS文件转成一个JS对象

5、生成要执行的JS语句(字符串形式)

6、调用eval函数,执行定义好的JS代码

模板如下(示例):

#导包
import execjs#创建node对象
node = execjs.get()#编译即将被执行的js代码对应的文件,返回上下文对象ctx
#js文件应该在对象执行之前被打开
fp = open("js文件目录",encoding='utf-8')
ctx = node.compile(fp.read())#生成要执行的js函数调用的字符串形式
funName = 'getPwd("xxx")'#两种执行JS代码的方式
# execjs.eval() eval方法中,整个函数调用包含在字符串内
# execjs.exec_()  call方法中,第一个参数是函数名(str),后面接参数
#基于ctx对象调用eval函数,执行上一条语句定义的JS代码
result = ctx.eval(funName)

三、网易云逆向思路分析

接下来将的内容,请忽视具体代码的实现,重点专注逆向的分析思路!!!

1、首先要打开你浏览器的无痕窗口

无痕窗口不会保存任何浏览历史、搜索历史、下载历史、表单历史、cookie 或者 Internet临时文件,这样有利于你对网站的判断。

2、关于两种JS逆向思路

以下讲述的是两种JS逆向思路,有麻烦一些的操作,也有简单一些的操作,各有各的优缺点,两种方式可以应用在不同的逆向作业上,希望大家都可以掌握这两种思路,这样就可以处理大多数的网站。

3、方案一、缺啥补啥型(比较万能的方案,适合绝大多数网站)

具体操作方案如下

(1)定位数据包

网易的歌曲随便挑一首即可(https://music.163.com/#/song?id=484056997)

第一步:进入到你挑选好的目标网址。

第二步:打开发者工具,点击Network。

第三步:点击下方的Fetch\XHR。

第四步:点击播放歌曲。

第五步:点位到最上层的数据包。

第六步:点击Preview。

(2)分析数据包

查看每一个数据包,在Preview中找是否存在该歌曲的播放链接

这里定位到名为···v1?csrf_token=····的数据包携带了相关音乐的播放链接

注:如若遇到两个及以上的相同数据包,则要查看每个数据包链接是否可以播放,若可以播放,则默认选择最上面的数据包进行逆向分析。

url: "http://m701.music.126.net/20221108142434/e38ce690bc9fcbdab138e79036fa3474/jdyyaac/5159/5608/0f52/f3ef6f469eab0b30dd8588a6490ffe13.m4a"

我们查看以下这个链接的真实性

这里看到可以正常的播放 ,验证了我们抓包的准确性。

这里我们看一下该数据包的数据是否被加密,这里我们看到有两个参数是被加密了

还要记住该数据包的url地址

https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=

(3)分析栈结构

点击Initiator,这里看到许多的链接,Initiator类似栈操作

就是从最上层函数起,逐级追寻调用到他的函数名

点击最上层的链接,进入到该文件的源码,点击 { } 格式化代码

可以看到,格式化完代码后,有一行代码被标注成黄色,而且光标也会停在这个位置

此时我们需要在本行前面打上断点(只需要在数字上点击以下即可打上断点)

接下来我们点击播放按钮,发现程序停在了我们打断点的位置,说明有数据产生或者是有数据的值被更改。

此时我们选中arguments,鼠标放在上面,会看到数据的值

我们接着分析其他文件,若发生了数据改变的文件,则证明该文件是加密数据的文件

我们查看所有的文件发现,当我们查看该文件的时候发现数据是加密的

但是下一个文件时,数据是没有被加密,由此可得,加密数据的算法在该文件中

所以我们逆向的主要工作就要还原该算法的实现过程

(4)分析t6n.be7X文件,还原算法过程

这里点击释放断点的时候,要注意Y6S的变化,要与之前记录该数据包的地址相同才可以

https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=

我们分析一下该语句

var bKB6v = window.asrsea(JSON.stringify(i3x), buU3x(["流泪", "强"]), buU3x(Rg9X.md), buU3x(["爱心", "女孩", "惊恐", "大笑"]));

在此语句中,window.asrsea一共有四个变量,其中buU3x(["流泪", "强"])与buU3x(["爱心", "女孩", "惊恐", "大笑"])是固定了,参数写死了,剩下的两个是不固定的,所以我们把切入点放在JSON.stringify(i3x)的参数i3x中,以及buU3x(Rg9X.md)的参数Rg9X.md中。

(5)开始编写逆向JS代码

打开PyCharm,新建一个JS文件,准好之后我们正式开始逆向代码的完成。

把鼠标放在JSON.stringify(i3x)的参数i3x上,看到它未加密之前的数据

把i3x复制到Console中查看,拿到它的数据,并且放在JS代码中

var i3x ={ids: '[484056997]',level: 'standard',encodeType: 'aac',csrf_token: ''
}

还原buU3x

 var buU3x = function(chL0x) {var m3x = [];j3x.bg4k(chL0x, function(chE0x) {m3x.push(Rg9X.emj[chE0x])});return m3x.join("")};

在JS代码,没有的函数它会有波浪线,我们按照上面的方法,把缺失的函数补上即可

(同样的道理,选中缺失的函数,跳转到目标地址,然后把函数的实现过程复制到js代码中)

以下是第一段缺啥补啥补出来的代码

var JW7P = function(i3x, v3x) {try {v3x = v3x.toLowerCase();if (i3x === null)return v3x == "null";if (i3x === undefined)return v3x == "undefined";return {}.toString.call(i3x).toLowerCase() == "[object " + v3x + "]"} catch (e) {return !1}
};var gV6P = function(i3x) {return JW7P(i3x, "function")
};var bg4k = function(k3x, cG4K, O4S) {if (!k3x || !k3x.length || !gV6P(cG4K))return this;if (!!k3x.forEach) {k3x.forEach(cG4K, O4S);return this}
}
var emj = {"色": "00e0b","流感": "509f6","这边": "259df","弱": "8642d","嘴唇": "bc356","亲": "62901","开心": "477df","呲牙": "22677","憨笑": "ec152","猫": "b5ff6","皱眉": "8ace6","幽灵": "15bb7","蛋糕": "b7251","发怒": "52b3a","大哭": "b17a8","兔子": "76aea","星星": "8a5aa","钟情": "76d2e","牵手": "41762","公鸡": "9ec4e","爱意": "e341f","禁止": "56135","狗": "fccf6","亲亲": "95280","叉": "104e0","礼物": "312ec","晕": "bda92","呆": "557c9","生病": "38701","钻石": "14af6","拜": "c9d05","怒": "c4f7f","示爱": "0c368","汗": "5b7a4","小鸡": "6bee2","痛苦": "55932","撇嘴": "575cc","惶恐": "e10b4","口罩": "24d81","吐舌": "3cfe4","心碎": "875d3","生气": "e8204","可爱": "7b97d","鬼脸": "def52","跳舞": "741d5","男孩": "46b8e","奸笑": "289dc","猪": "6935b","圈": "3ece0","便便": "462db","外星": "0a22b","圣诞": "8e7","流泪": "01000","强": "1","爱心": "0CoJU","女孩": "m6Qyw","惊恐": "8W8ju","大笑": "d"
};
var buU3x = function(chL0x) {var m3x = [];bg4k(chL0x, function(chE0x) {m3x.push(emj[chE0x])});return m3x.join("")
};var i3x ={ids: '[484056997]',level: 'standard',encodeType: 'aac',csrf_token: ''
}

此时我们测试buU3x,看一下是否与代码中加载的一样

在上面代码中加入一条语句

console.log(buU3x(["流泪", "强"]));

显示010001则证明这个参数逆向成功

这里测试第二个参数md

加入一条语句

console.log(buU3x(md))

得到相同的结果,证明该参数逆向成功

现在来逆向window.asrsea

思路跟逆向其他参数是一样的,选中window.asrsea,查看源代码,缺啥补啥

补到CryptoJS.enc.Utf8.parse这个位置时,可以采用第三方库导入,这样可以减少工作量

因为CryptoJS时JS的第三方库,以后遇到第三方库时也采用此方法

npm install crypto-js(要在此目录下的Terminal进行安装)

下图是打开此目录下的Terminal的方法

如下是安装成功的

综上逆向过程

代码总过程应该为

//CryptoJS公开的第三方库,使用npm安装
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} elsec.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 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 c(a, b, c) {var d, e;return setMaxDigits(131),d = new RSAKeyPair(b,"",c),e = encryptedString(d, 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)
}
// 导入模块
var CryptoJS = require("crypto-js");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
}var JW7P = function(i3x, v3x) {try {v3x = v3x.toLowerCase();if (i3x === null)return v3x == "null";if (i3x === undefined)return v3x == "undefined";return {}.toString.call(i3x).toLowerCase() == "[object " + v3x + "]"} catch (e) {return !1}
};var gV6P = function(i3x) {return JW7P(i3x, "function")
};var bg4k = function(k3x, cG4K, O4S) {if (!k3x || !k3x.length || !gV6P(cG4K))return this;if (!!k3x.forEach) {k3x.forEach(cG4K, O4S);return this}
};
var emj = {"色": "00e0b","流感": "509f6","这边": "259df","弱": "8642d","嘴唇": "bc356","亲": "62901","开心": "477df","呲牙": "22677","憨笑": "ec152","猫": "b5ff6","皱眉": "8ace6","幽灵": "15bb7","蛋糕": "b7251","发怒": "52b3a","大哭": "b17a8","兔子": "76aea","星星": "8a5aa","钟情": "76d2e","牵手": "41762","公鸡": "9ec4e","爱意": "e341f","禁止": "56135","狗": "fccf6","亲亲": "95280","叉": "104e0","礼物": "312ec","晕": "bda92","呆": "557c9","生病": "38701","钻石": "14af6","拜": "c9d05","怒": "c4f7f","示爱": "0c368","汗": "5b7a4","小鸡": "6bee2","痛苦": "55932","撇嘴": "575cc","惶恐": "e10b4","口罩": "24d81","吐舌": "3cfe4","心碎": "875d3","生气": "e8204","可爱": "7b97d","鬼脸": "def52","跳舞": "741d5","男孩": "46b8e","奸笑": "289dc","猪": "6935b","圈": "3ece0","便便": "462db","外星": "0a22b","圣诞": "8e7","流泪": "01000","强": "1","爱心": "0CoJU","女孩": "m6Qyw","惊恐": "8W8ju","大笑": "d"
};var md = ["色", "流感", "这边", "弱", "嘴唇", "亲", "开心", "呲牙", "憨笑", "猫", "皱眉", "幽灵", "蛋糕", "发怒", "大哭", "兔子", "星星", "钟情", "牵手", "公鸡", "爱意", "禁止", "狗", "亲亲", "叉", "礼物", "晕", "呆", "生病", "钻石", "拜", "怒", "示爱", "汗", "小鸡", "痛苦", "撇嘴", "惶恐", "口罩", "吐舌", "心碎", "生气", "可爱", "鬼脸", "跳舞", "男孩", "奸笑", "猪", "圈", "便便", "外星", "圣诞"];var buU3x = function(chL0x) {var m3x = [];bg4k(chL0x, function(chE0x) {m3x.push(emj[chE0x])});return m3x.join("")
};// var i3x ={
//     ids: '[484056997]',
//     level: 'standard',
//     encodeType: 'aac',
//     csrf_token: ''
// }// console.log(buU3x(["流泪", "强"]));
// console.log(buU3x(md))
// console.log(d(JSON.stringify(i3x),buU3x(["流泪", "强"]),buU3x(md), buU3x(["爱心", "女孩", "惊恐", "大笑"])))
function fn(i3x){return d(JSON.stringify(i3x),buU3x(["流泪", "强"]),buU3x(md), buU3x(["爱心", "女孩", "惊恐", "大笑"]));
}

(6)此时我们来编写python代码

#以下三行代码是用来解决gbk报错的,它需要在导入模块之前导入
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')import execjs
import requests#该首歌的参数
data = {"ids": '[484056997]',"level": 'standard',"encodeType": 'aac',"csrf_token": ''
}#创建node对象:
node = execjs.get()#编译即将被执行的js代码对应的文件,返回上下文对象js
f = open("music163.js", mode="r", encoding="utf-8")
js = execjs.compile(f.read())#基于js调用call函数,模拟执行js文件中的fn函数
r = js.call("fn", data)#上面请求到r的参数还不是我们想要的
#在原始数据包中,encText对应的数据应该是params,需要对数据做一下更改
real_data = {"params": r["encText"],"encSecKey": r["encSecKey"]
}#目标数据包地址
url = "https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token="
#请求头参数
headers={"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
}
#发生请求得到响应
response = requests.post(url=url, headers=headers,data=real_data)
print(response.text)

执行结果应该为:

到此为止,逆向过程完全结束

下节预告

网易云逆向的第二种思维--全局搜索法


总结

上述我们从PyExecJS模块的基本用法开始讲述,到node.js的安装,从逆向第一种思维缺啥补啥,分析了网易云逆向的基本思路。以上就算是逆向的基本入门了,虽然这只是一种比较笨拙的做法,但是它的准确率是比较高的。下一节我会讲述逆向的另外一种思维方式,想要学好逆向,躬体力行才是真!


望各位学者朋友提出问题,帮助我及时改正,若有雷同之处,纯属巧合,联系我改之!

QQ邮箱:1417170280@qq.com

wx:Zhangzhang11-12

JS逆向--PyExecJS基本用法--网易云音乐逆向思路,node.js安装教程,逆向思路,逆向分析,加密机制,RSA,AES加密算法,加密算法啊破解,js引擎,定位数据包,分析栈结构,无痕窗口相关推荐

  1. JS不跨域操控网易云音乐外链播放器

    JS不跨域操控网易云音乐外链播放器 今天写个人网站,用到了背景音乐. 一开始想使用H5的audio标签,蛮成功的,但是传到服务器上后加载缓慢(腾讯云服务器学生优惠版,最低的配置),体验很差. 使用外链 ...

  2. js逆向之爬取网易云音乐和歌曲评论

    前面我写的文章当中也有网易云音乐的爬取,只不过是借助了外链接口,本篇文章将介绍网易本身的接口进行爬取 ** 1 . 我们要获取的内容 ** 某一个歌单里面的所有歌曲 ** 2. 我们先分析一下歌曲的真 ...

  3. Vue.js全家桶高还原网易云音乐(Windows PC版)

    项目地址 由于网易云的api限制,部分功能可能会失效,如有需要可以clone项目下来在本地运行,如果api炸了,麻烦在评论中告知一下我 因为做的是PC端 所以请在电脑端访问 源码地址 项目预览(评论和 ...

  4. HTML5+CSS3+JS小实例:仿制网易云音乐网站的轮播图

    实例:仿制网易云音乐网站的轮播图 技术栈:HTML+CSS+JS 字体图标库:font-awesome 效果: 源码: <!DOCTYPE html> <html><he ...

  5. JS 解密剖析—爬虫之网易云音乐加密破解

    前言 网络爬虫的大障碍,就是各种加密.这其中包过登录的验证码以及加密.js混淆.js参数加密等等.其实以前也就了解过js加密.但是没有深入研究,借着这次实践研究了一下网易云音乐的加密方式. 博主通过网 ...

  6. 仿网易云音乐客户端的底部播放器的实现思路

    2019独角兽企业重金招聘Python工程师标准>>> 猜测网易云音乐是写了baseactivity,每一个activity底部都有一个播放器,注意网易云音乐的页面切换没有动画效果, ...

  7. linux 网易云音乐 ssh,网易云音乐For Linux的Fedora安装

    终于,网易云音乐出了For Linux的版本,但可惜的是只有For Ubuntu系列的deb包.那么Fedora怎么对付? 首先说明一点,在Fedora安装会比较麻烦,而且即使安装成功也不一定能稳定运 ...

  8. 如何哄骗文艺青年安装Node.js? 将网易云音乐灰色歌曲变亮

    Node.js是一门编程语言, 是世界上最流行的编程语言之一, 而一门语言的流行程度往往取决于, 它的好玩库多不多? 而 Node.js 的好玩库真的是超多, 即使是爱听网易云的文艺青年也会爱上它, ...

  9. python爬音乐评论生成词云图_python爬虫+词云图,爬取网易云音乐评论

    又到了清明时节,用python爬取了网易云音乐<清明雨上>的评论,统计词频和绘制词云图,记录过程中遇到一些问题 爬取网易云音乐的评论 一开始是按照常规思路,分析网页ajax的传参情况.看到 ...

最新文章

  1. Winform开发框架的业务对象统一调用方式
  2. visio 2013下载和安装
  3. java中的23中设计模式
  4. dock模拟macos教程_将macOS首选项窗格添加到您的Dock中以快速访问
  5. android媒体播放框架,Android 使用超简单的多媒体播放器JiaoZiVideoPlayer
  6. Mybatis在Maven项目中使用
  7. 业务运维:站在企业转型风口上的云智慧
  8. 排序算法专题-桶排序
  9. 网上打印个人完税证明流程
  10. kermit的安装、配置、使用 .
  11. “云”上就诊,泽塔云超融合助力医院数字化转型
  12. C语言必背经典程序代码
  13. HTML中overflow的作用
  14. C语言数据的输入输出
  15. 【操作系统】哲学家进餐问题
  16. 雨听 | 解决连接蓝牙后谷歌浏览器无声音(其他应用有声音)问题
  17. cad中explode是什么意思_为什么CAD图块炸开后多了很多图形?
  18. 微信小程序(原生):基本开发相关文档
  19. 订单波次出库详解:流程、系统与设备
  20. C#压缩ZIP,JAVA无法解压

热门文章

  1. 软考报名照片验证软件报错invalid floating point operation
  2. Qt 读取并且显示SVG图片
  3. 拉代码时提示:Waring:Remote Host Inentification Has Changed!
  4. 虚拟机的远程桌面连不上怎么解决
  5. 时间日期和时间增加量
  6. vue全局加水印(除登录页面)
  7. 八卦与十二地支方位图_万物变化的经典,十二生肖八卦图方位图解析
  8. 天翼展最潮美旗舰竟是它 网友:当之无愧
  9. 瞄准汽车云,字节云业务走向“阿里腾讯百度”化?
  10. 【英语语法入门】 第17讲 不定量表达法 (3)