一、webpack大致处理流程
-
方式一:手动处理
- 先全局定义一个变量(比如aaa),用于接收加载器中的导出函数
- 再定义一个全局变量(比如bbb),用于接收具体模块中的加密对象或方法
- 补模块、环境(通过日志调试,根据报错信息去抠代码,技巧:数组索引操作可以转换为对象)
- 手动调用加载,使得全局定义的变量生效(可以打印aaa来查看)
- 定义加密方法,供外部调用
-
方式二:工具
- 下载地址:https://gitcode.net/zjq592767809/webpack_ast
- 使用命令行方式:
node webpack_mixer.js -l loader.js -m module1.js -mmodule2.js -o output.js
-
参数说明
-
-l:指定加载器的js路径
- 特征:一般以自执行函数开头,并且定义了导出函数,并为导出函数定义了多个方法
-
-m:指定函数模块的js路径
- 一般以window.webpackJsonp开头,如果有多个(或者不确定具体哪一个),可以多次-m指定
- -o:指定导出文件
-
- 注意:需要自行安装babel相关插件
二、案例
-
案例1:某壳
- https://bj.ke.com/?utm_source=baidu&utm_medium=pinzhuan&utm_term=biaoti&utm_content=biaotimiaoshu&utm_campaign=wybeijing
- 代码示例
var window = {} window.location = { href: 'https://bj.ke.com/' } var document = {} var navigator = { 'appName': 'Netscape' } var aaa; // 定义全局变量,接收加载器中导出函数 var ddd; // 定义全局变量,接收模块中的加密对象 // 加载器 !function (n){...}({ 50: function (t, e, n){...}, // 内部通过ddd接收了加密对象 ... // 根据调试信息,补充后续各模块 }) // 加载模块中代码 aaa(50).default(); // 定义加密方法,供外部调用 function getNewPwd(pwd){ // 需要额外补上设置公钥相关代码 let publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJxBJn2gY+D2OdldUxpsNwIGyKc/QRvqbWWGIdIewE7SxyyGHNcLdT+2bb6E6Ko7jBlEElUBkKJJ93G761dp6pXu7ORTjJ1mta99Bjud7+u/3473mG+QReoH4ux8idsd+E0TW0HWUP6zyfYy42HPSaN3pjetM30sVazdWxpvAH6wIDAQAB" ddd.ec.setPublicKey(publicKey) ddd.publicKey = publicKey return ddd.ec.encrypt(pwd) }
-
案例2:酷我音乐
- 手动抠示例
function c(t, e) { var n = ['00','01','02','03','04','05','06','07','08','09','0a','0b','0c','0d','0e','0f','10','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f','50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f','70','71','72','73','74','75','76','77','78','79','7a','7b','7c','7d','7e','7f','80','81','82','83','84','85','86','87','88','89','8a','8b','8c','8d','8e','8f','90','91','92','93','94','95','96','97','98','99','9a','9b','9c','9d','9e','9f','a0','a1','a2','a3','a4','a5','a6','a7','a8','a9','aa','ab','ac','ad','ae','af','b0','b1','b2','b3','b4','b5','b6','b7','b8','b9','ba','bb','bc','bd','be','bf','c0','c1','c2','c3','c4','c5','c6','c7','c8','c9','ca','cb','cc','cd','ce','cf','d0','d1','d2','d3','d4','d5','d6','d7','d8','d9','da','db','dc','dd','de','df','e0','e1','e2','e3','e4','e5','e6','e7','e8','e9','ea','eb','ec','ed','ee','ef','f0','f1','f2','f3','f4','f5','f6','f7','f8','f9','fa','fb','fc','fd','fe','ff']; var i = e || 0 , r = n; return [r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], "-", r[t[i++]], r[t[i++]], "-", r[t[i++]], r[t[i++]], "-", r[t[i++]], r[t[i++]], "-", r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]], r[t[i++]]].join("") } // 加密函数 function reqId() { var t = {}; var e = undefined; var n = undefined; var r = [91, 94, 187, 123, 214, 240]; var o = 7611; var h = 0; var d = Date.now() - Math.round(Math.random()*1000+1); var i = e && n || 0 , b = e || [] , f = (t = t || {}).node || r , v = void 0 !== t.clockseq ? t.clockseq : o; if (null == f || null == v) { var m = l(); null == f && (f = r = [1 | m[0], m[1], m[2], m[3], m[4], m[5]]), null == v && (v = o = 16383 & (m[6] << 8 | m[7])) } var y = void 0 !== t.msecs ? t.msecs : (new Date).getTime() , w = void 0 !== t.nsecs ? t.nsecs : h + 1 , dt = y - d + (w - h) / 1e4; if (dt < 0 && void 0 === t.clockseq && (v = v + 1 & 16383), (dt < 0 || y > d) && void 0 === t.nsecs && (w = 0), w >= 1e4) throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); d = y, h = w, o = v; var x = (1e4 * (268435455 & (y += 122192928e5)) + w) % 4294967296; b[i++] = x >>> 24 & 255, b[i++] = x >>> 16 & 255, b[i++] = x >>> 8 & 255, b[i++] = 255 & x; var _ = y / 4294967296 * 1e4 & 268435455; b[i++] = _ >>> 8 & 255, b[i++] = 255 & _, b[i++] = _ >>> 24 & 15 | 16, b[i++] = _ >>> 16 & 255, b[i++] = v >>> 8 | 128, b[i++] = 255 & v; for (var A = 0; A < 6; ++A) b[i + A] = f[A]; return e || c(b) } console.log(reqId())
- 使用工具,输出代码示例
var export_function; !function (e){...}({ 0: function (t, e, n){...}, ... 109: function (t, e, n){...}, ... }) module.exports = export_function; // 调用具体加密模块 console.log(export_function(109)())
- 手动抠示例
-
案例3:产业政策大数据平台
- 链接地址:http://www.spolicy.com/
- 提交的post参数经过了特殊编码,需要逆向
- 难点:
- 利用hook脚本过debugger
- 定位加密函数位置:
- 搜索 r = r.then(s.shift(), s.shift())
- 查看s第一个元素函数位置
- 代码示例:
var commonjsGlobal var protobuf_min = { exports: {} }; var aaa; var data = { "policyType": '6', "province": "", "city": "", "downtown": "", "garden": "", "centralId": "", "sort": 0, "homePageFlag": 1, "pageNum": 1, "pageSize": 7 } // 加载器 (function (module){...})(protobuf_min) function PolicyInfoByTypeIdParam$encode(m, w) { if (!w) w = aaa.Writer.create() if (m.policyType != null && Object.hasOwnProperty.call(m, "policyType")) w.uint32(10).string(m.policyType) if (m.centralId != null && Object.hasOwnProperty.call(m, "centralId")) w.uint32(18).string(m.centralId) if (m.province != null && Object.hasOwnProperty.call(m, "province")) w.uint32(26).string(m.province) if (m.city != null && Object.hasOwnProperty.call(m, "city")) w.uint32(34).string(m.city) if (m.downtown != null && Object.hasOwnProperty.call(m, "downtown")) w.uint32(42).string(m.downtown) if (m.garden != null && Object.hasOwnProperty.call(m, "garden")) w.uint32(50).string(m.garden) if (m.sort != null && Object.hasOwnProperty.call(m, "sort")) w.uint32(56).uint32(m.sort) if (m.pageNum != null && Object.hasOwnProperty.call(m, "pageNum")) w.uint32(64).uint32(m.pageNum) if (m.pageSize != null && Object.hasOwnProperty.call(m, "pageSize")) w.uint32(72).uint32(m.pageSize) if (m.homePageFlag != null && Object.hasOwnProperty.call(m, "homePageFlag")) w.uint32(80).uint32(m.homePageFlag) return w } // 注意data中的policyType值需要改为字符串形式 function getEncodeData(data) { var result = PolicyInfoByTypeIdParam$encode(data).finish().slice() console.log(result) return result } getEncodeData(data)