赵县住房和城乡建设局网站,网页视频下载快捷指令,新站seo快速排名 排名,龙岗在线官网我们在爬取网站的时候#xff0c;会遇到一些需要分析接口或 URL 信息的情况#xff0c;这时会有各种各样类似加密的情况
1. 某个网站的URL 带有一些看不懂的长串加密字符#xff0c;要抓取就必须懂的这些参数是怎么构造的#xff0c;否则我们连完整的 URL 都构造不出来会遇到一些需要分析接口或 URL 信息的情况这时会有各种各样类似加密的情况
1. 某个网站的URL 带有一些看不懂的长串加密字符要抓取就必须懂的这些参数是怎么构造的否则我们连完整的 URL 都构造不出来更不用说爬取了
2. 在分析某个网站的 Ajax 接口时可以看到接口的一些参数也是加密的 Request Headers 里面的也可能带有一些加密参数 如果不知道这些参数的具体构造逻辑就没法直接用程序来模拟这些 Ajax 请求
3. 翻看网站的 JavaScrapt 源代码可以发现很多压缩了或者看不太懂字符 比如 JavaScrapt 文件名被编码 文件的内容被压缩成几行 变量被修改成单个字符或者一些十六进制的字符这些导致我们无法轻易根据 JavaScrapt 源代码找出某些接口的加密逻辑
以上情况基本上是网站为了保护其数据而采取的一些措施我们可以把它分为两大类
1. URL/API 参数加密
2. JavaScrapt 压缩混淆和加密
网站数据防护方案
URL/API 参数加密
网站运营者首先想到的防护措施可能是对某些数据接口的参数进行加密比如给某些 URL 的参数加上校验码 给一些 ID 信息编码 给某些 API 请求加上 token/ sign 等签名 这样这些请求发送到服务器时服务器会通过客户端发来的一些请求信息以及双方约定好的秘钥等来对当前的的请求进行校验只有校验通过才返回对应的数据结果
JavaScript 压缩混淆 和 加密
接口加密技术看起来确实是一个不错的方案但是单纯依靠它并不能很好的解决问题。因为
1. JavaScript 运行于客户端也就是它必须在用户浏览器端加载并运行
2. Javascript 代码是公开透明的 也就是说浏览器可以直接获取到正在运行的 JavaScript 的源码
基于这两个原因 JavaScript 代码是不安全的任何人都可以读分析复制盗用甚至篡改代码
所以说对于以上情形客户端 JavaScript 对于某些加密的实现是很容易被找到或模拟的了解了加密逻辑后模拟参数的构造和请求也就轻而易举了所以如果 JavaScript 没有做任何层面的保护的话接口的加密对数据起不到任何防护作用
如果不想数据被这么轻易获取那么就要用到 JavaScript 压缩混淆和加密技术了
代码压缩 去除 JavaScript 代码中不必要的空格换行等内容使源代码压缩为几行内容降低代码的可读性当然同时也提高了网站的加载速度
代码混淆 使用变量替换字符串阵列化控制流平坦化多态变异僵尸函数调试保护等手段是代码变得难以阅读和分析达到最终保护的目的。但这并不影响代码原有的功能使理想实用的 JavaScript 保护方案
代码加密可以通过某种手段将 JavaScript 代码进行加密 转成人无法阅读或者解析的代码如借用 WebAssembly 技术可以直接将 JavaScript 代码用 C/C 实现 JavaScript 调用其编译后形成的文件执行相应的功能
URL/API 参数加密
现在绝大多数的网站的数据一般都通过服务器提供的API 来获取的网站或 App 可以请求某个数据 API 获取对应的数据然后在把数据展示出来。 但有些数据是比较宝贵或私密的这些数据肯定需要一些层面上的防护所以不同的 API 的实现也就对应着不同的安全防护级别
为了提升接口的安全性客户端和服务端约定一种接口校验方式一般来说会用到各种加密和编码算法 如 Base64, Hex 编码 MD5 , AES, DES, RSA 等对称或非对称加密
JavaScript 压缩
JavaScript 压缩其实就是去除 JavaScript 代码中不必要的空格换行等内容或者把一些可能公用的代码进行处理实现共享最后输出的结果压缩为几行内容代码的可读性变的很差同时仅仅去除空格换行这样的压缩方式其实几乎是没有任何防护作用的因为这种压缩方式仅仅是降低了代码的直接可读性。 因为网上有一些常见的工具就可以直接将其格式化
目前主流的前端开发技术大多都会利用 webpack , Rollup 等工具进行打包。 webpack, Rollup 会对源代码进行编译和压缩输出几个打包好的 JavaScript 文件其中我们可以看到输出的 JavaScript 文件名带有一些不规则字符串同时文件内容可能只有几行 变量名都用一些简单的字母表示。这其中就包含 JavaScript 压缩技术 比如一些公共的库输出成 bundle 文件一些调用逻辑压缩和转义成冗长的几行代码这些都属于 JavaScript 压缩。
JavaScript 混淆
JavaScript 混淆完全是在 JavaScript 上面进行的处理 它的目的就是使得 JavaScript 变得难以阅读和分析。
变量名混淆 将带有含义的变量名方法名常量名随机变为毫无意义的乱码字符串
字符串混淆 将字符串阵列化集中放置并进行 MD5 或 Base64 加密存储使代码不出现明文字符串这样可以避免使用全局搜索字符串的方式定位到入口
对象键名替换 针对 JavaScript 对象的属性进行加密转化隐藏代码之间的调用关系
控制流平坦化: 打乱函数原有的代码的执行流程及调用关系使代码逻辑变得混乱无序
无用代码注入 随机在代码中插入不会被执行的无用代码进一步是代码看起更加混乱
调试保护基于调试器的特性对当前运行环境进行校验 加入一些 debugger 语句使其在调试模式下难以顺利执行 JavaScript 代码
多态变异 使JavaScript 每次被调试调用时将代码自身立刻发生变异变为与之前完全不同的代码即功能不变只是代码形式发生变异以杜绝代码被动态分析和调试
域名锁定使 JavaScript 代码只能在指定域名下运行
特殊编码 将 JavaScript 完全编码为人不可读的代码比如表情符号特殊符号等
在前端开发中现在实现 JavaScript 混淆的主流实现是 javascript-obfscatr 和 terser 这两个库
以 javascript-obfuscator 为例 它是支持 ES8 的免费高效的 JavaScript 混淆库 可以使得 JavaScript 代码经过混淆后难以被复用盗用混淆后的代码具有和原来的代码一模一样的功能
怎么使用能 首先 要装好 Node.js 12.x 及以上的版本 确保可以正常使用 npm 命令
首先创建一个项目
1. 创建一个文件夹 例如 js-obfuscate
2. 使用工具打开文件夹 例如 vscode cmd 都行
3. 输入 npm init 前面装了 Node.js ,并可以使用 npm 命令
4. 会出现一系列的提示 package name: 你的项目名字叫啥 version: 版本号 (默认 1.0.0)可选 description: 对项目的描述可选 entry point: 项目的入口文件默认 index.js可选 test command: 项目启动的时候要用什么命令来执行脚本文件默认为node app.js可选 git repository: 如果你要将项目上传到git中的话那么就需要填写git的仓库地址可选 keywirds 项目关键字我也不知道有啥用所以我就不写了 author: 作者的名字可选 license: 发行项目需要的证书可选 完成之后会出现一个 package.json
然后安装 js-obfuscate 库
npm i -D javascript-obfuscator
安装的时候如果报错有可能是网络问题可以多试几次如果出现了 node_modules 的文件夹依然会报错可以将命令再执行一遍不要删之前安装过的让他继续安装
安装完成之后node_modules 文件夹下会出现很多的文件夹 表示安装成功了
创建一个 main.js 文件 const code let x 1 1 console.log(x, x) const options { compact: false, controlFlowFlattening: true } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) 在命令行 node main.js 运行之后 (function (_0x4d092c, _0x2f5762) { const _0x281041 _0x26c1, _0x27e2de _0x4d092c(); while (!![]) { try { const _0x3151b1 parseInt(_0x281041(0x1f4)) / 0x1 * (parseInt(_0x281041(0x1f3)) / 0x2) -parseInt(_0x281041(0x1f7)) / 0x3 * (-parseInt(_0x281041(0x1f5)) / 0x4) parseInt(_0x281041(0x1f8)) / 0x5 parseInt(_0x281041(0x1f2)) / 0x6 -parseInt(_0x281041(0x1fc)) / 0x7 * (-parseInt(_0x281041(0x1fb)) / 0x8) -parseInt(_0x281041(0x1f9)) / 0x9 parseInt(_0x281041(0x1f6)) / 0xa * (-parseInt(_0x281041(0x1fa)) / 0xb); if (_0x3151b1 _0x2f5762) break; else _0x27e2de[push](_0x27e2de[shift]()); } catch (_0x456666) { _0x27e2de[push](_0x27e2de[shift]()); } } }(_0x3a8e, 0x236c9)); let x 1 0x1; function _0x26c1(_0x31b95d, _0x36c78f) { const _0x3a8e23 _0x3a8e(); return _0x26c1 function (_0x26c120, _0x2b8ed3) { _0x26c120 _0x26c120 - 0x1f2; let _0x35ab0b _0x3a8e23[_0x26c120]; return _0x35ab0b; }, _0x26c1(_0x31b95d, _0x36c78f); } console[log](x, x); function _0x3a8e() { const _0x4ea833 [ 232AFrliB, 20oCyCxY, 13893ZUBQDQ, 225280tUMyyY, 1679427ppLFEE, 2203410wXvAkQ, 280ZIEIAh, 41482jszBjV, 502092KVtJsN, 127574cmdaFW, 2OBrzKA ]; _0x3a8e function () { return _0x4ea833; }; return _0x3a8e(); 这里我们定义了两个变量一个是 code 即需要被混淆的代码另一个是混淆选项 options 是一个 Object 接下来我们引入了 javascript-obfuscator 这个库 然后定义了一个方法 给其传入 code 和 options 来获取混淆后的代码最后在控制台输出混淆后的代码
代码压缩
javascript-obfuscator 也提供了代码压缩功能 使用其参数 compact 即可完成 JavaScript 代码的压缩输出为一行内容。参数 compact 的默认值是 true 如果定义为 false 那么混淆后的代码会分行展示 const code let x 1 1 console.log(x, x) const options { compact: true, } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) 可以看到代码完全挤在一起了 const _0x5c6b41_0x546d;(function(_0xebf384,_0x54f3a9){const _0x302b00_0x546d,_0x367638_0xebf384();while(!![]){try{const _0x249619parseInt(_0x302b00(0x183))/0x1-parseInt(_0x302b00(0x185))/0x2*(parseInt(_0x302b00(0x17f))/0x3)parseInt(_0x302b00(0x182))/0x4-parseInt(_0x302b00(0x188))/0x5-parseInt(_0x302b00(0x187))/0x6*(parseInt(_0x302b00(0x186))/0x7)parseInt(_0x302b00(0x184))/0x8*(-parseInt(_0x302b00(0x180))/0x9)parseInt(_0x302b00(0x181))/0xa;if(_0x249619_0x54f3a9)break;else _0x367638[push](_0x367638[shift]());}catch(_0x9b3150){_0x367638[push](_0x367638[shift]());}}}(_0x15fd,0xb25e6));function _0x15fd(){const _0x274d2e[56jlGlMY,4TBRzYu,203VZEcKD,23334gBqhhL,767055ydWwNV,log,2186532ofYyfi,666351DYipZp,3326350TuZLDM,5096152PuNVOt,1366078zwxueh];_0x15fdfunction(){return _0x274d2e;};return _0x15fd();}let x10x1;function _0x546d(_0x51e0c2,_0x52160b){const _0x15fd52_0x15fd();return _0x546dfunction(_0x546d84,_0x12968b){_0x546d84_0x546d84-0x17f;let _0x3a2bc9_0x15fd52[_0x546d84];return _0x3a2bc9;},_0x546d(_0x51e0c2,_0x52160b);}console[_0x5c6b41(0x189)](x,x); 变量名混淆
变量名混淆可以通过在 javascript-obfuscator 中配置 identifierNamesGenerator 参数来实现。如果将其值设为 hexadecimal 则会将变量名替换为 十六进制形式的字符串
hexadecimal : 将变量名替换为十六进制形式的字符串 例如 0xabc123
mangled : 将变量名替换为普通的简写字符 例如 a, b , c等 const code let hello 1 1 console.log(hello, hello) const options { compact: true, identifierNamesGenerator: mangled } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) const ib;(function(c,d){const hb,ec();while(!![]){try{const fparseInt(h(0x10e))/0x1*(-parseInt(h(0x10c))/0x2)-parseInt(h(0x111))/0x3parseInt(h(0x115))/0x4*(parseInt(h(0x114))/0x5)parseInt(h(0x112))/0x6*(-parseInt(h(0x10f))/0x7)-parseInt(h(0x110))/0x8-parseInt(h(0x113))/0x9parseInt(h(0x117))/0xa;if(fd)break;else e[push](e[shift]());}catch(g){e[push](e[shift]());}}}(a,0x6c52f));function a(){const j[26031360NSHRFA,139570bWOiFJ,log,10vsDbgU,7WyBWmQ,25168GNiOri,1462830btnoTs,5186778KGtaFW,6696261JlGafx,3188285UAKRGV,4oDzIAv,hello];afunction(){return j;};return a();}function b(c,d){const ea();return bfunction(f,g){ff-0x10c;let he[f];return h;},b(c,d);}let hello10x1;console[i(0x10d)](i(0x116),hello); 可以看到变量名变成了 a ,b 的形式
也可以设置 identifiersPrefix 参数来控制混淆后的变量前缀 const code let hello 1 1 console.log(hello, hello) const options { identifiersPrefix: germey } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) const germey_0x5a7cecgermey_0x3c79;function germey_0x1462(){const _0x256596[5FxMIWA,14876HiEAWk,4175800QHkiZt,2604196ZCrwwo,95890cnxtCC,20DszwMR,log,30mIbOUa,1720938eHRKlL,137304kEtZRb,2506077rvjWdq];germey_0x1462function(){return _0x256596;};return germey_0x1462();}(function(_0x946c93,_0x40e486){const _0x206272germey_0x3c79,_0x136653_0x946c93();while(!![]){try{const _0x3771d9parseInt(_0x206272(0x106))/0x1*(-parseInt(_0x206272(0x105))/0x2)parseInt(_0x206272(0x10a))/0x3parseInt(_0x206272(0x10d))/0x4*(-parseInt(_0x206272(0x10c))/0x5)-parseInt(_0x206272(0x109))/0x6parseInt(_0x206272(0x104))/0x7parseInt(_0x206272(0x10e))/0x8parseInt(_0x206272(0x10b))/0x9*(parseInt(_0x206272(0x108))/0xa);if(_0x3771d9_0x40e486)break;else _0x136653[push](_0x136653[shift]());}catch(_0x15bd60){_0x136653[push](_0x136653[shift]());}}}(germey_0x1462,0x80578));let hello10x1;function germey_0x3c79(_0x581c10,_0x5dc5b2){const _0x14622agermey_0x1462();return germey_0x3c79function(_0x3c79bf,_0xef6b91){_0x3c79bf_0x3c79bf-0x104;let _0x5e9c40_0x14622a[_0x3c79bf];return _0x5e9c40;},germey_0x3c79(_0x581c10,_0x5dc5b2);}console[germey_0x5a7cec(0x107)](hello,hello); 可以看到混淆后的变量名前缀加上了我们自定义的 germey
另外 renameGlobals 这个参数还可以指定是否混淆全局变量名和函数名称默认值为 false const code var $ function(id) { return document.getElementById(id); }; const options { renameGlobals: true } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) (function(_0x2126f5,_0x4f498b){var _0x448046_0x10b3,_0x4912e1_0x2126f5();while(!![]){try{var _0x5c646b-parseInt(_0x448046(0x1c3))/0x1*(parseInt(_0x448046(0x1be))/0x2)parseInt(_0x448046(0x1bf))/0x3*(-parseInt(_0x448046(0x1b9))/0x4)parseInt(_0x448046(0x1bd))/0x5*(parseInt(_0x448046(0x1bc))/0x6)-parseInt(_0x448046(0x1c0))/0x7-parseInt(_0x448046(0x1c2))/0x8parseInt(_0x448046(0x1bb))/0x9-parseInt(_0x448046(0x1c4))/0xa*(-parseInt(_0x448046(0x1ba))/0xb);if(_0x5c646b_0x4f498b)break;else _0x4912e1[push](_0x4912e1[shift]());}catch(_0x5e6fb7){_0x4912e1[push](_0x4912e1[shift]());}}}(_0x4ccb,0x6f00e));function _0x10b3(_0x219820,_0x29bda8){var _0x4ccb5c_0x4ccb();return _0x10b3function(_0x10b31f,_0x3eb05f){_0x10b31f_0x10b31f-0x1b9;var _0x1d07f9_0x4ccb5c[_0x10b31f];return _0x1d07f9;},_0x10b3(_0x219820,_0x29bda8);}var _0x2695a4function(_0x524c7c){var _0x5dfa95_0x10b3;return document[_0x5dfa95(0x1c1)](_0x524c7c);};function _0x4ccb(){var _0x58c9f1[getElementById,347616xHAGlf,49906zAzpCm,1090EPDXUe,3556248GSaYKz,229394zZtUgU,700569Wnqqmy,6ofVjXU,1200825mUOHDu,26QTSxHw,3iUmEtj,3885910ffHvVO];_0x4ccbfunction(){return _0x58c9f1;};return _0x4ccb();} 可以看到我们定义的 $ 不见了如果后文用到了这个变量可能会出错因此酌情设置
字符串混淆
字符串混淆即将一个字符串声明放到一个数组里面 使之无法被直接搜到。 这可以通过 stringArray 参数控制 默认是 true 。 此外还可以通过 rotateStringArray 参数来控制数组化后结果的元素顺序 默认为 true 。 还可以通过 stringArrayEncoding 参数来控制数组的编码形式 默认不开启编码。 如果将其设置为 true 或 base64 则会使用 Base64 另外还可以通过 stringArrayThreshold 来控制启用编码的概率 其范围为 0-1 默认为 0.8 const code var a hello world const options { stringArray: true, rotateStringArray: true, stringArrayEncoding: [base64,], // base64 or rc4 or false stringArrayThreshold: 1, } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) var _0x35131b_0x4590;(function(_0x19c057,_0xc27b2d){var _0x15721b_0x4590,_0xa11bed_0x19c057();while(!![]){try{var _0x1e0433parseInt(_0x15721b(0x1f0))/0x1*(-parseInt(_0x15721b(0x1ee))/0x2)parseInt(_0x15721b(0x1f6))/0x3*(parseInt(_0x15721b(0x1f5))/0x4)-parseInt(_0x15721b(0x1ef))/0x5parseInt(_0x15721b(0x1f7))/0x6-parseInt(_0x15721b(0x1f9))/0x7*(parseInt(_0x15721b(0x1f8))/0x8)-parseInt(_0x15721b(0x1f3))/0x9*(-parseInt(_0x15721b(0x1f4))/0xa)-parseInt(_0x15721b(0x1f1))/0xb;if(_0x1e0433_0xc27b2d)break;else _0xa11bed[push](_0xa11bed[shift]());}catch(_0x5865c7){_0xa11bed[push](_0xa11bed[shift]());}}}(_0x2531,0xe366a));function _0x2531(){var _0x4fc026[otrVC3LczuG,mJi4nZCXne1JrKDPtG,AgvSBg8GD29YBgq,owTLAunqBq,nZqXmtu5mefgtMXYuW,nezctNLXqW,mtGZndyXn0D0y1nxEa,mteWmdC3mJb6v0DvrNi,nJq4ndy0qu5ms2Hx,nZDXD2HLtKi,otC0ogTZD0zLAG,mZq5mdu4merhBgLRBW];_0x2531function(){return _0x4fc026;};return _0x2531();}function _0x4590(_0x1d9eee,_0x2ca6fa){var _0x2531df_0x2531();return _0x4590function(_0x45909f,_0x694dc4){_0x45909f_0x45909f-0x1ee;var _0x5b178c_0x2531df[_0x45909f];if(_0x4590[jbdtDM]undefined){var _0x283592function(_0x581a43){var _0x23f657abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/;var _0x3f5727,_0x1dd216;for(var _0x5ea4f80x0,_0x18de19,_0x42a870,_0x5edc640x0;_0x42a870_0x581a43[charAt](_0x5edc64);~_0x42a870(_0x18de19_0x5ea4f8%0x4?_0x18de19*0x40_0x42a870:_0x42a870,_0x5ea4f8%0x4)?_0x3f5727String[fromCharCode](0xff_0x18de19(-0x2*_0x5ea4f80x6)):0x0){_0x42a870_0x23f657[indexOf](_0x42a870);}for(var _0x427e2f0x0,_0x3a1436_0x3f5727[length];_0x427e2f_0x3a1436;_0x427e2f){_0x1dd216%(00_0x3f5727[charCodeAt](_0x427e2f)[toString](0x10))[slice](-0x2);}return decodeURIComponent(_0x1dd216);};_0x4590[RwPTRB]_0x283592,_0x1d9eeearguments,_0x4590[jbdtDM]!![];}var _0x467615_0x2531df[0x0],_0x24ad2f_0x45909f_0x467615,_0x1db7f0_0x1d9eee[_0x24ad2f];return!_0x1db7f0?(_0x5b178c_0x4590[RwPTRB](_0x5b178c),_0x1d9eee[_0x24ad2f]_0x5b178c):_0x5b178c_0x1db7f0,_0x5b178c;},_0x4590(_0x1d9eee,_0x2ca6fa);}var a_0x35131b(0x1f2); 可以看到 字符串已经找不到了另外我们还可以用 unicodeEscapeSequence 这个参数对字符串进行 Unicode 转码 const code var a hello world const options { compact: false, unicodeEscapeSequence: true } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) function _0x363c(_0x228c16, _0x48aa18) { var _0x25c699 _0x25c6(); return _0x363c function (_0x363c29, _0x5b2b9c) { _0x363c29 _0x363c29 - 0xaa; var _0x23386b _0x25c699[_0x363c29]; return _0x23386b; }, _0x363c(_0x228c16, _0x48aa18); } var _0x940dfd _0x363c; (function (_0x19f7da, _0xf3603f) { var _0x4e557e _0x363c, _0x24e454 _0x19f7da(); while (!![]) { try { var _0x3bd4d1 -parseInt(_0x4e557e(0xb1)) / 0x1 * (-parseInt(_0x4e557e(0xb0)) / 0x2) parseInt(_0x4e557e(0xac)) / 0x3 -parseInt(_0x4e557e(0xaf)) / 0x4 -parseInt(_0x4e557e(0xab)) / 0x5 * (-parseInt(_0x4e557e(0xad)) / 0x6) parseInt(_0x4e557e(0xb2)) / 0x7 -parseInt(_0x4e557e(0xb4)) / 0x8 -parseInt(_0x4e557e(0xb3)) / 0x9 * (parseInt(_0x4e557e(0xaa)) / 0xa); if (_0x3bd4d1 _0xf3603f) break; else _0x24e454[push](_0x24e454[shift]()); } catch (_0x5cfa3b) { _0x24e454[push](_0x24e454[shift]()); } } }(_0x25c6, 0x56b69)); function _0x25c6() { var _0x1fbea8 [ \x32\x30\x31\x32\x35\x35\x32\x55\x6c\x4d\x6a\x76\x56, \x31\x30\x61\x75\x53\x66\x4d\x48, \x33\x35\x30\x37\x38\x33\x30\x49\x53\x72\x64\x61\x64, \x31\x33\x31\x35\x35\x30\x33\x71\x55\x66\x63\x6a\x4a, \x36\x57\x59\x45\x45\x50\x49, \x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64, \x31\x38\x30\x34\x34\x30\x56\x71\x4d\x6b\x7a\x50, \x32\x36\x63\x76\x51\x74\x6a\x43, \x32\x36\x34\x39\x44\x79\x61\x79\x51\x41, \x34\x35\x34\x39\x30\x33\x34\x53\x45\x48\x78\x62\x63, \x31\x30\x35\x35\x32\x35\x39\x30\x4c\x50\x62\x67\x78\x51 ]; _0x25c6 function () { return _0x1fbea8; }; return _0x25c6(); } var a _0x940dfd(0xae); 代码的自我保护
我们可以通过设置 selfDefending 参数来开启代码的自我保护功能。 开启之后 混淆后的 JavaScript 会强制以一行形式显示。 如果我们将混淆后的代码进行格式化或者重命名该段代码将无法执行 const code console.log(hello world) const options { selfDefending: true } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) var _0xd11e3f_0x439f;(function(_0x1c0305,_0x3a57cf){var _0x4bda0c_0x439f,_0x404764_0x1c0305();while(!![]){try{var _0x3613bc-parseInt(_0x4bda0c(0x87))/0x1*(parseInt(_0x4bda0c(0x8f))/0x2)parseInt(_0x4bda0c(0x91))/0x3*(parseInt(_0x4bda0c(0x92))/0x4)-parseInt(_0x4bda0c(0x8c))/0x5*(-parseInt(_0x4bda0c(0x96))/0x6)-parseInt(_0x4bda0c(0x94))/0x7-parseInt(_0x4bda0c(0x95))/0x8*(-parseInt(_0x4bda0c(0x93))/0x9)parseInt(_0x4bda0c(0x8e))/0xa-parseInt(_0x4bda0c(0x90))/0xb*(parseInt(_0x4bda0c(0x8b))/0xc);if(_0x3613bc_0x3a57cf)break;else _0x404764[push](_0x404764[shift]());}catch(_0x2b7399){_0x404764[push](_0x404764[shift]());}}}(_0x4dd7,0xb197e));var _0x3a491c(function(){var _0x1820bc!![];return function(_0x3fdfea,_0x148e5d){var _0x56780d_0x1820bc?function(){var _0xead5db_0x439f;if(_0x148e5d){var _0xe980a0_0x148e5d[_0xead5db(0x8d)](_0x3fdfea,arguments);return _0x148e5dnull,_0xe980a0;}}:function(){};return _0x1820bc![],_0x56780d;};}()),_0x5d3317_0x3a491c(this,function(){var _0x4d62e8_0x439f;return _0x5d3317[toString]()[_0x4d62e8(0x88)](_0x4d62e8(0x89))[toString]()[_0x4d62e8(0x8a)](_0x5d3317)[search](_0x4d62e8(0x89));});function _0x439f(_0x254843,_0x1192ee){var _0x28eb15_0x4dd7();return _0x439ffunction(_0x5d3317,_0x3a491c){_0x5d3317_0x5d3317-0x87;var _0x4dd7dc_0x28eb15[_0x5d3317];return _0x4dd7dc;},_0x439f(_0x254843,_0x1192ee);}function _0x4dd7(){var _0x36da29[constructor,12LIMnts,3410545JdsbGk,apply,5684260usRpJN,2086ZOaUxx,16507139lursEK,1448274nlOFbv,4VBSaXz,2297367hVvMsn,4346405zFrRkF,40iaruMA,6lVbCUP,log,154hbVypx,search,(((.)))$];_0x4dd7function(){return _0x36da29;};return _0x4dd7();}_0x5d3317(),console[_0xd11e3f(0x97)](hello\x20world); 如果我们将混淆后的代码运行是可以正常使用的 如果格式化之后再运行则会报错
控制流平坦化
控制流平坦化就是将代码的执行逻辑混淆 使其变得复杂难读。其基本思想是将一些逻辑处理快都统一加上一个前驱逻辑块 每个逻辑块都有前驱逻辑块进行条件判断和分发 构成一个个闭环逻辑这导致整个逻辑十分复杂
在 javascript-obfuscator 中我们可以使用 controlFlowFlattening 变量控制是否开启控制流平坦化 const code (function(){ function foo () { return function () { var sum 1 2; console.log(1); console.log(2); console.log(3); console.log(4); console.log(5); console.log(6); } } foo()(); })(); const options { compact: false, controlFlowFlattening: true } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) function _0x58e5(_0x27b691, _0x5104fa) { var _0x1e139d _0x1e13(); return _0x58e5 function (_0x58e5c3, _0x23afd1) { _0x58e5c3 _0x58e5c3 - 0x126; var _0x417bcb _0x1e139d[_0x58e5c3]; return _0x417bcb; }, _0x58e5(_0x27b691, _0x5104fa); } function _0x1e13() { var _0xe5c863 [ 10721970nxDJls, log, 150712pXmEVE, 182CzrguC, 7428828IljWVM, 1623ImHQdj, 524130sdQmZL, 166202xBaANC, 5NZTnsL, split, 16520290nSzLpD, 448PoSvMN ]; _0x1e13 function () { return _0xe5c863; }; return _0x1e13(); } (function (_0x41ed0b, _0x39aa00) { var _0x2b900e _0x58e5, _0x3f3043 _0x41ed0b(); while (!![]) { try { var _0x44b040 -parseInt(_0x2b900e(0x12a)) / 0x1 * (parseInt(_0x2b900e(0x129)) / 0x2) parseInt(_0x2b900e(0x127)) / 0x3 * (parseInt(_0x2b900e(0x12d)) / 0x4) -parseInt(_0x2b900e(0x128)) / 0x5 -parseInt(_0x2b900e(0x126)) / 0x6 -parseInt(_0x2b900e(0x131)) / 0x7 * (parseInt(_0x2b900e(0x130)) / 0x8) parseInt(_0x2b900e(0x12e)) / 0x9 parseInt(_0x2b900e(0x12c)) / 0xa; if (_0x44b040 _0x39aa00) break; else _0x3f3043[push](_0x3f3043[shift]()); } catch (_0xc4f29b) { _0x3f3043[push](_0x3f3043[shift]()); } } }(_0x1e13, 0xa0134), (function () { var _0x5e08d1 { Bsdmq: function (_0x2eda91) { return _0x2eda91(); } }; function _0x54c5b1() { return function () { var _0x5ce4e9 _0x58e5, _0x4507e7 1|3|4|5|0|2|6[_0x5ce4e9(0x12b)](|), _0x3531ae 0x0; while (!![]) { switch (_0x4507e7[_0x3531ae]) { case 0: console[_0x5ce4e9(0x12f)](0x4); continue; case 1: var _0x39a77b 0x1 0x2; continue; case 2: console[log](0x5); continue; case 3: console[log](0x1); continue; case 4: console[_0x5ce4e9(0x12f)](0x2); continue; case 5: console[log](0x3); continue; case 6: console[_0x5ce4e9(0x12f)](0x6); continue; } break; } }; } _0x5e08d1[Bsdmq](_0x54c5b1)(); }())); 另外我们还可以使用 controlFlowFlatteningThreshold 这个参数来控制比例取值范围是 0 到 1默认值为 0.75 如果为 0 则是不设置
无用代码注入
无用代码注入即不会被执行的代码或对上下文没有任何影响的代码 注入之后可以对现有的 JavaScript 代码阅读形成干扰。 我们可以使用 deadCodeInjection 参数开启这个选项默认为 false const code console.log(abc); console.log(cde); console.log(efg); console.log(hij); const options { compact: false, deadCodeInjection: true, deadCodeInjectionThreshold: 1 } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) function _0x488e() { var _0x3c144e [ abc, log, 1401706bMgzVB, 3053718NwChnb, 15781493nKgPHo, hij, 2606500HDxpBP, 16320UHJLfq, 2861355LWkVsM, 1142771eYCHKY, efg ]; _0x488e function () { return _0x3c144e; }; return _0x488e(); } function _0x49e4(_0x57d459, _0x5e4fbf) { var _0x488e97 _0x488e(); return _0x49e4 function (_0x49e47c, _0x6c16a7) { _0x49e47c _0x49e47c - 0x1dd; var _0x2d6b25 _0x488e97[_0x49e47c]; return _0x2d6b25; }, _0x49e4(_0x57d459, _0x5e4fbf); } var _0x585613 _0x49e4; (function (_0x248c50, _0x13dd30) { var _0x39d544 _0x49e4, _0xf5f349 _0x248c50(); while (!![]) { try { var _0x2cb33b parseInt(_0x39d544(0x1e7)) / 0x1 -parseInt(_0x39d544(0x1e0)) / 0x2 -parseInt(_0x39d544(0x1e6)) / 0x3 -parseInt(_0x39d544(0x1e4)) / 0x4 parseInt(_0x39d544(0x1e5)) / 0x5 -parseInt(_0x39d544(0x1e1)) / 0x6 parseInt(_0x39d544(0x1e2)) / 0x7; if (_0x2cb33b _0x13dd30) break; else _0xf5f349[push](_0xf5f349[shift]()); } catch (_0x51933b) { _0xf5f349[push](_0xf5f349[shift]()); } } }(_0x488e, 0x8ee66), console[_0x585613(0x1df)](_0x585613(0x1de)), console[_0x585613(0x1df)](cde), console[_0x585613(0x1df)](_0x585613(0x1dd)), console[_0x585613(0x1df)](_0x585613(0x1e3))); 这里可以看到在每个方法内部额外增加了一些 if....else 语句这些代码有的会被执行但不影响结果有的压根不会执行。
在 javascript-obfuscator 中 我们可以通过 deadCodeInjection 参数控制代码的注入
还可以通过 deadCodeInjectionThreshold 参数控制无用代码注入的比例 取值范围 0-1 默认 0.4
对象键名替换
如果是一个对象可以使用 transformObjectkeys 来对对象的键值进行替换 const code (function(){ var object { foo: test1, bar: { baz: test2 } }; })(); const options { compact: false, transformObjectKeys: true } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) function _0x5980(_0x29a057, _0x2d593f) { var _0x470dfa _0x470d(); return _0x5980 function (_0x598085, _0x47a11e) { _0x598085 _0x598085 - 0x15f; var _0x52f61c _0x470dfa[_0x598085]; return _0x52f61c; }, _0x5980(_0x29a057, _0x2d593f); } (function (_0x184600, _0x14a2e4) { var _0x626b65 _0x5980, _0x57441a _0x184600(); while (!![]) { try { var _0x511c72 -parseInt(_0x626b65(0x16c)) / 0x1 * (parseInt(_0x626b65(0x169)) / 0x2) parseInt(_0x626b65(0x162)) / 0x3 * (-parseInt(_0x626b65(0x160)) / 0x4) parseInt(_0x626b65(0x15f)) / 0x5 * (parseInt(_0x626b65(0x16a)) / 0x6) parseInt(_0x626b65(0x16e)) / 0x7 parseInt(_0x626b65(0x16d)) / 0x8 * (-parseInt(_0x626b65(0x164)) / 0x9) -parseInt(_0x626b65(0x161)) / 0xa * (-parseInt(_0x626b65(0x16b)) / 0xb) parseInt(_0x626b65(0x168)) / 0xc * (parseInt(_0x626b65(0x166)) / 0xd); if (_0x511c72 _0x14a2e4) break; else _0x57441a[push](_0x57441a[shift]()); } catch (_0x34fab0) { _0x57441a[push](_0x57441a[shift]()); } } }(_0x470d, 0x1c3c5), (function () { var _0x230e06 _0x5980, _0x3791d7 {}; _0x3791d7[_0x230e06(0x16f)] _0x230e06(0x165); var _0x59e14a {}; _0x59e14a[_0x230e06(0x167)] test1, _0x59e14a[_0x230e06(0x163)] _0x3791d7; var _0x3f3925 _0x59e14a; }())); function _0x470d() { var _0x3d92c8 [ 4CIKdSY, 2980asQFWz, 639417qrHvJJ, bar, 306azjkbB, test2, 91sGTAtg, foo, 200892zgruwY, 2QIzZua, 564cFfEZN, 2519gCnZUy, 155317nKchsb, 4168doMXgy, 677670NkEqkC, baz, 11680tPdurf ]; _0x470d function () { return _0x3d92c8; }; return _0x470d(); } 可以看到 Object 的变量名被替换为了特殊变量代码可读性变差
禁用控制台输出
我们可以用 disableConsoleOutput 来禁用掉 console.log 输出功能加大调试难度 const code console.log(hello world) const options { disableConsoleOutput: true } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) function _0x4c23(_0x529d5e,_0x3f3a42){var _0x6403d0_0x54cf();return _0x4c23function(_0x4cafa9,_0x47fa2b){_0x4cafa9_0x4cafa9-0x169;var _0x1416bb_0x6403d0[_0x4cafa9];return _0x1416bb;},_0x4c23(_0x529d5e,_0x3f3a42);}var _0x4855c1_0x4c23;function _0x54cf(){var _0x2d65b1[161640PiLPKs,exception,73OSEmJG,prototype,info,apply,4462FhELTj,981680fHVvFG,608922acGYGj,error,2230MVSzAU,toString,log,28DIFbWN,hello\x20world,constructor,433748yAzFLk,length,bind,13707SZdGMu,console,61735TddpUM,return\x20(function()\x20,table];_0x54cffunction(){return _0x2d65b1;};return _0x54cf();}(function(_0x3b62e9,_0x25ec1e){var _0x1bc584_0x4c23,_0x49701b_0x3b62e9();while(!![]){try{var _0x5964d5parseInt(_0x1bc584(0x17d))/0x1*(parseInt(_0x1bc584(0x169))/0x2)parseInt(_0x1bc584(0x17b))/0x3parseInt(_0x1bc584(0x170))/0x4*(parseInt(_0x1bc584(0x178))/0x5)parseInt(_0x1bc584(0x16b))/0x6-parseInt(_0x1bc584(0x173))/0x7parseInt(_0x1bc584(0x16a))/0x8-parseInt(_0x1bc584(0x176))/0x9*(parseInt(_0x1bc584(0x16d))/0xa);if(_0x5964d5_0x25ec1e)break;else _0x49701b[push](_0x49701b[shift]());}catch(_0x3bb303){_0x49701b[push](_0x49701b[shift]());}}}(_0x54cf,0x1eb50));var _0x47fa2b(function(){var _0x525183!![];return function(_0x52bd98,_0x4fa7d4){var _0x207e5f_0x525183?function(){var _0x345c2f_0x4c23;if(_0x4fa7d4){var _0x151451_0x4fa7d4[_0x345c2f(0x180)](_0x52bd98,arguments);return _0x4fa7d4null,_0x151451;}}:function(){};return _0x525183![],_0x207e5f;};}()),_0x4cafa9_0x47fa2b(this,function(){var _0x1394fc_0x4c23,_0x151177;try{var _0x25a489Function(_0x1394fc(0x179){}.constructor(\x22return\x20this\x22)(\x20)););_0x151177_0x25a489();}catch(_0x41a93c){_0x151177window;}var _0x8df322_0x151177[_0x1394fc(0x177)]_0x151177[_0x1394fc(0x177)]||{},_0x281853[_0x1394fc(0x16f),warn,_0x1394fc(0x17f),_0x1394fc(0x16c),_0x1394fc(0x17c),_0x1394fc(0x17a),trace];for(var _0x1092fa0x0;_0x1092fa_0x281853[_0x1394fc(0x174)];_0x1092fa){var _0x387edc_0x47fa2b[_0x1394fc(0x172)][_0x1394fc(0x17e)][bind](_0x47fa2b),_0x323379_0x281853[_0x1092fa],_0x228196_0x8df322[_0x323379]||_0x387edc;_0x387edc[__proto__]_0x47fa2b[_0x1394fc(0x175)](_0x47fa2b),_0x387edc[_0x1394fc(0x16e)]_0x228196[_0x1394fc(0x16e)][bind](_0x228196),_0x8df322[_0x323379]_0x387edc;}});_0x4cafa9(),console[_0x4855c1(0x16f)](_0x4855c1(0x171)); 此时运行这段代码发现不会有输出
调试保护
我们知道在 JavaScript 代码中加入 debugger 关键字那么执行到该位置的时候就会进入断点调试模式。 如果在代码多个位置都加入 debugger 关键字 或者定义某个逻辑来反复执行 debugger 就会反复不断执行断点调试模式原本的代码就无法顺利执行了。这个过程可以被称为调试保护 const code for (let i 0; i 5; i ) { console.log(i, i) } const options { debugProtection: true } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) const _0x5074be_0x5732;(function(_0x1f8fda,_0xd0b477){const _0x54b142_0x5732,_0x5e27f1_0x1f8fda();while(!![]){try{const _0x5b6004parseInt(_0x54b142(0xa5))/0x1*(parseInt(_0x54b142(0x90))/0x2)parseInt(_0x54b142(0xa4))/0x3*(parseInt(_0x54b142(0xa3))/0x4)parseInt(_0x54b142(0x93))/0x5*(-parseInt(_0x54b142(0x99))/0x6)-parseInt(_0x54b142(0x9b))/0x7*(-parseInt(_0x54b142(0x8d))/0x8)parseInt(_0x54b142(0x8a))/0x9*(-parseInt(_0x54b142(0x8e))/0xa)parseInt(_0x54b142(0x9c))/0xb*(parseInt(_0x54b142(0x98))/0xc)-parseInt(_0x54b142(0x89))/0xd*(parseInt(_0x54b142(0xa1))/0xe);if(_0x5b6004_0xd0b477)break;else _0x5e27f1[push](_0x5e27f1[shift]());}catch(_0x325412){_0x5e27f1[push](_0x5e27f1[shift]());}}}(_0x4ed7,0x42b62));const _0x172872(function(){let _0x1c32a0!![];return function(_0xab5ad5,_0x372292){const _0x454208_0x1c32a0?function(){const _0x56fbd1_0x5732;if(_0x372292){const _0x2ac506_0x372292[_0x56fbd1(0x8f)](_0xab5ad5,arguments);return _0x372292null,_0x2ac506;}}:function(){};return _0x1c32a0![],_0x454208;};}());(function(){_0x172872(this,function(){const _0x195a67_0x5732,_0xb2e1e7new RegExp(_0x195a67(0x94)),_0x5215eenew RegExp(\x5c\x5c\x20*(?:[a-zA-Z_$][0-9a-zA-Z_$]*),i),_0x3ecded_0x361448(_0x195a67(0x9e));!_0xb2e1e7[_0x195a67(0x8b)](_0x3ecded_0x195a67(0x9a))||!_0x5215ee[test](_0x3ecded_0x195a67(0x95))?_0x3ecded(0):_0x361448();})();}());function _0x5732(_0x27968c,_0x1f308b){const _0x35e508_0x4ed7();return _0x5732function(_0x361448,_0x172872){_0x361448_0x361448-0x89;let _0x4ed76c_0x35e508[_0x361448];return _0x4ed76c;},_0x5732(_0x27968c,_0x1f308b);}for(let i0x0;i0x5;i){console[_0x5074be(0x96)](i,i);}function _0x4ed7(){const _0x507280[352dZVXHu,call,init,while\x20(true)\x20{},length,1618064KkIAqb,stateObject,781772JsYWOq,6dRWoSu,1KgjMCA,constructor,91LRDVyE,788463aoMygo,test,debu,14536trNqnc,60EkmNSX,apply,946754hoNyrg,string,gger,72555YIiVjC,function\x20*\x5c(\x20*\x5c),input,log,action,90804Fclkuh,6FsZrWw,chain,1988NIaEkw];_0x4ed7function(){return _0x507280;};return _0x4ed7();}function _0x361448(_0x1a5d66){function _0x55ce50(_0x3e9c24){const _0x4118a3_0x5732;if(typeof _0x3e9c24_0x4118a3(0x91))return function(_0x4c4676){}[constructor](_0x4118a3(0x9f))[_0x4118a3(0x8f)](counter);else(_0x3e9c24/_0x3e9c24)[_0x4118a3(0xa0)]!0x1||_0x3e9c24%0x140x0?function(){return!![];}[_0x4118a3(0xa6)](_0x4118a3(0x8c)_0x4118a3(0x92))[_0x4118a3(0x9d)](_0x4118a3(0x97)):function(){return![];}[_0x4118a3(0xa6)](_0x4118a3(0x8c)_0x4118a3(0x92))[_0x4118a3(0x8f)](_0x4118a3(0xa2));_0x55ce50(_0x3e9c24);}try{if(_0x1a5d66)return _0x55ce50;else _0x55ce50(0x0);}catch(_0x4641a0){}} 此时如果在控制台执行这段代码就会反复执行调试模式
还可以使用 debugProtectionInterval 来启用无限调试模式 const options { debugProtection: true, debugProtectionInterval: true, } 域名锁定
我们还可以通过 domainLock 来控制 JavaScript 代码只能在特定域名下运行 const code console.log(hello world) const options { domainLock: [cuiqingcai.com] } const obfuscator require(javascript-obfuscator) function obfuscate(code, options) { return obfuscator.obfuscate(code, options).getObfuscatedCode() } console.log(obfuscate(code, options)) function _0x1916(_0x1589c6,_0x450239){var _0x443af4_0x1f31();return _0x1916function(_0x364a66,_0x310ca4){_0x364a66_0x364a66-0xd6;var _0x2ee6d3_0x443af4[_0x364a66];return _0x2ee6d3;},_0x1916(_0x1589c6,_0x450239);}var _0x22fa0d_0x1916;(function(_0xfe7e55,_0xdccc62){var _0x48e40b_0x1916,_0x63ab55_0xfe7e55();while(!![]){try{var _0x1d5e97parseInt(_0x48e40b(0xd9))/0x1parseInt(_0x48e40b(0xe4))/0x2parseInt(_0x48e40b(0xe1))/0x3parseInt(_0x48e40b(0xe3))/0x4-parseInt(_0x48e40b(0xdf))/0x5*(-parseInt(_0x48e40b(0xdd))/0x6)-parseInt(_0x48e40b(0xe7))/0x7*(parseInt(_0x48e40b(0xde))/0x8)-parseInt(_0x48e40b(0xe2))/0x9*(parseInt(_0x48e40b(0xea))/0xa);if(_0x1d5e97_0xdccc62)break;else _0x63ab55[push](_0x63ab55[shift]());}catch(_0x56f2ce){_0x63ab55[push](_0x63ab55[shift]());}}}(_0x1f31,0x282e7));function _0x1f31(){var _0x58ca4a[933066kGSYxp,503368MkwFBA,520424qxbVzY,hello\x20world,replace,21FvkLpW,return\x20(function()\x20,charCodeAt,30iWGKtb,length,[zAZMxKrjbvyRUBAlkdlzWfrzLfAxbR],indexOf,fromCharCode,6326jZKuue,[EgIPgeQHdUfdOqXNfZwZwUPHK],log,czuiAZqiMxKrngjbcai.vcyoRmUBAlkdlzWfrzLfAxbR,6PjOarF,358808gxaCme,845560NSKczn,split,145998haiAkg];_0x1f31function(){return _0x58ca4a;};return _0x1f31();}var _0x310ca4(function(){var _0x1f5f9d!![];return function(_0x5a7483,_0x2f0bf9){var _0x4bcf23_0x1f5f9d?function(){if(_0x2f0bf9){var _0x211a31_0x2f0bf9[apply](_0x5a7483,arguments);return _0x2f0bf9null,_0x211a31;}}:function(){};return _0x1f5f9d![],_0x4bcf23;};}()),_0x364a66_0x310ca4(this,function(){var _0x2c2c80_0x1916,_0x436706;try{var _0x32de61Function(_0x2c2c80(0xe8){}.constructor(\x22return\x20this\x22)(\x20)););_0x436706_0x32de61();}catch(_0x1dcb5a){_0x436706window;}var _0x47f32anew RegExp(_0x2c2c80(0xd6),g),_0x2677ee_0x2c2c80(0xdc)[replace](_0x47f32a,)[_0x2c2c80(0xe0)](;),_0x3f9e1b,_0x47bbe7,_0x110eeb,_0x4a2130,_0x4c3c97function(_0x53147f,_0xd1512c,_0x4559e5){var _0x242519_0x2c2c80;if(_0x53147f[length]!_0xd1512c)return![];for(var _0x2dd23a0x0;_0x2dd23a_0xd1512c;_0x2dd23a){for(var _0x22390c0x0;_0x22390c_0x4559e5[_0x242519(0xeb)];_0x22390c0x2){if(_0x2dd23a_0x4559e5[_0x22390c]_0x53147f[_0x242519(0xe9)](_0x2dd23a)!_0x4559e5[_0x22390c0x1])return![];}}return!![];},_0x2792aafunction(_0x343d35,_0x4209b3,_0x3c3e42){return _0x4c3c97(_0x4209b3,_0x3c3e42,_0x343d35);},_0x5ca24efunction(_0x14c619,_0x259b22,_0x16fe46){return _0x2792aa(_0x259b22,_0x14c619,_0x16fe46);},_0x1b8790function(_0x2f23cb,_0x5a6704,_0x420d41){return _0x5ca24e(_0x5a6704,_0x420d41,_0x2f23cb);};for(var _0x9962c0 in _0x436706){if(_0x4c3c97(_0x9962c0,0x8,[0x7,0x74,0x5,0x65,0x3,0x75,0x0,0x64])){_0x3f9e1b_0x9962c0;break;}}for(var _0x525ea4 in _0x436706[_0x3f9e1b]){if(_0x1b8790(0x6,_0x525ea4,[0x5,0x6e,0x0,0x64])){_0x47bbe7_0x525ea4;break;}}for(var _0x16c178 in _0x436706[_0x3f9e1b]){if(_0x5ca24e(_0x16c178,[0x7,0x6e,0x0,0x6c],0x8)){_0x110eeb_0x16c178;break;}}if(!(~_0x47bbe7))for(var _0x29bc73 in _0x436706[_0x3f9e1b][_0x110eeb]){if(_0x2792aa([0x7,0x65,0x0,0x68],_0x29bc73,0x8)){_0x4a2130_0x29bc73;break;}}if(!_0x3f9e1b||!_0x436706[_0x3f9e1b])return;var _0x433c3a_0x436706[_0x3f9e1b][_0x47bbe7],_0x547e9b!!_0x436706[_0x3f9e1b][_0x110eeb]_0x436706[_0x3f9e1b][_0x110eeb][_0x4a2130],_0x17440e_0x433c3a||_0x547e9b;if(!_0x17440e)return;var _0x4e6c49![];for(var _0x315ef40x0;_0x315ef4_0x2677ee[_0x2c2c80(0xeb)];_0x315ef4){var _0x47bbe7_0x2677ee[_0x315ef4],_0x187c9f_0x47bbe7[0x0]String[_0x2c2c80(0xd8)](0x2e)?_0x47bbe7[slice](0x1):_0x47bbe7,_0x1992ee_0x17440e[_0x2c2c80(0xeb)]-_0x187c9f[length],_0x495921_0x17440e[_0x2c2c80(0xd7)](_0x187c9f,_0x1992ee),_0x458918_0x495921!-0x1_0x495921_0x1992ee;_0x458918((_0x17440e[_0x2c2c80(0xeb)]_0x47bbe7[_0x2c2c80(0xeb)]||_0x47bbe7[indexOf](.)0x0)(_0x4e6c49!![]));}if(!_0x4e6c49){var _0x54a16enew RegExp(_0x2c2c80(0xda),g),_0x4e6f87EagIbPougeQHdUftd:blanOkqXNfZwZwUPHK[_0x2c2c80(0xe6)](_0x54a16e,);_0x436706[_0x3f9e1b][_0x110eeb]_0x4e6f87;}});_0x364a66(),console[_0x22fa0d(0xdb)](_0x22fa0d(0xe5)); 这样代码如果被单独剥离出来或者不在指定域名下都是不可执行的
特殊编码
另外还有一些特殊的工具包 比如 aaencode ,jjencode, jsfuck 等它们可以对代码进行混淆和编码这些工具会将原本简单的代码转化为基本不可读的代码但实际上运行效果还是相同的。这些混淆方式比较另类看起来虽然没有什么头绪但实际上找到规律非常好还原并没有达到真正强力混淆的效果
WebAssembly
WebAssembly 的基本思路是将原本需要 JavaScript 的代码编写的核心机制使用其他语言如 C/C来编写 并编译成字节码的文件并通过 JavaScript 调用执行从起到二进制级别的防护作用