JS逆向进阶篇【过咪咕登录】【附带源码】

这篇具有很好参考价值的文章主要介绍了JS逆向进阶篇【过咪咕登录】【附带源码】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

每篇前言:

  • 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者

  • 🔥🔥本文已收录于爬虫进阶+实战系列教程专栏:《爬虫进阶+实战系列教程》
  • 🔥🔥热门专栏推荐:《Python全栈系列教程》、《爬虫从入门到精通系列教程》、《爬虫进阶+实战系列教程》、《Scrapy框架从入门到实战》、《Flask框架从入门到实战》、《Django框架从入门到实战》、《Tornado框架从入门到实战》、《前端系列教程》。
  • 📝​📝本专栏面向广大程序猿,为的是大家都做到Python全栈技术从入门到精通,穿插有很多实战优化点。
  • 🎉🎉订阅专栏后可私聊进一千多人Python全栈交流群(手把手教学,问题解答); 进群可领取Python全栈教程视频 + 多得数不过来的计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
  • 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

咪咕登录

之前的请求中找数据:

  1. 上级页面搜索: 静态页面搜索参数内容

  2. 本级页面:Network里搜索内容

复杂登录特点:

  • 参数多
  • 加密参数来源复杂
  • 多次请求

简单拓展:

  • Ajax请求的底层是基于XMLHttpRequests对象实现,所以在抓包时有两个特征:页面不刷新 + 请求类型为xhr。

参数对比

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

captcha参数

这个值对应的是验证码的数据,第一次登录时并没有这个验证码,提交空值给表单就可以了,验证码是账号或密码输错导致登录失败的时候会出现。这个时候会给服务器发送一条请求,返回值就是验证码经过base64编码后的数据。

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

enpassword参数

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

通过观察两次请求的参数可以看出来enpassword参数是不相同的,所以这个参数显然是动态变化生成的,再仔细观察一下发现这个值每个字符的范围都是0-9和a-f,通过我们的经验可以猜想这个参数是16进制的字符串,而且很有可能是经过加密的。

搜索enpassword参数

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

但是搜索发现都是HTML源码里,显然不可能包含此参数的值。经验可知此参数肯定是JS动态生成的,所以我们就看HTML源码中此参数对应的代码:(既然name值参数搜索没用,那么就来搜索一下class的值J_RsaPsd)

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

搜索J_RsaPsd参数

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

分析JS文件,会发现三个地方都有此参数,而且结构几乎一致,所以为了找到目标数据,我们将这三个都打上断点进行观察!执行观察会停在哪一个上,那我们就只分析那一个即可!
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

执行过程,分析可知是个RSA加密!

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

分析最近的一个函数,当选中var b = $(this)这句时,密码输入框标记选中,可知此句是将密码赋值给b。
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

进入db函数

这里看不出有什么东西,先跳过不管。

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

setPublic函数

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

这里需要传入两个参数,这两个值在上一个请求的response中可以得到,而且都是固定值。
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

这两个参数可以作为固定值写在代码里。
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

encrypt加密函数

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

传进去的参数b.val()在console中执行发现就是我们在密码框中输入的明文。

encrypt函数实际就是gb函数
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

这里是将gb函数赋值给db对象的原型对象,下面又把db对象赋值给c.RSAKey,这就是最开始定义c的语句。

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

gb函数执行到c.toString(16)的时候就得到了加密结果

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

改写JS加密基本逻辑(下面的代码就写入改写的JS代码中)

function getEncryptedPwd(pwd, modulus, publicExponent) {
    c = new RSAKey;
    c.setPublic(modulus, publicExponent);
    var d = c.encrypt(pwd);
    return d;
}

pwd传入明文密码,modulus和publicExponent是固定值,现在只要把里面有关联的函数复制出来再进行调试就可以了。
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

这里是RSA加密函数定义的起止位置(注意:我们复制两个大括号内部的所有代码!)

Python调用JS加密函数(最终编写爬虫文件中使用!)

def make_encrypt_password(self, password, modulus, publicExponent):
        """生成加密后的密码

        Args:
            password (str): 输入框内输入的原始密码
            modulus (str): rsa加密参数,两个质数的乘积,固定值,前一个请求获得
            publicExponent (str): rsa加密参数,大于1的奇数,固定值,前一个请求获得

        Returns:
            str: 加密后的密码
        """
        return self.js_object.call('getEncryptedPwd', password, modulus, publicExponent)

运行时可能会遇到的问题

  1. 遇到的错误1

    • 报错
      JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录
  • 解决方法 把alert中的中文删去
    JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录
  1. 遇到的错误2

    • 报错
      JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录
  • 解决方法 定义navigator和window
    JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录
  1. 遇到的错误3

    • 报错
      JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录
  • 解决方法 修改如下代码
    JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

此部分改写的最终形态JS代码:

var navigator = {},window={};

function d(a, b, c) {
    null != a && ("number" == typeof a ? this.fromNumber(a, b, c) : null == b && "string" != typeof a ? this.fromString(a, 256) : this.fromString(a, b))
}
function e() {
    return new d(null)
}
function f(a, b, c, d, e, f) {
    for (; --f >= 0; ) {
        var g = b * this[a++] + c[d] + e;
        e = Math.floor(g / 67108864),
        c[d++] = 67108863 & g
    }
    return e
}
function g(a, b, c, d, e, f) {
    for (var g = 32767 & b, h = b >> 15; --f >= 0; ) {
        var i = 32767 & this[a]
          , j = this[a++] >> 15
          , k = h * i + j * g;
        i = g * i + ((32767 & k) << 15) + c[d] + (1073741823 & e),
        e = (i >>> 30) + (k >>> 15) + h * j + (e >>> 30),
        c[d++] = 1073741823 & i
    }
    return e
}
function h(a, b, c, d, e, f) {
    for (var g = 16383 & b, h = b >> 14; --f >= 0; ) {
        var i = 16383 & this[a]
          , j = this[a++] >> 14
          , k = h * i + j * g;
        i = g * i + ((16383 & k) << 14) + c[d] + e,
        e = (i >> 28) + (k >> 14) + h * j,
        c[d++] = 268435455 & i
    }
    return e
}
function i(a) {
    return nb.charAt(a)
}
function j(a, b) {
    var c = ob[a.charCodeAt(b)];
    return null == c ? -1 : c
}
function k(a) {
    for (var b = this.t - 1; b >= 0; --b)
        a[b] = this[b];
    a.t = this.t,
    a.s = this.s
}
function l(a) {
    this.t = 1,
    this.s = 0 > a ? -1 : 0,
    a > 0 ? this[0] = a : -1 > a ? this[0] = a + this.DV : this.t = 0
}
function m(a) {
    var b = e();
    return b.fromInt(a),
    b
}
function n(a, b) {
    var c;
    if (16 == b)
        c = 4;
    else if (8 == b)
        c = 3;
    else if (256 == b)
        c = 8;
    else if (2 == b)
        c = 1;
    else if (32 == b)
        c = 5;
    else {
        if (4 != b)
            return void this.fromRadix(a, b);
        c = 2
    }
    this.t = 0,
    this.s = 0;
    for (var e = a.length, f = !1, g = 0; --e >= 0; ) {
        var h = 8 == c ? 255 & a[e] : j(a, e);
        0 > h ? "-" == a.charAt(e) && (f = !0) : (f = !1,
        0 == g ? this[this.t++] = h : g + c > this.DB ? (this[this.t - 1] |= (h & (1 << this.DB - g) - 1) << g,
        this[this.t++] = h >> this.DB - g) : this[this.t - 1] |= h << g,
        g += c,
        g >= this.DB && (g -= this.DB))
    }
    8 == c && 0 != (128 & a[0]) && (this.s = -1,
    g > 0 && (this[this.t - 1] |= (1 << this.DB - g) - 1 << g)),
    this.clamp(),
    f && d.ZERO.subTo(this, this)
}
function o() {
    for (var a = this.s & this.DM; this.t > 0 && this[this.t - 1] == a; )
        --this.t
}
function p(a) {
    if (this.s < 0)
        return "-" + this.negate().toString(a);
    var b;
    if (16 == a)
        b = 4;
    else if (8 == a)
        b = 3;
    else if (2 == a)
        b = 1;
    else if (32 == a)
        b = 5;
    else {
        if (4 != a)
            return this.toRadix(a);
        b = 2
    }
    var c, d = (1 << b) - 1, e = !1, f = "", g = this.t, h = this.DB - g * this.DB % b;
    if (g-- > 0)
        for (h < this.DB && (c = this[g] >> h) > 0 && (e = !0,
        f = i(c)); g >= 0; )
            b > h ? (c = (this[g] & (1 << h) - 1) << b - h,
            c |= this[--g] >> (h += this.DB - b)) : (c = this[g] >> (h -= b) & d,
            0 >= h && (h += this.DB,
            --g)),
            c > 0 && (e = !0),
            e && (f += i(c));
    return e ? f : "0"
}
function q() {
    var a = e();
    return d.ZERO.subTo(this, a),
    a
}
function r() {
    return this.s < 0 ? this.negate() : this
}
function s(a) {
    var b = this.s - a.s;
    if (0 != b)
        return b;
    var c = this.t;
    if (b = c - a.t,
    0 != b)
        return this.s < 0 ? -b : b;
    for (; --c >= 0; )
        if (0 != (b = this[c] - a[c]))
            return b;
    return 0
}
function t(a) {
    var b, c = 1;
    return 0 != (b = a >>> 16) && (a = b,
    c += 16),
    0 != (b = a >> 8) && (a = b,
    c += 8),
    0 != (b = a >> 4) && (a = b,
    c += 4),
    0 != (b = a >> 2) && (a = b,
    c += 2),
    0 != (b = a >> 1) && (a = b,
    c += 1),
    c
}
function u() {
    return this.t <= 0 ? 0 : this.DB * (this.t - 1) + t(this[this.t - 1] ^ this.s & this.DM)
}
function v(a, b) {
    var c;
    for (c = this.t - 1; c >= 0; --c)
        b[c + a] = this[c];
    for (c = a - 1; c >= 0; --c)
        b[c] = 0;
    b.t = this.t + a,
    b.s = this.s
}
function w(a, b) {
    for (var c = a; c < this.t; ++c)
        b[c - a] = this[c];
    b.t = Math.max(this.t - a, 0),
    b.s = this.s
}
function x(a, b) {
    var c, d = a % this.DB, e = this.DB - d, f = (1 << e) - 1, g = Math.floor(a / this.DB), h = this.s << d & this.DM;
    for (c = this.t - 1; c >= 0; --c)
        b[c + g + 1] = this[c] >> e | h,
        h = (this[c] & f) << d;
    for (c = g - 1; c >= 0; --c)
        b[c] = 0;
    b[g] = h,
    b.t = this.t + g + 1,
    b.s = this.s,
    b.clamp()
}
function y(a, b) {
    b.s = this.s;
    var c = Math.floor(a / this.DB);
    if (c >= this.t)
        return void (b.t = 0);
    var d = a % this.DB
      , e = this.DB - d
      , f = (1 << d) - 1;
    b[0] = this[c] >> d;
    for (var g = c + 1; g < this.t; ++g)
        b[g - c - 1] |= (this[g] & f) << e,
        b[g - c] = this[g] >> d;
    d > 0 && (b[this.t - c - 1] |= (this.s & f) << e),
    b.t = this.t - c,
    b.clamp()
}
function z(a, b) {
    for (var c = 0, d = 0, e = Math.min(a.t, this.t); e > c; )
        d += this[c] - a[c],
        b[c++] = d & this.DM,
        d >>= this.DB;
    if (a.t < this.t) {
        for (d -= a.s; c < this.t; )
            d += this[c],
            b[c++] = d & this.DM,
            d >>= this.DB;
        d += this.s
    } else {
        for (d += this.s; c < a.t; )
            d -= a[c],
            b[c++] = d & this.DM,
            d >>= this.DB;
        d -= a.s
    }
    b.s = 0 > d ? -1 : 0,
    -1 > d ? b[c++] = this.DV + d : d > 0 && (b[c++] = d),
    b.t = c,
    b.clamp()
}
function A(a, b) {
    var c = this.abs()
      , e = a.abs()
      , f = c.t;
    for (b.t = f + e.t; --f >= 0; )
        b[f] = 0;
    for (f = 0; f < e.t; ++f)
        b[f + c.t] = c.am(0, e[f], b, f, 0, c.t);
    b.s = 0,
    b.clamp(),
    this.s != a.s && d.ZERO.subTo(b, b)
}
function B(a) {
    for (var b = this.abs(), c = a.t = 2 * b.t; --c >= 0; )
        a[c] = 0;
    for (c = 0; c < b.t - 1; ++c) {
        var d = b.am(c, b[c], a, 2 * c, 0, 1);
        (a[c + b.t] += b.am(c + 1, 2 * b[c], a, 2 * c + 1, d, b.t - c - 1)) >= b.DV && (a[c + b.t] -= b.DV,
        a[c + b.t + 1] = 1)
    }
    a.t > 0 && (a[a.t - 1] += b.am(c, b[c], a, 2 * c, 0, 1)),
    a.s = 0,
    a.clamp()
}
function C(a, b, c) {
    var f = a.abs();
    if (!(f.t <= 0)) {
        var g = this.abs();
        if (g.t < f.t)
            return null != b && b.fromInt(0),
            void (null != c && this.copyTo(c));
        null == c && (c = e());
        var h = e()
          , i = this.s
          , j = a.s
          , k = this.DB - t(f[f.t - 1]);
        k > 0 ? (f.lShiftTo(k, h),
        g.lShiftTo(k, c)) : (f.copyTo(h),
        g.copyTo(c));
        var l = h.t
          , m = h[l - 1];
        if (0 != m) {
            var n = m * (1 << this.F1) + (l > 1 ? h[l - 2] >> this.F2 : 0)
              , o = this.FV / n
              , p = (1 << this.F1) / n
              , q = 1 << this.F2
              , r = c.t
              , s = r - l
              , u = null == b ? e() : b;
            for (h.dlShiftTo(s, u),
            c.compareTo(u) >= 0 && (c[c.t++] = 1,
            c.subTo(u, c)),
            d.ONE.dlShiftTo(l, u),
            u.subTo(h, h); h.t < l; )
                h[h.t++] = 0;
            for (; --s >= 0; ) {
                var v = c[--r] == m ? this.DM : Math.floor(c[r] * o + (c[r - 1] + q) * p);
                if ((c[r] += h.am(0, v, c, s, 0, l)) < v)
                    for (h.dlShiftTo(s, u),
                    c.subTo(u, c); c[r] < --v; )
                        c.subTo(u, c)
            }
            null != b && (c.drShiftTo(l, b),
            i != j && d.ZERO.subTo(b, b)),
            c.t = l,
            c.clamp(),
            k > 0 && c.rShiftTo(k, c),
            0 > i && d.ZERO.subTo(c, c)
        }
    }
}
function D(a) {
    var b = e();
    return this.abs().divRemTo(a, null, b),
    this.s < 0 && b.compareTo(d.ZERO) > 0 && a.subTo(b, b),
    b
}
function E(a) {
    this.m = a
}
function F(a) {
    return a.s < 0 || a.compareTo(this.m) >= 0 ? a.mod(this.m) : a
}
function G(a) {
    return a
}
function H(a) {
    a.divRemTo(this.m, null, a)
}
function I(a, b, c) {
    a.multiplyTo(b, c),
    this.reduce(c)
}
function J(a, b) {
    a.squareTo(b),
    this.reduce(b)
}
function K() {
    if (this.t < 1)
        return 0;
    var a = this[0];
    if (0 == (1 & a))
        return 0;
    var b = 3 & a;
    return b = b * (2 - (15 & a) * b) & 15,
    b = b * (2 - (255 & a) * b) & 255,
    b = b * (2 - ((65535 & a) * b & 65535)) & 65535,
    b = b * (2 - a * b % this.DV) % this.DV,
    b > 0 ? this.DV - b : -b
}
function L(a) {
    this.m = a,
    this.mp = a.invDigit(),
    this.mpl = 32767 & this.mp,
    this.mph = this.mp >> 15,
    this.um = (1 << a.DB - 15) - 1,
    this.mt2 = 2 * a.t
}
function M(a) {
    var b = e();
    return a.abs().dlShiftTo(this.m.t, b),
    b.divRemTo(this.m, null, b),
    a.s < 0 && b.compareTo(d.ZERO) > 0 && this.m.subTo(b, b),
    b
}
function N(a) {
    var b = e();
    return a.copyTo(b),
    this.reduce(b),
    b
}
function O(a) {
    for (; a.t <= this.mt2; )
        a[a.t++] = 0;
    for (var b = 0; b < this.m.t; ++b) {
        var c = 32767 & a[b]
          , d = c * this.mpl + ((c * this.mph + (a[b] >> 15) * this.mpl & this.um) << 15) & a.DM;
        for (c = b + this.m.t,
        a[c] += this.m.am(0, d, a, b, 0, this.m.t); a[c] >= a.DV; )
            a[c] -= a.DV,
            a[++c]++
    }
    a.clamp(),
    a.drShiftTo(this.m.t, a),
    a.compareTo(this.m) >= 0 && a.subTo(this.m, a)
}
function P(a, b) {
    a.squareTo(b),
    this.reduce(b)
}
function Q(a, b, c) {
    a.multiplyTo(b, c),
    this.reduce(c)
}
function R() {
    return 0 == (this.t > 0 ? 1 & this[0] : this.s)
}
function S(a, b) {
    if (a > 4294967295 || 1 > a)
        return d.ONE;
    var c = e()
      , f = e()
      , g = b.convert(this)
      , h = t(a) - 1;
    for (g.copyTo(c); --h >= 0; )
        if (b.sqrTo(c, f),
        (a & 1 << h) > 0)
            b.mulTo(f, g, c);
        else {
            var i = c;
            c = f,
            f = i
        }
    return b.revert(c)
}
function T(a, b) {
    var c;
    return c = 256 > a || b.isEven() ? new E(b) : new L(b),
    this.exp(a, c)
}
function U() {
    this.i = 0,
    this.j = 0,
    this.S = new Array
}
function V(a) {
    var b, c, d;
    for (b = 0; 256 > b; ++b)
        this.S[b] = b;
    for (c = 0,
    b = 0; 256 > b; ++b)
        c = c + this.S[b] + a[b % a.length] & 255,
        d = this.S[b],
        this.S[b] = this.S[c],
        this.S[c] = d;
    this.i = 0,
    this.j = 0
}
function W() {
    var a;
    return this.i = this.i + 1 & 255,
    this.j = this.j + this.S[this.i] & 255,
    a = this.S[this.i],
    this.S[this.i] = this.S[this.j],
    this.S[this.j] = a,
    this.S[a + this.S[this.i] & 255]
}
function X() {
    return new U
}
function Y(a) {
    qb[rb++] ^= 255 & a,
    qb[rb++] ^= a >> 8 & 255,
    qb[rb++] ^= a >> 16 & 255,
    qb[rb++] ^= a >> 24 & 255,
    rb >= sb && (rb -= sb)
}
function Z() {
    Y((new Date).getTime())
}
function $() {
    if (null == pb) {
        for (Z(),
        pb = X(),
        pb.init(qb),
        rb = 0; rb < qb.length; ++rb)
            qb[rb] = 0;
        rb = 0
    }
    return pb.next()
}
function _(a) {
    var b;
    for (b = 0; b < a.length; ++b)
        a[b] = $()
}
function ab() {}
function bb(a, b) {
    return new d(a,b)
}
function cb(a, b) {
    if (b < a.length + 11)
        return alert("Message too long for RSA"),
        null;
    for (var c = new Array, e = a.length - 1; e >= 0 && b > 0; ) {
        var f = a.charCodeAt(e--);
        128 > f ? c[--b] = f : f > 127 && 2048 > f ? (c[--b] = 63 & f | 128,
        c[--b] = f >> 6 | 192) : (c[--b] = 63 & f | 128,
        c[--b] = f >> 6 & 63 | 128,
        c[--b] = f >> 12 | 224)
    }
    c[--b] = 0;
    for (var g = new ab, h = new Array; b > 2; ) {
        for (h[0] = 0; 0 == h[0]; )
            g.nextBytes(h);
        c[--b] = h[0]
    }
    return c[--b] = 2,
    c[--b] = 0,
    new d(c)
}
function db() {
    this.n = null,
    this.e = 0,
    this.d = null,
    this.p = null,
    this.q = null,
    this.dmp1 = null,
    this.dmq1 = null,
    this.coeff = null
}
function eb(a, b) {
    null != a && null != b && a.length > 0 && b.length > 0 ? (this.n = bb(a, 16),
    this.e = parseInt(b, 16)) : alert("")
}
function fb(a) {
    return a.modPowInt(this.e, this.n)
}
function gb(a) {
    var b = cb(a, this.n.bitLength() + 7 >> 3);
    if (null == b)
        return null;
    var c = this.doPublic(b);
    if (null == c)
        return null;
    var d = c.toString(16);
    return 0 == (1 & d.length) ? d : "0" + d
}
var hb, ib = 0xdeadbeefcafe, jb = 15715070 == (16777215 & ib);
jb && "Microsoft Internet Explorer" == navigator.appName ? (d.prototype.am = g,
hb = 30) : jb && "Netscape" != navigator.appName ? (d.prototype.am = f,
hb = 26) : (d.prototype.am = h,
hb = 28),
d.prototype.DB = hb,
d.prototype.DM = (1 << hb) - 1,
d.prototype.DV = 1 << hb;
var kb = 52;
d.prototype.FV = Math.pow(2, kb),
d.prototype.F1 = kb - hb,
d.prototype.F2 = 2 * hb - kb;
var lb, mb, nb = "0123456789abcdefghijklmnopqrstuvwxyz", ob = new Array;
for (lb = "0".charCodeAt(0),
mb = 0; 9 >= mb; ++mb)
    ob[lb++] = mb;
for (lb = "a".charCodeAt(0),
mb = 10; 36 > mb; ++mb)
    ob[lb++] = mb;
for (lb = "A".charCodeAt(0),
mb = 10; 36 > mb; ++mb)
    ob[lb++] = mb;
E.prototype.convert = F,
E.prototype.revert = G,
E.prototype.reduce = H,
E.prototype.mulTo = I,
E.prototype.sqrTo = J,
L.prototype.convert = M,
L.prototype.revert = N,
L.prototype.reduce = O,
L.prototype.mulTo = Q,
L.prototype.sqrTo = P,
d.prototype.copyTo = k,
d.prototype.fromInt = l,
d.prototype.fromString = n,
d.prototype.clamp = o,
d.prototype.dlShiftTo = v,
d.prototype.drShiftTo = w,
d.prototype.lShiftTo = x,
d.prototype.rShiftTo = y,
d.prototype.subTo = z,
d.prototype.multiplyTo = A,
d.prototype.squareTo = B,
d.prototype.divRemTo = C,
d.prototype.invDigit = K,
d.prototype.isEven = R,
d.prototype.exp = S,
d.prototype.toString = p,
d.prototype.negate = q,
d.prototype.abs = r,
d.prototype.compareTo = s,
d.prototype.bitLength = u,
d.prototype.mod = D,
d.prototype.modPowInt = T,
d.ZERO = m(0),
d.ONE = m(1),
U.prototype.init = V,
U.prototype.next = W;
var pb, qb, rb, sb = 256;
if (null == qb) {
    qb = new Array,
    rb = 0;
    var tb;
    if (window.crypto && window.crypto.getRandomValues) {
        var ub = new Uint8Array(32);
        for (window.crypto.getRandomValues(ub),
        tb = 0; 32 > tb; ++tb)
            qb[rb++] = ub[tb]
    }
    if ("Netscape" == navigator.appName && navigator.appVersion < "5" && window.crypto) {
        var vb = window.crypto.random(32);
        for (tb = 0; tb < vb.length; ++tb)
            qb[rb++] = 255 & vb.charCodeAt(tb)
    }
    for (; sb > rb; )
        tb = Math.floor(65536 * Math.random()),
        qb[rb++] = tb >>> 8,
        qb[rb++] = 255 & tb;
    rb = 0,
    Z()
}
ab.prototype.nextBytes = _,
db.prototype.doPublic = fb,
db.prototype.setPublic = eb,
db.prototype.encrypt = gb,
RSAKey =  db


function getEncryptedPwd(pwd, modulus, publicExponent) {
    c = new RSAKey;
    c.setPublic(modulus, publicExponent);
    var d = c.encrypt(pwd);
    return d;
}


运行结果

python编写脚本运行此JS代码:
import execjs

password = '123'                # 模拟的密码(随便写的!)
modulus = '00833c4af965ff7a8409f8b5d5a83d87f2f19d7c1eb40dc59a98d2346cbb145046b2c6facc25b5cc363443f0f7ebd9524b7c1e1917bf7d849212339f6c1d3711b115ecb20f0c89fc2182a985ea28cbb4adf6a321ff7e715ba9b8d7261d1c140485df3b705247a70c28c9068caabbedbf9510dada6d13d99e57642b853a73406817'
publicExponent = '010001'

def make_execjs_object():
    with open('en_pwd.js', 'r') as f:
        js = f.read()
    return execjs.compile(js)

js_object = make_execjs_object()

a = js_object.call('getEncryptedPwd',  password, modulus, publicExponent)
print(a)


运行结果:

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

loginID 参数

步骤同上面的enpassword,一步步搜索会发现找到了图中的J_RsaAccout,这个就是loginID参数的加密:(我们继续一步步分析,会发现此参数的加密方式和刚刚的enpassword的加密方式一模一样,那处理方法不就简单了!)

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

JS加密账号函数(直接将下面的JS函数加入刚刚自己改写的JS代码文件中即可!)

function getEncryptedAccount(account, modulus, publicExponent) {
    c = new RSAKey;
    c.setPublic(modulus, publicExponent);
    var d = c.encrypt(account);
    return d;
}

Python调用JS加密函数(编写爬虫脚本文件时用以下函数调用JS文件生成所需参数!形同enpassword的写法)

def make_encrypt_account(self, account, modulus, publicExponent):
        """生成加密后的账号

        Args:
            account (str): 输入框内输入的账号
            modulus (str): 同上
            publicExponent (str): 同上

        Returns:
            str: 加密后的账号
        """
        return self.js_object.call('getEncryptedAccount', account, modulus, publicExponent)

运行结果

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

FingerPrint和FingerPrintDetail参数

找到指纹加密的主函数(会发现就在刚刚的函数下面)

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

分析函数功能

这里比较不好理解的是$.fingerprint.details$.fingerprint.result,这两个变量的定义位置是下面图片这里
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

这两个值也都是固定值,据观察,其中c的值就是使用者计算机的一些属性,只要计算机不换,这些值就是固定的,所以我们直接传固定值即可(它也不知道你电脑信息是啥样的呀);而且d的值是根据c的值得出的,所以也可以写死!后面编写爬虫代码时直接复制此处的值即可!

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

修改FingerPrint的JS函数

function rsaFingerprint(a, b, details, result) {		//details和result是固定值,直接作为参数传进来赋值;  此处的a和b的值通过观察可知就是a.result.modulus和a.result.publicExponent这俩值,前面获取过!
    var c = details
      , d = result
      , e = c.length
      , f = ""
      , g = new RSAKey;
    g.setPublic(a, b);
    for (var h = g.encrypt(d), i = 0; e > i; i += 117)
        f += g.encrypt(c.substr(i, 117));
    // return {
    //     details: f,
    //     result: h
    // }
    return {
        fingerPrintDetail: f,	//这里代码会返回字典类型的数据,直接可以合并到表单里,所以直接修改为表单里可以用的key值。当然不改也可!
        fingerPrint: h
    }
}

Python调用JS加密函数

def make_rsa_fingerprint(self, modulus, publicExponent, details, result):
        """生成rsa指纹参数

        Args:
            details (str): 请求headers信息
            result (str): headers的加密信息,如果headers不改变这个值也是固定的

        Returns (dict):
            details: 加密后的fingerprint_details信息,fingerPrintDetail表单参数
            result: 加密后的fingerprint_result信息,fingerPrint表单参数
        """
        return self.js_object.call('rsaFingerprint', modulus, publicExponent, details, result)

运行结果

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

编写爬虫脚本:

(1)首先,编写脚本构造出post表单!

import requests
import json

import execjs

class Migu_login(object):
    def __init__(self, account, password):
        modules = '00833c4af965ff7a8409f8b5d5a83d87f2f19d7c1eb40dc59a98d2346cbb145046b2c6facc25b5cc363443f0f7ebd9524b7c1e1917bf7d849212339f6c1d3711b115ecb20f0c89fc2182a985ea28cbb4adf6a321ff7e715ba9b8d7261d1c140485df3b705247a70c28c9068caabbedbf9510dada6d13d99e57642b853a73406817'
        publicExponent = '010001'
        # 获取FingerPrint和FingerPrintDetail参数中JS函数所需的参数c和d
        details_params = '"{"user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89","language":"zh-CN","color_depth":"24","pixel_ratio":"1.25","hardware_concurrency":"8","resolution":"1536,864","available_resolution":"1536,834","timezone_offset":"-480","session_storage":"1","local_storage":"1","indexed_db":"1","open_database":"1","cpu_class":"unknown","navigator_platform":"Win32","do_not_track":"unknown","regular_plugins":"Chrome PDF Plugin::Portable Document Format::application/x-google-chrome-pdf~pdf,Chrome PDF Viewer::","webgl_vendor":"Google Inc.~ANGLE (Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0)","adblock":"false","has_lied_languages":"false","has_lied_resolution":"false","has_lied_os":"false","has_lied_browser":"false","touch_support":"0,false,false","js_fonts":"Arial,Arial Black,Arial Narrow,Arial Unicode MS,Book Antiqua,Bookman Old Style,Calibri,Cambria,Cambr"}"'
        result_params = '984eb0bda24963a23008f493d58a84e0'

        headers = {
            "Accept": "application/json, text/javascript, */*; q=0.01",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Host": "passport.migu.cn",
            "Origin": "https://passport.migu.cn",
            "Referer": "https://passport.migu.cn/login?sourceid=208003&apptype=0&forceAuthn=false&isPassive=false&authType=MiguPassport&passwordControl=0&display=web&referer=https://www.migu.cn/&logintype=1&qq=null&weibo=null&alipay=null&weixin=null&andPass=null&phoneNumber=&callbackURL=https%3A%2F%2Fwww.migu.cn%2F&relayState=",
            "Sec-Fetch-Dest": "empty",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Site": "same-origin",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36",
            "X-Requested-With": "XMLHttpRequest",
        }

        self.form = {
            # 需要传递的构造出来的参数先写空,后面再使用update即可!
            "sourceID": "208003",
            "appType": "0",
            "relayState": "",
            "loginID":"",             # 加密后的账号
            "enpassword": "",         # 加密后的密码
            "captcha": "",
            "rememberMeBox": "1",
            "fingerPrint": "",         # 指纹
            "fingerPrintDetail":"",    # 指纹detail
            "isAsync": True,
        }

        # 开启会话,保持连接!
        self.session = requests.Session()
        self.session.headers = headers
        self.get_cookie()

        # Python执行JS代码,生成所需参数并更新进表单
        self.js_object = self.compile_js()
        update_form = self.make_rsa_fingerprint(modules, publicExponent, details_params, result_params)
        update_form['loginID'] = self.make_encrypt_account(account, modules, publicExponent)
        update_form['enpassword'] = self.make_encrypt_password(password, modules, publicExponent)
        self.form.update(update_form)


    def compile_js(self):
        """
        python直接执行本地编写的JS代码
        :return:
        """
        with open('en_pwd.js', 'r') as f:
            js = f.read()
        return execjs.compile(js)


    def get_cookie(self):
        """
        为了让会话携带cookie,所以进行如下操作。因为使用的session会话技术,所以即使不return也携带了cookie等一系列参数。
        :return:
        """
        url = 'https://passport.migu.cn/'
        self.session.get(url)

        return self.session.cookies


    def make_encrypt_password(self, password, modulus, publicExponent):
        """生成加密后的密码

        Args:
            password (str): 输入框内输入的原始密码
            modulus (str): rsa加密参数,两个质数的乘积,固定值,前一个请求获得
            publicExponent (str): rsa加密参数,大于1的奇数,固定值,前一个请求获得

        Returns:
            str: 加密后的密码
        """
        return self.js_object.call('getEncryptedPwd', password, modulus, publicExponent)

    def make_encrypt_account(self, account, modulus, publicExponent):
        """生成加密后的账号

        Args:
            account (str): 输入框内输入的账号
            modulus (str): 同上
            publicExponent (str): 同上

        Returns:
            str: 加密后的账号
        """
        return self.js_object.call('getEncryptedAccount', account, modulus, publicExponent)

    def make_rsa_fingerprint(self, modulus, publicExponent, details, result):
        """生成rsa指纹参数

        Args:
            details (str): 请求headers信息
            result (str): headers的加密信息,如果headers不改变这个值也是固定的

        Returns (dict):
            details: 加密后的fingerprint_details信息,fingerPrintDetail表单参数
            result: 加密后的fingerprint_result信息,fingerPrint表单参数
        """
        return self.js_object.call('rsaFingerprint', modulus, publicExponent, details, result)

(2)然后,编写脚本发送请求并通过获取响应判断是否登录成功!

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

分析可知,我们应该向如上图中的url携带表单发送post请求!

第一步:直接向其发送请求,观察响应,是否为登录成功的界面!
    def login(self):
        """
        登录函数
        :return: 
        """
        url = 'https://passport.migu.cn/authn'
        response = self.session.post(url, data=self.form)

        print(response.text)
        
        
        
if __name__ == '__main__':
    # 注意:账号密码放在了info.txt中
    with open('info.txt', 'r') as f:
        info = json.loads(f.read())
    act = info['account']
    pwd = info['password']
    mg = Migu_login(act,pwd)
    mresponse = mg.login()

观察响应分析可知,当我们登录成功之后,页面进行了重定向,而不是直接返回给我们登录成功的界面:
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

第二步:所以下面我们要做的就是,通过分析浏览器登录,找到一系列的重定向的URL,并找到最终返回登录成功界面的URL:

第一个登录成功之后出现的URL,很容易知道这就是登录后的重定向,其URL的构造只需要拼接token参数即可(token参数在刚刚的响应中又存在,直接提取即可!)

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

第二个登录成功之后出现的URL,多次测试可知其URL是固定值!

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

第三个登录成功之后出现的URL,图一中多次测试也可知其URL是固定值;图二中可知此URL刚好是由上一个URL跳转来的;图三可知此URL的响应刚好是登录成功的界面!
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录
JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

第三步:构造登录成功之后的重定向URL,并通过依此请求模拟网站登录时候的一次次重定向跳转,最终达到获取咪咕登录成功的界面!
    def login(self):
        """
        登录函数
        :return:
        """
        url = 'https://passport.migu.cn/authn'
        response = self.session.post(url, data=self.form)

        response_dict = json.loads(response.text)
        token = response_dict.get('result',{}).get('token', '')
        if not token:
            return

        rest_url = [
            'https://passport.migu.cn/portal/sso/authn?callbackURL=&relayState=&token={}'.format(token),
            'https://passport.migu.cn/portal/sso/authn_success?relateToMiguPassport=1&callbackURL=&relayState=',
            'https://passport.migu.cn/portal/home/profile?sourceid=100001',
            'https://passport.migu.cn/portal/home/profile?sourceid=100001',
        ]
        for ru in rest_url:
            response = self.session.get(ru)

        return response

if __name__ == '__main__':
    with open('info.txt', 'r') as f:
        info = json.loads(f.read())
    act = info['account']
    pwd = info['password']
    mg = Migu_login(act,pwd)
    mresponse = mg.login()
    print(mresponse.text)

(3)观察可知登录成功!

JS逆向进阶篇【过咪咕登录】【附带源码】,爬虫进阶+实战系列教程,javascript,python,爬虫,js逆向,过登录

项目源码链接:

代码:
链接:https://pan.baidu.com/s/1zM19dGyvEpX4BuXsr_8s7Q
提取码:xkxh
复制这段内容后打开百度网盘手机App,操作更方便哦
文章来源地址https://www.toymoban.com/news/detail-833745.html

到了这里,关于JS逆向进阶篇【过咪咕登录】【附带源码】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 爬虫逆向实战(十九)--某号站登录

    主页地址:某号站 1、抓包 通过抓包可以发现登录接口 2、判断是否有加密参数 请求参数是否加密? 通过查看“载荷”模块可以发现有一个 jsondata_rsa 的加密参数 请求头是否加密? 无 响应是否加密? 无 cookie是否加密? 无 1、看启动器 查看启动器发现里面有一个 LoginNow 的调

    2024年02月11日
    浏览(42)
  • 爬虫逆向实战(二十六)--某某学堂登录

    主页地址:某某学堂 1、抓包 通过抓包可以发现数据接口是Account/LoginPost 2、判断是否有加密参数 请求参数是否加密? 通过查看“载荷”模块可以发现 pass 是加密参数 请求头是否加密? 无 响应是否加密? 无 cookie是否加密? 无 1、看启动器 查看启动器发现里面有一个 Login

    2024年02月11日
    浏览(40)
  • 逆向爬虫技术的进阶应用与实战技巧

    在互联网的海洋中,数据是无价的财富。爬虫技术作为获取这些数据的重要手段,一直备受关注。然而,随着网站反爬虫机制的日益完善,简单的爬虫程序已经很难满足我们的需求。因此,掌握爬虫逆向技术,突破反爬虫机制,成为了爬虫开发者必须面对的挑战。 本文将带领

    2024年03月26日
    浏览(66)
  • 【hacker送书第12期】爬虫逆向进阶实战

    引领技术创新,突破网络界限,《爬虫逆向进阶实战》为你揭示数据抓取的深层奥秘。这是一本超越爬虫技术的书籍,更是通往高级逆向工程世界的通行证。 作者李玺凭借丰富经验,深入浅出地阐述了网络爬虫和Python爬虫的架构设计,助您掌握构建高效、稳定爬虫系统的核心

    2024年02月04日
    浏览(57)
  • 【爬虫逆向案例】某道翻译js逆向—— sign解密

    声明:本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢! 相信各位小伙伴在写爬虫的时候经常会遇到这样的情况,一些需要携带的参数一直在变化,今天逆向的这个网站某道翻译也如此: 可以发现变的就两个参数,一个 sign,一个是 m

    2024年02月15日
    浏览(44)
  • WebSocket爬虫与JS逆向实战

    声明:本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除!由于本人水平有限,如有理解或者描述不准确的地方,还望各位大佬指教!! 练习网站: Q3JhenkgUHJvTW9ua2V5IGh0dHBzOi8vd3d3LnBhbnpob3UuZ292LmNuL3p3Z2tfMTU4NjEve

    2024年02月07日
    浏览(47)
  • JS逆向案例:破解登录密码

    本人不是专业IT人员,但是对python爬虫这块非常感兴趣,在抖音上看了zhen老师的python全栈直播课程,果断选择加入zhen老师的VIP大家庭,给zhen老师投稿发文章还能挣钱, 50元 。 废话不多说,进入主题。最近在学习 JS逆向 方面的知识,由于之前做过12306的自动抢票软件,因此对

    2024年02月05日
    浏览(40)
  • 【爬虫逆向分析实战】某笔登录算法分析——本地替换分析法

    作者最近在做一个 收集粉币 的项目,可以用来干嘛这里就不展开了😁,需要进行登录换算token从而达到监控收集的作用,手机抓包发现他是通过APP进行计算之后再请求接口的,通过官网分析可能要比 APP逆向方便多 ,但是通过这几天的观察我并没有头绪,这篇文章草稿创建了

    2024年02月05日
    浏览(47)
  • 【爬虫逆向案例】某易云音乐(评论)js逆向—— params、encSecKey解密

    声明:本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢! 今天逆向的这个网站 某易云音乐 歌曲的评论列表 而要拿到评论列表爬虫发送的表单需要两个参数 params 和 encSecKey。这两个玩意是加密的,所以重点就是怎么搞定这两个参数。 话

    2024年02月14日
    浏览(43)
  • Python爬虫:抖音 JS XB逆向解析

    哈喽兄弟们,抖音现在有JS加密,以前的方法爬不了饿了,今天来实现一下某音短视频的JS逆向解析。 知识点 动态数据抓包`在这里插入代码片` requests发送请求 X-Bogus 参数逆向 环境模块 python 3.8               运行代码 pycharm 2022.3           辅助敲代码 requests 

    2024年02月08日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包