webpack逆向
别人花三天打包的代码,你花一个下午就能拆回半成品——这就是webpack逆向的乐趣。别误会,这活儿不违法,只要你不是冲着破解商业软件去的。我干这行纯粹是因为好奇:那些压缩成一行、变量名全是a、b、c的bundle文件,到底藏了多少开发者的心思。
先从最简单的入口说起。你打开一个网站,按F12,切到Sources面板,找那些名字带数字的js文件——比如`1.chunk.js`、`2.chunk.js`——十有八九是webpack产物。真正的入口文件通常叫`main.js`或者`app.js`,但被混淆过后,你只能看到一个巨大的函数包裹。别慌,第一步是找到webpack的运行时,那玩意儿一般长这样:一堆`__webpack_require__`调用,中间夹着个模块数组或对象。
我习惯直接搜`webpackJsonp`这个全局变量。它是个数组,每个元素对应一个chunk,里头第二项就是模块表。你把模块表里的函数体挨个复制出来,格式化一下,代码就变得可读了。但光可读没用,变量名还是a、b、c。这时候得靠逻辑推理——比如看到`Object.prototype.toString.call`,八成是类型判断;看到`document.createElement`,肯定是DOM操作。猜多了,你甚至能闻出作者写代码时的习惯:有的人喜欢用`lodash`,有的人直接原生造轮子,这些细节在压缩代码里照样藏不住。
真正棘手的是sourcemap。有些站点会故意把`.map`文件藏起来,或者只对内部人员开放。我碰到过一家电商网站,源码里明明引用了`vendor.js.map`,但请求直接404。试了试改`Referer`头,没用;加个`X-Forwarded-For`伪装内网IP,还是没用。最后我换个思路——不找map,直接改代码。用Chrome的`Local Overrides`功能,把格式化后的js文件存到本地,手动改几个变量名,再刷新页面,居然能跑通。那一刻,感觉像在玩一场高难度的拼图游戏。
还有更野的路子。webpack打包时经常留下一些特征字符串,比如`__esModule`、`"use strict"`,甚至作者忘了删的注释。有次我逆向一个后台管理系统,在压缩代码里翻到一句中文注释:“别改这个函数,改了会炸”。顺着注释找到那个函数,果然是整个权限校验的核心。你说这开发者心多大?但反过来想,这也提醒我们:上线前得跑一遍`terser`的`stripComments`选项,别给逆向者留路标。
逆向webpack不只是为了偷代码。我干这行更常是为了调试——线上出了bug,sourcemap又没发到CDN,只能靠逆向定位问题。还有做安全审计的,得检查第三方依赖有没有被篡改。这时候,你手里那堆压缩代码就是唯一的线索。说实话,每次成功还原一个模块的调用关系,那种爽感不亚于解开一道复杂的数学题。
工具方面,我推荐先试`webpack-devtool`插件,它能自动识别chunk并还原模块结构。但别全指望它——遇到动态加载或者手写的自定义运行时,照样歇菜。这时候老老实实手动跟栈,用`debugger`断点慢慢摸。再配个`prettier`做格式化,就够用了。至于那些号称“一键还原源码”的商业工具,我劝你别信,它们连`eval`包裹的模块都搞不定。
最后说句实在的:webpack逆向拼的是耐心,不是技巧。你坐在电脑前,一杯咖啡,一行行代码翻过去,突然某个函数名跳进眼里,你一拍大腿——“原来你在这儿!”那种感觉,比看什么技术文档都来得痛快。
