初识javascript逆向——以网易云音乐和招标网站为例-kb88凯时官网登录

时间:2024-03-01
阅读:

我们平常在浏览网站的时候会看到许多加密的参数,如果需要知道它的原始数据,就需要知道整个加密过程,所以本篇文章就来介绍一下本人在初学逆向的时候一些笔记。
想要获取加密过程大概来说有以下两个方法:
(1)通过浏览器的initiator中的栈调用来判断,因为initiator里面记录着浏览器执行javascript的过程。
(2)在search中搜索关键字,例如url中的一些路径或者加密参数。
下面通过两个案例来进行讲解。

url地址:
按f12,打开浏览器的开发者工具,切换到network模块,在界面上点击播放按钮,会产生数据。
初识javascript逆向——以网易云音乐和招标网站为例
一条一条数据进行查看,找到该首音乐的具体下载url地址是哪个。查看每一个流量的响应包,看看哪个流量的响应包中带有下载地址,这里在如下的数据包中找到(本文将该数据包的url地址记为music_url,方便文章的续写)。
初识javascript逆向——以网易云音乐和招标网站为例
看到url的后缀是m4a,熟悉音乐格式的都知道这是个音频文件的扩展名,复制该url地址,确认一下是否可以通过该url地址进行下载。
初识javascript逆向——以网易云音乐和招标网站为例
确实可以,但是我们可以看到界面的传参和流量包的传参不一致。
初识javascript逆向——以网易云音乐和招标网站为例
这大概率就是在请求的时候把我们的传参进行了加密,我们这里的目标就是去知道整个加密过程,并且通过python代码将音乐下载下来。
介绍两种方法。

通过initiator找到加密过程

选中music_url,切换到initiator。
初识javascript逆向——以网易云音乐和招标网站为例
栈的特点是先进后出,所以initiator中从上至下就是计算机底层调用函数的过程,最下面的最先调用。点击最后一个调用的地方。
初识javascript逆向——以网易云音乐和招标网站为例
跳转到如下的地方。
初识javascript逆向——以网易云音乐和招标网站为例
这就说明点击播放的时候,是肯定会触发该地方的,所以在这行代码打断点。只需要在该行的前面点击一下,看到变蓝了即可。
初识javascript逆向——以网易云音乐和招标网站为例
再次点击播放,就可以看到停在打断点的这个地方了。
初识javascript逆向——以网易云音乐和招标网站为例
这里要特别关注右侧的call stack,这就是函数调用的过程。我们将鼠标移动到arguments上,就可以看到该变量的值。
初识javascript逆向——以网易云音乐和招标网站为例
或者在console里面输入arguments来查看。
初识javascript逆向——以网易云音乐和招标网站为例
发现这个参数还是加密的,所以此处就不是加密的过程,根据call stack继续往下查找。
初识javascript逆向——以网易云音乐和招标网站为例
看该行代码的参数。
初识javascript逆向——以网易云音乐和招标网站为例
还是加密的,继续往下找。直到执行到如下处,出现了明文。
初识javascript逆向——以网易云音乐和招标网站为例
在该函数的上面都是密文,执行到该函数才是明文,说明该函数的上一个函数就是加密的过程了,着重看一下。
初识javascript逆向——以网易云音乐和招标网站为例
下面代码就是整个参数加密的过程。
初识javascript逆向——以网易云音乐和招标网站为例
查看"x6r"和"e6c"这两个参数的值。
初识javascript逆向——以网易云音乐和招标网站为例
参数是加密后的,但是这个url地址好像不是music_url,所在我们在该函数的开始设置断点。
初识javascript逆向——以网易云音乐和招标网站为例
这里要介绍下调试的三个按钮。最左边的那个按钮的作用是让程序继续执行,直到下一个断点位置或者运行完毕;中间那个按钮的作用是执行到下一行代码(不论当前行是否是函数调用);最右边的那个按钮的作用是向后走一步(如果有函数,进入函数;如果没函数或者是javascript原生函数,向后走一步)。
初识javascript逆向——以网易云音乐和招标网站为例
点击最左边的按钮,看"x6r"的值。
初识javascript逆向——以网易云音乐和招标网站为例
还是不对,继续放。再放了两次之后,发现"x6r"的值发生了变化。
初识javascript逆向——以网易云音乐和招标网站为例
跟music_url进行比较,非常相似。
初识javascript逆向——以网易云音乐和招标网站为例
"e6c"的值也发生了变化,出现了明文。
初识javascript逆向——以网易云音乐和招标网站为例
这就对了,这时就需要一步一步往下跟,看看是如何加密的,点击中间那个按钮。在执行到如下代码之前,参数还是明文。
初识javascript逆向——以网易云音乐和招标网站为例
执行完该行代码,参数就被加密了,说明加密过程就在这行代码上。(其实看到json.stringify函数,就可以猜测加密过程99%在这里)
初识javascript逆向——以网易云音乐和招标网站为例
着重看下该行代码。
var bvi7b = window.asrsea(json.stringify(i6c), bsu6o(["流泪", "强"]), bsu6o(xo0x.md), bsu6o(["爱心", "女孩", "惊恐", "大笑"]));
有四个参数,console输出一下看看每个参数的值是什么。
初识javascript逆向——以网易云音乐和招标网站为例
后面三个参数都是固定的,最前面那个参数的ids就是歌的id号了,也就是url地址栏中显示的参数。再看下window.asrsea是如何实现的,鼠标移动到函数上面,会有location提示。
初识javascript逆向——以网易云音乐和招标网站为例
点进去定位到如下函数。
初识javascript逆向——以网易云音乐和招标网站为例
该函数中调用了a、b、c三个函数,就在d函数的上面。
初识javascript逆向——以网易云音乐和招标网站为例
找到加密过程了,接下来我们只需要把加密过程的相关函数扒下来即可。

这里介绍下如何抠代码
(1)找到入口,把入口拿下来,尝试着一个函数一个函数的去填补。过程非常曲折,直到最终的结果产生,并且和你的预期相符
(2)找到代码的边界
(3)直接找第三方库(这个需要经验)

第一种抠代码方法

先介绍一下cryptojs库,这个库是javascript中的一个跟加密相关的库。需要在npmd88尊龙官网手机app官网上进行下载。
npmd88尊龙官网手机app官网:
搜索"crypto-js",第一个就是。
初识javascript逆向——以网易云音乐和招标网站为例
点进去,复制安装命令即可。
初识javascript逆向——以网易云音乐和招标网站为例
由于默认的下载源在国外,下载速度慢,所以这里需要对其进行换源。找到个人主目录下的.npmrc文件,用记事本打开,添加上如下代码。如果没有该文件,就创建一个。

点击查看代码
registry=http://registry.npmmirror.com/
disturl=https://registry.npmmirror.com/-/binary/node/
# node-sass预编译二进制文件下载地址
sass_binary_site=https://registry.npmmirror.com/-/binary/node-sass
# sharp预编译共享库, 截止2022-09-20 sharp@0.31.0的预编译共享库并未同步到镜像, 入安装失败可切换到sharp@0.30.7使用
sharp_libvips_binary_host=https://registry.npmmirror.com/-/binary/sharp-libvips
python_mirror=https://registry.npmmirror.com/-/binary/python/
electron_mirror=https://registry.npmmirror.com/-/binary/electron/
electron_builder_binaries_mirror=https://registry.npmmirror.com/-/binary/electron-builder-binaries/
# 无特殊配置参考{pkg-name}_binary_host_mirror={mirror}
canvas_binary_host_mirror=https://registry.npmmirror.com/-/binary/canvas
node_sqlite3_binary_host_mirror=https://registry.npmmirror.com/-/binary/sqlite3
better_sqlite3_binary_host_mirror=https://registry.npmmirror.com/-/binary/better-sqlite3

添加完成之后,保存文件,打开终端,输入安装命令。如果出现如下错误,就说明是权限问题。
初识javascript逆向——以网易云音乐和招标网站为例
只需要将下载目录所有用户的权限打开即可。
初识javascript逆向——以网易云音乐和招标网站为例
再执行安装命令,安装成功。
初识javascript逆向——以网易云音乐和招标网站为例
安装成功后,会出现如下的一个文件夹和两个文件。(不要删除)
初识javascript逆向——以网易云音乐和招标网站为例
如果想在js文件中引入crypto-js库,只需写上一句代码即可。
var cryptojs = require("crypto-js")
接下来就是抠代码了,只需要将加密过程的相关函数全部扒下来即可,如果提示没有哪个函数,再去源代码中找即可。下面是完整的代码。

点击查看代码
var cryptojs = require("crypto-js");
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
}
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 bigint(a) {
    this.digits = "boolean" == typeof a && 1 == a ? null : zero_array.slice(0),
    this.isneg = !1
}
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 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 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 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 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 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 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 bidivide(a, b) {
    return bidividemodulo(a, b)[0]
}
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 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 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 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 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 reversestr(a) {
    var c, b = "";
    for (c = a.length - 1; c > -1; --c)
        b  = a.charat(c);
    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 bitohex(a) {
    var d, b = "";
    for (bihighindex(a),
    d = bihighindex(a); d > -1; --d)
        b  = digittohex(a.digits[d]);
    return b
}
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 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) {
    // 当你在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 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 is not defined 这里你用的是node环境,node里面没有window
let i0x = {
    "csrf_token": "",
    "encodetype": "aac",
    "ids": "[1325905146]",
    "level": "standard",
};
var res = d(json.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0cojum6qyw8w8jud');
console.log(res);
// function fn(i0x) {
//     return d(json.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0cojum6qyw8w8jud');
// }

运行结果如下,这就说明我们找到的加密代码是没有问题的。
初识javascript逆向——以网易云音乐和招标网站为例
接下来通过python代码来调用javascript代码实现下载。

点击查看代码
# 在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)
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/122.0.0.0 safari/537.36"})
song_url = resp.json()['data'][0]['url']
print(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/122.0.0.0 safari/537.36"})
with open("mymusic.m4a", mode="wb") as f:
    f.write(song_resp.content)

第二种抠代码方法

注意到d函数其实是位于一个自运行函数内的。
初识javascript逆向——以网易云音乐和招标网站为例
所以可以直接把这一块代码复制下来。再看c函数调用的setmaxdigits函数的位置。
初识javascript逆向——以网易云音乐和招标网站为例
其他函数都是跟setmaxdigits函数平行的,所以往上翻翻。
初识javascript逆向——以网易云音乐和招标网站为例
89行上面是一个函数的结束。
初识javascript逆向——以网易云音乐和招标网站为例
90行下面是一个自运行函数的开始。
初识javascript逆向——以网易云音乐和招标网站为例
所以这中间的代码就可以一块复制下来。

点击查看代码

function rsakeypair(a, b, c) {
    this.e = bifromhex(a),
    this.d = bifromhex(b),
    this.m = bifromhex(c),
    this.chunksize = 2 * bihighindex(this.m),
    this.radix = 16,
    this.barrett = new barrettmu(this.m)
}
function twodigit(a) {
    return (10 > a ? "0" : "")   string(a)
}
function encryptedstring(a, b) {
    for (var f, g, h, i, j, k, l, c = new array, d = b.length, e = 0; d > e; )
        c[e] = b.charcodeat(e),
        e  ;
    for (; 0 != c.length % a.chunksize; )
        c[e  ] = 0;
    for (f = c.length,
    g = "",
    e = 0; f > e; e  = a.chunksize) {
        for (j = new bigint,
        h = 0,
        i = e; i < e   a.chunksize;   h)
            j.digits[h] = c[i  ],
            j.digits[h]  = c[i  ] << 8;
        k = a.barrett.powmod(j, a.e),
        l = 16 == a.radix ? bitohex(k) : bitostring(k, a.radix),
        g  = l   " "
    }
    return g.substring(0, g.length - 1)
}
function decryptedstring(a, b) {
    var e, f, g, h, c = b.split(" "), d = "";
    for (e = 0; e < c.length;   e)
        for (h = 16 == a.radix ? bifromhex(c[e]) : bifromstring(c[e], a.radix),
        g = a.barrett.powmod(h, a.d),
        f = 0; f <= bihighindex(g);   f)
            d  = string.fromcharcode(255 & g.digits[f], g.digits[f] >> 8);
    return 0 == d.charcodeat(d.length - 1) && (d = d.substring(0, d.length - 1)),
    d
}
function setmaxdigits(a) {
    maxdigits = a,
    zero_array = new array(maxdigits);
    for (var b = 0; b < zero_array.length; b  )
        zero_array[b] = 0;
    bigzero = new bigint,
    bigone = new bigint,
    bigone.digits[0] = 1
}
function bigint(a) {
    this.digits = "boolean" == typeof a && 1 == a ? null : zero_array.slice(0),
    this.isneg = !1
}
function bifromdecimal(a) {
    for (var d, e, f, b = "-" == a.charat(0), c = b ? 1 : 0; c < a.length && "0" == a.charat(c); )
          c;
    if (c == a.length)
        d = new bigint;
    else {
        for (e = a.length - c,
        f = e % dpl10,
        0 == f && (f = dpl10),
        d = bifromnumber(number(a.substr(c, f))),
        c  = f; c < a.length; )
            d = biadd(bimultiply(d, lr10), bifromnumber(number(a.substr(c, dpl10)))),
            c  = dpl10;
        d.isneg = b
    }
    return d
}
function bicopy(a) {
    var b = new bigint(!0);
    return b.digits = a.digits.slice(0),
    b.isneg = a.isneg,
    b
}
function bifromnumber(a) {
    var c, b = new bigint;
    for (b.isneg = 0 > a,
    a = math.abs(a),
    c = 0; a > 0; )
        b.digits[c  ] = a & maxdigitval,
        a >>= biradixbits;
    return b
}
function reversestr(a) {
    var c, b = "";
    for (c = a.length - 1; c > -1; --c)
        b  = a.charat(c);
    return b
}
function bitostring(a, b) {
    var d, e, c = new bigint;
    for (c.digits[0] = b,
    d = bidividemodulo(a, c),
    e = hexatrigesimaltochar[d[1].digits[0]]; 1 == bicompare(d[0], bigzero); )
        d = bidividemodulo(d[0], c),
        digit = d[1].digits[0],
        e  = hexatrigesimaltochar[d[1].digits[0]];
    return (a.isneg ? "-" : "")   reversestr(e)
}
function bitodecimal(a) {
    var c, d, b = new bigint;
    for (b.digits[0] = 10,
    c = bidividemodulo(a, b),
    d = string(c[1].digits[0]); 1 == bicompare(c[0], bigzero); )
        c = bidividemodulo(c[0], b),
        d  = string(c[1].digits[0]);
    return (a.isneg ? "-" : "")   reversestr(d)
}
function digittohex(a) {
    var b = 15
      , c = "";
    for (i = 0; 4 > i;   i)
        c  = hextochar[a & b],
        a >>>= 4;
    return reversestr(c)
}
function bitohex(a) {
    var d, b = "";
    for (bihighindex(a),
    d = bihighindex(a); d > -1; --d)
        b  = digittohex(a.digits[d]);
    return b
}
function chartohex(a) {
    var h, b = 48, c = b   9, d = 97, e = d   25, f = 65, g = 90;
    return h = a >= b && c >= a ? a - b : a >= f && g >= a ? 10   a - f : a >= d && e >= a ? 10   a - d : 0
}
function hextodigit(a) {
    var d, b = 0, c = math.min(a.length, 4);
    for (d = 0; c > d;   d)
        b <<= 4,
        b |= chartohex(a.charcodeat(d));
    return b
}
function bifromhex(a) {
    var d, e, b = new bigint, c = a.length;
    for (d = c,
    e = 0; d > 0; d -= 4,
      e)
        b.digits[e] = hextodigit(a.substr(math.max(d - 4, 0), math.min(d, 4)));
    return b
}
function bifromstring(a, b) {
    var g, h, i, j, c = "-" == a.charat(0), d = c ? 1 : 0, e = new bigint, f = new bigint;
    for (f.digits[0] = 1,
    g = a.length - 1; g >= d; g--)
        h = a.charcodeat(g),
        i = chartohex(h),
        j = bimultiplydigit(f, i),
        e = biadd(e, j),
        f = bimultiplydigit(f, b);
    return e.isneg = c,
    e
}
function bidump(a) {
    return (a.isneg ? "-" : "")   a.digits.join(" ")
}
function biadd(a, b) {
    var c, d, e, f;
    if (a.isneg != b.isneg)
        b.isneg = !b.isneg,
        c = bisubtract(a, b),
        b.isneg = !b.isneg;
    else {
        for (c = new bigint,
        d = 0,
        f = 0; f < a.digits.length;   f)
            e = a.digits[f]   b.digits[f]   d,
            c.digits[f] = 65535 & e,
            d = number(e >= biradix);
        c.isneg = a.isneg
    }
    return c
}
function bisubtract(a, b) {
    var c, d, e, f;
    if (a.isneg != b.isneg)
        b.isneg = !b.isneg,
        c = biadd(a, b),
        b.isneg = !b.isneg;
    else {
        for (c = new bigint,
        e = 0,
        f = 0; f < a.digits.length;   f)
            d = a.digits[f] - b.digits[f]   e,
            c.digits[f] = 65535 & d,
            c.digits[f] < 0 && (c.digits[f]  = biradix),
            e = 0 - number(0 > d);
        if (-1 == e) {
            for (e = 0,
            f = 0; f < a.digits.length;   f)
                d = 0 - c.digits[f]   e,
                c.digits[f] = 65535 & d,
                c.digits[f] < 0 && (c.digits[f]  = biradix),
                e = 0 - number(0 > d);
            c.isneg = !a.isneg
        } else
            c.isneg = a.isneg
    }
    return c
}
function bihighindex(a) {
    for (var b = a.digits.length - 1; b > 0 && 0 == a.digits[b]; )
        --b;
    return b
}
function binumbits(a) {
    var e, b = bihighindex(a), c = a.digits[b], d = (b   1) * bitsperdigit;
    for (e = d; e > d - bitsperdigit && 0 == (32768 & c); --e)
        c <<= 1;
    return e
}
function bimultiply(a, b) {
    var d, h, i, k, c = new bigint, e = bihighindex(a), f = bihighindex(b);
    for (k = 0; f >= k;   k) {
        for (d = 0,
        i = k,
        j = 0; e >= j;   j,
          i)
            h = c.digits[i]   a.digits[j] * b.digits[k]   d,
            c.digits[i] = h & maxdigitval,
            d = h >>> biradixbits;
        c.digits[k   e   1] = d
    }
    return c.isneg = a.isneg != b.isneg,
    c
}
function bimultiplydigit(a, b) {
    var c, d, e, f;
    for (result = new bigint,
    c = bihighindex(a),
    d = 0,
    f = 0; c >= f;   f)
        e = result.digits[f]   a.digits[f] * b   d,
        result.digits[f] = e & maxdigitval,
        d = e >>> biradixbits;
    return result.digits[1   c] = d,
    result
}
function arraycopy(a, b, c, d, e) {
    var g, h, f = math.min(b   e, a.length);
    for (g = b,
    h = d; f > g;   g,
      h)
        c[h] = a[g]
}
function bishiftleft(a, b) {
    var e, f, g, h, c = math.floor(b / bitsperdigit), d = new bigint;
    for (arraycopy(a.digits, 0, d.digits, c, d.digits.length - c),
    e = b % bitsperdigit,
    f = bitsperdigit - e,
    g = d.digits.length - 1,
    h = g - 1; g > 0; --g,
    --h)
        d.digits[g] = d.digits[g] << e & maxdigitval | (d.digits[h] & highbitmasks[e]) >>> f;
    return d.digits[0] = d.digits[g] << e & maxdigitval,
    d.isneg = a.isneg,
    d
}
function bishiftright(a, b) {
    var e, f, g, h, c = math.floor(b / bitsperdigit), d = new bigint;
    for (arraycopy(a.digits, c, d.digits, 0, a.digits.length - c),
    e = b % bitsperdigit,
    f = bitsperdigit - e,
    g = 0,
    h = g   1; g < d.digits.length - 1;   g,
      h)
        d.digits[g] = d.digits[g] >>> e | (d.digits[h] & lowbitmasks[e]) << f;
    return d.digits[d.digits.length - 1] >>>= e,
    d.isneg = a.isneg,
    d
}
function bimultiplybyradixpower(a, b) {
    var c = new bigint;
    return arraycopy(a.digits, 0, c.digits, b, c.digits.length - b),
    c
}
function bidividebyradixpower(a, b) {
    var c = new bigint;
    return arraycopy(a.digits, b, c.digits, 0, c.digits.length - b),
    c
}
function bimodulobyradixpower(a, b) {
    var c = new bigint;
    return arraycopy(a.digits, 0, c.digits, 0, b),
    c
}
function bicompare(a, b) {
    if (a.isneg != b.isneg)
        return 1 - 2 * number(a.isneg);
    for (var c = a.digits.length - 1; c >= 0; --c)
        if (a.digits[c] != b.digits[c])
            return a.isneg ? 1 - 2 * number(a.digits[c] > b.digits[c]) : 1 - 2 * number(a.digits[c] < b.digits[c]);
    return 0
}
function bidividemodulo(a, b) {
    var f, g, h, i, j, k, l, m, n, o, p, q, r, s, c = binumbits(a), d = binumbits(b), e = b.isneg;
    if (d > c)
        return a.isneg ? (f = bicopy(bigone),
        f.isneg = !b.isneg,
        a.isneg = !1,
        b.isneg = !1,
        g = bisubtract(b, a),
        a.isneg = !0,
        b.isneg = e) : (f = new bigint,
        g = bicopy(a)),
        new array(f,g);
    for (f = new bigint,
    g = a,
    h = math.ceil(d / bitsperdigit) - 1,
    i = 0; b.digits[h] < bihalfradix; )
        b = bishiftleft(b, 1),
          i,
          d,
        h = math.ceil(d / bitsperdigit) - 1;
    for (g = bishiftleft(g, i),
    c  = i,
    j = math.ceil(c / bitsperdigit) - 1,
    k = bimultiplybyradixpower(b, j - h); -1 != bicompare(g, k); )
          f.digits[j - h],
        g = bisubtract(g, k);
    for (l = j; l > h; --l) {
        for (m = l >= g.digits.length ? 0 : g.digits[l],
        n = l - 1 >= g.digits.length ? 0 : g.digits[l - 1],
        o = l - 2 >= g.digits.length ? 0 : g.digits[l - 2],
        p = h >= b.digits.length ? 0 : b.digits[h],
        q = h - 1 >= b.digits.length ? 0 : b.digits[h - 1],
        f.digits[l - h - 1] = m == p ? maxdigitval : math.floor((m * biradix   n) / p),
        r = f.digits[l - h - 1] * (p * biradix   q),
        s = m * biradixsquared   (n * biradix   o); r > s; )
            --f.digits[l - h - 1],
            r = f.digits[l - h - 1] * (p * biradix | q),
            s = m * biradix * biradix   (n * biradix   o);
        k = bimultiplybyradixpower(b, l - h - 1),
        g = bisubtract(g, bimultiplydigit(k, f.digits[l - h - 1])),
        g.isneg && (g = biadd(g, k),
        --f.digits[l - h - 1])
    }
    return g = bishiftright(g, i),
    f.isneg = a.isneg != e,
    a.isneg && (f = e ? biadd(f, bigone) : bisubtract(f, bigone),
    b = bishiftright(b, i),
    g = bisubtract(b, g)),
    0 == g.digits[0] && 0 == bihighindex(g) && (g.isneg = !1),
    new array(f,g)
}
function bidivide(a, b) {
    return bidividemodulo(a, b)[0]
}
function bimodulo(a, b) {
    return bidividemodulo(a, b)[1]
}
function bimultiplymod(a, b, c) {
    return bimodulo(bimultiply(a, b), c)
}
function bipow(a, b) {
    for (var c = bigone, d = a; ; ) {
        if (0 != (1 & b) && (c = bimultiply(c, d)),
        b >>= 1,
        0 == b)
            break;
        d = bimultiply(d, d)
    }
    return c
}
function bipowmod(a, b, c) {
    for (var d = bigone, e = a, f = b; ; ) {
        if (0 != (1 & f.digits[0]) && (d = bimultiplymod(d, e, c)),
        f = bishiftright(f, 1),
        0 == f.digits[0] && 0 == bihighindex(f))
            break;
        e = bimultiplymod(e, e, c)
    }
    return d
}
function barrettmu(a) {
    this.modulus = bicopy(a),
    this.k = bihighindex(this.modulus)   1;
    var b = new bigint;
    b.digits[2 * this.k] = 1,
    this.mu = bidivide(b, this.modulus),
    this.bkplus1 = new bigint,
    this.bkplus1.digits[this.k   1] = 1,
    this.modulo = barrettmu_modulo,
    this.multiplymod = barrettmu_multiplymod,
    this.powmod = barrettmu_powmod
}
function barrettmu_modulo(a) {
    var i, b = bidividebyradixpower(a, this.k - 1), c = bimultiply(b, this.mu), d = bidividebyradixpower(c, this.k   1), e = bimodulobyradixpower(a, this.k   1), f = bimultiply(d, this.modulus), g = bimodulobyradixpower(f, this.k   1), h = bisubtract(e, g);
    for (h.isneg && (h = biadd(h, this.bkplus1)),
    i = bicompare(h, this.modulus) >= 0; i; )
        h = bisubtract(h, this.modulus),
        i = bicompare(h, this.modulus) >= 0;
    return h
}
function barrettmu_multiplymod(a, b) {
    var c = bimultiply(a, b);
    return this.modulo(c)
}
function barrettmu_powmod(a, b) {
    var d, e, c = new bigint;
    for (c.digits[0] = 1,
    d = a,
    e = b; ; ) {
        if (0 != (1 & e.digits[0]) && (c = this.multiplymod(c, d)),
        e = bishiftright(e, 1),
        0 == e.digits[0] && 0 == bihighindex(e))
            break;
        d = this.multiplymod(d, d)
    }
    return c
}
var maxdigits, zero_array, bigzero, bigone, dpl10, lr10, hexatrigesimaltochar, hextochar, highbitmasks, lowbitmasks, biradixbase = 2, biradixbits = 16, bitsperdigit = biradixbits, biradix = 65536, bihalfradix = biradix >>> 1, biradixsquared = biradix * biradix, maxdigitval = biradix - 1, maxinteger = 9999999999999998;
setmaxdigits(20),
dpl10 = 15,
lr10 = bifromnumber(1e15),
hexatrigesimaltochar = new array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"),
hextochar = new array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"),
highbitmasks = new array(0,32768,49152,57344,61440,63488,64512,65024,65280,65408,65472,65504,65520,65528,65532,65534,65535),
lowbitmasks = new array(0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535);
var cryptojs = require("crypto-js");
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
}
    let i0x = {
    "csrf_token": "",
    "encodetype": "aac",
    "ids": "[1325905146]",
    "level": "standard",
};
let r = d(json.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0cojum6qyw8w8jud');
console.log(r);

运行结果和第一种方法运行出来的结果是一致的。
初识javascript逆向——以网易云音乐和招标网站为例
python的代码跟第一种方法处一致,就不重复写了。

第三种抠代码方法

看到c函数中调用的setmaxdigits、rsakeypair和encryptedstring三个函数,有经验的人就可以猜测大概率是rsa加密,它的相关加密过程可以直接从一个网站上复制。
url地址:
打开界面,将如下三个链接中的代码完全复制进一个js文件中即可。
初识javascript逆向——以网易云音乐和招标网站为例
js文件代码:

点击查看代码
var cryptojs = require("crypto-js");
// bigint, a suite of routines for performing multiple-precision arithmetic in
// javascript.
//
// d88尊龙官网手机app copyright 1998-2005 david shapiro.
//
// you may use, re-use, abuse,
// copy, and modify this code to your liking, but please keep this header.
// thanks!
//
// dave shapiro
// dave@ohdave.com
// important thing: be sure to set maxdigits according to your precision
// needs. use the setmaxdigits() function to do this. see comments below.
//
// tweaked by ian bunning
// alterations:
// fix bug in function bifromhex(s) to allow
// parsing of strings of length != 0 (mod 4)
// changes made by dave shapiro as of 12/30/2004:
//
// the bigint() constructor doesn't take a string anymore. if you want to
// create a bigint from a string, use bifromdecimal() for base-10
// representations, bifromhex() for base-16 representations, or
// bifromstring() for base-2-to-36 representations.
//
// bifromarray() has been removed. use bicopy() instead, passing a bigint
// instead of an array.
//
// the bigint() constructor now only constructs a zeroed-out array.
// alternatively, if you pass , it won't construct any array. see the
// bicopy() method for an example of this.
//
// be sure to set maxdigits depending on your precision needs. the default
// zeroed-out array zero_array is constructed inside the setmaxdigits()
// function. so use this function to set the variable. don't just set the
// value. use the function.
//
// zero_array exists to hopefully speed up construction of bigints(). by
// precalculating the zero array, we can just use slice(0) to make copies of
// it. presumably this calls faster native code, as opposed to setting the
// elements one at a time. i have not done any timing tests to verify this
// claim.
// max number = 10^16 - 2 = 9999999999999998;
//               2^53     = 9007199254740992;
var biradixbase = 2;
var biradixbits = 16;
var bitsperdigit = biradixbits;
var biradix = 1 << 16; // = 2^16 = 65536
var bihalfradix = biradix >>> 1;
var biradixsquared = biradix * biradix;
var maxdigitval = biradix - 1;
var maxinteger = 9999999999999998;
// maxdigits:
// change this to accommodate your largest number size. use setmaxdigits()
// to change it!
//
// in general, if you're working with numbers of size n bits, you'll need 2*n
// bits of storage. each digit holds 16 bits. so, a 1024-bit key will need
//
// 1024 * 2 / 16 = 128 digits of storage.
//
var maxdigits;
var zero_array;
var bigzero, bigone;
function setmaxdigits(value)
{
	maxdigits = value;
	zero_array = new array(maxdigits);
	for (var iza = 0; iza < zero_array.length; iza  ) zero_array[iza] = 0;
	bigzero = new bigint();
	bigone = new bigint();
	bigone.digits[0] = 1;
}
setmaxdigits(20);
// the maximum number of digits in base 10 you can convert to an
// integer without javascript throwing up on you.
var dpl10 = 15;
// lr10 = 10 ^ dpl10
var lr10 = bifromnumber(1000000000000000);
function bigint(flag)
{
	if (typeof flag == "boolean" && flag == true) {
		this.digits = null;
	}
	else {
		this.digits = zero_array.slice(0);
	}
	this.isneg = false;
}
function bifromdecimal(s)
{
	var isneg = s.charat(0) == '-';
	var i = isneg ? 1 : 0;
	var result;
	// skip leading zeros.
	while (i < s.length && s.charat(i) == '0')   i;
	if (i == s.length) {
		result = new bigint();
	}
	else {
		var digitcount = s.length - i;
		var fgl = digitcount % dpl10;
		if (fgl == 0) fgl = dpl10;
		result = bifromnumber(number(s.substr(i, fgl)));
		i  = fgl;
		while (i < s.length) {
			result = biadd(bimultiply(result, lr10),
			               bifromnumber(number(s.substr(i, dpl10))));
			i  = dpl10;
		}
		result.isneg = isneg;
	}
	return result;
}
function bicopy(bi)
{
	var result = new bigint(true);
	result.digits = bi.digits.slice(0);
	result.isneg = bi.isneg;
	return result;
}
function bifromnumber(i)
{
	var result = new bigint();
	result.isneg = i < 0;
	i = math.abs(i);
	var j = 0;
	while (i > 0) {
		result.digits[j  ] = i & maxdigitval;
		i >>= biradixbits;
	}
	return result;
}
function reversestr(s)
{
	var result = "";
	for (var i = s.length - 1; i > -1; --i) {
		result  = s.charat(i);
	}
	return result;
}
var 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'
);
function bitostring(x, radix)
	// 2 <= radix <= 36
{
	var b = new bigint();
	b.digits[0] = radix;
	var qr = bidividemodulo(x, b);
	var result = hexatrigesimaltochar[qr[1].digits[0]];
	while (bicompare(qr[0], bigzero) == 1) {
		qr = bidividemodulo(qr[0], b);
		digit = qr[1].digits[0];
		result  = hexatrigesimaltochar[qr[1].digits[0]];
	}
	return (x.isneg ? "-" : "")   reversestr(result);
}
function bitodecimal(x)
{
	var b = new bigint();
	b.digits[0] = 10;
	var qr = bidividemodulo(x, b);
	var result = string(qr[1].digits[0]);
	while (bicompare(qr[0], bigzero) == 1) {
		qr = bidividemodulo(qr[0], b);
		result  = string(qr[1].digits[0]);
	}
	return (x.isneg ? "-" : "")   reversestr(result);
}
var hextochar = new array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                          'a', 'b', 'c', 'd', 'e', 'f');
function digittohex(n)
{
	var mask = 0xf;
	var result = "";
	for (i = 0; i < 4;   i) {
		result  = hextochar[n & mask];
		n >>>= 4;
	}
	return reversestr(result);
}
function bitohex(x)
{
	var result = "";
	var n = bihighindex(x);
	for (var i = bihighindex(x); i > -1; --i) {
		result  = digittohex(x.digits[i]);
	}
	return result;
}
function chartohex(c)
{
	var zero = 48;
	var nine = zero   9;
	var littlea = 97;
	var littlez = littlea   25;
	var biga = 65;
	var bigz = 65   25;
	var result;
	if (c >= zero && c <= nine) {
		result = c - zero;
	} else if (c >= biga && c <= bigz) {
		result = 10   c - biga;
	} else if (c >= littlea && c <= littlez) {
		result = 10   c - littlea;
	} else {
		result = 0;
	}
	return result;
}
function hextodigit(s)
{
	var result = 0;
	var sl = math.min(s.length, 4);
	for (var i = 0; i < sl;   i) {
		result <<= 4;
		result |= chartohex(s.charcodeat(i))
	}
	return result;
}
function bifromhex(s)
{
	var result = new bigint();
	var sl = s.length;
	for (var i = sl, j = 0; i > 0; i -= 4,   j) {
		result.digits[j] = hextodigit(s.substr(math.max(i - 4, 0), math.min(i, 4)));
	}
	return result;
}
function bifromstring(s, radix)
{
	var isneg = s.charat(0) == '-';
	var istop = isneg ? 1 : 0;
	var result = new bigint();
	var place = new bigint();
	place.digits[0] = 1; // radix^0
	for (var i = s.length - 1; i >= istop; i--) {
		var c = s.charcodeat(i);
		var digit = chartohex(c);
		var bidigit = bimultiplydigit(place, digit);
		result = biadd(result, bidigit);
		place = bimultiplydigit(place, radix);
	}
	result.isneg = isneg;
	return result;
}
function bitobytes(x)
	// returns a string containing raw bytes.
{
	var result = "";
	for (var i = bihighindex(x); i > -1; --i) {
		result  = digittobytes(x.digits[i]);
	}
	return result;
}
function digittobytes(n)
	// convert two-byte digit to string containing both bytes.
{
	var c1 = string.fromcharcode(n & 0xff);
	n >>>= 8;
	var c2 = string.fromcharcode(n & 0xff);
	return c2   c1;
}
function bidump(b)
{
	return (b.isneg ? "-" : "")   b.digits.join(" ");
}
function biadd(x, y)
{
	var result;
	if (x.isneg != y.isneg) {
		y.isneg = !y.isneg;
		result = bisubtract(x, y);
		y.isneg = !y.isneg;
	}
	else {
		result = new bigint();
		var c = 0;
		var n;
		for (var i = 0; i < x.digits.length;   i) {
			n = x.digits[i]   y.digits[i]   c;
			result.digits[i] = n & 0xffff;
			c = number(n >= biradix);
		}
		result.isneg = x.isneg;
	}
	return result;
}
function bisubtract(x, y)
{
	var result;
	if (x.isneg != y.isneg) {
		y.isneg = !y.isneg;
		result = biadd(x, y);
		y.isneg = !y.isneg;
	} else {
		result = new bigint();
		var n, c;
		c = 0;
		for (var i = 0; i < x.digits.length;   i) {
			n = x.digits[i] - y.digits[i]   c;
			result.digits[i] = n & 0xffff;
			// stupid non-conforming modulus operation.
			if (result.digits[i] < 0) result.digits[i]  = biradix;
			c = 0 - number(n < 0);
		}
		// fix up the negative sign, if any.
		if (c == -1) {
			c = 0;
			for (var i = 0; i < x.digits.length;   i) {
				n = 0 - result.digits[i]   c;
				result.digits[i] = n & 0xffff;
				// stupid non-conforming modulus operation.
				if (result.digits[i] < 0) result.digits[i]  = biradix;
				c = 0 - number(n < 0);
			}
			// result is opposite sign of arguments.
			result.isneg = !x.isneg;
		} else {
			// result is same sign.
			result.isneg = x.isneg;
		}
	}
	return result;
}
function bihighindex(x)
{
	var result = x.digits.length - 1;
	while (result > 0 && x.digits[result] == 0) --result;
	return result;
}
function binumbits(x)
{
	var n = bihighindex(x);
	var d = x.digits[n];
	var m = (n   1) * bitsperdigit;
	var result;
	for (result = m; result > m - bitsperdigit; --result) {
		if ((d & 0x8000) != 0) break;
		d <<= 1;
	}
	return result;
}
function bimultiply(x, y)
{
	var result = new bigint();
	var c;
	var n = bihighindex(x);
	var t = bihighindex(y);
	var u, uv, k;
	for (var i = 0; i <= t;   i) {
		c = 0;
		k = i;
		for (j = 0; j <= n;   j,   k) {
			uv = result.digits[k]   x.digits[j] * y.digits[i]   c;
			result.digits[k] = uv & maxdigitval;
			c = uv >>> biradixbits;
		}
		result.digits[i   n   1] = c;
	}
	// someone give me a logical xor, please.
	result.isneg = x.isneg != y.isneg;
	return result;
}
function bimultiplydigit(x, y)
{
	var n, c, uv;
	result = new bigint();
	n = bihighindex(x);
	c = 0;
	for (var j = 0; j <= n;   j) {
		uv = result.digits[j]   x.digits[j] * y   c;
		result.digits[j] = uv & maxdigitval;
		c = uv >>> biradixbits;
	}
	result.digits[1   n] = c;
	return result;
}
function arraycopy(src, srcstart, dest, deststart, n)
{
	var m = math.min(srcstart   n, src.length);
	for (var i = srcstart, j = deststart; i < m;   i,   j) {
		dest[j] = src[i];
	}
}
var highbitmasks = new array(0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800,
                             0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0,
                             0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff);
function bishiftleft(x, n)
{
	var digitcount = math.floor(n / bitsperdigit);
	var result = new bigint();
	arraycopy(x.digits, 0, result.digits, digitcount,
	          result.digits.length - digitcount);
	var bits = n % bitsperdigit;
	var rightbits = bitsperdigit - bits;
	for (var i = result.digits.length - 1, i1 = i - 1; i > 0; --i, --i1) {
		result.digits[i] = ((result.digits[i] << bits) & maxdigitval) |
		                   ((result.digits[i1] & highbitmasks[bits]) >>>
		                    (rightbits));
	}
	result.digits[0] = ((result.digits[i] << bits) & maxdigitval);
	result.isneg = x.isneg;
	return result;
}
var lowbitmasks = new array(0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f,
                            0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff,
                            0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff);
function bishiftright(x, n)
{
	var digitcount = math.floor(n / bitsperdigit);
	var result = new bigint();
	arraycopy(x.digits, digitcount, result.digits, 0,
	          x.digits.length - digitcount);
	var bits = n % bitsperdigit;
	var leftbits = bitsperdigit - bits;
	for (var i = 0, i1 = i   1; i < result.digits.length - 1;   i,   i1) {
		result.digits[i] = (result.digits[i] >>> bits) |
		                   ((result.digits[i1] & lowbitmasks[bits]) << leftbits);
	}
	result.digits[result.digits.length - 1] >>>= bits;
	result.isneg = x.isneg;
	return result;
}
function bimultiplybyradixpower(x, n)
{
	var result = new bigint();
	arraycopy(x.digits, 0, result.digits, n, result.digits.length - n);
	return result;
}
function bidividebyradixpower(x, n)
{
	var result = new bigint();
	arraycopy(x.digits, n, result.digits, 0, result.digits.length - n);
	return result;
}
function bimodulobyradixpower(x, n)
{
	var result = new bigint();
	arraycopy(x.digits, 0, result.digits, 0, n);
	return result;
}
function bicompare(x, y)
{
	if (x.isneg != y.isneg) {
		return 1 - 2 * number(x.isneg);
	}
	for (var i = x.digits.length - 1; i >= 0; --i) {
		if (x.digits[i] != y.digits[i]) {
			if (x.isneg) {
				return 1 - 2 * number(x.digits[i] > y.digits[i]);
			} else {
				return 1 - 2 * number(x.digits[i] < y.digits[i]);
			}
		}
	}
	return 0;
}
function bidividemodulo(x, y)
{
	var nb = binumbits(x);
	var tb = binumbits(y);
	var origyisneg = y.isneg;
	var q, r;
	if (nb < tb) {
		// |x| < |y|
		if (x.isneg) {
			q = bicopy(bigone);
			q.isneg = !y.isneg;
			x.isneg = false;
			y.isneg = false;
			r = bisubtract(y, x);
			// restore signs, 'cause they're references.
			x.isneg = true;
			y.isneg = origyisneg;
		} else {
			q = new bigint();
			r = bicopy(x);
		}
		return new array(q, r);
	}
	q = new bigint();
	r = x;
	// normalize y.
	var t = math.ceil(tb / bitsperdigit) - 1;
	var lambda = 0;
	while (y.digits[t] < bihalfradix) {
		y = bishiftleft(y, 1);
		  lambda;
		  tb;
		t = math.ceil(tb / bitsperdigit) - 1;
	}
	// shift r over to keep the quotient constant. we'll shift the
	// remainder back at the end.
	r = bishiftleft(r, lambda);
	nb  = lambda; // update the bit count for x.
	var n = math.ceil(nb / bitsperdigit) - 1;
	var b = bimultiplybyradixpower(y, n - t);
	while (bicompare(r, b) != -1) {
		  q.digits[n - t];
		r = bisubtract(r, b);
	}
	for (var i = n; i > t; --i) {
    var ri = (i >= r.digits.length) ? 0 : r.digits[i];
    var ri1 = (i - 1 >= r.digits.length) ? 0 : r.digits[i - 1];
    var ri2 = (i - 2 >= r.digits.length) ? 0 : r.digits[i - 2];
    var yt = (t >= y.digits.length) ? 0 : y.digits[t];
    var yt1 = (t - 1 >= y.digits.length) ? 0 : y.digits[t - 1];
		if (ri == yt) {
			q.digits[i - t - 1] = maxdigitval;
		} else {
			q.digits[i - t - 1] = math.floor((ri * biradix   ri1) / yt);
		}
		var c1 = q.digits[i - t - 1] * ((yt * biradix)   yt1);
		var c2 = (ri * biradixsquared)   ((ri1 * biradix)   ri2);
		while (c1 > c2) {
			--q.digits[i - t - 1];
			c1 = q.digits[i - t - 1] * ((yt * biradix) | yt1);
			c2 = (ri * biradix * biradix)   ((ri1 * biradix)   ri2);
		}
		b = bimultiplybyradixpower(y, i - t - 1);
		r = bisubtract(r, bimultiplydigit(b, q.digits[i - t - 1]));
		if (r.isneg) {
			r = biadd(r, b);
			--q.digits[i - t - 1];
		}
	}
	r = bishiftright(r, lambda);
	// fiddle with the signs and stuff to make sure that 0 <= r < y.
	q.isneg = x.isneg != origyisneg;
	if (x.isneg) {
		if (origyisneg) {
			q = biadd(q, bigone);
		} else {
			q = bisubtract(q, bigone);
		}
		y = bishiftright(y, lambda);
		r = bisubtract(y, r);
	}
	// check for the unbelievably stupid degenerate case of r == -0.
	if (r.digits[0] == 0 && bihighindex(r) == 0) r.isneg = false;
	return new array(q, r);
}
function bidivide(x, y)
{
	return bidividemodulo(x, y)[0];
}
function bimodulo(x, y)
{
	return bidividemodulo(x, y)[1];
}
function bimultiplymod(x, y, m)
{
	return bimodulo(bimultiply(x, y), m);
}
function bipow(x, y)
{
	var result = bigone;
	var a = x;
	while (true) {
		if ((y & 1) != 0) result = bimultiply(result, a);
		y >>= 1;
		if (y == 0) break;
		a = bimultiply(a, a);
	}
	return result;
}
function bipowmod(x, y, m)
{
	var result = bigone;
	var a = x;
	var k = y;
	while (true) {
		if ((k.digits[0] & 1) != 0) result = bimultiplymod(result, a, m);
		k = bishiftright(k, 1);
		if (k.digits[0] == 0 && bihighindex(k) == 0) break;
		a = bimultiplymod(a, a, m);
	}
	return result;
}
// barrettmu, a class for performing barrett modular reduction computations in
// javascript.
//
// requires bigint.js.
//
// d88尊龙官网手机app copyright 2004-2005 david shapiro.
//
// you may use, re-use, abuse, copy, and modify this code to your liking, but
// please keep this header.
//
// thanks!
//
// dave shapiro
// dave@ohdave.com
function barrettmu(m)
{
	this.modulus = bicopy(m);
	this.k = bihighindex(this.modulus)   1;
	var b2k = new bigint();
	b2k.digits[2 * this.k] = 1; // b2k = b^(2k)
	this.mu = bidivide(b2k, this.modulus);
	this.bkplus1 = new bigint();
	this.bkplus1.digits[this.k   1] = 1; // bkplus1 = b^(k 1)
	this.modulo = barrettmu_modulo;
	this.multiplymod = barrettmu_multiplymod;
	this.powmod = barrettmu_powmod;
}
function barrettmu_modulo(x)
{
	var q1 = bidividebyradixpower(x, this.k - 1);
	var q2 = bimultiply(q1, this.mu);
	var q3 = bidividebyradixpower(q2, this.k   1);
	var r1 = bimodulobyradixpower(x, this.k   1);
	var r2term = bimultiply(q3, this.modulus);
	var r2 = bimodulobyradixpower(r2term, this.k   1);
	var r = bisubtract(r1, r2);
	if (r.isneg) {
		r = biadd(r, this.bkplus1);
	}
	var rgtem = bicompare(r, this.modulus) >= 0;
	while (rgtem) {
		r = bisubtract(r, this.modulus);
		rgtem = bicompare(r, this.modulus) >= 0;
	}
	return r;
}
function barrettmu_multiplymod(x, y)
{
	/*
	x = this.modulo(x);
	y = this.modulo(y);
	*/
	var xy = bimultiply(x, y);
	return this.modulo(xy);
}
function barrettmu_powmod(x, y)
{
	var result = new bigint();
	result.digits[0] = 1;
	var a = x;
	var k = y;
	while (true) {
		if ((k.digits[0] & 1) != 0) result = this.multiplymod(result, a);
		k = bishiftright(k, 1);
		if (k.digits[0] == 0 && bihighindex(k) == 0) break;
		a = this.multiplymod(a, a);
	}
	return result;
}
/*
* d88尊龙官网手机app copyright (c) 2015 eric wilde.
* d88尊龙官网手机app copyright 1998-2015 david shapiro.
*
* rsa.js is a suite of routines for performing rsa public-key computations
* in javascript.  the cryptographic functions herein are used for encoding
* and decoding strings to be sent over unsecure channels.
*
* to use these routines, a pair of public/private keys is created through a
* number of means (openssl tools on linux/unix, dave shapiro's
* rsakeygenerator program on windows).  these keys are passed to rsakeypair
* as hexadecimal strings to create an encryption key object.  this key object
* is then used with encryptedstring to encrypt blocks of plaintext using the
* public key.  the resulting cyphertext blocks can be decrypted with
* decryptedstring.
*
* note that the cryptographic functions herein are complementary to those
* found in cryptofuncs.php and cryptofuncs.pm.  hence, encrypted messages may
* be sent between programs written in any of those languages.  the most
* useful, of course is to send messages encrypted by a web page using rsa.js
* to a php or perl script running on a web servitron.
*
* also, the optional padding flag may be specified on the call to
* encryptedstring, in which case blocks of cyphertext that are compatible
* with real crypto libraries such as openssl or microsoft will be created.
* these blocks of cyphertext can then be sent to web servitron that uses one
* of these crypto libraries for decryption.  this allows messages encrypted
* with longer keys to be decrypted quickly on the web server as well as
* making for more secure communications when a padding algorithm such as
* pkcs1v1.5 is used.
*
* these routines require bigint.js and barrett.js.
*/
/*****************************************************************************/
/*
* modifications
* -------------
*
* 2014 jan 11  e. wilde       add optional padding flag to encryptedstring
*                             for compatibility with real crypto libraries
*                             such as openssl or microsoft.  add pkcs1v1.5
*                             padding.
*
* 2015 jan 5  d. shapiro      add optional encoding flag for encryptedstring
*                             and encapsulate padding and encoding constants
*                             in rsaapp object.
*
* original code
* -------------
*
* d88尊龙官网手机app copyright 1998-2005 david shapiro.
*
* you may use, re-use, abuse, copy, and modify this code to your liking, but
* please keep this header.
*
* thanks!
*
* dave shapiro
* dave@ohdave.com
*/
/*****************************************************************************/
var rsaapp = {};
rsaapp.nopadding = "nopadding";
rsaapp.pkcs1padding = "pkcs1padding";
rsaapp.rawencoding = "rawencoding";
rsaapp.numericencoding = "numericencoding"
/*****************************************************************************/
function rsakeypair(encryptionexponent, decryptionexponent, modulus, keylen)
/*
* encryptionexponent                    the encryption exponent (i.e. public
*                                       encryption key) to be used for
*                                       encrypting messages.  if you aren't
*                                       doing any encrypting, a dummy
*                                       exponent such as "10001" can be
*                                       passed.
*
* decryptionexponent                    the decryption exponent (i.e. private
*                                       decryption key) to be used for
*                                       decrypting messages.  if you aren't
*                                       doing any decrypting, a dummy
*                                       exponent such as "10001" can be
*                                       passed.
*
* modulus                               the modulus to be used both for
*                                       encrypting and decrypting messages.
*
* keylen                                the optional length of the key, in
*                                       bits.  if omitted, rsakeypair will
*                                       attempt to derive a key length (but,
*                                       see the notes below).
*
* returns                               the "new" object creator returns an
*                                       instance of a key object that can be
*                                       used to encrypt/decrypt messages.
*
* this routine is invoked as the first step in the encryption or decryption
* process to take the three numbers (expressed as hexadecimal strings) that
* are used for rsa asymmetric encryption/decryption and turn them into a key
* object that can be used for encrypting and decrypting.
*
* the key object is created thusly:
*
*      rsakey = new rsakeypair("abc12345", 10001, "987654fe");
*
* or:
*
*      rsakey = new rsakeypair("abc12345", 10001, "987654fe", 64);
*
* note that rsakeypair will try to derive the length of the key that is being
* used, from the key itself.  the key length is especially useful when one of
* the padding options is used and/or when the encrypted messages created by
* the routine encryptedstring are exchanged with a real crypto library such
* as openssl or microsoft, as it determines how many padding characters are
* appended.
*
* usually, rsakeypair can determine the key length from the modulus of the
* key but this doesn't always work properly, depending on the actual value of
* the modulus.  if you are exchanging messages with a real crypto library,
* such as openssl or microsoft, that depends on the fact that the blocks
* being passed to it are properly padded, you'll want the key length to be
* set properly.  if that's the case, of if you just want to be sure, you
* should specify the key length that you used to generated the key, in bits
* when this routine is invoked.
*/
{
/*
* convert from hexadecimal and save the encryption/decryption exponents and
* modulus as big integers in the key object.
*/
this.e = bifromhex(encryptionexponent);
this.d = bifromhex(decryptionexponent);
this.m = bifromhex(modulus);
/*
* using big integers, we can represent two bytes per element in the big
* integer array, so we calculate the chunk size as:
*
*      chunksize = 2 * (number of digits in modulus - 1)
*
* since bihighindex returns the high index, not the number of digits, the
* number 1 has already been subtracted from its answer.
*
* however, having said all this, "user knows best".  if our caller passes us
* a key length (in bits), we'll treat it as gospel truth.
*/
if (typeof(keylen) != 'number') { this.chunksize = 2 * bihighindex(this.m); }
else { this.chunksize = keylen / 8; }
this.radix = 16;
/*
* precalculate the stuff used for barrett modular reductions.
*/
this.barrett = new barrettmu(this.m);
}
/*****************************************************************************/
function encryptedstring(key, s, pad, encoding)
/*
* key                                   the previously-built rsa key whose
*                                       public key component is to be used to
*                                       encrypt the plaintext string.
*
* s                                     the plaintext string that is to be
*                                       encrypted, using the rsa assymmetric
*                                       encryption method.
*
* pad                                   the optional padding method to use
*                                       when extending the plaintext to the
*                                       full chunk size required by the rsa
*                                       algorithm.  to maintain compatibility
*                                       with other crypto libraries, the
*                                       padding method is described by a
*                                       string.  the default, if not
*                                       specified is "ohdave".  here are the
*                                       choices:
*
*                                         ohdave - this is the original
*                                           padding method employed by dave
*                                           shapiro and rob saunders.  if
*                                           this method is chosen, the
*                                           plaintext can be of any length.
*                                           it will be padded to the correct
*                                           length with zeros and then broken
*                                           up into chunks of the correct
*                                           length before being encrypted.
*                                           the resultant cyphertext blocks
*                                           will be separated by blanks.
*
*                                           note that the original code by
*                                           dave shapiro reverses the byte
*                                           order to little-endian, as the
*                                           plaintext is encrypted.  if
*                                           either these javascript routines
*                                           or one of the complementary
*                                           php/perl routines derived from
*                                           this code is used for decryption,
*                                           the byte order will be reversed
*                                           again upon decryption so as to
*                                           come out correctly.
*
*                                           also note that this padding
*                                           method is claimed to be less
*                                           secure than pkcs1padding.
*
*                                         nopadding - this method truncates
*                                           the plaintext to the length of
*                                           the rsa key, if it is longer.  if
*                                           its length is shorter, it is
*                                           padded with zeros.  in either
*                                           case, the plaintext string is
*                                           reversed to preserve big-endian
*                                           order before it is encrypted to
*                                           maintain compatibility with real
*                                           crypto libraries such as openssl
*                                           or microsoft.  when the
*                                           cyphertext is to be decrypted
*                                           by a crypto library, the
*                                           library routine's rsaapp.nopadding
*                                           flag, or its equivalent, should
*                                           be used.
*
*                                           note that this padding method is
*                                           claimed to be less secure than
*                                           pkcs1padding.
*
*                                         pkcs1padding - the pkcs1v1.5
*                                           padding method (as described in
*                                           rfc 2313) is employed to pad the
*                                           plaintext string.  the plaintext
*                                           string must be no longer than the
*                                           length of the rsa key minus 11,
*                                           since pkcs1v1.5 requires 3 bytes
*                                           of overhead and specifies a
*                                           minimum pad of 8 bytes.  the
*                                           plaintext string is padded with
*                                           randomly-generated bytes and then
*                                           its order is reversed to preserve
*                                           big-endian order before it is
*                                           encrypted to maintain
*                                           compatibility with real crypto
*                                           libraries such as openssl or
*                                           microsoft.  when the cyphertext
*                                           is to be decrypted by a crypto
*                                           library, the library routine's
*                                           rsaapp.pkcs1padding flag, or its
*                                           equivalent, should be used.
*
* encoding                              the optional encoding scheme to use
*                                       for the return value. if ommitted,
*                                       numeric encoding will be used.
*
*                                           rawencoding - the return value
*                                           is given as its raw value.
*                                           this is the easiest method when
*                                           interoperating with server-side
*                                           openssl, as no additional conversion
*                                           is required. use the constant
*                                           rsaapp.rawencoding for this option.
*
*                                           numericencoding - the return value
*                                           is given as a number in hexadecimal.
*                                           perhaps useful for debugging, but
*                                           will need to be translated back to
*                                           its raw equivalent (e.g. using
*                                           php's hex2bin) before using with
*                                           openssl. use the constant
*                                           rsaapp.numericencoding for this option.
*
* returns                               the cyphertext block that results
*                                       from encrypting the plaintext string
*                                       s with the rsa key.
*
* this routine accepts a plaintext string that is to be encrypted with the
* public key component of the previously-built rsa key using the rsa
* assymmetric encryption method.  before it is encrypted, the plaintext
* string is padded to the same length as the encryption key for proper
* encryption.
*
* depending on the padding method chosen, an optional header with block type
* is prepended, the plaintext is padded using zeros or randomly-generated
* bytes, and then the plaintext is possibly broken up into chunks.
*
* note that, for padding with zeros, this routine was altered by rob saunders
* (rob@robsaunders.net). the new routine pads the string after it has been
* converted to an array. this fixes an incompatibility with flash mx's
* actionscript.
*
* the various padding schemes employed by this routine, and as presented to
* rsa for encryption, are shown below.  note that the rsa encryption done
* herein reverses the byte order as encryption is done:
*
*      plaintext in
*      ------------
*
*      d5 d4 d3 d2 d1 d0
*
*      ohdave
*      ------
*
*      d5 d4 d3 d2 d1 d0 00 00 00 /.../ 00 00 00 00 00 00 00 00
*
*      nopadding
*      ---------
*
*      00 00 00 00 00 00 00 00 00 /.../ 00 00 d0 d1 d2 d3 d4 d5
*
*      pkcs1padding
*      ------------
*
*      d0 d1 d2 d3 d4 d5 00 p0 p1 /.../ p2 p3 p4 p5 p6 p7 02 00
*                            \------------  ------------/
*                                         \/
*                             minimum 8 bytes pad length
*/
{
var a = new array();                    // the usual alice and bob stuff
var sl = s.length;                      // plaintext string length
var i, j, k;                            // the usual fortran index stuff
var padtype;                            // type of padding to do
var encodingtype;                       // type of output encoding
var rpad;                               // random pad
var al;                                 // array length
var result = "";                        // cypthertext result
var block;                              // big integer block to encrypt
var crypt;                              // big integer result
var text;                               // text result
/*
* figure out the padding type.
*/
if (typeof(pad) == 'string') {
  if (pad == rsaapp.nopadding) { padtype = 1; }
  else if (pad == rsaapp.pkcs1padding) { padtype = 2; }
  else { padtype = 0; }
}
else { padtype = 0; }
/*
* determine encoding type.
*/
if (typeof(encoding) == 'string' && encoding == rsaapp.rawencoding) {
	encodingtype = 1;
}
else { encodingtype = 0; }
/*
* if we're not using dave's padding method, we need to truncate long
* plaintext blocks to the correct length for the padding method used:
*
*       nopadding    - key length
*       pkcs1padding - key length - 11
*/
if (padtype == 1) {
  if (sl > key.chunksize) { sl = key.chunksize; }
}
else if (padtype == 2) {
  if (sl > (key.chunksize-11)) { sl = key.chunksize - 11; }
}
/*
* convert the plaintext string to an array of characters so that we can work
* with individual characters.
*
* note that, if we're talking to a real crypto library at the other end, we
* reverse the plaintext order to preserve big-endian order.
*/
i = 0;
if (padtype == 2) { j = sl - 1; }
else { j = key.chunksize - 1; }
while (i < sl) {
  if (padtype) { a[j] = s.charcodeat(i); }
  else { a[i] = s.charcodeat(i); }
  i  ; j--;
}
/*
* now is the time to add the padding.
*
* if we're doing pkcs1v1.5 padding, we pick up padding where we left off and
* pad the remainder of the block.  otherwise, we pad at the front of the
* block.  this gives us the correct padding for big-endian blocks.
*
* the padding is either a zero byte or a randomly-generated non-zero byte.
*/
if (padtype == 1) { i = 0; }
j = key.chunksize - (sl % key.chunksize);
while (j > 0) {
  if (padtype == 2) {
    rpad = math.floor(math.random() * 256);
    while (!rpad) { rpad = math.floor(math.random() * 256); }
    a[i] = rpad;
  }
  else { a[i] = 0; }
  i  ; j--;
}
/*
* for pkcs1v1.5 padding, we need to fill in the block header.
*
* according to rfc 2313, a block type, a padding string, and the data shall
* be formatted into the encryption block:
*
*      encrblock = 00 || blocktype || padstring || 00 || data
*
* the block type shall be a single octet indicating the structure of the
* encryption block. for this version of the document it shall have value 00,
* 01, or 02. for a private-key operation, the block type shall be 00 or 01.
* for a public-key operation, it shall be 02.
*
* the padding string shall consist of enough octets to pad the encryption
* block to the length of the encryption key.  for block type 00, the octets
* shall have value 00; for block type 01, they shall have value ff; and for
* block type 02, they shall be pseudorandomly generated and nonzero.
*
* note that in a previous step, we wrote padding bytes into the first three
* bytes of the encryption block because it was simpler to do so.  we now
* overwrite them.
*/
if (padtype == 2)
  {
  a[sl] = 0;
  a[key.chunksize-2] = 2;
  a[key.chunksize-1] = 0;
  }
/*
* carve up the plaintext and encrypt each of the resultant blocks.
*/
al = a.length;
for (i = 0; i < al; i  = key.chunksize) {
  /*
  * get a block.
  */
  block = new bigint();
  j = 0;
  for (k = i; k < (i key.chunksize);   j) {
    block.digits[j] = a[k  ];
    block.digits[j]  = a[k  ] << 8;
  }
  /*
  * encrypt it, convert it to text, and append it to the result.
  */
  crypt = key.barrett.powmod(block, key.e);
  if (encodingtype == 1) {
	  text = bitobytes(crypt);
  }
  else {
	  text = (key.radix == 16) ? bitohex(crypt) : bitostring(crypt, key.radix);
  }
  result  = text;
}
/*
* return the result, removing the last space.
*/
//result = (result.substring(0, result.length - 1));
return result;
}
/*****************************************************************************/
function decryptedstring(key, c)
/*
* key                                   the previously-built rsa key whose
*                                       private key component is to be used
*                                       to decrypt the cyphertext string.
*
* c                                     the cyphertext string that is to be
*                                       decrypted, using the rsa assymmetric
*                                       encryption method.
*
* returns                               the plaintext block that results from
*                                       decrypting the cyphertext string c
*                                       with the rsa key.
*
* this routine is the complementary decryption routine that is meant to be
* used for javascript decryption of cyphertext blocks that were encrypted
* using the ohdave padding method of the encryptedstring routine (in this
* module).  it can also decrypt cyphertext blocks that were encrypted by
* rsaencode (in cryptofuncs.pm or cryptofuncs.php) so that encrypted
* messages can be sent of insecure links (e.g. http) to a web page.
*
* it accepts a cyphertext string that is to be decrypted with the public key
* component of the previously-built rsa key using the rsa assymmetric
* encryption method.  multiple cyphertext blocks are broken apart, if they
* are found in c, and each block is decrypted.  all of the decrypted blocks
* are concatenated back together to obtain the original plaintext string.
*
* this routine assumes that the plaintext was padded to the same length as
* the encryption key with zeros.  therefore, it removes any zero bytes that
* are found at the end of the last decrypted block, before it is appended to
* the decrypted plaintext string.
*
* note that the encryptedstring routine (in this module) works fairly quickly
* simply by virtue of the fact that the public key most often chosen is quite
* short (e.g. 0x10001).  this routine does not have that luxury.  the
* decryption key that it must employ is the full key length.  for long keys,
* this can result in serious timing delays (e.g. 7-8 seconds to decrypt using
* 2048 bit keys on a reasonably fast machine, under the firefox web browser).
*
* if you intend to send encrypted messagess to a javascript program running
* under a web browser, you might consider using shorter keys to keep the
* decryption times low.  alternately, a better scheme is to generate a random
* key for use by a symmetric encryption algorithm and transmit it to the
* other end, after encrypting it with encryptedstring.  the other end can use
* a real crypto library (e.g. openssl or microsoft) to decrypt the key and
* then use it to encrypt all of the messages (with a symmetric encryption
* algorithm such as twofish or aes) bound for the javascript program.
* symmetric decryption is orders of magnitude faster than asymmetric and
* should yield low decryption times, even when executed in javascript.
*
* also note that only the ohdave padding method (e.g. zeros) is supported by
* this routine *and* that this routine expects little-endian cyphertext, as
* created by the encryptedstring routine (in this module) or the rsaencode
* routine (in either cryptofuncs.pm or cryptofuncs.php).  you can use one of
* the real crypto libraries to create cyphertext that can be decrypted by
* this routine, if you reverse the plaintext byte order first and then
* manually pad it with zero bytes.  the plaintext should then be encrypted
* with the nopadding flag or its equivalent in the crypto library of your
* choice.
*/
{
var blocks = c.split(" ");              // multiple blocks of cyphertext
var b;                                  // the usual alice and bob stuff
var i, j;                               // the usual fortran index stuff
var bi;                                 // cyphertext as a big integer
var result = "";                        // plaintext result
/*
* carve up the cyphertext into blocks.
*/
for (i = 0; i < blocks.length;   i) {
  /*
  * depending on the radix being used for the key, convert this cyphertext
  * block into a big integer.
  */
  if (key.radix == 16) { bi = bifromhex(blocks[i]); }
  else { bi = bifromstring(blocks[i], key.radix); }
  /*
  * decrypt the cyphertext.
  */
  b = key.barrett.powmod(bi, key.d);
  /*
  * convert the decrypted big integer back to the plaintext string.  since
  * we are using big integers, each element thereof represents two bytes of
  * plaintext.
  */
  for (j = 0; j <= bihighindex(b);   j) {
    result  = string.fromcharcode(b.digits[j] & 255, b.digits[j] >> 8);
  }
}
/*
* remove trailing null, if any.
*/
if (result.charcodeat(result.length - 1) == 0) {
  result = result.substring(0, result.length - 1);
}
/*
* return the plaintext.
*/
return (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 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;
    // 也是一个第三方库,但是该库不在npm中
    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
}
    let i0x = {
    "csrf_token": "",
    "encodetype": "aac",
    "ids": "[1325905146]",
    "level": "standard",
};
let r = d(json.stringify(i0x), '010001', '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7', '0cojum6qyw8w8jud');
console.log(r);

运行结果和上面两个方法一致。
初识javascript逆向——以网易云音乐和招标网站为例
python代码也一致。

通过搜索关键字找到加密过程

点击开发者工具右上角的三个点,再点击search,可以实现全局搜索。
初识javascript逆向——以网易云音乐和招标网站为例
搜索music_url中的关键字,先搜索"v1",结果有很多,不好判断。
初识javascript逆向——以网易云音乐和招标网站为例
再搜索"url/v1",只有一处结果了。
初识javascript逆向——以网易云音乐和招标网站为例
点进去,在该文件中搜索"url/v1",也只有一处。
初识javascript逆向——以网易云音乐和招标网站为例
所以就可以在该行打断点进行调试,也是跳入如下的函数,跟用第一种方法找加密过程是一样的。
初识javascript逆向——以网易云音乐和招标网站为例
只不过这种方法比第一种方法快点。但是没有哪种方法比哪种方法好的说法。

url地址:
老样子,找到network模块,刷新界面,看触发了哪些数据包。
初识javascript逆向——以网易云音乐和招标网站为例
不要一个一个流量包找,直接找类型为xhr/fetch的就可以了。
初识javascript逆向——以网易云音乐和招标网站为例
这里只有一条,看他的响应内容也是一串加密字符串。
初识javascript逆向——以网易云音乐和招标网站为例
找它的加密过程。查看initiators,发现有promise对象,且出现了async关键字,是异步加载。
初识javascript逆向——以网易云音乐和招标网站为例
大概率采用的是axios,加密过程很有可能是在拦截器中实现的,所以直接全局搜索"interceptors"。
初识javascript逆向——以网易云音乐和招标网站为例
总共有7处,一处一处查看。
第一个文件的两处如下。
初识javascript逆向——以网易云音乐和招标网站为例
第二个文件的三处如下。
初识javascript逆向——以网易云音乐和招标网站为例
第三个文件的两处如下。
初识javascript逆向——以网易云音乐和招标网站为例
第二个文件只是对interceptors进行定义,不是调用的地方,第二处直接忽略。
第一个文件的响应拦截器处出现如下代码,大概率c就是加密函数了。
初识javascript逆向——以网易云音乐和招标网站为例
在该行打断点,进行调试。发现这里打断点打不上,一打断点就直接打到了第三个文件里的响应拦截器的地方。试了几次都是这样,说明第三个文件里的才是真正的加密代码。
初识javascript逆向——以网易云音乐和招标网站为例
可以明显的看到有个"decryptbydes"函数,这就是des解密函数了,找到该函数的实现代码。
初识javascript逆向——以网易云音乐和招标网站为例
将该代码抠出来,用加密的参数进行测试。

点击查看代码
var cryptojs = require("crypto-js");
function decryptbydes(ciphertext) {
    var keyhex = cryptojs.enc.utf8.parse("1qaz@wsx3e");
    //  ctpstp@custominfo!@#qweasd
    // direct decrypt ciphertext
    var decrypted = cryptojs.des.decrypt({
            ciphertext: cryptojs.enc.base64.parse(ciphertext),
        },
        keyhex, {
            mode: cryptojs.mode.ecb,
            padding: cryptojs.pad.pkcs7,
        }
    );
    return decrypted.tostring(cryptojs.enc.utf8);
}
// 本地测试
var s = 'jwdscjmm05e4niazd3zokxjfjcskzflud1joo6 h0tgjmj0y4azxiiflvnggu02joe0wzw7i8sqisjudn4sdeidnjkjadjq5cbyjaxwcf5gz 2gsmglqep5g/ea css5edpx5ne5rldgosp  hqdytkf9nymqmnqfy87jvxflsjnzapdsj4ur8s1fp0chh7y2bps8ysrsimglijbrkfwycgqhehne4gsiauszf161m6npf1mv93fxf7mmr7togn49ktagu4pxlcfgia2sym6oy5/ii42vteenym/cqntjlikondn/nw2f/acsfvutzhyrip9ivx3onyo2sg7kckw7q2vyu ybtgxpvrskbap6xynqud1ccl4fmqnzfdg/mliwrokx07suelnajz2cag2shegrlggb7nrjqzovoq9utrtf 8xd0qsdxxl/c9lc hzizgttktimmg vjpumu5u/thrshwohlvvfcqa97qkonoy0zstkuod4ru4ujrkmpiogvnxez4nxbp6m8ojmo z4jqwgrlpouuhsmjgzgx71xuved niytve sdtsynnb awu epyjok6dcbnt9pusrrg4saxdlpz5pcqmaopget6maaefmxsszkkql6nka hxsn05ep20ttjc56q0 m/ipspwr1nn87tk3iagr905q3zsqnd0dqn6buogeeazcgqsjfnvcetacb5wm7rjtjynqky0omrg4wqkgcf38xv449h6x evcs5diqmhe/io/sgdvifh1pqmswezfrr0f1wflxo5b3qjgcgsayniq3cuk9eed7ejrthezt6kjuko/mfz3lsxqfou4e0hocowijzrglpusahtlobniuropghgchk0qzwytndjg3iyqgtjiarrrsu0i0vfh7zfuhzia22ooktdy0thkymx7xs8dbgmoj5swv03g g20/v8b1hq2g6em1srap5do2d6v gy3uhegxmsuwyemka/a64ucpyxk4njfq5bzohq/ekb3e7fqvavma3gaeqkddw5fe 28aqhotlvxfzwehevsnlkov0erebsvngay8ubzlcuzvpj4svz 1kk63ungxu9rongho7e93jiz3cnaifcvx3yg3zkcyojzgeo62wnelatyee vqcnsfke91ik5lxwl3gjw ux uimlcwrsz6rbfqk564e/grsww86hfeg gnobwqswuiovd54ytllocxxmnsfyirdxl3zhlpwkph0yhjqzbgcwpthw1lz5gnzom/66clm1txmes3yrxiewbnnnuxu2cv2sjbnwv5g6oofsiy/b33xar9intonrc 0tk8sq2uijkbgl diuwfs242kkgd4uddhcu2yfut4kpc3myj8jujdik fwpcqtiqpd2v qqh0at4wd mq0lznhp8loutjqxxqvmustjdzbf9bodoxa1tgdoq8ixkuotp0vtrvvcoocn0hnmywoc9tcdqefovxoyy/qtnqxdhkqmpvnriy/agmt3zcchz/mnbeucfv33jahentxya37ngmzdy5tfwvrd5gepxgsa ei2agpf12924mdgxhtseiy9uhzliq412f dbyxabqnpe7hlugk1lauqtrzwh avczqmvylpjps6ghs6lxz 56kw5n5msd37mwmxk/vijwokyxubo7uscxuwwnsavzfgvcpy37misdhv3oiyka/1ig4xz/6frzbuarn8wtglrhfpyge73tuvnnyvov2nctsq6qlylm6rxi9cearr/sw9aqlz8ksnjffmg03hq5ak7vzsq/sa4frqi0ah2svvnlcuqjgxj6zpholu0rpxzdzganzgvz7ericuhukdq76wc6wjxs97r9edgtdcjztxx3qddqf9wp9qjqsnefsfpny76ln8eor8/musxw9p6kancodn1ma1q5gms72dcggrusx7zfy bkjdhesy4cecc5c ivoibcocp02afxqp7hrtlvyxhqqea9ljcsjcyd15yijcl9 yxzefb351ddi4uyf9s/gwms1xtz17kbv5g0qbstbwnyjh/u1g/o/ll0k5cefc5x 4ql0kbumdtfs9sxcbr5twsb w3ms7heuk/av16vgbpveg7q e lnkqkkzcdqm/47wkndua/hmegtjzfc ivoibcocp02afxqp7hrtlvyxhqqea9ljcsjcyd15yijcl9 yxzefb351ddi4uyf9s/gwms1xtz17kbv5g0qbstbwnyjh/u1g/o/ll0k5cefc5x 4ql0kbumdtfs9sxcbr5twsb w429hf2qqnlo0dgwdagevvv9yod3tao407lrlk2s6gph22lcepguioaldb6xcprojtictkwwpebdcrsz7zszz6n6lvddi3iyaeyqfylcd6j28wkvwdw6hs2hl6nukqxzv/pjbgnvfjg/ 4qqttk200wzyhkeykph/f4ohdkadbg/xbvx5ywml3gnkb8i5taff/ct5flkfcrngznia6klwalr4ufnczsrpphned5stq5dqlm3ivj7nzs47hcagkwxablgdpbp3d q4u4jmnfzkawwi x4xj32s0esohy/yi/uyxboegomwjrozwozf8zh gclqmandmi0lnunxh9uwbeb7pmdqona/decs9fzbpk/he3o67r3mu/osyxf7rph0r3t6ou0d5lpvfhid5s8nnjs scbvfr kr2dz0budejdpjxhvf7y2ee0ellmqqhnfkpeflwls5ralnynudntv070emchraf9vrw9 dqw4ufgj601kz5aasuiuf wxonl3ltgv9n7ngkpntvf5yes47t4gbrfds1f76g8kcxh2sc9yb3d7wbdjq/svtnnckoucwnmzhpxoib4/i7q6q8d64vhjuqtfrsfqxnm1ttqgzpl6 fbffekyvi2drxxyxbb8cjozf3aoennerwv3lleybznfuj2z5xapq/4bldqcsbejjzfyuabqdkskpy1mxintitkn ylf9uucbcw068iwfpc ivoibcocp02afxqp7hrtlvyxhqqea9ljcsjcyd15yijcl9 yxzefb351ddi4uyf9s/gwms1xyyelpxpiylsdhs/adwjgb/wgxc59cxbpsfawyp2jjfcnpy0dg i 72pmsleprxbyhwjlm8wy 6jjdjxz/51thf2y5xfnmhut41lkddkps6471zsvi5o fbhwmmfzvatnp66clm1txmefph6kfxg513op ftkwhmpeo3b5hosmdvoxpxni0skaresmq3/rcwrrhjhvr1ricijjwiihx70y3/u1dkwgwl4k pcd4axy3qza1l8mb8ywlprlbvienljzm/okcfqw1g4z4cwtnap8ei0zkqya4ymfwntgeh hxhrne uoddqgtumjhie/vh4t9w7gnjglkwhjqzbgcwptencolrmqwzqu3eg4taweryvo1wkwkmska7gm dept6n0unc5ql09piopbabtykeirnzdm1ys4b duc/hw56iug5wfq5k5ahfaekhwll4za4poaqwbgxloqidtfcl0nju6towrxcjr4g5lhnnk26neicbvw9chwqfuxcyvmqvwk zqc uxpdxrfphr2os8hvoxwi63d754drpb1ddtmmfxyriv6pstr3gpy17otzc3ou3hw0mpfns56l/fjsu3xjj9ursrzukafotb3wck78pz9zsk1w3zqg/fphlibkudcoumrv3cdw3gzxxv6ff3gdwihnikusilv4wqzwibrr3ajuecezgi0qnj1t7gjjjykntkjvnmd3qpkflhvcbdktynhomx usgg9pv74lcyowmn/kc3i7np9glzhpzsp4btf /4ch3/s6u63pwiafxxhxusseirryojnkaharh5pdp4 xelbeqyc4fofdbq xdyiw3y ytyf39c/kngbgansgvelor4kuox3juc/hw56iug7xrtz71lobgxyc40w3wds2y9xarsvlr8kqde1avp8hosv7cxyrx3nafgcz3/xx3cia5h9x/pjwzzaq9z1bodle4ya9ljckdxtqrhq1pqbcmzo6p1cl7ehgoczmta7qtaly7r/wkwxvmwdf5459gy8d8fik/byblg4ybbfvnb3gbsfg6wbaa3tbylcjpk6ipuzcnlo/v9yakng795xinw7termo1qcxqfoeqtpjpyd7lm/dqpqvdute1jfwhrhgg1/5cx/a5bkov15x3nfisama0sjpicuybtaw9raylv8exev3ld5lmzhifhlquirj/avzzagnqg apgteofhfuk1wrby1vds8jtm29cq gc4f583b48a26uoytetyzklx2ncqw9p5z///00pr9sr7dnhyqpiqtadlau01oe2/gd53op/izeftg8bnhk zn7mhusriy/agmt3za5urn 5agxgxcfm70w0gg/zuqbd puyyhrelv18jfkdag/beoagubl6z 79nvxsejipynqkmit4wi/pylsfwcsw05uhn8krlaahqfviunrff xmfwoqzkfqpw9a0j m7hboyrt9mk2mxfbvgx0m6ycdvs6fagebkvzmygnyqyt1ox zoqytl6gt5amrnklxrdcjacnrbhdd8szvevlftsk5knzgyfjrftdvkvho7u1gmejt/bakrnh9hm3iruaqfoeocwmkqf60 nhxfpstsikf/hu1lxyncajznlrsdthzuautauwqjihhftfeymjswvfkbil13tplq4hzsxfk0fjoxqmhsfnjsdc7h/qndu5nisqfb2qf9hvmgbbzsbes5c20l836/femtuc/hw56iugdcegmhoodlrbwim8ahpc1slg0yvpeyf4bofspmbfoqc/8wbninxb2omtz0 mzrbiuda/mdo6h9jqom/eiayeycee/2zqyucmyckxbqhxjt32vwob0aemf28q0 1/dqqjmbdsotjclspgf8qptan3czragylrnxhmm1aecrbuki8egm7 wfx6gnacens m0nvcuay3l/ypvfsbvgayvmo/nmqytxgutwdt61kvd hheqmo37mz87vzafsmbry7mlcgb5aifesh9jvjouvv2uatw14adfogpna9hbwnogediia1dqf2ucpwhxw2uitzokqvbeggubxbl8lqk2ekjhiodlam3493fioxu7kvcl1yerwfxd1yfzaw7pubwaeq8utughfg ndfjpe1ah2bgs9iqswiuhzzjuvcbrhvuhc3geeldmgbxy9mdojihe1havfqtttd5zcug6cywkdlweffrr5zlwe6zwg kwnz8r4icazoki7ndiag3bpn0jbsd12upm6r naoy5dd0dyk6gmpy7bq1kysxeft3ouq3xvdayxyppaglr3ksbecisya5ai7cq1ugbqxmvst2bnmq7f5zur36chho971rfohufb4szzgo5ybe7rkri0zurub6738ny vo0/hxavqqwltn7cxsn8w/4amaf5k 05bnwf jthybaqdsld7tboqwox0taws7ar/yuorrlymrbnoigfd6qq0qzlluxvb5etftox2nr/mnslkwfqbciavwgzvqde0/gbxgxcx eicq7usef9dorabytgjcaylwvbzaor6w36f6xdv4jn28myvcwcck28ulordercjvc9gozwxg1grkidudqwk3pu8qh1bfp0ail82zxpsd3ryv4s6vis47heo4l8fdnqk6dtetnnvuugebfhzjtddyozns5by7hrnpaztph9hsiuuvgxee06iyv3qpdrbmuu5e8hl5mw05fadh aewsrb psigc/cblvb0tt8yhebfzh4sjxdu6x5/105fofi0ykjrivc8hmchhpbfoxpco/iofbwxi8jyiirby6when5fynul2a7pbedwcsogo52pyrc 7yqhvswnrqkbikifrz1isbukwa qsd5fg 0prcx bfnfyojqppu6q44d7xnu7dlmrpiks66ytrj44wppeurgfa/zzv1rkqppdmod9rznkazyocdw01bosodfph1rmnverrgkw1qw/uhqt8bvhoqnygpm2 j2hmptbdrvjhuw7 nmcsrd2y85hmbbrnrs2zbvbij2tjtpxhigyfktmdeeench/4n3t30 6u6x2wv/nuqtzmpm7hwzdvhh/xnfsaoen0g cl09vktemzxee5zykq6qvhzbdvbegaaefmxsszkhocgbnpaak51srap5do2d7hc2kag7t ikl2hfqk7ruajuhoogzhlw2dp7zncrawymopjqxiidd5q5xesugquuf28idrjgzlsvebv18i/j3u9en itksde3bytx4 bsi4jm/okcfqw1gfnlad2lwru dsws3yjjr2q7ab/ js5nmkdsyjlspe/cb7pmdqona/yg15n1dtdo3m 6znudjqp2y7qjs8uftkzotvyapbhkjkchc2imk5z53rmtbjo93snmzm235xwh1smxe4recekneadi28dhh5l50tx u6ioku x37ykeayxiam8udrx/pv8b1hq2g6em1srap5do2d6v gy3uhegxmsuwyemka/a64ucpyxk4njfq5bzohq/ekb3e7fqvavma3gaeqkddw5fe 28aqhotlvxfzwehevsnlkov0erebsvngay8ubzlcuzvpj4svz 1kk63ungxu9rongho7e93jiz3cnaifcvx3yg3zkcyoimwivi0wumrqtyee vqcnsfke91ik5lxwl3gjw ux ujboqwox0taws7ar/yuorrlymrbnoigfd6qq0qzlluxvqhhdswcg3l4vc8i/k83axk nuv1hanuaiutphxe2iciqptrjmzj8zkftt f2ar5/aarmciukbydqjjeggnchoas8lajeahue2rsy/nuzb8vxbqoq4om207nwv5g6oofsrak2bvyqjampokiqpavmd b8dqpzsxd01siyadokguiaxbh6pflutgs/senpnnk9n lgsc28rrziskvpczt431usdzvwfocdbairbwugg5o0aa0ybk/w08j/ew8dw3hctle40mv6rzh9ecm51zp2kl4qso8iilkgguf2p3x05iob1qqkhj9b5zgmkhpuwg0hn6l8agmv6kzalwx5ejqbzaygpwbprd8wnb8/zjwrfhbb99yqb3jbccmt 5xps3wobrvr6w yhqcrkmvninmhqrddvdujg4f4buhcmvvb8y4kondn/nw2f2gajaxu4zvbpnzqlqruwcifmlqmajl2c6st7oob7opv2fueisoz tla9 5sjszp7ycvjpmsbm6o1enmbsmj7al2xxr3kwn zirhr79zigcmv9yhuf2f huwqvak5/mexpur36chho97vl5zclafdp3lbkuqpcpzukvypqnmkuf7fvqejwfjldsx35onnx6uqcu787kv7guh60cnaidklvzywlei4fyesz4ti1neacc3wyadc4l2exk4nlobphuo lnolo10ve6/xnrrxqic08cd0aw0h/vj/aaiuehaxu2g3olytbu0gc9johv8dnbkrakhwd dkdxfkos hzfw4d7kse838vgsixrxlgohbhaujwz00jaj0jvcmke6u5x6noj8y0wz7hbo3x bnkarkyqczg7rvsei5g3qfggbyknlg8aa9qaoxth9h2hxc6lgwxcth hjuid1wsfq4wnpgtkfgypo8ftqtpoaqwbgxloqfoiglbrmc164awtaej3woo fsydnqjk6lgpaea3/6/g3bdl5hhzz7ybmleaxjtced5kv 89suryi6wvv4qbzkhctj4mmrebbq5uc zo4dxee6gjyxraioe1xbmqvjjvfkginbtue6yh188fvgy296usarbwrd9qeq3xu e6o1ia bb6pagam1t1g8ke5bv6cxxkt3zjzkezsfe2tlzkg8egnzoo2nggkbguq2z0r4q1wf/g3e3ft7ptpfzzx826q3oy bsfdmnwgh9ed wa56fqb5yxt2 s16bpeqtllisrpc8fnt1vt4zoaqwbgxloqc5yagekbornvkto/l07ypstocvqvtbdg3nhccrfnpkglqeg6dogxdz2ntmdytpziaimndeij0pmy30ic0gazltmfpklq4olupoporccbyen ggjornlxbg10mfmuzgqylnunxh9uwbeb7pmdqona/decs9fzbpk/he3o67r3mu/osyxf7rph0r3t6ou0d5lpvfhid5s8nnjs scbvfr krtw3kh 4wn9pjxhvf7y2efpdeqfiokfm7x9dxqwulmmvgircanu09hgbqiat09pp7txwlsknp9bgznia6klwai529w82hd/iksfequra94dsmnmilixjd2b17awzr mctmfacapvntrxohuucu se te5xqwgok0mnskqsrvoz hqnnutjdjplkrda67ywpmwcreb9bxo1dom0g5oh7tcrwfxd1yfzaw0t87 ynrfqvq6dfo66/dap/pldrsb6y5/7sndlxvvbmm5nhiwfstgoatvfcez642r4ikxgp1npyfawoeohwhi4jrfvh2dvi1ymapj3bhumvcoiluze2jf 7srw7hdhylj6swfi6q5dsm1qj8ixhcwx2gz8b1amyh1 1evxdrirxavmhot3w5veenlr2d6l7vakywt6mvfvidykszzdl7okkondn/nw2f/bllcweye5pjuuqmmqmzrjvxoxwlk758edayx9m8c2c/rokwbvncwr mhop9ednxc6n59mrcgakq7chmgiyz1u7glc2lrkqcsriyrf tzbfecmg vwshyikicjatxqo/abtdrm 7dyetnxyngvk5wvyd3ifvmiwu0cdku8idpxk876fgnuktflh90garsqqpp9juwlyfnvmlcvopejfwmz/jg9m7gvmovlj yfsks vco63zhw1k92ewtp7rsy4vfx6o1kxon4dmgbbzsbes5dq2jszhqg2hn6iyt3hanabht4ycxfsriyyj181qge68jmllsdhggemrfxwv rygpftseiy9uhzliq412f dbyxabqnpe7hlugk1lauqtrzwh avczqmvylpjps6ghs6lxz 56kw5n5msd37mwmxk/vijwokyxubo7uscxuwwnsavzfgvcpy37misdhv3oiyka/1ig4xz/6frzbuarn8wtglrhfpyge73tuvnnyvov2nctsq6qlylm6rxi9cearr/sw9aqlz8ksnjffmg03hq5ak7vzsq/sa4frqi0ah2svvnlcuqjgxj6zsallz9vj/g4dumy4ye9x 7qzp2nf5j/u9bz1aa5wgesuhjv bapf vz1fqpskny99k1mvv30ic3bbsegm/s84qs/p0ovwte6xh8y7mmreeszd5kqf9owfzlyeymt3ueg3pg5zjiqhvqkoqpnfplpzhgpfrlopakfomnvy2g/glbc8ahzzockhcauczrhvrmpqu2epjydhtfxusch8rsqsphsukfvmsommjquttbirvls1xsgpswh514s6vis47heo4l8fdnqk6dtetnnvuugebfhzjtddyozofdcl7my8x aizdaks97gww9cmzbdadbnwecetiy9 maikrvikf qapyuzj06h8h2mvsmxivxlaqgbzu7oyqvsvldrr95s3k8mxynm2uaff0pkbseurfcxfbxrructsjxohuucu se8wtuj1dbuegjwpwljqb 7zcezmgngiihjeekdrqsr5bi0c2/mnohsu s7pu159mxbkpemnozv8defz00pf1gnpniuouqie1soqag1tnqtrkiczhgfpgawz/5cx/a5bkov15x3nfisamsqxlujjnmw2lqidzelfclqeldmgbxy9mzzvqh wcsdqw0a/03s2ao8azgfvyqpfvq0d/pmz4ii edvqnuri3nby1tpikvbbpkig63zb3wzzjgoqvalrx4kxcanvtbdsbzyj5fhcnfzlqsw6hl9il9qlzntqkcpsnqcpkqwcpwe7nulkt2cy0dqu2gf/ibotzig0mi5ujxpwm 6znudjqp2btetdxu3tt5vumz1a40d9su0i0vfh7zgqsi/brg4uw nfww9kus7rd0zrqstvd7c4awtaej3womt51evmyymssfragbr1jwnrcyarcqn1boyqyekmrnhzaw9raylv8euc9h2uda9 45ur36chho97aafzlcaf2d8rsyb4vzk 9q6eqlq8d/s/ql5ojmkh88zewqfdbkdy7w3pstrnb2ipfesrisp 7swfy//pme5n/hkysdwcbujt 9tdefjsj32ogeqyobip4jtisimhbk/atqfu0oykq5m8wnoiuhuhcwnvplpitfyutnjonr37uoeqdisavkdoxxkkjmzofeihrokrxf5av ejhon9mfjz2uftt f2ar5/aarmciukbydqjjeggnchoas8lajeahue2rsy/nuzb8vxbqoq4om207nwv5g6oofsrak2bvyqjampokiqpavmd b8dqpzsxd01siyadokguiaxbh6pflutgs/senpnnk9n lgsc28rrziskvpczt431usdzvwfocdxmskbfxrmemgbay34y1z430qbe8mhfm2tle40mv6rzh/jg9m7gvmovlj yfsks vco63zhw1k92ewtp7rsy4vfx6o1kxon4dmgbbzsbes5dq2jszhqg2hn6iyt3hanabht4ycxfsriyyj181qge68jmllsdhggemrfxwv rygpftseiy9uhzliq412f dbyxabqnpe7hlugk1lauqtrzwh avczqmvylpjps6ghs6lxz 56kw5n5msd37mwmxk/vijwokyxubo7uscxuwwnsavzfgvcpy37misdhv3oiyka/1ig4xz/6frzbuarn8wtglrhfpyge73tuvnnyvov2nctsq6qlylm6rxi9cearr/sw9aqlz8ksnjffmg03hq5ak7vzsq/sa4frqi0ah2svvnlcuqjgxj6zsallz9vj/g4dumy4ye9x 7qzp2nf5j/u9bz1aa5wgesuhjv bapf vwkw5ba91xsnof9metgap34sgbxdcrhjlphyebbgr/g0dbwjg0tels4hhtm5l f6jlyeymt3ueg3pg5zjiqhvt/xpn0tj8mac0naerqz5xubhslckmzu/vu5g5h8vnwhzlanydzfirogb8etbnr32u3vix4lnydlmibnuhingdx25ond4nounmiobsy4jkww4nifs4jwdbqwelcrkylwr1vu2b08fcqbr0qnq/vjw9sfvjllnhzff6m8h thcf6ynmwb6v 2bspu7gqwk 1bbyeldmgbxy9me5edzbejehh/ff1/ivm22ojz2mldj36wbwqzs6uzmu2zn0yzcexq7tvv1zj6clgofe j5udsjvm1qzhdspe1egbvgn k6idqt1nbxnsaczwio836ifiwnjmj2 yq28m5ft tfymc1xj5nafakqwvou m2q4/2qxhzf8hckel1mfwkhrdiywanl2jzhuav3xonhrshwohlvvfcqa97qkonoy0zstkuod4ru4ujrkmpiogvnxez4nxbp6m8ojmo z4jqwgrlpouuhsmjgzgx71xuved niytve sdtsynnb awu epyjok6dcbnt9pusrrg4saxdlpz5pcqmaopget6maaefmxsszkkql6nka hxsn05ep20ttjc56q0 m/ipspwr1nn87tk3iagr905q3zsqnd0dqn6bupvxaibhe9mlfnvcetacb5wm7rjtjynqky0omrg4wqkgcmqvs6/l ab 5oylxugt4paroo7caopomtg7bikbyrg0i uemvq8jomuo3h1aimi5rf6w hl7mjjnamo1ahrkckxwg6cer3idkn 5s/o783hq9xmvta5orbbl70ggumtta5xc0piyrecepfgfafpqgdk8jubuyhxvhpptzejjmyncl x7xk9qzzv7gkouz/l39igsc5gg2v7txqrdiqknfcqjvbtuc4vnojkkafut8atkivzfqdbo b1tztmndqrbjsegx1plufnxsjrouvhzyct4huztxjj7ownwfz4kptbtypcl jxat5twshykkxlwvyrtcwp9kz1mjekvxr4v 7rbqces5in5qfec8bb mwznarapiffu9djnsi35c0vrlrw6xeci7gskpy1mxintitkn ylf9uucbcw068iwfrja2hirmoq0oicdg rqdlkddk0h1fnzxazxuk9wrltrphyjwvfgmgcbfvefozigl9yiozgtn3ooutpevxewlfhsbyu1/a9zsvbbu/hdgeef2gethcfjg2haisrbhpwotmkvjqi3mh1htkbmvzbmw/fv26jkodjnto51r yojqh0q2pngvcqiwjdzpced2lznfm/a0kwusxdnbcgahtpbromsqyej35vlyev0np6zzzptfi4latvea84kiltws7en9bkg81vnznhddiwc5tidi0s1qmvlbpha/6ygf2cfhhp9u8nm1/lgkuzwwejocttqii0zkqya4ymfwntgeh hxhrne uoddqgtumjhie/vh4t9w7gnjglkwhjqzbgcwptencolrmqwzqu3eg4taweryvo1wkwkmska7gm dept6n0unc5ql09piopbabtykeirnzdm1ys4b duc/hw56iug5wfq5k5ahfaekhwll4za4poaqwbgxloqidtfcl0nju6towrxcjr4g5lhnnk26neicbvw9chwqfuxcyvmqvwk zqc uxpdxrfphr2os8hvoxwi63d754drpb1ddtmmfxyriv6pstr3gpy17otzc3ou3hw0mpfns56l/fjsu3xjj9ursrzukafotb3wck78pz9zsk1w3zqg/fphlibkudcoumrv3cdw3gz39tipa1c1u3yuvyewrhcr7icuhukdq76wc6wjxs97r9edgtdcjztxx3qddqf9wp928ez/bggwuzrstxbcgtdmdlx 8mdngdca8srcvqmug eduhcgjjjeesx7zfy bkjdhesy4cecc55wn2jrixko3lkoes6g8jjbhxyidsdpoakel0xceattux1151c3z9cpbmzfnnhy8zlw2by4aegp ue/ni0v kcpv2r q6rlxw0n1cwfeztjh7ps cv1gw3fxcnfm3f5wvvt6aa5veev16b1lnfpknv4rznitj3fwudemkhevajjwr2j/fyxcnz9l0kkknpwrnwbs55mvos12abhytu1qka29zsmgo9uzpx8asg/uwaanjk6ipvlls7x0bjfmaooyapvpg6vuphluyejjpeajtqfcqa97qkonoy0zstkuod4ru4ujrkmpiogvnxez4nxbp6m8ojmo z4jqwgrlpouuhsmjgzgx71xuved niytve sdtsynnb awu epyjok6dcbnt9pusrrg4saxdlpz5pcqmaopget6maaefmxsszkkql6nka hxsn05ep20ttjc56q0 m/ipspwr1nn87tk3iagr905q3zsqnd0dqn6buhh2y7klsfkffnvcetacb5wm7rjtjynqky0omrg4wqkgkyf4cwbgni0dyjc5rj ftb8ixa0mjezqifh1pqmsweyidvuajzcoipjlw3feamugyniq3cuk9eed7ejrthezt6kjuko/mfz3lsxqfou4e0hocowijzrglpusahtlobniuropghgchk0qzwytndjg3gthal083orvsu0i0vfh7zfm5ypyqwvdqpcbd fd6npj2ocqfdl9sjawv03g g20/v8b1hq2g6em1srap5do2d6v gy3uhegxmsuwyemka/a64ucpyxk4njfq5bzohq/ekb3e7fqvavma3gaeqkddw5fe 28aqhotlvxfzwehevsnlkov0erebsvngay8ubzlcuzvpj4svz 1kk63ungxu9rongho7e93jiz3cnaifcvx3yg3zkcyoi90univi9lxqtyee vqcnsfke91ik5lxwl3gjw ux ujboqwox0tawnyd/ tynbuo0uwxjtpjors f5rph7g4h2mzrn4t0fwe9phyzuueorp1tiq9emqnbsdiqhnwyjs3y2ffiskgdrhbmnhj0vb4ktz/2msbtrgmk67jzis5otfw3obrm8qs/vwgtachnmewsnwbva849b0brctzzssxgsybcdhovmuu34ucwlbxgvdjwyblmh9x6ctjtchwkxrsmkj0ts8slor  pfoqsxfw4hqetdwg9f6p7 o40b5dq1z6k iiekginnclj7c6nv251yx p9ktt2ukkwklipxlms1eqj19vr7360ijfjg8lfwntgeh hxhrne uoddqgtumjhie/vh4t9w7gnjglkwhjqzbgcwptencolrmqwzqu3eg4taweryvo1wkwkmska7gm dept6n0unc5ql09pice83qlux3xztvcr7mk4r1l6dfghi/u2mhwyjrb 20hhwgptof1kie4sumwyhfj0xlnclrsc2cefprpmoxh3izfrjpptvjyy3zqov3leozlcxedfmybgxrroytcimw hy5by2dtijsbndk0zfd1aqcfusdzvwfocdaxtdiqwod8daojou8xupqlvga5ikpdynpjpvcibyseftypn0m3yh4cgbmjlhtjykry7zpzp dhm 5/sbfpw78qqiq1zdai0hhbt4ohfzsdrowrvbfoob8xvldwfeq3q/whm/dn/vfja i65oez7/qajkhao oblqhyfaimhavlin9pfffrvvndnaco63pggoktcsndpx2xyzpeyvm2yseevxwllqqksmww5jbriieuwdm2idqsvzov9ssae5qoryznnumdql8dukcutkisiygbf0xk3glicxihvemvqqxc5/qsow5b mp/ihcxnjfxe116vgbpveg7q e lnkqkkzcdqm/47wkndua/hmegtjzhgwcys0x12ksdrkku5o0rvala7rzwiajwc0lxpkrbr9gqnzfdg/mlipjt4bimo0tkscyrhugs1uudrpgtm2cwgtlvyxhqqea9ljcsjcyd15w9l92tbmcg52meamkb0f9epu9eoztg fwhwoppuvnoanxianksjoqmzobrip2yze28ctcgw7iklug0/wf/u5srhgf8or2sejcocdw01bosodfph1rmnverrgkw1qw/uhqt8bvhoqnygpm2 j2hmptbdrvjhuw7 nmcsrd2y85hmbbrnrs2zbvbij2tjtpxhigyfktmdeeench/4n3t30 6u6x2wv/nuqtzmpm7hwzdvhh/xnfsaoen0g cl09vktemzxee5zykq6qvhzbdvbegaaefmxsszkhocgbnpaak51srap5do2d5zkcejl//s0ul2hfqk7ruajuhoogzhlw2dp7zncrawymopjqxiidd5d4nmtujvymbs05adekvc01ebv18i/j3u9en itksde2jlqkif m4z2cu1/z87pgfsraazsookv aaefmxsszknirbayhfgrbrtoh/4mzk2bqhe/ikdqv167ab/ js5nmca5v0kjont2ohg01yetsg3la8wxtx9hbtwownalncm2qr54deeu 2ezarwtoakf3iio/xge0ajbegds5xt5j78non9irxc5aqrj uf/u8y2drorchpaij5zjaqmtyr8wnd8kagtoqob6hwke07mha43qihxgqsaayy1elx0bbalzztu00bs6s/haykhgiowrrne9i4/q4zqtbzvizbk0o7 0exxn3oxiclhdwitt1wp9uwapfdl5ctu1rewbloo0cd/ujb6gdcgd8ehhkn/p7imnynwewenlqhthkcrskaz98xx8huzbanotnqiazudmt75rpu3a6pebtyfxc4sgspv4uusxmhwmeyqolcop8qhdb3qvsw3ily3ni7f5s1mxtpe0z4drjkc7xgeexltk53kkjmzofeihrokrxf5av flhht8xr5hpkftt f2ar5/aarmciukbydqjjeggnchoas8lajeahue2rsy/nuzb8vxbqoq4om207nwv5g6oofsrak2bvyqjampokiqpavmd b8dqpzsxd01siyadokguiaxbh6pflutgs/senpnnk9n lgsc28rrziskvpczt431usdzvwfocdrhmkyboetvfa0aylztglols78l4ukngpzsqrcqsg9eubytz m3e6gcoavj/ sbokgy7hyo0socbimnaaquaxy6stjluvvuembwpuaufpgiutcxaw 5jt2qnpomgurg3cc mlyyfnbnkpda6iutpymgclizjzzl59o8c3wenwgeqsx6uyae5awjoaqwbgxloqz2q5tckug/hfypjxiworncxvkxf771lo6diw5lrnuly 8wdk00eltscfa5lf8irplfgrwbnxofdl56poxpqywcwnoxxozb4dvbucc2trlqozoki7ndiag17c0f1wjig5ykbslwy2vs5tlo99wgitcblz cfes0gvkxikasojspouy481el0zxwrrfw1z/lb/48hw/s8aned7emkv uq4bbpjk6/jaml5cgasseuw7gpe/q/fkcyjxffapvtnem0e2z7li3bl8r6cywkdlweffptojodt1l2raltx 0jy1qp90w61cuqrvqzb1mjwq0oqutcihkck08h2nmrk3647klaps/0r1gragk73wnmeunovyvt/slo9bvw8v4wzsld12htjau2uoud1ktivlrahrmqnzfdg/mli0hnojtfljjqwbxgzjlugl0nqb36/n3kdrnnaogqsrvp seaezqewzv4s6vis47heo4l8fdnqk6dtetnnvuugebfhzjtddyoz0itwr//hhw6h gudxlzchctvuzbsr50ijr5unsyj8khlljmli57yxknpak6q33lkogytpxzqxyn/zn93diudosxf8w8pixksnhdynziinjm/snmiyxgjwtilza8b1wu zrnq7k/r2adegds5xt5j7xa24nunu54ynclawopv7vmj5myacaigemr6r2tcyvkglqlb y2gext5ls 7xn2zdsql4yc5m/wmr9ntq9/wa2k0i45sogtwyiocdw01bosohxkcyu8ybbp/lzh8dkgshxxnhed8ixqzjdgvqkk0xbytagpn6uvwuosumwyhfj0xno9af7bxj2pbrr/tezycjxrmz 9ha8vvfp0ohhmvlwl4nvce6sjc0fjw0 ipufumsibrdkhfbnmmcipvotffgpdxo29nsowflipl fyd9ktbldocv2iv1n8ztr6pbtjv06qehnbkxumdsws3yjjr2q7ab/ js5nmkdsyjlspe/cb7pmdqona/yg15n1dtdo3m 6znudjqp2y7qjs8uftkedcibv8frphocmwmn/4ijv3rmtbjo93slfjabgindwpuokgivav ar3g3fnw p6swtxgbeja3vuhhdj6qxgcdkdd1editxx5rz0fzr0d37jlrhfpyge73saavmvxoxypyuzihhvmt72rp5aurwp9l ovmimyshzzmtbav1sp3ltbeljoudvakkurkukw/7uzavj/ kx7mf8cpiwpbwg4lp72114ulkpfy6aspiggkninojkkafut8bnb 7q5isrmsurv48mgx0ja1wmwkhmxk5oem41hftsgsoojibup07fcoqmxk596kfe6rfcxlpx4z/fuxfznghcqw1p4xybhn9obexwhsrth2okkqyacke5plyucn5odr7zgzl825lvxvduo5dg4zbtuda/mdo6h9ktqtyfxkolow86qha9pwz35vwnclllf3twwhgb06qa6jregho9 vs2bl9j6emc2t034ucwlbxgvojipu8lo3jfw5ipnvz85x0vyvt/slo9bvw8v4wzsld12htjau2uoud1ktivlrahrmqnzfdg/mligszmci45sdkjqdlex/kluwxtuybhuw782zdjpea5pb1prwrv36ecrayjfubpzu/np9kzuvluytyahkcj96yh2o m669xzrpnbxhon gy80ckk3f4jllim840trd2ffaag8plezmqtr2eldmgbxy9mw1vxhuyrhhw7z1cxnjcptr6bld3r5qmh1low3eda7rq1stb7aqaiff1nd2jyhz/8bnlxw6cywl6f8fuxm9oqfj3ikofs5gzejoaqwbgxloqqggw9pws7ctedouzqr7u9nsrfvy26aqv/ouq4dkp6awpfg/ya/vyinb2mp0gp1sory7zpzp dho9bzuu 1ufqqdb769shjec3n4gipz9ras/cvbjj/df6geytstsr5wqwf4kjjgdlqltxdvsbupea yo/ay9snsqa3avgl yaukpcyuwl3 w7iu4jqvwa9sens2m03ztsyya1ovhn34w zhp0svmsggdgkjfszbavjijzb28yajqfz2hepruxr48aq6fm9oobofwvislqhfdsny xafvzdbh'
let res = decryptbydes(s);
console.log(res);

运行结果如下。

点击查看代码
{"success":true,"data":{"datalist":[{"bulletinid":"2127d78a-cc63-4946-a3fc-667ed8f7f3b4","tenderprojectname":"上海浦东发展银行股份有限公司信用卡中心2024年度国产数据库维保采购项目","bidsectionname":null,"noticename":"上海浦东发展银行股份有限公司信用卡中心2024年度国产数据库维保采购项目 招标公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-26 13:30:00","notieindustriestname":"信息电子","reginprovince":"上海市","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"310000","regionname":"上海市 上海市","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179240.html","supervisedeptname":"/","leftopenbidday":24,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"上海浦东发展银行股份有限公司信用卡中心","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":false,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":false,"subcription":false},{"bulletinid":"6bcbb909-45e1-498a-8475-16505c4c1062","tenderprojectname":"中国邮政集团有限公司内蒙古自治区分公司全区邮资票品库安防达标改造-ups项目","bidsectionname":null,"noticename":"中国邮政集团有限公司内蒙古自治区分公司全区邮资票品库安防达标改造-ups项目招标公告","noticemedia":"内蒙古招标投标网","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-22 14:30:00","notieindustriestname":"其他","reginprovince":"内蒙古自治区","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"150000","regionname":"内蒙古自治区 内蒙古自治区","noticesendtime":"2024-03-01","bulletinsource":"内蒙古招标投标网","noticeurl":"http://zbgg.nmgztb.com.cn/biddingbulletin/2024-03-01/563437.html","supervisedeptname":"中国邮政集团有限公司内蒙古自治区分公司","leftopenbidday":20,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"中国邮政集团有限公司内蒙古自治区分公司","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":true,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":false,"subcription":false},{"bulletinid":"dc5bcc1e-d082-4634-a71a-13fd731b642e","tenderprojectname":"虹口港驳岸景观绿化整修项目","bidsectionname":null,"noticename":"虹口港驳岸景观绿化整修项目招标公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-13 14:00:00","notieindustriestname":"园林绿化","reginprovince":"上海市","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"310109","regionname":"上海市 市辖区","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179266.html","supervisedeptname":"/","leftopenbidday":11,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"上海市虹口区市政和水务管理中心","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":false,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":true,"subcription":false},{"bulletinid":"5f30d33f-372e-4489-ad1e-a949719846a6","tenderprojectname":"中国黄金集团建设有限公司矿业分公司乌努格吐山铜钼矿低铜废石环境污染预防及资源综合回收利用工程","bidsectionname":null,"noticename":"中国黄金集团建设有限公司矿业分公司乌努格吐山铜钼矿低铜废石环境污染预防及资源综合回收利用工程钢结构制安及彩板维护工程专业分包(标段一)招标公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-08 14:00:00","notieindustriestname":"矿产冶金","reginprovince":"内蒙古自治区","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"150000","regionname":"内蒙古自治区 内蒙古自治区","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179273.html","supervisedeptname":"中国黄金集团建设有限公司相关部门","leftopenbidday":6,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"中国黄金集团建设有限公司矿业分公司","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":false,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":false,"subcription":false},{"bulletinid":"03568039-a27f-45df-afff-e8e462c3017c","tenderprojectname":"云南省安宁监狱(企业)2024年-2025年水电维修材料采购","bidsectionname":null,"noticename":"云南省安宁监狱(企业)2024年-2025年水电维修材料采购竞争性磋商公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-15 10:00:00","notieindustriestname":"其他","reginprovince":"云南省","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"530000","regionname":"云南省 云南省","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179264.html","supervisedeptname":"云南省安宁监狱审计科,安宁监狱纪委监察室","leftopenbidday":13,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"云南省安宁监狱、云南金马集团光明实业有限责任公司","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":true,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":true,"subcription":false},{"bulletinid":"5822fab0-ab8c-46fb-b234-1f7a32f3aadc","tenderprojectname":"昆明滇池水务4家子公司股权转让资产评估服务机构选聘","bidsectionname":null,"noticename":"昆明滇池水务4家子公司股权转让资产评估服务机构选聘竞争性谈判公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-12 14:30:00","notieindustriestname":"商业服务","reginprovince":"云南省","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"530100","regionname":"云南省 昆明市","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179274.html","supervisedeptname":"/","leftopenbidday":10,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"昆明滇池水务股份有限公司","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":true,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":true,"subcription":false},{"bulletinid":"882ecfd8-da7d-4d54-9959-8d902e915d6d","tenderprojectname":"松花江水上旅游大通道—松花江源生态文化旅游建设项目(松江湖岸山村建设项目一标段)监理","bidsectionname":null,"noticename":"松花江水上旅游大通道—松花江源生态文化旅游建设项目(松江湖岸山村建设项目一标段)监理-招标公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-25 13:30:00","notieindustriestname":"其他","reginprovince":"吉林省","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"220000","regionname":"吉林省 吉林省","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179277.html","supervisedeptname":"靖宇县建设工程招投标管理办公室","leftopenbidday":23,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"白山松花江商业运营管理有限公司","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":true,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":true,"subcription":false},{"bulletinid":"9ff8b973-5d64-47b6-8cf8-d4e7c9c0f5de","tenderprojectname":"聊城市公共资源交易中心证照“三联办”信息系统升级项目","bidsectionname":null,"noticename":"聊城市公共资源交易中心证照“三联办”信息系统升级项目采购公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-19 14:00:00","notieindustriestname":"商业服务","reginprovince":"山东省","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"371500","regionname":"山东省 聊城市","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179255.html","supervisedeptname":"中国银行股份有限公司聊城分行","leftopenbidday":17,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"中国银行股份有限公司聊城分行","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":false,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":false,"subcription":false},{"bulletinid":"81431cb1-6b13-4f7b-8fd0-e5a19dd63a74","tenderprojectname":"2024年3个月液体葡萄糖采购项目(第三次)","bidsectionname":null,"noticename":"浙江省成套招标代理有限公司关于杭州市环境集团有限公司2024年3个月液体葡萄糖采购项目(第三次)的公开招标公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-21 14:00:00","notieindustriestname":"化学工业","reginprovince":"浙江省","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"330100","regionname":"浙江省 杭州市","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179319.html","supervisedeptname":"杭州市环境集团有限公司纪检监察室;郑先生,13336041895","leftopenbidday":19,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"杭州市环境集团有限公司","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":true,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":false,"subcription":false},{"bulletinid":"88cadd3d-a3cf-4bff-a22e-5b84a668a5b9","tenderprojectname":"中央储备粮临沂直属库有限公司新库区项目沉降观测项目","bidsectionname":null,"noticename":"中央储备粮临沂直属库有限公司新库区项目沉降观测项目竞争性磋商采购公告","noticemedia":"中国招标投标公共服务平台","bulletintypename":"招标公告","docgetendtime":null,"biddocrefferendtime":null,"bidopentime":"2024-03-14 09:30:00","notieindustriestname":"商业服务","reginprovince":"山东省","serverplat":null,"tradeplat":null,"dataplat":null,"regioncode":"370000","regionname":"山东省 山东省","noticesendtime":"2024-03-01","bulletinsource":"发布工具","noticeurl":"https://bulletin.cebpubservice.com/biddingbulletin/2024-03-01/12179251.html","supervisedeptname":"/","leftopenbidday":12,"platformcode":null,"platformname":null,"commentcount":0,"hot":0,"viewcount":0,"favcount":0,"subscriptioncount":0,"tenderbidder":"中央储备粮临沂直属库有限公司","tenderagency":"","isnew":0,"grade":null,"datasource":"0","potentialbidderdetails":true,"classifyname":null,"classifycode":null,"isbulletinchain":"0","upbulletinstatus":0,"winprice":null,"winbidder":"","bulletinuuid":null,"vipwinbidder":false,"fav":false,"similarprojectsbidinfo":false,"subcription":false}],"totalpage":2435375,"currentpage":1,"totalcount":24353746,"pagesize":10},"errormessage":""}

得到该页面显示的数据内容,这样就可以用python代码来获取页面内容了。

点击查看代码
from functools import partial  # 锁定参数
import subprocess
subprocess.popen = partial(subprocess.popen, encoding="utf-8")
import execjs
import requests
url = "https://ctbpsp.com/cutominfoapi/recommand/type/5/pagesize/10/currentpage/1"
resp = requests.get(url, headers={"user-agent": "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, "
                                                "like gecko) chrome/122.0.0.0 safari/537.36"})
f = open("某招标网站.js", mode="r", encoding="utf-8")
js_code = f.read()
f.close()
js = execjs.compile(js_code)
result = js.call("decryptbydes", resp.text.strip('"'))
print(result)
返回顶部
顶部
网站地图