在现代前端开发中,Webpack 已经成为了一个不可或缺的工具。它通过模块化的方式将 JavaScript、CSS、图片等资源打包成一个或多个文件,极大地提高了前端项目的可维护性和性能。然而,Webpack 打包后的代码往往难以阅读和理解,这给逆向工程带来了不小的挑战。本文将深入探讨 Webpack 打包的原理、形式以及如何逆向解析 Webpack 打包后的 JavaScript 代码,并通过实战案例帮助读者更好地理解这一过程。
> 本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
一、Webpack 打包介绍
1.1 Webpack 是什么?
Webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。它将应用程序的所有资源(如 JavaScript、CSS、图片等)视为模块,并通过依赖关系将它们打包成一个或多个文件。Webpack 的核心概念包括:
-
入口(Entry):指定 Webpack 开始构建依赖图的起点。
-
输出(Output):指定打包后的文件输出位置和文件名。
-
加载器(Loader):用于处理非 JavaScript 文件,将其转换为 Webpack 能够处理的模块。
-
插件(Plugin):用于执行更广泛的任务,如打包优化、资源管理等。
1.2 加载器样式
在进行 Webpack 打包后的代码逆向时,加载器是核心部分。加载器通常是网站开发人员使用工具生成的,我们无需关心其生成过程,直接拿来使用即可
!function (modules) {
// 用于缓存已加载的模块
var moduleCache = {};
// 定义模块加载函数,moduleId 为模块的唯一标识符
function loadModule(moduleId) {
// 如果模块已经加载过,则直接返回缓存的模块
if (moduleCache[moduleId]) {
return moduleCache[moduleId].exports;
}
// 创建一个新的模块对象,并将其缓存
var module = moduleCache[moduleId] = {
id: moduleId, // 模块的唯一标识符
loaded: false, // 标记模块是否已加载
exports: {} // 模块的导出对象
};
console.log(module); // 打印当前模块信息
// 执行模块函数,将模块的导出内容挂载到 module.exports 上
modules[moduleId].call(module.exports, module, module.exports, loadModule);
// 标记模块为已加载
module.loaded = true;
// 返回模块的导出内容
return module.exports;
}
// 将模块加载函数的属性指向原始模块对象
loadModule.modules = modules;
// 加载入口模块(假设入口模块的 ID 为 2)
loadModule(2);
}([]);
扣代码看到的样式大概是类似下面的
function n(r) {
if (t[r]) {
return t[r].exports;
}
var o = t[r] = {
i: r,
l: !1,
exports: {}
};
return e[r].call(o.exports, o, o.exports, n),
o.l = !0,
o.exports
}
1.3 Webpack 打包的形式
(1)数组形式
数组形式的打包,经常取值是通过 列表的下标值
!function(e) {
var t = {};
function n(r) {
if (t[r])
return t[r].exports;
var o = t[r] = {
i: r,
l: !1,
exports: {}
};
return e[r].call(o.exports, o, o.exports, n),
o.l = !0,
o.exports
}
n(0)
}([
function () {
console.log('123456')
},
function () {
console.log('模块2')
},
])
(2)对象形式
对象形式的打包,经常取值是通过 key(键值)
!function(e) {
var t = {};
function n(r) {
if (t[r])
return t[r].exports;
var o = t[r] = {
i: r,
l: !1,
exports: {}
};
return e[r].call(o.exports, o, o.exports, n),
o.l = !0,
o.exports
}
n(1) // 对象 根据KEY 找模块
}({
0: function () {
console.log('我是模块1')
},
1: function () {
console.log('我是模块2')
}
});
(3)对文件打包
二、webpack逆向扣取步骤
(一)定位到加载器(找函数入口)
通过得到加密或者解密的位置,然后打上断点,然后仔细找一下类似 o = n("c0d6"), s = n("4328") , l = n.n(s) , u = n("3452")这些,然后把鼠标放在n上,刷新页面,然后就能就去找到加载器了
(二)找到加载器,进入主文件后,把加载器部分扣下来。
接着上一步点击进去主文件后,看到类似下面图片的内容
然后直接拉到顶,对函数进行折叠,然后直接复制,不要复制到数组或者对象。扣下来后补上后面的})即可
(三)自动化扣去所需的子文件
子文件可以都拿下来,但是本篇博客介绍的是自动化扣所需的子文件就好。
(1)断点打在加载器的 if 判断处

(2)在调用返回值处打上日志断点
日志断点内容为: code += '"'+ e+ '":' + t[e] + ","+"\n" 注意:此处的 t 和 t[e] 要根据实际情况修改
图片中t[e]: e就是对象形式的键值, t[e]就是函数的内容
(3) 控制台(console)定义 code = ''
(4) 释放断在 if 处的断点,然后跳到加密或者解密位置处
(5)控制台(console)直接复制code ,然后导入刚刚扣下来下载器后面即可
(6)定义一个全局变量,然后导出加载器
三、实战案例
目标网址:全国建筑服务监管平台
(一)加密位置为response
(二)找到解密位置
这个找到解密位置建议一步步得去跟堆栈,但是既然指导是response加密,直接搜索拦截器
interceptors.response,然后打上断点直接就是加密解密位置了
t.data 密文
b(t.data) 明文
然后进到b函数,可以直接看出是简单的aes,可以直接通过crypto-js直接实现。
但是本技术博客讲解的是webpack形式了,就扣webpack吧
(三) 按着wepack扣去步骤直接实操就好
(1)断点打在加载器的 if 判断处
(2)在调用返回值处打上日志断点
(3) 控制台(console)定义 code = ''
(4) 释放断在 if 处的断点,然后跳到加密或者解密位置处
(5)控制台(console)直接复制code ,然后导入刚刚扣下来下载器后面即可
(6)定义一个全局变量,然后导出加载器
四、完整代码
<如果您对代码感兴趣(不白嫖)迪迦,可以在评论区留言(主页 \/)伪 善,我会根据需求提供指导和帮助>
子文件太多了,自动化扣去下来添加上去即可
window = global;
(function (t) {
function e(e) {
for (var a, r, o = e[0], s = e[1], l = e[2], u = 0, d = []; u < o.length; u++)
r = o[u],
i[r] && d.push(i[r][0]),
i[r] = 0;
for (a in s)
Object.prototype.hasOwnProperty.call(s, a) && (t[a] = s[a]);
p && p(e);
while (d.length)
d.shift()();
return c.push.apply(c, l || []),
n()
}
function n() {
for (var t, e = 0; e < c.length; e++) {
for (var n = c[e], a = !0, r = 1; r < n.length; r++) {
var o = n[r];
0 !== i[o] && (a = !1)
}
a && (c.splice(e--, 1),
t = s(s.s = n[0]))
}
return t
}
var a = {}
, r = {
app: 0
}
, i = {
app: 0
}
, c = [];
function o(t) {
return s.p + "js/" + ({}[t] || t) + "." + {
"chunk-00a81eaa": "c224db86",
"chunk-069fcdc2": "18229a34",
"chunk-06dbe252": "e957e683",
"chunk-06fc6f33": "94841577",
"chunk-0aef68b6": "8022bfeb",
"chunk-12aa76ee": "959f26a6",
"chunk-1abcfd41": "fd354bcf",
"chunk-24b82bb4": "fc92ce42",
"chunk-25a7f7b1": "3c5b1374",
"chunk-29e09c48": "45e8b366",
"chunk-29e23870": "774c0c76",
"chunk-2d0c8a24": "6a47a540",
"chunk-31971bbe": "8f0826bf",
"chunk-3418bc79": "d242be15",
"chunk-389d5b12": "c0159fe8",
"chunk-3994b142": "993a2cfb",
"chunk-3ab27eb0": "426f7ae5",
"chunk-3c69403a": "eab4901b",
"chunk-4197927b": "0b047bf6",
"chunk-49e98f9f": "b53aca78",
"chunk-54c368e7": "b03b5af4",
"chunk-5af5c923": "f1c06b53",
"chunk-60128d0e": "131e0840",
"chunk-60b3ee3d": "c192da57",
"chunk-64d0068e": "d9044ad7",
"chunk-6bfba406": "7c3ea998",
"chunk-6ffe139a": "85796ae6",
"chunk-7591556e": "91e692b5",
"chunk-997597ce": "1bfd45a4",
"chunk-a9fb3ca8": "8c9bff36",
"chunk-afd044e8": "6acf43e0",
"chunk-e69a778e": "5b39fcd5",
"chunk-ffc5ef96": "94becbff",
"chunk-ffdfa8dc": "5eadcfc2",
"chunk-237327fc": "0863c518",
"chunk-144064f5": "2c0f0bc5",
"chunk-149776d8": "a63904d8",
"chunk-1dc9eb2c": "a9c10302",
"chunk-430c71f5": "48135412",
"chunk-75ca5a96": "99a13734"
}[t] + ".js"
}
function s(e) {
if (a[e])
return a[e].exports;
var n = a[e] = {
i: e,
l: !1,
exports: {}
};
return t[e].call(n.exports, n, n.exports, s),
n.l = !0,
n.exports
}
window.ss = s
s.e = function (t) {
var e = []
, n = {
"chunk-00a81eaa": 1,
"chunk-069fcdc2": 1,
"chunk-06dbe252": 1,
"chunk-06fc6f33": 1,
"chunk-0aef68b6": 1,
"chunk-12aa76ee": 1,
"chunk-1abcfd41": 1,
"chunk-24b82bb4": 1,
"chunk-25a7f7b1": 1,
"chunk-29e09c48": 1,
"chunk-29e23870": 1,
"chunk-31971bbe": 1,
"chunk-3418bc79": 1,
"chunk-389d5b12": 1,
"chunk-3994b142": 1,
"chunk-3ab27eb0": 1,
"chunk-3c69403a": 1,
"chunk-4197927b": 1,
"chunk-49e98f9f": 1,
"chunk-54c368e7": 1,
"chunk-5af5c923": 1,
"chunk-60128d0e": 1,
"chunk-60b3ee3d": 1,
"chunk-64d0068e": 1,
"chunk-6bfba406": 1,
"chunk-6ffe139a": 1,
"chunk-7591556e": 1,
"chunk-997597ce": 1,
"chunk-a9fb3ca8": 1,
"chunk-afd044e8": 1,
"chunk-e69a778e": 1,
"chunk-ffc5ef96": 1,
"chunk-ffdfa8dc": 1,
"chunk-237327fc": 1
};
r[t] ? e.push(r[t]) : 0 !== r[t] && n[t] && e.push(r[t] = new Promise(function (e, n) {
for (var a = "css/" + ({}[t] || t) + "." + {
"chunk-00a81eaa": "d6beb8c6",
"chunk-069fcdc2": "5146ffaf",
"chunk-06dbe252": "eace3679",
"chunk-06fc6f33": "a517a0ef",
"chunk-0aef68b6": "63a8e70f",
"chunk-12aa76ee": "85939cb4",
"chunk-1abcfd41": "6c388e72",
"chunk-24b82bb4": "24164baf",
"chunk-25a7f7b1": "ccc62824",
"chunk-29e09c48": "4e543501",
"chunk-29e23870": "1fa162ad",
"chunk-2d0c8a24": "31d6cfe0",
"chunk-31971bbe": "f63b0dad",
"chunk-3418bc79": "6d0020cc",
"chunk-389d5b12": "b02b12e0",
"chunk-3994b142": "e03d7577",
"chunk-3ab27eb0": "a8b1f4fc",
"chunk-3c69403a": "fa3d2b14",
"chunk-4197927b": "246a1ce6",
"chunk-49e98f9f": "56c773f4",
"chunk-54c368e7": "f3c8b3ef",
"chunk-5af5c923": "69d2d7f1",
"chunk-60128d0e": "a258f5ab",
"chunk-60b3ee3d": "1364df80",
"chunk-64d0068e": "c7dd89e7",
"chunk-6bfba406": "2fd8990f",
"chunk-6ffe139a": "d5d904b8",
"chunk-7591556e": "c3107520",
"chunk-997597ce": "6976f5a4",
"chunk-a9fb3ca8": "4c2d7282",
"chunk-afd044e8": "93fe247b",
"chunk-e69a778e": "fc5ca905",
"chunk-ffc5ef96": "5927e7b1",
"chunk-ffdfa8dc": "ccd9847e",
"chunk-237327fc": "35b91f58",
"chunk-144064f5": "31d6cfe0",
"chunk-149776d8": "31d6cfe0",
"chunk-1dc9eb2c": "31d6cfe0",
"chunk-430c71f5": "31d6cfe0",
"chunk-75ca5a96": "31d6cfe0"
}[t] + ".css", i = s.p + a, c = document.getElementsByTagName("link"), o = 0; o < c.length; o++) {
var l = c[o]
, u = l.getAttribute("data-href") || l.getAttribute("href");
if ("stylesheet" === l.rel && (u === a || u === i))
return e()
}
var d = document.getElementsByTagName("style");
for (o = 0; o < d.length; o++) {
l = d[o],
u = l.getAttribute("data-href");
if (u === a || u === i)
return e()
}
var p = document.createElement("link");
p.rel = "stylesheet",
p.type = "text/css",
p.onload = e,
p.onerror = function (e) {
var a = e && e.target && e.target.src || i
, c = new Error("Loading CSS chunk " + t + " failed.\n(" + a + ")");
c.code = "CSS_CHUNK_LOAD_FAILED",
c.request = a,
delete r[t],
p.parentNode.removeChild(p),
n(c)
}
,
p.href = i;
var f = document.getElementsByTagName("head")[0];
f.appendChild(p)
}
).then(function () {
r[t] = 0
}));
var a = i[t];
if (0 !== a)
if (a)
e.push(a[2]);
else {
var c = new Promise(function (e, n) {
a = i[t] = [e, n]
}
);
e.push(a[2] = c);
var l, u = document.createElement("script");
u.charset = "utf-8",
u.timeout = 120,
s.nc && u.setAttribute("nonce", s.nc),
u.src = o(t),
l = function (e) {
u.onerror = u.onload = null,
clearTimeout(d);
var n = i[t];
if (0 !== n) {
if (n) {
var a = e && ("load" === e.type ? "missing" : e.type)
, r = e && e.target && e.target.src
, c = new Error("Loading chunk " + t + " failed.\n(" + a + ": " + r + ")");
c.type = a,
c.request = r,
n[1](c)
}
i[t] = void 0
}
}
;
var d = setTimeout(function () {
l({
type: "timeout",
target: u
})
}, 12e4);
u.onerror = u.onload = l,
document.head.appendChild(u)
}
return Promise.all(e)
}
,
s.m = t,
s.c = a,
s.d = function (t, e, n) {
s.o(t, e) || Object.defineProperty(t, e, {
enumerable: !0,
get: n
})
}
,
s.r = function (t) {
"undefined" !== typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, {
value: "Module"
}),
Object.defineProperty(t, "__esModule", {
value: !0
})
}
,
s.t = function (t, e) {
if (1 & e && (t = s(t)),
8 & e)
return t;
if (4 & e && "object" === typeof t && t && t.__esModule)
return t;
var n = Object.create(null);
if (s.r(n),
Object.defineProperty(n, "default", {
enumerable: !0,
value: t
}),
2 & e && "string" != typeof t)
for (var a in t)
s.d(n, a, function (e) {
return t[e]
}
.bind(null, a));
return n
}
,
s.n = function (t) {
var e = t && t.__esModule ? function () {
return t["default"]
}
: function () {
return t
}
;
return s.d(e, "a", e),
e
}
,
s.o = function (t, e) /**/ {
return Object.prototype.hasOwnProperty.call(t, e)
}
,
s.p = "/",
s.oe = function (t) {
throw console.error(t),
t
}
;
var l = window["webpackJsonp"] = window["webpackJsonp"] || []
, u = l.push.bind(l);
l.push = e,
l = l.slice();
for (var d = 0; d < l.length; d++)
e(l[d]);
var p = u;
c.push([0, "chunk-vendors"]),
n()
}
)({
})
d = window.ss.n(window.ss("3452"))
// console.log(d.a.enc)
f = d.a.enc.Utf8.parse("Dt8j9wGw%6HbxfFn")
m = d.a.enc.Utf8.parse("0123456789ABCDEF")
function b(t) {
var e = d.a.enc.Hex.parse(t)
, nnn = d.a.enc.Base64.stringify(e)
, a = d.a.AES.decrypt(nnn, f, {
iv: m,
mode: d.a.mode.CBC,
padding: d.a.pad.Pkcs7
})
, r = a.toString(d.a.enc.Utf8);
return r.toString()
}
function decrypt_(data) {
return JSON.parse(b(data))
}
//data 自行把密文扣下来就好,太多了就不放了
var e = decrypt_(data);
console.log(e)