下载网易云音乐音频案例

只爬免费歌曲,付费和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) => 明文

posted @ 2023-07-28 20:44  屠魔的少年  阅读(6)  评论(0)    收藏  举报