webpack逆向全解析:打包原理+代码自吐方案介绍
大家好,今天分享一下 webpack 的原理和算法自吐方案。
webpack
在逆向中,webpack 大家应该碰到很多次了,它是一个 JS 应用程序的静态模块打包器,负责将 JS 文件和其他的资源文件都当做一个模块打包到一起。借用一张官网的图片,更多的信息大家可以去 webpack 的官网查看。
webpack 原理
本篇文章只从逆向的角度讲解 webpack 的原理,具体 webpack 的实现方式和其他更加深入的使用方法不做分析。
下面使用猿人学联系平台第 21 题作为示例,它的代码长这样:
为了简化调试步骤,我删减了部分对 console
方法进行覆盖的代码。
这里教大家一个小技巧,要想快速直观的查看代码结构,可以使用 pycharm 或者其他代码编辑工具,选择全部收起,pycharm 会将代码能折叠的地方全部折叠。
代码被全部折叠后,会发现其实整个文件就只有一个自执行函数,函数有一个参数,并且传入了一个有 60 个元素的数组。
将函数体和参数都展开,会发现传入的参数是一个 Object
,并且函数体有一个自执行函数和一些函数调用。其实这个自执行函数就是一个调度器,它通过传入一个大的 Object
,依次分发执行,实际执行的业务代码分布在传入的 Object
中,并且使用索引值将业务代码之间做关联。
webpack 调度器
说到调度器,可能不是很好理解,那就打个断点,把代码跑起来看看。
在调度器的第一行打个断点,发现实际传入的参数如刚才所说,是一个 Object
参数,并且有大量的函数定义。
实际的调度器函数是:_0xe63c45
,并且调度器的第一个参数是 110,也就是说整个文件的入口就是 110 这个数字对应的函数,110 这个函数做了什么暂时先不用关系,继续往下走。
这里的 _0x2e44f1
是一个缓存,如果模块多次被使用,那么会从缓存中获取已经导入过的模块,提升性能。由于是第一次进入,缓存为空,所以继续往下。
这里生成了一个新的 Object
对象 _0xfaa4fe
,同时将它放到缓存中去,对象的 i
属性就是刚才说的入口函数索引 110,l 可能是标识是否已经成功导入,现在的 l
还是 false
,exports
中保存需要被导出的函数,现在还是空的。
在实际的调用中,会将已经导出的函数作为当前的命名空间传入进去,也会将调度器函数传入进去,并且在执行完需要执行的业务代码后,使用调度器函数调度下一个函数来执行。这里实际调用的是 512 这个索引对应的函数,有点类似于接力比赛,上一个人完成任务后,告诉下一个人索引,然后下一个人去执行。
红框中实际调用了对应索引的目标函数,并且将 l
标识为 true
,证明已经成功导入对应的模块,并且返回模块中的导出函数。
上面的流程在 webpack 执行的过程中会不停的嵌套执行下去,直到执行完所有的业务代码为止。
可能几张图无法讲的很明白,大家找一个 webpack 打包好的代码自己打断点单步跟一下基本上就明白了。
webpack 扣代码
现在我们已经懂了原理,之前不懂原理的时候看到 webpack 的代码,可能连扣代码的勇气都没有,跳来跳去的无从下手。现在搞懂了原理,扣代码的方法也就呼之欲出了。
webpack 扣代码有两种方案:
一种就是自己手动扣,单步调试一步一步的将执行过的代码收集起来,最终形成一份可以执行的代码,不过操作起来很繁琐,而且具体调度了哪个索引也不知道,要运行起来才能直到,比较麻烦。
另外一种就是删减,按照调度器执行的顺序,将不需要的代码统统删除,只保留需要的代码,并且解决删减中出现的问题,这个方案操作起来也比较复杂,而且同样要知道调度器执行的顺序,才能知道哪些代码是用不到的。
webpack 代码自吐
上面讲到了两种扣代码的方案,既然两种方案都需要将代码跑起来,那就跑起来。结合浏览器日志断点的方式让 webpack 执行过的代码都自己打印出来,简称代码自吐,就是自己将执行过的函数都吐出来,方便收集分析。
刚才分析的时候了解到图中 27 行就是实际执行对应索引中的函数位置,那就使用浏览器的日志断点,将索引对应的函数使用 toString
都打印出来,这样就不用我们一步一步的跟代码,直接刷新网页即可获取所有执行过的代码。
刷新网页,即可在控制台看到所有执行过的代码,将其都收集起来即可完成扣代码逻辑。当然了,别忘记给这些函数补上调度器相关的参数,否则可能会执行出错。
如果想要使用之前的两种方法扣代码,可以使用浏览器自吐的方法获取所有执行过的索引,只需要在日志断点中将输出代码改成输出索引即可。
刷新后,即可看到入口是 110 这个索引,后面就是 webpack 执行过的所有代码对应的索引了,可以在扣代码的时候保留以上索引,其余的都可以删除了。
webpack_ast
还有一种方法就是通过 AST 的方式来自动扣代码,全自动化,无需动手,地址为:https://github.com/p0ise/webpack_ast,有需要的小伙伴可以自取。
声明:以上方法我没有使用过,是否还有效以及是否可以适配所有场景暂不可知,大家可以自行尝试。
总结
以上就是 webpack 的原理介绍以及所有扣代码的方案了,看完上面的文章,下次再遇到 webpack 打包的 JS 代码,相信你也可以有勇气尝试一下了。
本文章首发于个人博客 LLLibra146’s blog
本文作者:LLLibra146
更多文章请关注公众号 (LLLibra146):
版权声明:本博客所有文章除特别声明外,均采用 © BY-NC-ND 许可协议。非商用转载请注明出处!严禁商业转载!