本次案例以天安保险登录为例。
首先是XHR断点,断到关键部位,之后查看右边的调用堆栈,找到password相关,进入加密JS。突然卡死了,原来要扣的代码特别多,而且循环嵌套,会引用其他包,需要的代码太多了,有十二万行!!最外边是一个括号包含webpack,是一个数组,压入了许多数据。但是这些文件都是直接被压入的,里边导入的包没有运行。
那我们在console里先执行webpack,之后取出函数来看能不能运行?不行,因为缺少参数,这样一来第一反应是其他地方调用了。我们在首页里边查看script,发现引用了不少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=
-----------------------------运行结果-----------------------------