JS解混淆
JS解混淆最近在整理之前和一些同伴的分享资料,发现时间已经过了好久,特此整理一些有价值的分享记录。
JS混淆
学习js混淆可以逆向分析混淆和加密过程,实战可用于爬虫和渗透信息获取
本文档用于初步介绍js混淆的基础概念以及如何解混淆、调试,便于干掉反爬虫和渗透信息收集思路拓展
概念解释
混淆/加密
降低代码可读性加强安全性,防止被人任意查看,在一定程度保护资源
理想的混淆或加密应该具备如下特点
1、没有确定的破解模式;
2、很难编制自动破解程序(只能手工破解);
3、破解过程繁琐、耗时;
4、“混淆|加密”后的代码,比原始代码长度增加少;
代码里诸如此类就是经过了混淆的结果,可以通过console+断点打出来看看值
js混淆和eval加密
前端虽然开源, 但是由于前端代码量很多,也有一些特殊的保护代码的方法
其中Eval、js混淆是常用的方式,但是在大的互联网产品上用得很少,因为前端加密(RSA、AES、MD5等)是为了保证数据传输中的安全性,而非要让人难以模仿数据传输请求
而前端中的js混淆、eval对于专业的人来说形同虚设,所以也没必要做混淆和eval,并且对于代码维护是及其不利的
eval加密
js中的eval()方法就是一个js语言的执行器
它能把其中的参数按照JavaScript语法进行解析并执行
简单来说就是把原本的js代码变成了eval的参数,变成参数后代码就成了字符串,其中的一些字符就会被按照特定格式“编码”
是最早JS出现的混淆加密,据说第一天就被破解,修改一下代码,alert一下就可以破解了
#eval加密
源代码:
var showmsg="粘贴要加密/解密的javascript代码到这里";
if(1==1){
alert(showmsg);
}
加密后的样子:
eval(function(p,a,c,k,e,d){e=function(c)
{return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?
String.fromCharCode(c+29):c.toString(36))};
if(!''.replace(/^/,String)){while(c--)d=k||e(c);k=[function(e){return
d}];e=function(){return'\\w+'};c=1};while(c--)if(k)p=p.replace(new
RegExp('\\b'+e(c)+'\\b','g'),k);return p}('5 4="粘贴要加密/解密的3代码到这里";2(0==0){
1(4);}',62,6,'1|alert|if|javascript|showmsg|var'.split('|'),0,{}))eval()语句还有一个重要用途:在反调试中可以使用该语句来进行一些函数值赋空从而跳出debugger的函数
JS混淆
把其中的变量、方法位置顺序打乱,但是又用一些无关的变量或者方法来保证执行顺序
常见手段
1、去除缩进、空行、换行、注释
2、变量名替换(缩短/改乱)
3、通过自定义变量名引用JS关键字
4、添加大段空白,增加代码前后间隔,干扰阅读
5、混眼法(通过利用[]和["、']及变量定义语句来添加与代码功能无关的字符/增添与代码功能无关的运算语句)
6、对源代码进行加密,同时附上解密的代码(运行时先解密,然后通过document.write()或eval()或innerHTML把代码释放出来执行)
其他混淆类型
hash类型
压缩类型
常用工具
混淆
这里是从使用工具加密信息方出发,具体工具的使用可以自行学习。
[*]webassembly
[*]esprima
针对JavaScript
[*]JavaScript Obfuscator
具体使用参考:7.8k Star!一个强大的 JS 代码混淆工具 - 掘金 (juejin.cn)
[*]terser
[*]uglify-js
[*]uglify-es
[*]Google Closure Compiler
[*]YUI Compressor
针对CSS
[*]PostCSS
[*]clean-css
[*]CSSO
[*]YUI Compressor
针对HTML
[*]html-minifier
混淆示例
此处使用JavaScript Obfuscator Tool,由JavaScript Obfuscator作者搭建的一个在线混淆网站,直接输入需要混淆的代码输出混淆结果即可
以下面的一个简单hello world为例
##源代码
function hi() {
console.log("Hello World!");
}
hi();经过混淆之后
##混淆后的代码
(function(_0x1522cf,_0x263348){var _0x2bf84c=_0x42bb,_0x47bae4=_0x1522cf();while(!![]){try{var _0x301f10=parseInt(_0x2bf84c(0x11b))/0x1*(-parseInt(_0x2bf84c(0x10f))/0x2)+-parseInt(_0x2bf84c(0x114))/0x3+parseInt(_0x2bf84c(0x112))/0x4*(-parseInt(_0x2bf84c(0x117))/0x5)+-parseInt(_0x2bf84c(0x110))/0x6+parseInt(_0x2bf84c(0x115))/0x7*(parseInt(_0x2bf84c(0x118))/0x8)+parseInt(_0x2bf84c(0x119))/0x9*(parseInt(_0x2bf84c(0x116))/0xa)+parseInt(_0x2bf84c(0x11a))/0xb*(parseInt(_0x2bf84c(0x113))/0xc);if(_0x301f10===_0x263348)break;else _0x47bae4['push'](_0x47bae4['shift']());}catch(_0x2af3c3){_0x47bae4['push'](_0x47bae4['shift']());}}}(_0x22dc,0x1e93e));function hi(){var _0xfdbe99=_0x42bb;console('Hello\x20World!');}hi();function _0x42bb(_0x4a56bb,_0x17e1ee){var _0x22dca2=_0x22dc();return _0x42bb=function(_0x42bb1c,_0x597cba){_0x42bb1c=_0x42bb1c-0x10f;var _0x2ad529=_0x22dca2;return _0x2ad529;},_0x42bb(_0x4a56bb,_0x17e1ee);}function _0x22dc(){var _0x1ca681=['937926xGdCzf','log','344SUuAGG','1124988WMYeGw','111081MLZhWo','35SqOFWp','670aFpiLz','12820fkuEha','108152xzQqbd','15975Prsnjz','44YZHRMa','1oaFebR','44836HvkwgV'];_0x22dc=function(){return _0x1ca681;};return _0x22dc();}
##为了展示直观,经过代码美化处理结果如下
(function(_0x1522cf, _0x263348) {
var _0x2bf84c = _0x42bb,
_0x47bae4 = _0x1522cf();
while (!![]) {
try {
var _0x301f10 = parseInt(_0x2bf84c(0x11b)) / 0x1 * (-parseInt(_0x2bf84c(0x10f)) / 0x2) + -parseInt(_0x2bf84c(0x114)) / 0x3 + parseInt(_0x2bf84c(0x112)) / 0x4 * (-parseInt(_0x2bf84c(0x117)) / 0x5) + -parseInt(_0x2bf84c(0x110)) / 0x6 + parseInt(_0x2bf84c(0x115)) / 0x7 * (parseInt(_0x2bf84c(0x118)) / 0x8) + parseInt(_0x2bf84c(0x119)) / 0x9 * (parseInt(_0x2bf84c(0x116)) / 0xa) + parseInt(_0x2bf84c(0x11a)) / 0xb * (parseInt(_0x2bf84c(0x113)) / 0xc);
if (_0x301f10 === _0x263348) break;
else _0x47bae4['push'](_0x47bae4['shift']());
} catch (_0x2af3c3) {
_0x47bae4['push'](_0x47bae4['shift']());
}
}
}(_0x22dc, 0x1e93e));
function hi() {
var _0xfdbe99 = _0x42bb;
console('Hello\x20World!');
}
hi();
function _0x42bb(_0x4a56bb, _0x17e1ee) {
var _0x22dca2 = _0x22dc();
return _0x42bb = function(_0x42bb1c, _0x597cba) {
_0x42bb1c = _0x42bb1c - 0x10f;
var _0x2ad529 = _0x22dca2;
return _0x2ad529;
}, _0x42bb(_0x4a56bb, _0x17e1ee);
}
function _0x22dc() {
var _0x1ca681 = ['937926xGdCzf', 'log', '344SUuAGG', '1124988WMYeGw', '111081MLZhWo', '35SqOFWp', '670aFpiLz', '12820fkuEha', '108152xzQqbd', '15975Prsnjz', '44YZHRMa', '1oaFebR', '44836HvkwgV'];
_0x22dc = function() {
return _0x1ca681;
};
return _0x22dc();
}可以发现代码混淆有几个比较固定的特征,一些变量的命名会赋随机值,而后通过一个数组去进行存储。同时使用一个while-try-catch的结构。
再看一下实际环境中经过混淆的代码
// 此处也是经过格式美化,源代码只有一行eval(function(p, a, c, k, e, d) { e = function(c) { return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) }; if (!''.replace(/^/, String)) { while (c--) d = k || e(c); k = }]; e = function() { return '\\w+' }; c = 1; }; while (c--) if (k) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k); return p;}('4 3(1){2 0=5 8();7 0.6(1)}', 9, 9, 'b|tksl|var|dswejwehxt|function|new|decode|return|Base64'.split('|'), 0, {}));// respondeval(function(p, a, c, k, e, d) { e = function(c) { return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) }; if (!''.replace(/^/, String)) { while (c--) d = k || e(c); k = }]; e = function() { return '\\w+' }; c = 1; }; while (c--) if (k) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k); return p;}('(c(w){"2O 2E";8 7={};w.7=7;7.21=c(){};8 V=[],1T=(c(){8 16=1E;2t{16=1l w.2s()}2u(e){16=1l w.2w("2v.2o")}l c(){l 16}})(),14=c(1t,22){8 p=1T();5(!p){l}p.2n("2p",1t,1f);p.2r=c(){5(p.1Q!==4||p.2a!==2q&&p.2a!==2D){l}22(p.2C)};5(p.1Q===4){l}p.2G(1b)},1J=c(25){l 25.U(7.f.2g,\'\').I(7.f.1R)};7.14=14;7.2F=V;7.2y=1J;7.f={b:/@b[^\\{]+\\{([^\\{\\}]*\\{[^\\}\\{]*\\})+/17,1j:/@(?:\\-(?:o|2x|2z)\\-)?1j[^\\{]+\\{(?:[^\\{\\}]*\\{[^\\}\\{]*\\})+[^\\}]*\\}/17,2f:/\\/\\*[^*]*\\*+([^/][^*]*\\*+)*\\//17,20:/(1t\\()[\'"]?([^\\/\\)\'"][^:\\)\'"]+)[\'"]?(\\))/g,1U:/@b *([^\\{]+)\\{([\\S\\s]+?)$/,Y:/(Y\\s+)?(+)\\s?/,12:/\\(\\s*v\\-19\\s*:\\s*(\\s*+)(1o|E)\\s*\\)/,15:/\\(\\s*u\\-19\\s*:\\s*(\\s*+)(1o|E)\\s*\\)/,2g:/\\(\\s*m(1h|2B)\\-(2A|19)\\s*:\\s*(\\s*+)(1o|E)\\s*\\)/17,1R:/\\([^\\)]*\\)/g};7.2b=w.1s&&w.1s("Y 1M")!==1b&&w.1s("Y 1M").2k;5(7.2b){l}8 h=w.2j,t=h.2m,X=[],F=[],B=[],1i={},1w=30,G=h.1H("G")||t,1z=h.1H("1z"),W=G.1H("2l"),1a,1p,1c,T=c(){8 Q,H=h.1k(\'H\'),d=h.d,29=t.q.J,1n=d&&d.q.J,1d=1E;H.q.26="2i:2H;34-33:1Z;19:1Z";5(!d){d=1d=h.1k("d");d.q.36="35"}t.q.J="1S%";d.q.J="1S%";d.27(H);5(1d){t.23(d,t.2Z)}Q=H.2Y;5(1d){t.1r(d)}K{d.1r(H)}t.q.J=29;5(1n){d.q.J=1n}Q=1c=10(Q);l Q},18=c(1X){8 1C="32",1m=t,1u=h.31==="3c"&&1m||h.d||1m,C={},28=W,1v=(1l 3a()).37();5(1X&&1a&&1v-1a-1?(1c||T()):1)}5(!!u){u=10(u)*(u.1D(E)>-1?(1c||T()):1)}5(!z.1Y||(!1y||!1x)&&(1y||1u>=v)&&(1x||1u
页:
[1]