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模块

你可能感兴趣的:(Webpack打包后逆向分析)