JS安全防护算法与逆向分析——webpack改写方案

webpack改写方案

本次案例以天安保险登录为例。

首先是XHR断点,断到关键部位,之后查看右边的调用堆栈,找到password相关,进入加密JS。突然卡死了,原来要扣的代码特别多,而且循环嵌套,会引用其他包,需要的代码太多了,有十二万行!!最外边是一个括号包含webpack,是一个数组,压入了许多数据。但是这些文件都是直接被压入的,里边导入的包没有运行。

那我们在console里先执行webpack,之后取出函数来看能不能运行?不行,因为缺少参数,这样一来第一反应是其他地方调用了。我们在首页里边查看script,发现引用了不少script文件,但是你单独去调试它们的话,因为网站过大可能会卡死奔溃。

<script type="text/javascript" src="runtime.288d04140a139e9db1a1.js"></script>
<script type="text/javascript" src="polyfills.fe1c0f9fd9f3421c06da.js"></script>
<script type="text/javascript" src="vendor.fa7691b546a5ad5b0c54.js"></script>
<script type="text/javascript" src="main.106c62a84f7eaae10682.js"></script>
<script src="assets/js/slideVerification.js"></script>

我们进入第一个script,发现里边定义了webpack,这里它覆盖了push方法,那我们一开的找到的push方法就会调用这个。那显然这些脚本使我们需要的,我们下断点,调试进入

    var i = window.webpackJsonp = window.webpackJsonp || []
      , f = i.push.bind(i);
    i.push = r,
    i = i.slice();
    for (var c = 0; c < i.length; c++)
        r(i[c]);
    var l = f;
    t()

发现了一个非常关键的call方法

  function a(r) {
    if (n[r]) return n[r].exports;
    var t = n[r] = {
      i: r,
      l: !1,
      exports: {
      }
    };
    return e[r].call(t.exports, t, t.exports, a),
    t.l = !0,
    t.exports
  }

我们进入查看,发现它能够回调函数,那这个玩意就关键的很了,我们需要把它抠出来

  1: function (t, n, e) {
    t.exports = e('hN/g')
  },

它在一个匿名函数里边,我们怎么拿出来呢?很好办,我们定义一个全局变量取出来即可,比如losenine,

this.window=this;
var losenine=null;

!function (e) {
  function r(r) {
    for (var n, a, i = r[0], f = r[1], c = r[2], d = 0, p = [
    ]; d < i.length; d++) a = i[d],
    o[a] && p.push(o[a][0]),
    o[a] = 0;
    for (n in f) Object.prototype.hasOwnProperty.call(f, n) && (e[n] = f[n]);
    for (l && l(r); p.length; ) p.shift() ();
    return u.push.apply(u, c || [
    ]),
    t()
  }
  function t() {
    for (var e, r = 0; r < u.length; r++) {
      for (var t = u[r], n = !0, i = 1; i < t.length; i++) {
        var f = t[i];
        0 !== o[f] && (n = !1)
      }
      n && (u.splice(r--, 1), e = a(a.s = t[0]))
    }
    return e
  }
  var n = {
  },
  o = {
    0: 0
  },
  u = [
  ];
  function a(r) {
    if (n[r]) return n[r].exports;
    var t = n[r] = {
      i: r,
      l: !1,
      exports: {
      }
    };
    return e[r].call(t.exports, t, t.exports, a),
    t.l = !0,
    t.exports
  }
losenine=a;
  a.e = function (e) {
    var r = [
    ],
    t = o[e];
    if (0 !== t) if (t) r.push(t[2]);
     else {
      var n = new Promise(function (r, n) {
        t = o[e] = [
          r,
          n
        ]
      });
      r.push(t[2] = n);
      var u,
      i = document.createElement('script');
      i.charset = 'utf-8',
      i.timeout = 120,
      a.nc && i.setAttribute('nonce', a.nc),
      i.src = function (e) {
        return a.p + '' + ({
        }
        [
          e
        ] || e) + '.' + {
          1: 'd9234d91e50a53c6ac2e',
          6: '19a0da142e67165fe85a',
          7: '9e63622e2f9e88f9c1f5',
          8: '79d337966225585daf3f',
          9: 'bf347bd0b85841d3696a',
          10: '723594d0cc27a410d93f',
          11: 'de941b69ea0b58948bb8',
          12: '3090819dee86121eba12',
          13: 'c158abd12f23735e1d20'
        }
        [
          e
        ] + '.js'
      }(e),
      u = function (r) {
        i.onerror = i.onload = null,
        clearTimeout(f);
        var t = o[e];
        if (0 !== t) {
          if (t) {
            var n = r && ('load' === r.type ? 'missing' : r.type),
            u = r && r.target && r.target.src,
            a = new Error('Loading chunk ' + e + ' failed.\n(' + n + ': ' + u + ')');
            a.type = n,
            a.request = u,
            t[1](a)
          }
          o[e] = void 0
        }
      };
      var f = setTimeout(function () {
        u({
          type: 'timeout',
          target: i
        })
      }, 120000);
      i.onerror = i.onload = u,
      document.head.appendChild(i)
    }
    return Promise.all(r)
  },
  a.m = e,
  a.c = n,
  a.d = function (e, r, t) {
    a.o(e, r) || Object.defineProperty(e, r, {
      enumerable: !0,
      get: t
    })
  },
  a.r = function (e) {
    'undefined' != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
      value: 'Module'
    }),
    Object.defineProperty(e, '__esModule', {
      value: !0
    })
  },
  a.t = function (e, r) {
    if (1 & r && (e = a(e)), 8 & r) return e;
    if (4 & r && 'object' == typeof e && e && e.__esModule) return e;
    var t = Object.create(null);
    if (a.r(t), Object.defineProperty(t, 'default', {
      enumerable: !0,
      value: e
    }), 2 & r && 'string' != typeof e) for (var n in e) a.d(t, n, (function (r) {
      return e[r]
    }).bind(null, n));
    return t
  },
  a.n = function (e) {
    var r = e && e.__esModule ? function () {
      return e.default
    }
    : function () {
      return e
    };
    return a.d(r, 'a', r),
    r
  },
  a.o = function (e, r) {
    return Object.prototype.hasOwnProperty.call(e, r)
  },
  a.p = '',
  a.oe = function (e) {
    throw console.error(e),
    e
  };
  var i = window.webpackJsonp = window.webpackJsonp || [
  ],
  f = i.push.bind(i);
  i.push = r,
  i = i.slice();
  for (var c = 0; c < i.length; c++) r(i[c]);
  var l = f;
  t()
}([]);

显然,这样我们就可以在外边操作这个回调函数了。

之后就是把那十二万行的巨额webpack放在我们的这个回调函数下边,然后写我们自己的调用函数去除加密结果

function test(){
            var t = c.enc.Utf8.parse('t171420100302rsa'),
            n = c.enc.Utf8.parse('t171420100302rsa'),
            e = c.enc.Utf8.parse('{\"body\":{\"loginMethod\":\"1\",\"name\":\"13520791022\",\"password\":\"123456789\"},\"head\":{\"userCode\":\"13520791088\",\"channelCode\":\"101\",\"transTime\":1589554105813,\"transToken\":\"\",\"customerId\":null,\"transSerialNumber\":\"\"}}'),
            a = c.AES.encrypt(e, t, {
              iv: n,
              mode: c.mode.CBC,
              padding: c.pad.Pkcs7
            });
            return c.enc.Base64.stringify(a.ciphertext)
}

我们运行一下,完毕。

-----------------------------运行结果-----------------------------
NBLetNAD6tHSqG1kmgP12SFiv6oyyRDdvklJemP+PaWrJqZR5Q0Uh7Bd0P1PEWmQCZ7pTCy4yKvrnybusMV3iqREjywYAqWfDykowenMf3s9N0+hvsoU2SVY2xVXUx0k9DrYQaHQ1ipE2QK+2mekVQ03uxjwNdHA5JbHYbE5fUHQk0N+Pfcw/wSY0GIHz3J4idb7eDp++fb0V163aR1ajNleNRPffRNbqk4OrGIPsX8Uvwin1oCoIUT3s1bASOaq5/um9iiZbQKpK7JmW5I9NocG9jPR8fEfPtO4vhwfoBE=
-----------------------------运行结果-----------------------------

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JavaScript逆向工程涉及到逆向分析、代码还原、代码修改等多个方面,其中Webpack作为一个重要的静态模块打包器,也是逆向工程中需要重点关注的一部分。以下是一些关于Webpack逆向的笔记: 1. Webpack的打包过程是从入口文件开始的,Webpack会递归地遍历所有依赖模块,并将它们打包成一个或多个Bundle文件。因此,逆向工程的第一步就是找到Webpack打包的入口文件。 2. 在入口文件中,Webpack会通过require或import语句加载其他模块,并递归地遍历所有依赖模块。因此,我们可以通过分析入口文件来了解应用的整体结构和模块依赖关系。 3. 在Webpack的打包过程中,每个模块都会被赋予一个唯一的标识符,这个标识符可以通过module.id来获取。因此,我们可以通过分析打包后的代码,来了解每个模块的标识符和依赖关系。 4. 在Webpack的打包过程中,Loader和Plugin是非常重要的扩展机制,它们可以对模块进行转换和优化。因此,我们可以通过分析Loader和Plugin的源代码,来了解它们的作用和实现原理。 5. 在逆向工程中,我们可以使用Webpack的source-map选项来生成源映射文件,从而方便我们进行代码还原和调试。同时,我们也可以使用Webpack的devtool选项来设置不同的调试工具,以便更好地进行逆向分析和调试。 总的来说,Webpack作为静态模块打包器,在JavaScript逆向工程中扮演着重要的角色。通过对Webpack逆向分析,我们可以更加深入地了解应用的整体结构和模块依赖关系,从而更好地进行代码还原和调试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值