【JS逆向实战】——基于全国建筑市场监管公共服务平台的webpack

在现代前端开发中,Webpack 已经成为了一个不可或缺的工具。它通过模块化的方式将 JavaScript、CSS、图片等资源打包成一个或多个文件,极大地提高了前端项目的可维护性和性能。然而,Webpack 打包后的代码往往难以阅读和理解,这给逆向工程带来了不小的挑战。本文将深入探讨 Webpack 打包的原理、形式以及如何逆向解析 Webpack 打包后的 JavaScript 代码,并通过实战案例帮助读者更好地理解这一过程。

> 本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

一、Webpack 打包介绍

1.1 Webpack 是什么?

Webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。它将应用程序的所有资源(如 JavaScript、CSS、图片等)视为模块,并通过依赖关系将它们打包成一个或多个文件。Webpack 的核心概念包括:

  • 入口(Entry):指定 Webpack 开始构建依赖图的起点。

  • 输出(Output):指定打包后的文件输出位置和文件名。

  • 加载器(Loader):用于处理非 JavaScript 文件,将其转换为 Webpack 能够处理的模块。

  • 插件(Plugin):用于执行更广泛的任务,如打包优化、资源管理等。

--------但无疑是对 js 逆向 造成了妨碍。但如果掌握了扣取 webpack的一些技巧也是不难的-----------

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)对文件打包

如果模块比较多,就会将模块打包成 JS 文件 , 然后定义一 个全局变量 window["webpackJsonp"] = [ ] ,它的作用 是存储需要动态导入的模块。 然后重写 window["webpackJsonp"] 数组的 push( ) 方 法为 webpackJsonpCallback( ), 也就是说 window["webpackJsonp"].push( ) 其实执行的是
webpackJsonpCallback( ),window["webpackJsonp"].push( )接收三个参数 , 第一 个参数是模块的ID, 第二个参数是 一个数组或者对象 , 里面 定义大量的函数, 第三个参数是要调用的函数 ( 可选)

二、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)