下载网易云音乐音频案例
只爬免费歌曲,付费和vip的不爬。
地址:https://music.163.com/#/song?id=1325905146
打开F12,点击播放后,看请求的URL,其中先看一个叫“detail?csrf_token”开头的URL,Preview 找了一圈,没找到需要的信息。

继续找另外的URL。。。

看到一个返回的数据里,有一条数据:
url: "http://m801.music.126.net/20230728213854/fd99fbe579f551567eef1c8d6ee21e70/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/28481676823/4af4/3b82/de3c/082fc537ce73819afdeb6694703f398a.m4a"
复制这个url到浏览器另外窗口:

看到歌曲时间长短是 3:34,再对比页面上的时间也是一样的。

为了确保严谨性,点开复制的URL,所听音乐完全相同。所以可以判定所需要的URL就是这么来的。
再来看下面的参数:
经过多次请求,最终发现params和encSecKey每次都是不一样的。


csrf_token为空,因为我们没有登录。所以这个值为空。
小知识: 逆向过程中,看到请求参数是:enc、secret key、sign等字眼,基本都需要逆向。
到此,我们知道可以从参数作为入口去逆向。
小知识: 找到加密入口(找加密入口一般比较难)的方案目标:1,参数加密前什么样?2,怎么加密的?
找到加密入口的方案
第一种找加密入口:找浏览器的initiator(启动器)
如果通过抓包看到返回的数据被加密了。所以通过浏览器的initiator(启动器)找入口,就没有什么意义了。
这是下下策,不到万不得已不用此法。
它里面记录着浏览器执行js的过程( request(请求)、call(调用)、stack(栈) 。
类似下面的调用:
function fn_3(mmm){
加密...
$.ajax({}) // 发送ajax
return "我爱你"
}
function fn_2(abc){
xxxx
ret = fn_3(abc)
console.log(ret);
return "我不爱你"
}
function fn_1(){
xxxxx
我要上天....
fn_fn2()
}
<button onclick=fn_1()>播放</button>
上面就是堆栈的调用。比如点了播放按钮之后,v1?csrf_token 那个URL发生的JS请求调用过程(调用过程是从下往上调用,一直调用到最上面的时候,请求就发送出去了)。

一般来说,除了瑞数级别的,xxx.send这种请求太低层了,它相当于是发ajax请求的最后一关,除了瑞数级别的,一般没人在这个请求上搞事情。我们看到....send一般都是直接过,不用看。
第一个函数因为是 xxx.send,所以不用看了,直接看下一个 music-corona.min.js,点击它。

所以下图所示先找堆栈上面除了 ....send以外的第一个。如果没找到所需要的,就继续按照call stack的顺序往下找。
至于找什么?什么是需要的呢?也就是我们要找到参数中是有加密的数据,以及在什么地方加密的。

点击上面之后,进入下图所示界面,然后在所在行前面打断点。
注意:打完断点之后,不会自己运行,需要我们再次运行,才会断在这里。
在下图中有可能打断点会打不上,很多时候打不上断点很正常,解决办法是:在前面不远处(不能太前面哦,不能超过这个函数的范围)找地方打断点。


打上断点后,注意看右边的Breakpoints会自己打上勾。如果让JS代码再次运行的话,就会断在这里。
所以我们需要想办法让程序再次运行到这里。怎么样才能再次运行到这里?需要再次发送请求才会来到这里。怎么样发送请求?我们之前是点击了播放按钮,触发了一些请求,这些请求有一个调用了打断点的请求。所以我们再次点击播放按钮就可以了。

如果出现下面的特征,说明断点成功:

如果想看i(i在这里是一个函数),鼠标划中选中,再点进去然后可以看这个函数是什么。

选中变量,可以看到变量的值,如下所示:

同时,也可以在Console里面调式和查看变量的值:

断点:如果让JS代码可以运行到这里的话,就会断在这里。
var haha = 19999;
function fn(){
var an = 18;
function hehe(){
}
function gn(){
var bn = 999;
//断点 <--------如果断点断在这里,能够看到变量haha、an、bn的内容;hehe这个函数也可以执行。
hehe() //这个函数也可以用
}
}
// 一个断点的应用(改变当前的函数声明):
// 在前面设断点 -> setInterval = function(){} 然后让函数setInterval置空,这样就间接的处理了无限debugger
setInterval(function(){
debugger;
}, 1000)
断点的目的:
(1).断点可以查看当前这个位置你能使用到的所有变量的内容(内存中的)。
(2).断点可以查看当前位置可以执行的函数是什么? 以及函数执行之后的结果是什么?
(3).断点甚至可以改变当前位置的函数声明...
在断点状态下. 选择一个变量或者函数. 鼠标画上去. 看一下有什么东西。在断点状态下. 在console中输入一个变量或者函数. 来查看该函数或变量的内容。
断点的这个位置看一下下面的参数,由两部分组成:一个是params=,一个是ecKey=,因此可以断定程序执行到这里,已经被加密了。所以要往前找。

同时还可能在下面红框里面加密

由此需要在上图红框的地方做一个断点,看看数据有没有被加密,然后让程序重新运行。
本来断点位置在【i.apply。。。】的地方,现在断点位置要改到【var t = this。。。】的地方,只能让程序重新运行到【var t = this。。。】的地方。

先释放断点,如下:

一释放,就走到这了,说明这个函数应该是点击播放按钮触发了好多次请求,而这些好多个请求都执行了这个断点函数,才会从【i.apply。。。】又到【var t = this。。。】。

看看谁调用的这个函数,需要去看Call Stack。
注意Call Stack调用过程和执行过程是从下往上调用的,最上面一个就说最后一个调用。

如果没有加密,就继续找,再看看谁在调用这个函数了。往下依次点击Call Stack,在里面设断点,然后看变量params的值改了没有,是不是还是被加密的。

有时候调试,有时候会忘了断点位置在哪,可以在下图所示位置找到断点位置。点一下右侧Call Stack可以回到断点位置。

通过call stack可以查看上一步调用位置的参数, 数据, 内存, 函数 (可能会有风险, 问题不大).
但是不要去单步调试...可能会有问题...(尽可能在当前断点位置进行调试)。
再继续找,看到这个参数还是加密,说明还要继续往前找。这些断点就没用了,需要先把这些断点释放。再往前设置新的断点。
再往前找,我们就看这个params的值就可以了,看看有没有被加密。


当找到这个数据 data:"logs=...... 这明显不是加密过的。这里不是params,不是seckey,所以基本上可以锁定参数到这里的时候,还什么都没有,然后这里之后就加密了。

到这里基本找到了加密的地方了。

注意看下图的URL和我们请求的URL很类似。肯定有关系。


所以我们从这里开始,就需要看从哪里开始加密的。我们接下来要做的事情,就需要一行一行的往下走,一步一步调试,到底是哪一行代码加密的。这里就涉及到单步调试了。

单步调试: 让代码 一行一行的去执行. 看看到底是谁.把数据加密成的。
第一个, 释放断点: 让程序继续执行 -> 直到下一个断点位置或者运行完毕。
第二个, 下一步: 执行到下一行代码(不论当前行是否是函数调用. )。
第三个, step into: 向后走一步(如果有函数, 进入函数, 如果没函数或者是js原生的函数, 向后走一步)
当我们step into进入一个函数后,我想回去怎么办?一个方法是点击Step over next,让它执行完。另外一个方法是通过点击Call Stack也可以回去。

回去之后,在NEJ 函数之后设置一个断点。

再点一下Pause/Resume script execution按钮,释放了就回去了。

一般来说我们如果要清除所有断点,在BreakPoints的位置右键,然后使用下面的Remove all beeakpoints。或者如果想临时去掉的话,可以使用Disable all breakpoints。或者把勾去掉也行。

在我们逆向中,可能会有很多这类函数,发现某个函数.莫名其妙的被执行, 执行之后的结果貌似对原内容没有改变,可以认为该函数就是没用的..规避掉它。比如下面这个函数,很莫名其妙的不知道这个函数干嘛的,点进去后发现也不知道这个函数什么意思。



再看我们的URL和参数,看到是不是有一种豁然开朗的感觉。所以我们接下来要去观察一下这些参数是怎么变化的。

比如下面这行代码都还没有运行,接下来就要继续往后走

这里if判断,我们不用人工去读是真还是假,浏览器会告诉你,直接往后走下一步,看看能不能走到if里面来,能走进来就是真,走不进来就是假。

if有可能对我们的变量做修改,而我们关注的点应该是变量是否有变化。我们可以在执行if之前看看变量的值,执行if之后看看变量的值有没有变化。

同时还有另外一种观察变量值的方法:
在右侧Watch,点开加号,输入变量的值。

也能观察到变量值的变化

看到下面这个window.asrsea,注意这里参数准备完毕,要处理成字符串进行加密。

看到这种,基本可以确定是RSA加密。

跑一下后面的结果,发现和最终结果很相似了。


下图的函数,就是加密入口,终于找到我们所需要的东西了,点一下:

走到了d这个函数,也就是说,最终运行的是这个函数

我们再仔细看:这个函数被包裹起来了

再看最前面,可以看到是一个自运行函数

我们把这个自运行函数摘出来:
!function() {
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
}
function e(a, b, d, e) {
var f = {};
return f.encText = c(a + e, b, d),
f
}
window.asrsea = d,
window.ecnonasr = e
}();
注意: CryptoJS 是一个第三方库。
可以通过上面的信息,进一步处理JS代码。
接下来要做的是:调通d这个函数,能出跑正确的结果出来,就完成任务了。
先把d函数扣下来,跑起来试试:

然后发现这四个参数:d, e, f, g需要给。那接下来要找这四个参数,其实就是下面这几个。

如果用扣代码的方式(扣代码方式省略),当报错(如果不是扣代码方式没有这种报错) window is not defined 这里你用的是node环境. node里面没有window

解决办法:在node环境可以临时使用this来代替window。
var window = this;
可以看到下面这个参数在浏览器中是固定的,所以后面参数可以直接获取,如果是变化的,那么只能去扣代码了。




所以四个参数可以直接拿来用
let i0x = {
"csrf_token": "",
"encodeType": "aac",
"ids": "[1325905146]",
"level": "standard"
}
let r = d(JSON.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0CoJUm6Qyw8W8jud');
上面的参数准备好之后,放在pychar中运行,发现还是会报错(后续还是会报很多错,需要慢慢一点一点去调试):


报错这个a函数不存在,要想办法找到这个a函数,怎么找这个a函数呢?回到浏览器中,在a函数之前(在能使用到a函数的地方)设断点

然后放行:

然后鼠标划到a上,一点

然后a函数就出来了:

直接拷贝:

还有b函数不存在也会报错:


然后b函数扣代码:


补完b函数之后,再次运行。又报错:


提示:在在JS代码中看到了如下格式,它是一个第三方库,专门用来做AES、DES加密的,可以直接怼,就完事了。
CryptoJS.enc.Utf8.parse(b)
CryptoJS.enc.Utf8.parse("0102030405060708")
CryptoJS.enc.Utf8.parse(a)
CryptoJS.AES.encrypt(e, c, {
iv: d,
mode: CryptoJS.mode.CBC
})
安装第三方库:
注意:我们要在JS文件里引入第三方库,安装的库是JS库,不是python库。所以要遵守node 安装规则(python安装第三方库是pip,而node安装第三方库是npm)。
安装命令:
npm官方库搜索: https://www.npmjs.com/
注意:不是cryptojs (12 years ago ,那么老了,明显不是。)

搜索关键词是:crypto-js

点进去,然后可以看到安装命令:

可以用命令安装这个库,然后在所在项目的目录(一个项目安装一次,不要全局安装),输入下面的命令:
npm i crypto-js
然后怎么用?
var CryptoJS = require("crypto-js");
番外篇:如果遇到的是下面这种不是标准代码,怎么办?

回答:把 _.a 换成 CryptoJS 即可。
补完cryptojs环境之后,我们继续运行,发现又报错了,这个报错说明前面弄的cryptojs没问题了,但是c这个函数又得弄。

又来扣c函数的代码

下面这几个函数应该也会报错,所以要先找这几个函数

在网页断点去找:

点进去:

然后发现这些也需要去找:

类似这样的操作有很多,反正就是哪个缺少找哪个,此处就不再赘述。。。
下面是扣出来的完整的代码:
第一种方法扣出来的JS代码
// 引入你安装的第三方库 -> from xxxx improt xxxx
var CryptoJS = require("crypto-js");
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 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 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
} else
c.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 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 biModuloByRadixPower(a, b) {
var c = new BigInt;
return arrayCopy(a.digits, 0, c.digits, 0, b),
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 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 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 b(a, b) {
// 当你在js代码中看到了如下格式... 它是一个第三方库...
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 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 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 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 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
}
function biToHex(a) {
var d, b = "";
for (biHighIndex(a),
d = biHighIndex(a); d > -1; --d)
b += digitToHex(a.digits[d]);
return b
}
function c(a, b, c) {
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b,"",c),
e = encryptedString(d, a)
}
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 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 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 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 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 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 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 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
}
// 本地做测试, window is not defined 这里你用的是node环境. node里面没有window
let i0x = {
"csrf_token": "",
"encodeType": "aac",
"ids": "[1325905146]",
"level": "standard"
}
let r = d(JSON.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0CoJUm6Qyw8W8jud');
console.log(r);
总结一些前面用到的网页逆向过程中扣代码方法:
找到入口. 把入口拿下来. 尝试着一个函数一个函数的去填补..
过程非常曲折...直到 最终的结果产生. 并且和你的预期相符...当没有其他思路的时候,这是最low的一种方案,最下下策的方案。
另外一种用到的网页逆向过程中扣代码方法:找到代码的边界,就可以把边界的代码抠出来。
一般来说,这些边界是:
(1)一个大闭包。
(2)两个闭包之间。
这些边界肯定是具有相似性(需要 人为的去判别)。
比如下图就是一个边界:
到了12852没有了这个缩进。很明显上面12851是一个自运行函数。然后下面的函数12852、12860、12863是一个级别的。

所以就可以从上开始,一直拉到下图的位置13275,13275是一个自运行函数,是一个边界。 所以13274前面如果要扣代码的话,就一直扣到13274为止。

下面是第二种扣代码的方法:找到代码的边界,就可以把边界的代码抠出来。
回到我们JS代码开始阶段,第二次扣代码,也是找到程序的入口(找入口的方法不再赘述),然后点进去:

也是直接跳到d这个函数这里了。
观察到d这个函数用到的b、c等都是在同一个边界里面。

所以找到最上面的边界:

一直到下面的边界,都拷贝过去:

第二种找加密入口:在search中进行搜索
注意:没有百分之百的方案. 又快, 有准确. 没有。只能是各种尝试。
首先第一步找到Search(是在Sources里面所有东西的搜索)

但是我们在search搜索什么?有下面几个东西可以考虑:
找加密入口:在search中进行搜索方案(1)在URL上进行搜索。
来看看我们URL

如果使用URL全名(即:https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=)去搜,大概率是搜不到的。
使用搜参数最好的方式是:找到问号之前(也就是 ?csrf_token= 前面的内容),比如:先去搜 v1 (一般搜一个词的话大概率不这样做的,因为结果太多了,起不到搜索的效果了)所以一般搜索 url/v1 再这样搜: player/url/v1 然后再一个词一个词追加着搜。

然后我们就找到这样的内容:

搜索出来结果之后,还需拿到 api/song/enhance/player/url/v1 再搜索一次,还要看看有多少个。因为第一次搜索出来的内容是一个压缩的代码,就一行,所以可能说有好好多地方是符合这个内容的,但是第一次搜索出来的内容就看到一条,所以就会以为有一条。所以再次搜索可以锁定到底有多少个内容

或者该url中某些看着比较特殊的单词. 也可以单独搜索,比如 enhance 。
通过搜索enhance 单词,也可以搜索到:

但是另外一个就不是,注意分辨。

找加密入口:在search中进行搜索方案(2)搜参数,请求上的各种参数(主要针对加密参数)。
经验之谈:搜索JSON.stringify很难,因为太多了。
比如搜索参数:encSecKey

找加密入口:在search中进行搜索方案(3)搜拦截器,前提是该网站使用的是异步,使用promise才行。
通过前面搜索到结果后,然后在前面打断点,打完断点之后可以看看它是什么意思,这个函数在干啥,有啥参数。

然后点击播放:

然后就停在这了,划上选中,然后点击函数进入。

进入之后,再打一个断点,再点击Step over next 按钮继续走:

然后就找到我们加密的入口了。

自此,通过搜索的方法以及达到目的。
接下来介绍一下在python中完成网易云音乐的下载
首先准备一下前面扣好的JS代码,需要将可变部分,也就是歌曲的ID,把调用的代码封装函数的形式,方便代码调用:
let i0x = {
"csrf_token": "",
"encodeType": "aac",
"ids": "[1325905146]",
"level": "standard"
}
let r = d(JSON.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0CoJUm6Qyw8W8jud');
console.log(r);
改为:
let i0x = {
"csrf_token": "",
"encodeType": "aac",
"ids": "[1325905146]",
"level": "standard"
}
function fn(i0x){
return d(JSON.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0CoJUm6Qyw8W8jud');
}
所以修改后的JS代码为:
网易云.js
// 网易云....
// 免费歌曲...付费不管. vip的不管...
// https://music.163.com/#/song?id=1325905146
// 引入你安装的第三方库 -> from xxxx improt xxxx
var CryptoJS = require("crypto-js");
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 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 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
} else
c.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 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 biModuloByRadixPower(a, b) {
var c = new BigInt;
return arrayCopy(a.digits, 0, c.digits, 0, b),
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 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 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 b(a, b) {
// 当你在js代码中看到了如下格式... 它是一个第三方库...
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 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 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 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 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
}
function biToHex(a) {
var d, b = "";
for (biHighIndex(a),
d = biHighIndex(a); d > -1; --d)
b += digitToHex(a.digits[d]);
return b
}
function c(a, b, c) {
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b,"",c),
e = encryptedString(d, a)
}
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 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 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 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 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 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 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 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
}
// 本地做测试, window is not defined 这里你用的是node环境. node里面没有window
let i0x = {
"csrf_token": "",
"encodeType": "aac",
"ids": "[1325905146]",
"level": "standard"
}
function fn(i0x){
return d(JSON.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0CoJUm6Qyw8W8jud');
}
Python代码如下:
# 在python中完成网易云音乐的下载
from functools import partial # 锁定参数
import subprocess
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
import execjs
import requests
url = "https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token="
data = {
"csrf_token": "",
"encodeType": "aac",
"ids": "[1325905146]",
"level": "standard"
}
# 把参数进行加密. 得到密文. 发请求
f = open("网易云.js", mode="r", encoding="utf-8")
js_code = f.read()
f.close()
js = execjs.compile(js_code)
mi = js.call("fn", data)
# print(mi) print(type(mi))
resp = requests.post(url, data={
"params": mi['encText'],
"encSecKey": mi['encSecKey']
}, headers={
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
})
song_url = resp.json()['data'][0]['url']
# print(song_url)
song_resp = requests.get(song_url, headers={
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
})
with open('mymusic.m4a', mode="wb") as f:
f.write(song_resp.content)
网易的加密逻辑:
1.明文
2.生成一个随机值() => i
3.对明文进行AES加密 => 固定秘钥 => g => 结果: encText
4.对encText进行AES加密 => 不固定的秘钥 => i => 结果: encText => params
5.对变量i进行rsa加密. => 密文 => encSecKey
服务器:
拿到的参数有: params, encSecKey
encSecKey => rsa解密 => i
对params 进行AES解密(i) => encText
对encText 进行AES解密(g) => 明文
浙公网安备 33010602011771号