Webpack打包后逆向分析

webpack对前端js源码进行压缩打包后,一般会生成如下几个文件:
bootstrap.js 入口文件:

(function (modules) { // webpackBootstrap
    // install a JSONP callback for chunk loading
    var parentJsonpFunction = window["webpackJsonp"];
    window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
        // add "moreModules" to the modules object,
        // then flag all "chunkIds" as loaded and fire callback
        var moduleId, chunkId, i = 0,
            resolves = [],
            result;
        for (; i < chunkIds.length; i++) {
            chunkId = chunkIds[i];
            if (installedChunks[chunkId]) {
                resolves.push(installedChunks[chunkId][0]);
            }
            installedChunks[chunkId] = 0;
        }

        /*遍历数组moreModules中的模块(也就是一个一个的函数),只要moreModules含有属性moduleId,则存入全局modules数组中
        moduleId就是数组的moreModules数组的下标*/
        for (moduleId in moreModules) {
            //hasOwnProperty()用来判断一个属性是定义在对象本身而不是继承自原型链。
            //Object.prototype.hasOwnProperty 表示Object对象是否含有某个属性,在此处变成moreModules是否含有moduleId属性
            if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
                modules[moduleId] = moreModules[moduleId];
            }
        }

        if (parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules);
        while (resolves.length) {
            resolves.shift()();
        }
        if (executeModules) {
            for (i = 0; i < executeModules.length; i++) {
                result = __webpack_require__(__webpack_require__.s = executeModules[i]);
            }
        }


        return result;
    };

    // The module cache
    var installedModules = {};

    // objects to store loaded and loading chunks
    var installedChunks = {
        8: 0
    };

    // The require function
    function __webpack_require__(moduleId) {
        // console.log('zhixing:'+moduleId);
        // Check if module is in cache
        if (installedModules[moduleId]) {
            return installedModules[moduleId].exports;
        }
        // Create a new module (and put it into the cache)
        var module = installedModules[moduleId] = {
            i: moduleId,
            l: false,
            exports: {}
        };

        // Execute the module function
        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

        // Flag the module as loaded
        module.l = true;

        // Return the exports of the module
        return module.exports;
    }

    /*其他代码*/
})([]);

这是一个自执行函数,当使用webpack对js文件进行功能分割时在window对象会中定义一个webpackJsonp函数,供其他模块调用,第二个参数是一个数组,里面定义大量的函数,第三个参数表示要调用哪个函数。

比如项目中可能会出现main1.js 、main2.js、about.js、download.js等等分功能的js模块文件,每一个js文件中都是类似这样的开头形式:

//第一个参数表示要依赖哪个模块先加载,第二个参数是数组,每个数组元素是一个函数,调用webpackJsonp对第二个参数中的没一个函数注册进上面的modules数组中存储起来
webpackJsonp([7], [
    /* 0 */
    /***/
    (function (module, exports, __webpack_require__) {
        var global = __webpack_require__(3);
        var core = __webpack_require__(21);
         //其他代码
    })
]);

//或者第二个参数是一个对象形式:
//这里第三个参数[181]表示要执行modules数组中第181号函数,如果要执行多个函数块,[181,32,78]等等
//__webpack_require__表示要引入哪个函数模块
webpackJsonp([0], {

    /***/
    181:
    /***/
        (function (module, exports, __webpack_require__) {
        "use strict";
        Object.defineProperty(exports, "__esModule", {
            value: true
        });
        var global = __webpack_require__(3);
        var core = __webpack_require__(21);
         //其他代码 1
        var url = new _urlParse2.default(url);
        var algo = "sha256";
        var digest = "hex";
        var hash = (0, _createHmac2.default)(algo, url.href).update(url.query).update(url.hostname).update(url.pathname).digest(digest);
        console.log(hash);
        global_auth = hash;
    })
},[181]);

具体到我们逆向分析的层面,当我们再chrome中调式分析到我们所关注的代码逻辑后,确定其所在哪一个序号模块中,然后修改webpackJsonp的第三个参数就ok了。
比如我这里,我分析到需要计算url的一个加密值,发现它在181号模块中,将 “其他代码 1” 这段代码块单独扣出来,删掉181号模块中其他不相关的逻辑代码,只要保证”其他代码 1“这个代码中引入的函数(如_createHmac2)能正常require进来就行

如何具体到操作层面呢?

这里以python中的pyv8为例讲解(用node执行也是一样),pyv8内嵌了google的V8 js引擎,虽说版本比较老了,但还是能用的。

但是直接在chrome浏览器上分析出来的结果,是不能全部直接丢进pyv8进行执行操作的,因为V8引擎是一个纯js执行环境,它不包含浏览器js环境中的dom window等这些对象,所以要对分析出的js文件进行适当修改。

将所有js文件整合到一个js文件中,注意顺序,首先copy boostrap.js入口文件,然后main1.js、main2.js等所有的模块代码都copy进来,最后才将需要调用的模块引入,并传入需要执行的具体模块序号,如[181],整体js代码形式如下:

var window = [];  //V8没有window对象,手动定义一个全局的
var global_auth = ''; //用来接收后面计算出来的url加密值,pyv8可以获取到这个变量的值
//boostrap.js入口文件
(function (modules) { // webpackBootstrap
    var parentJsonpFunction = window["webpackJsonp"];
    .......
})([]);

//main1.js模块
webpackJsonp([7], [
    (function (module, exports, __webpack_require__) {
          .......
    })
]);
//其他模块
.....
//最后目标代码所在的模块
webpackJsonp([0], {

    /***/
    181:
    /***/
        (function (module, exports, __webpack_require__) {
        "use strict";
        Object.defineProperty(exports, "__esModule", {
            value: true
        });

        var _createClass = function () {
            function defineProperties(target, props) {
                for (var i = 0; i < props.length; i++) {
                    var descriptor = props[i];
                    descriptor.enumerable = descriptor.enumerable || false;
                    descriptor.configurable = true;
                    if ("value" in descriptor) descriptor.writable = true;
                    Object.defineProperty(target, descriptor.key, descriptor);
                }
            }
            return function (Constructor, protoProps, staticProps) {
                if (protoProps) defineProperties(Constructor.prototype, protoProps);
                if (staticProps) defineProperties(Constructor, staticProps);
                return Constructor;
            };
        }();
        var _react = __webpack_require__(2);
        var _react2 = _interopRequireDefault(_react);
        var _reactStatic = __webpack_require__(119);
        var _Meta = __webpack_require__(480);
        var _Meta2 = _interopRequireDefault(_Meta);
        var _Header = __webpack_require__(481);
        var _Header2 = _interopRequireDefault(_Header);
        var _Footer = __webpack_require__(482);
        var _Footer2 = _interopRequireDefault(_Footer);
        var _Thumbnails = __webpack_require__(483);
        var _Thumbnails2 = _interopRequireDefault(_Thumbnails);
        var _DownloadLink = __webpack_require__(507);
        var _DownloadLink2 = _interopRequireDefault(_DownloadLink);
        var _fuzzyTile = __webpack_require__(488);
        var _fuzzyTile2 = _interopRequireDefault(_fuzzyTile);
        var _createHmac = __webpack_require__(508);
        var _createHmac2 = _interopRequireDefault(_createHmac);
        var _icons = __webpack_require__(475);
        var _icons2 = _interopRequireDefault(_icons);
        var _urlParse = __webpack_require__(531);
        var _urlParse2 = _interopRequireDefault(_urlParse);
        var _axios = __webpack_require__(120);
        var _axios2 = _interopRequireDefault(_axios);

        function _interopRequireDefault(obj) {
            return obj && obj.__esModule ? obj : {
                default: obj
            };
        }

        url = 'https://www.youtube.com/watch?v=3_VsTMc1auM';
        var url = new _urlParse2.default(url);
        var algo = "sha256";
        var digest = "hex";
        var hash = (0, _createHmac2.default)(algo, url.href).update(url.query).update(url.hostname).update(url.pathname).digest(digest);
        console.log(hash);
        global_auth = hash;
    })
},[181]);  //执行181模块
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容