js混淆还原

1.数组类混淆
现象:定义一个数组,然后js代码中用 [ ] 式访问数组成员
处理后:将数组内成员字符串替换到js中
# -*- coding: utf-8 -*-

# 混淆前js
js = """
var arr = ["Date", "getTime"];
console.log(window[arr[0]]()[arr[1]])
"""

import re

# 1.正则匹配出列表
js_arr_name = 'arr'  # 混淆js中数组定义的名称
arr = eval(re.findall(js_arr_name + ' = (\[[\s\S]+?\])', js)[0])

# 2.正则匹配出所有需要替换的数组引用
be_replaced_arr_set = set(re.findall(js_arr_name + '\[\d+\]', js))

# 3.循环遍历进行替换
for be_replaced_arr in be_replaced_arr_set:
    res = eval(be_replaced_arr)
    js = js.replace(be_replaced_arr, '"' + res + '"')
    print('{} 替换完成'.format(res))

print('解混淆后:\n', js)
2.函数混淆
混淆的js代码
var _0xa12e = ['appendChild', 'fromCharCode', 'ifLSL', 'undefined', 'mPDrG', 'DWwdv', 'styleSheets', 'addRule', '::before', '.context_kw', '::before{content:\x20\x22', 'cssRules', 'pad', 'clamp', 'sigBytes', 'YEawH', 'yUSXm', 'PwMPi', 'pLCFG', 'ErKUI', 'OtZki', 'prototype', 'endWith', 'test', '8RHz0u9wbbrXYJjUcstWoRU1SmEIvQZQJtdHeU9/KpK/nBtFWIzLveG63e81APFLLiBBbevCCbRPdingQfzOAFPNPBw4UJCsqrDmVXFe6+LK2CSp26aUL4S+AgWjtrByjZqnYm9H3XEWW+gLx763OGfifuNUB8AgXB7/pnNTwoLjeKDrLKzomC+pXHMGYgQJegLVezvshTGgyVrDXfw4eGSVDa3c/FpDtban34QpS3I=', 'enc', 'Latin1', 'parse', 'window', 'location', 'href', '146385F634C9CB00', 'decrypt', 'ZeroPadding', 'toString', 'split', 'length', 'style', 'type', 'setAttribute', 'async', 'getElementsByTagName', 'NOyra', 'fgQCW', 'nCjZv', 'parentNode', 'insertBefore', 'head'];
(function(_0x4db306, _0x3b5c31) {
	var _0x24d797 = function(_0x1ebd20) {
		while (--_0x1ebd20) {
			_0x4db306['push'](_0x4db306['shift']());
		}
	};
	_0x24d797(++_0x3b5c31);
}(_0xa12e, 0xcc));
var _0xea12 = function(_0x56430f, _0x7f6841) {
	_0x56430f = _0x56430f - 0x0;
	var _0x4f7a0f = _0xa12e[_0x56430f];
	return _0x4f7a0f;
};
CryptoJS[_0xea12('0x0')]['ZeroPadding'] = {
	'pad': function(_0x1df06f, _0x314b39) {
		var _0x2f7121 = {
			'YEawH': function _0x304fdc(_0x154e7c, _0x47ce8e) {
				return _0x154e7c - _0x47ce8e;
			},
			'yUSXm': function _0x15667f(_0x2118a7, _0x202af9) {
				return _0x2118a7 % _0x202af9;
			}
		};
		var _0x301b79 = _0x314b39 * 0x4;
		_0x1df06f[_0xea12('0x1')]();
		_0x1df06f[_0xea12('0x2')] += _0x2f7121[_0xea12('0x3')](_0x301b79, _0x2f7121[_0xea12('0x4')](_0x1df06f['sigBytes'], _0x301b79) || _0x301b79);
	},
	'unpad': function(_0x3994de) {
		var _0x542e1d = {
			'PwMPi': function _0x13be60(_0x37e2b3, _0x34d2aa) {
				return _0x37e2b3 - _0x34d2aa;
			},
			'byONr': function _0x41eeb1(_0x42220d, _0x40e5bd) {
				return _0x42220d & _0x40e5bd;
			},
			'pLCFG': function _0x562ecb(_0x2581d9, _0x590c51) {
				return _0x2581d9 >>> _0x590c51;
			},
			'FRqnC': function _0x582fef(_0x4c5451, _0x219412) {
				return _0x4c5451 - _0x219412;
			},
			'DwxPM': function _0x13a0d9(_0x3ce2bb, _0x236747) {
				return _0x3ce2bb * _0x236747;
			},
			'ErKUI': function _0x31d02b(_0x42d286, _0x4a8edd) {
				return _0x42d286 % _0x4a8edd;
			},
			'OtZki': function _0x4024cd(_0x163bf9, _0x543826) {
				return _0x163bf9 + _0x543826;
			}
		};
		var _0x32bd3a = _0x3994de['words'];
		var _0x2a5053 = _0x542e1d[_0xea12('0x5')](_0x3994de[_0xea12('0x2')], 0x1);
		while (!_0x542e1d['byONr'](_0x542e1d['pLCFG'](_0x32bd3a[_0x542e1d[_0xea12('0x6')](_0x2a5053, 0x2)], _0x542e1d['FRqnC'](0x18, _0x542e1d['DwxPM'](_0x542e1d[_0xea12('0x7')](_0x2a5053, 0x4), 0x8))), 0xff)) {
			_0x2a5053--;
		}
		_0x3994de[_0xea12('0x2')] = _0x542e1d[_0xea12('0x8')](_0x2a5053, 0x1);
	}
};
String[_0xea12('0x9')][_0xea12('0xa')] = function(_0x4ae995) {
	var _0x5ac4ca = {
		'khqHo': function _0x4168d6(_0x311e85, _0x420e7f) {
			return _0x311e85 + _0x420e7f;
		}
	};
	var _0xa42d0b = new RegExp(_0x5ac4ca['khqHo'](_0x4ae995, '$'));
	return _0xa42d0b[_0xea12('0xb')](this);
}
;
var data = _0xea12('0xc');
var keywords = CryptoJS[_0xea12('0xd')][_0xea12('0xe')][_0xea12('0xf')]('6B0600CA9BCE5B24');
var iv = '';
try {
	if (top[_0xea12('0x10')][_0xea12('0x11')][_0xea12('0x12')] != window[_0xea12('0x11')]['href']) {
		top['window'][_0xea12('0x11')]['href'] = window[_0xea12('0x11')][_0xea12('0x12')];
	}
	iv = CryptoJS['enc'][_0xea12('0xe')]['parse']('6B0600CA9BCE5B24');
} catch (_0x3f6f9e) {
	iv = CryptoJS[_0xea12('0xd')][_0xea12('0xe')]['parse'](_0xea12('0x13'));
}
var decrypted = CryptoJS['AES'][_0xea12('0x14')](data, keywords, {
	'iv': iv,
	'padding': CryptoJS[_0xea12('0x0')][_0xea12('0x15')]
});
var secWords = decrypted[_0xea12('0x16')](CryptoJS['enc']['Utf8'])[_0xea12('0x17')](',');
var words = new Array(secWords[_0xea12('0x18')]);
var n = document['createElement'](_0xea12('0x19'));
n['setAttribute'](_0xea12('0x1a'), 'text/css');
n[_0xea12('0x1b')](_0xea12('0x1c'), !![]);
var jsLast = function() {
	var _0x28d7f2 = {
		'NOyra': 'head',
		'fgQCW': 'link',
		'nCjZv': function _0x5de21d(_0x48b6d5, _0x51ba19) {
			return _0x48b6d5 > _0x51ba19;
		}
	};
	var _0x4f2f4a = document[_0xea12('0x1d')](_0x28d7f2[_0xea12('0x1e')])[0x0][_0xea12('0x1d')](_0x28d7f2[_0xea12('0x1f')]);
	if (_0x4f2f4a && _0x28d7f2[_0xea12('0x20')](_0x4f2f4a[_0xea12('0x18')], 0x0)) {
		return _0x4f2f4a[0x0];
	} else {
		return null;
	}
}();
if (jsLast) {
	jsLast[_0xea12('0x21')][_0xea12('0x22')](n, jsLast);
} else {
	document[_0xea12('0x1d')](_0xea12('0x23'))[0x0][_0xea12('0x24')](n);
}
for (var i = 0x0; i < secWords[_0xea12('0x18')]; i++) {
	var _0x5420ee = '3|5|2|4|0|1'[_0xea12('0x17')]('|')
	  , _0x9ff9d9 = 0x0;
	while (!![]) {
		switch (_0x5420ee[_0x9ff9d9++]) {
		case '0':
			_0x423190 = _0x5796d9(_0x423190);
			continue;
		case '1':
			words[i] = String[_0xea12('0x25')](_0x423190);
			continue;
		case '2':
			var _0x5796d9 = function(_0x490c80) {
				var _0x1532b6 = {
					'ifLSL': function _0x256992(_0x118bb, _0x36aa09) {
						return _0x118bb + _0x36aa09;
					}
				};
				return _0x1532b6[_0xea12('0x26')](_0x490c80, 0x3 * +!(typeof document === _0xea12('0x27')));
			};
			continue;
		case '3':
			var _0x423190 = secWords[i];
			continue;
		case '4':
			_0x423190 = _0x3e8e1e(_0x423190);
			continue;
		case '5':
			var _0x3e8e1e = function(_0xd024e1) {
				var _0x3e40d1 = {
					'mPDrG': function _0x411e6f(_0xa8939, _0x278c20) {
						return _0xa8939 % _0x278c20;
					},
					'DWwdv': function _0x1e0293(_0x5b15eb, _0x443876) {
						return _0x5b15eb - _0x443876;
					}
				};
				return _0x3e40d1[_0xea12('0x28')](_0xd024e1, 0x2) ? _0x3e40d1[_0xea12('0x29')](_0xd024e1, 0x2) : _0xd024e1 - 0x4;
			};
			continue;
		}
		break;
	}
}
for (var i = 0x0; i < words[_0xea12('0x18')]; i++) {
	try {
		document[_0xea12('0x2a')][0x0][_0xea12('0x2b')]('.context_kw' + i + _0xea12('0x2c'), 'content:\x20\x22' + words[i] + '\x22');
	} catch (_0x527f83) {
		document['styleSheets'][0x0]['insertRule'](_0xea12('0x2d') + i + _0xea12('0x2e') + words[i] + '\x22}', document[_0xea12('0x2a')][0x0][_0xea12('0x2f')][_0xea12('0x18')]);
	}
}

1.混淆的代码中先定义了一个数组_0xa12e
var _0xea12 = function(_0x56430f, _0x7f6841) {
	_0x56430f = _0x56430f - 0x0;
	var _0x4f7a0f = _0xa12e[_0x56430f];
	return _0x4f7a0f;
};
2.将数组重新排序
(function(_0x4db306, _0x3b5c31) {
	var _0x24d797 = function(_0x1ebd20) {
		while (--_0x1ebd20) {
			_0x4db306['push'](_0x4db306['shift']());
		}
	};
	_0x24d797(++_0x3b5c31);
}(_0xa12e, 0xcc));
3.定义一个函数用于解混淆,可以看到下面混淆js代码中多处调用这个函数,最终返回一个字符串,我们的目的就是将函数调用处替换为字符串
var _0xea12 = function(_0x56430f, _0x7f6841) {
	_0x56430f = _0x56430f - 0x0;
	var _0x4f7a0f = _0xa12e[_0x56430f];
	return _0x4f7a0f;
};
4.python代码解混淆实现如下:
# -*- coding: utf-8 -*-

import re
import execjs

func_js = """
// 直接用重组后的数组替换原来的数组
var _0xa12e = ['pad', 'clamp', 'sigBytes', 'YEawH', 'yUSXm', 'PwMPi', 'pLCFG', 'ErKUI', 'OtZki', 'prototype', 'endWith', 'test', '8RHz0u9wbbrXYJjUcstWoRU1SmEIvQZQJtdHeU9/KpK/nBtFWIzLveG63e81APFLLiBBbevCCbRPdingQfzOAFPNPBw4UJCsqrDmVXFe6+LK2CSp26aUL4S+AgWjtrByjZqnYm9H3XEWW+gLx763OGfifuNUB8AgXB7/pnNTwoLjeKDrLKzomC+pXHMGYgQJegLVezvshTGgyVrDXfw4eGSVDa3c/FpDtban34QpS3I=', 'enc', 'Latin1', 'parse', 'window', 'location', 'href', '146385F634C9CB00', 'decrypt', 'ZeroPadding', 'toString', 'split', 'length', 'style', 'type', 'setAttribute', 'async', 'getElementsByTagName', 'NOyra', 'fgQCW', 'nCjZv', 'parentNode', 'insertBefore', 'head', 'appendChild', 'fromCharCode', 'ifLSL', 'undefined', 'mPDrG', 'DWwdv', 'styleSheets', 'addRule', '::before', '.context_kw', '::before{content: "', 'cssRules']

// 解混淆用到的函数
function _0xea12(_0x56430f, _0x7f6841) {
	_0x56430f = _0x56430f - 0x0;
	var _0x4f7a0f = _0xa12e[_0x56430f];
	return _0x4f7a0f;
};
"""

# 1.编译解混淆函数到node.js环境中
js_func_name = '_0xea12'  # 混淆js中函数定义的名称
ctx = execjs.compile(func_js)

# 2.正则匹配出所有需要替换的函数
with open('混淆.js') as f1:
    js = f1.read()
be_replaced_func_set = set(re.findall(js_func_name + "\([\s\S]+?\)", js))

# 3.循环遍历进行替换
for be_replaced_func in be_replaced_func_set:
    args_tuple = re.findall("\(([\s\S]+?)\)", be_replaced_func)[0]
    args0 = eval(args_tuple.split(',')[0])

    res = ctx.call(js_func_name, args0)
    js = js.replace(be_replaced_func, "'" + res + "'")
    print('{} 替换完成'.format(res))

with open('解混淆后.js', 'w') as f2:
    js = f2.write(js)
6.解混淆后的代码如下
CryptoJS['pad']['ZeroPadding'] = {
	'pad': function(_0x1df06f, _0x314b39) {
		var _0x2f7121 = {
			'YEawH': function _0x304fdc(_0x154e7c, _0x47ce8e) {
				return _0x154e7c - _0x47ce8e;
			},
			'yUSXm': function _0x15667f(_0x2118a7, _0x202af9) {
				return _0x2118a7 % _0x202af9;
			}
		};
		var _0x301b79 = _0x314b39 * 0x4;
		_0x1df06f['clamp']();
		_0x1df06f['sigBytes'] += _0x2f7121['YEawH'](_0x301b79, _0x2f7121['yUSXm'](_0x1df06f['sigBytes'], _0x301b79) || _0x301b79);
	},
	'unpad': function(_0x3994de) {
		var _0x542e1d = {
			'PwMPi': function _0x13be60(_0x37e2b3, _0x34d2aa) {
				return _0x37e2b3 - _0x34d2aa;
			},
			'byONr': function _0x41eeb1(_0x42220d, _0x40e5bd) {
				return _0x42220d & _0x40e5bd;
			},
			'pLCFG': function _0x562ecb(_0x2581d9, _0x590c51) {
				return _0x2581d9 >>> _0x590c51;
			},
			'FRqnC': function _0x582fef(_0x4c5451, _0x219412) {
				return _0x4c5451 - _0x219412;
			},
			'DwxPM': function _0x13a0d9(_0x3ce2bb, _0x236747) {
				return _0x3ce2bb * _0x236747;
			},
			'ErKUI': function _0x31d02b(_0x42d286, _0x4a8edd) {
				return _0x42d286 % _0x4a8edd;
			},
			'OtZki': function _0x4024cd(_0x163bf9, _0x543826) {
				return _0x163bf9 + _0x543826;
			}
		};
		var _0x32bd3a = _0x3994de['words'];
		var _0x2a5053 = _0x542e1d['PwMPi'](_0x3994de['sigBytes'], 0x1);
		while (!_0x542e1d['byONr'](_0x542e1d['pLCFG'](_0x32bd3a[_0x542e1d['pLCFG'](_0x2a5053, 0x2)], _0x542e1d['FRqnC'](0x18, _0x542e1d['DwxPM'](_0x542e1d['ErKUI'](_0x2a5053, 0x4), 0x8))), 0xff)) {
			_0x2a5053--;
		}
		_0x3994de['sigBytes'] = _0x542e1d['OtZki'](_0x2a5053, 0x1);
	}
};
String['prototype']['endWith'] = function(_0x4ae995) {
	var _0x5ac4ca = {
		'khqHo': function _0x4168d6(_0x311e85, _0x420e7f) {
			return _0x311e85 + _0x420e7f;
		}
	};
	var _0xa42d0b = new RegExp(_0x5ac4ca['khqHo'](_0x4ae995, '$'));
	return _0xa42d0b['test'](this);
}
;
var data = '8RHz0u9wbbrXYJjUcstWoRU1SmEIvQZQJtdHeU9/KpK/nBtFWIzLveG63e81APFLLiBBbevCCbRPdingQfzOAFPNPBw4UJCsqrDmVXFe6+LK2CSp26aUL4S+AgWjtrByjZqnYm9H3XEWW+gLx763OGfifuNUB8AgXB7/pnNTwoLjeKDrLKzomC+pXHMGYgQJegLVezvshTGgyVrDXfw4eGSVDa3c/FpDtban34QpS3I=';
var keywords = CryptoJS['enc']['Latin1']['parse']('6B0600CA9BCE5B24');
var iv = '';
try {
	if (top['window']['location']['href'] != window['location']['href']) {
		top['window']['location']['href'] = window['location']['href'];
	}
	iv = CryptoJS['enc']['Latin1']['parse']('6B0600CA9BCE5B24');
} catch (_0x3f6f9e) {
	iv = CryptoJS['enc']['Latin1']['parse']('146385F634C9CB00');
}
var decrypted = CryptoJS['AES']['decrypt'](data, keywords, {
	'iv': iv,
	'padding': CryptoJS['pad']['ZeroPadding']
});
var secWords = decrypted['toString'](CryptoJS['enc']['Utf8'])['split'](',');
var words = new Array(secWords['length']);
var n = document['createElement']('style');
n['setAttribute']('type', 'text/css');
n['setAttribute']('async', !![]);
var jsLast = function() {
	var _0x28d7f2 = {
		'NOyra': 'head',
		'fgQCW': 'link',
		'nCjZv': function _0x5de21d(_0x48b6d5, _0x51ba19) {
			return _0x48b6d5 > _0x51ba19;
		}
	};
	var _0x4f2f4a = document['getElementsByTagName'](_0x28d7f2['NOyra'])[0x0]['getElementsByTagName'](_0x28d7f2['fgQCW']);
	if (_0x4f2f4a && _0x28d7f2['nCjZv'](_0x4f2f4a['length'], 0x0)) {
		return _0x4f2f4a[0x0];
	} else {
		return null;
	}
}();
if (jsLast) {
	jsLast['parentNode']['insertBefore'](n, jsLast);
} else {
	document['getElementsByTagName']('head')[0x0]['appendChild'](n);
}
for (var i = 0x0; i < secWords['length']; i++) {
	var _0x5420ee = '3|5|2|4|0|1'['split']('|')
	  , _0x9ff9d9 = 0x0;
	while (!![]) {
		switch (_0x5420ee[_0x9ff9d9++]) {
		case '0':
			_0x423190 = _0x5796d9(_0x423190);
			continue;
		case '1':
			words[i] = String['fromCharCode'](_0x423190);
			continue;
		case '2':
			var _0x5796d9 = function(_0x490c80) {
				var _0x1532b6 = {
					'ifLSL': function _0x256992(_0x118bb, _0x36aa09) {
						return _0x118bb + _0x36aa09;
					}
				};
				return _0x1532b6['ifLSL'](_0x490c80, 0x3 * +!(typeof document === 'undefined'));
			};
			continue;
		case '3':
			var _0x423190 = secWords[i];
			continue;
		case '4':
			_0x423190 = _0x3e8e1e(_0x423190);
			continue;
		case '5':
			var _0x3e8e1e = function(_0xd024e1) {
				var _0x3e40d1 = {
					'mPDrG': function _0x411e6f(_0xa8939, _0x278c20) {
						return _0xa8939 % _0x278c20;
					},
					'DWwdv': function _0x1e0293(_0x5b15eb, _0x443876) {
						return _0x5b15eb - _0x443876;
					}
				};
				return _0x3e40d1['mPDrG'](_0xd024e1, 0x2) ? _0x3e40d1['DWwdv'](_0xd024e1, 0x2) : _0xd024e1 - 0x4;
			};
			continue;
		}
		break;
	}
}
for (var i = 0x0; i < words['length']; i++) {
	try {
		document['styleSheets'][0x0]['addRule']('.context_kw' + i + '::before', 'content:\x20\x22' + words[i] + '\x22');
	} catch (_0x527f83) {
		document['styleSheets'][0x0]['insertRule']('.context_kw' + i + '::before{content: "' + words[i] + '\x22}', document['styleSheets'][0x0]['cssRules']['length']);
	}
}
解混淆的代码可以用火狐浏览器的美化源代码把0x0这种16进制字符替换。
_0x3e8e1e 形式的变量名是无法还原的,不过经过上面的步骤代码阅读性明显提升
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: JS ob混淆还原工具是一种可以通过对经过混淆的JavaScript代码进行解析和还原的工具。在前端开发中,为了保护代码的安全性和减少代码的可读性,开发者经常会使用混淆工具对代码进行混淆处理,使其变得更加难以理解和阅读。 JS ob混淆还原工具通过逆向工程的方式,分析混淆后的代码的特征和逻辑,将其还原为可读性较高的代码。这种工具通常会借助静态分析、动态执行和模式匹配等技术手段,识别并还原代码中的关键变量和函数,恢复其原有的结构和逻辑。 然而,要完全还原混淆的代码并非易事。混淆工具会对代码进行各种复杂的变形,包括变量重命名、函数内联、控制流混淆等,使得代码的结构和逻辑被混淆起来。因此,即使使用了JS ob混淆还原工具,也无法保证还原的代码百分之百准确和完整。 此外,使用JS ob混淆还原工具需要具备一定的前端开发知识和经验,对JavaScript语法和代码结构有一定的了解。对于复杂的混淆代码,可能需要结合其他辅助工具和技术来辅助还原。 总的来说,JS ob混淆还原工具是一种有助于解析和还原混淆JavaScript代码的工具,但其效果和可靠性受到混淆的复杂程度和工具的能力的限制。在实际使用中,需要综合考虑各种因素,并结合其他技术手段来还原混淆代码。 ### 回答2: JS ob混淆还原工具是用于还原经过混淆处理的JavaScript代码的工具。在开发过程中,为了保护源代码的安全性和保密性,开发者经常会使用混淆工具对JavaScript代码进行混淆处理。 混淆工具会对JavaScript代码进行一系列的转换和修改,使得代码变得难以理解和分析。这些转换包括重命名变量名、函数名和类名,删除空格和注释,提取字符串并进行加密等等。 然而,有时候需要对混淆后的代码进行还原,以方便理解、分析和调试代码。这时候,就需要使用JS ob混淆还原工具。 JS ob混淆还原工具通常可以通过分析混淆后的代码结构和特征,还原出原始的代码结构和变量名。它可以识别和还原经过转换的代码,恢复出可读性较高的代码。 尽管JS ob混淆还原工具可以在一定程度上帮助开发者还原混淆后的代码,但并不能完全还原出原始的代码,尤其是在代码经过复杂混淆处理的情况下。此外,由于混淆工具使用了一些高级技术进行代码转换和加密,还原工具可能存在一定的局限性。 综上所述,JS ob混淆还原工具是一种帮助开发者还原经过混淆处理的JavaScript代码的工具,但需要注意它不能完全还原出原始的代码,并且其还原效果受到混淆处理的复杂程度和技术选用的影响。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值