- Published on
javascript-obfuscator —— 保护你的js代码
- Authors
- Name
- Pony Ma
javascript-obfuscator —— 保护你的前端代码
JavaScript代码由于天然暴露在客户端的特性,很容易被人读取。在代码的安全性和知识产权日益重要的当下,保护JavaScript代码不被恶意用户轻易理解和篡改就显得尤为重要。
这就是 javascript-obfuscator
上场的时候了
javascript-obfuscator
**
什么是**javascript-obfuscator
是一个开源的 JavaScript 混淆工具,他通过各种技术手段改变代码的外观和结构,而不影响其执行功能。使代码变得难以阅读和理解,从而增加了逆向工程的难度。
怎么实现混淆
javascript-obfuscator
通过以下几种方式来混淆代码:
- 变量名和函数名替换:将这些名字替换为难以理解的字符串,使代码不可读,隐藏其原始意图和功能。
- 字符串数组转换和加密:将代码中的字符串转移到一个数组中,在运行时动态解密,增加逆向难度。
- 控制流混淆:改变代码的执行流程,使逻辑结构变得复杂、难以追踪。
- 死代码注入:加入无用的代码片段,误导分析者。
- 环境检测:检测代码是否运行在某些特定环境(如浏览器的开发者工具)中,并根据需要改变代码行为或停止运行。
- 自我防御机制:如果检测到代码结构被修改(例如尝试美化代码)代码将改变行为或停止运行。
使用方式
javascript-obfuscator
是一个nodeJS的包,你可以直接通过yarn
或者npm
进行安装
$ yarn add --dev javascript-obfuscator
$ npm install --save-dev javascript-obfuscator
直接导入
你可以直接在JS文件中进行导入,调用混淆函数进行代码混淆
var JavaScriptObfuscator = require('javascript-obfuscator');
var obfuscationResult = JavaScriptObfuscator.obfuscate(
`
(function(){
var variable1 = '5' - 3;
var variable2 = '5' + 3;
var variable3 = '5' + - '2';
var variable4 = ['10','10','10','10','10'].map(parseInt);
var variable5 = 'foo ' + 1 + 1;
console.log(variable1);
console.log(variable2);
console.log(variable3);
console.log(variable4);
console.log(variable5);
})();
`,
{
compact: false,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 1,
numbersToExpressions: true,
simplify: true,
stringArrayShuffle: true,
splitStrings: true,
stringArrayThreshold: 1
}
);
console.log(obfuscationResult.getObfuscatedCode());
/*
var _0x9947 = [
'map',
'log',
'foo\x20',
'bvmqO',
'133039ViRMWR',
'xPfLC',
'ytpdx',
'1243717qSZCyh',
'2|7|4|6|9|',
'1ErtbCr',
'1608314VKvthn',
'1ZRaFKN',
'XBoAA',
'423266kQOYHV',
'3|0|5|8|1',
'235064xPNdKe',
'13RUDZfG',
'157gNPQGm',
'1639212MvnHZL',
'rDjOa',
'iBHph',
'9926iRHoRl',
'split'
];
function _0x33e4(_0x1809b5, _0x37ef6e) {
return _0x33e4 = function (_0x338a69, _0x39ad79) {
_0x338a69 = _0x338a69 - (0x1939 + -0xf * 0x1f3 + 0x1 * 0x469);
var _0x2b223a = _0x9947[_0x338a69];
return _0x2b223a;
}, _0x33e4(_0x1809b5, _0x37ef6e);
}
(function (_0x431d87, _0x156c7f) {
var _0x10cf6e = _0x33e4;
while (!![]) {
try {
var _0x330ad1 = -parseInt(_0x10cf6e(0x6c)) * -parseInt(_0x10cf6e(0x6d)) + -parseInt(_0x10cf6e(0x74)) * -parseInt(_0x10cf6e(0x78)) + parseInt(_0x10cf6e(0x6a)) + -parseInt(_0x10cf6e(0x70)) + parseInt(_0x10cf6e(0x6e)) * -parseInt(_0x10cf6e(0x75)) + parseInt(_0x10cf6e(0x72)) + -parseInt(_0x10cf6e(0x67)) * parseInt(_0x10cf6e(0x73));
if (_0x330ad1 === _0x156c7f)
break;
else
_0x431d87['push'](_0x431d87['shift']());
} catch (_0x9f878) {
_0x431d87['push'](_0x431d87['shift']());
}
}
}(_0x9947, -0xb6270 + 0x4dfd2 * 0x2 + 0x75460 * 0x2), function () {
var _0x1f346d = _0x33e4, _0x860db8 = {
'ytpdx': _0x1f346d(0x6b) + _0x1f346d(0x71),
'bvmqO': function (_0x560787, _0x519b9e) {
return _0x560787 - _0x519b9e;
},
'rDjOa': function (_0x4501fe, _0x2b07a3) {
return _0x4501fe + _0x2b07a3;
},
'xPfLC': function (_0x5f3c9b, _0x434936) {
return _0x5f3c9b + _0x434936;
},
'XBoAA': function (_0x535b8a, _0x42eef4) {
return _0x535b8a + _0x42eef4;
},
'iBHph': _0x1f346d(0x65)
}, _0x346c55 = _0x860db8[_0x1f346d(0x69)][_0x1f346d(0x79)]('|'), _0x3bf817 = 0x4bb * 0x1 + 0x801 + -0xcbc;
while (!![]) {
switch (_0x346c55[_0x3bf817++]) {
case '0':
console[_0x1f346d(0x7b)](_0x4c96d8);
continue;
case '1':
console[_0x1f346d(0x7b)](_0x101028);
continue;
case '2':
var _0x65977d = _0x860db8[_0x1f346d(0x66)]('5', -0x586 + -0x2195 + -0x6 * -0x685);
continue;
case '3':
console[_0x1f346d(0x7b)](_0x65977d);
continue;
case '4':
var _0x56d39b = _0x860db8[_0x1f346d(0x76)]('5', -'2');
continue;
case '5':
console[_0x1f346d(0x7b)](_0x56d39b);
continue;
case '6':
var _0x544285 = [
'10',
'10',
'10',
'10',
'10'
][_0x1f346d(0x7a)](parseInt);
continue;
case '7':
var _0x4c96d8 = _0x860db8[_0x1f346d(0x68)]('5', 0x622 * -0x6 + 0x4a * 0x3 + 0x1 * 0x23f1);
continue;
case '8':
console[_0x1f346d(0x7b)](_0x544285);
continue;
case '9':
var _0x101028 = _0x860db8[_0x1f346d(0x6f)](_0x860db8[_0x1f346d(0x6f)](_0x860db8[_0x1f346d(0x77)], 0x6fb * 0x5 + 0x1ebf * 0x1 + -0x41a5), 0x209 * 0xa + 0x1314 + -0x276d);
continue;
}
break;
}
}());
*/
命令行工具
也可以通过命令行工具直接针对整个JS文件进行混淆
javascript-obfuscator input.js --output output.js --compact true --control-flow-flattening false
在线工具
官方还提供了一个在线的混淆工具,方便进行测试和学习
常见配置项
官方提供了很多混淆的配置项,来决定你代码的混淆程度,例如
compact
代码是否在一行controlFlowFlattening
控制流扁平化deadCodeInjection
插入随机死代码debugProtection
禁用开发者工具debugProtectionInterval
无限进入debugger模式disableConsoleOutput
禁用所有console
更多配置项请参考官方文档
注意事项
- 性能影响:混淆会增加代码的复杂度,对代码的性能产生一定影响,混淆越多性能越低,需要在安全和性能之间做好取舍
- 调试困难:一旦代码被混淆,调试和维护将变得更加困难,难住的不仅仅是恶意用户,还有开发者
逆向
目前大部分网站都是基于Obfuscator开发框架的二次封装,可能会和原有框架逻辑略有不同
判定
Ob反混淆的代码结构很明显,一般分为三大块
- 声明大数组(密码表)
- 对数组进行移位(密码表纠正)
- 加密函数,进行代码解密
处理
网上有很多反混淆的工具,很方便做一些初级的解混淆。 https://tool.yuanrenxue.cn/decode_obfuscator https://deobfuscate.relative.im/ https://obf-io.deobfuscate.io/
Ob最大的难题是移除一些 格式化检查
和 内存爆破
问题,通常都是用正则表达式来检查,同时利用循环执行大正则实现内存溢出,导致页面不可用
常见位置
updateCookie, newState,等等
解决方式
hook正则表达式
RegExp.prototype.test = function(params) { console.log(params); debugger; return true; }
既然是通过正则就行检查,那我们可以直接hook
RegExp
函数不格式化代码 不格式化代码的话就不会触发一些一些检查,但相应的代码就会很难调试
删掉相关检查 找到相关的检查代码,将其删掉,这个很考验经验和眼力了