由于工作需要,临时客串了半个前端人员(鄙人才疏学浅),协助处理一下前端混淆JS,抓取某站数据 (哈哈~~邪恶的笑声)。
JS常见反调试手段:压缩JS文件、源码中添加debugger、加密请求参数。
压缩JS文件就不说了,这个严格来说不算(之前遇到过使用16进制重命名变量的)。
JS防止调试
这里说一下防止 debug,常见手段是随机在脚本处插入 debugger
代码,防止前端人员调试,或者插入一段定时代码,代码就不停执行 debugger
,下面是一段伪代码:
setInterval(function () {
debugger;
}, 50);
更高级的写法:
(function() {}['constructor']('debugger')())
对于JS,有时候一些代码看起来是如此的另类,通过字符串,就能调用成员,后缀加 ()
就是调用方法了,例如:
var w = window;
var cmdArr = ['console', 'log'];
w[cmdArr[0]][cmdArr[1]]('hello, world!');
// output: hello, world!
说完了防止 debug 和JS一些高级写法后,接下来说一下破解手段:
关于 Fiddler JS拦截,请查看这篇文章:Fiddler - 超好用的http抓包工具使用介绍。
另外 JS 防止调试,还有一种变态的做法,就是 消耗PC资源,通过不停的调用 console.log
和 console.clear
来疯狂出信息,然后清空,过一小会儿,你就会发现你的PC资源过高(当然你的 PC 强到离谱,当我没说)。
加密请求参数
经过上面的步骤后,我们基本可以正常调试 JS 了。在这先说一下,如何高效的利用 Chrome Dev Tools:
- 通常我们抓取数据都是通过查看 Network 面板中的请求数据,通过点击 Initiator 项(在标题栏),就可以直接定位到请求代码了。
- 通过 Sources 面板,右侧的调试工具,如 XHR/fetch Breakpoints 监视 XHR 请求、通过 Event Listener Breakpoints 监听事件,可以监听如 Mouse(鼠标相关操作,如点击), Timer (监听定时器,如setTimeout 代码段)。
这里就罗列两种,后续如果发现最新好玩,还会继续补上
一般情况下,都是采用 匿名自执行函数 写法,例如:
(function (msg) {
console.log(msg);
})('hello');
通过事先加密一段字符串(字符串通过加入特殊符号,如 ASCII 不可见码),通过上面的形式,传入到函数内,在函数内解密字符串,并解析出请求地址(有时候还会在里面加入 debugger 防调试代码)。一般采用的都是 XOR加密。
先上一段有意思的代码:
(function (c2) {
var E2 = 2;
while (E2 !== 14) {
switch (E2) {
case 1:
var N2 = 0, P2 = 0;
E2 = 5;
break;
case 9:
a2 += String.fromCharCode(e2.charCodeAt(N2) ^ c2.charCodeAt(P2));
E2 = 8;
break;
case 2:
var a2 = '', e2 = decodeURI("1'-$&zf%7B%7F(%20(c+:");
E2 = 1;
break;
case 5:
E2 = N2 < e2.length ? 4 : 7;
break;
case 4:
E2 = P2 === c2.length ? 3 : 9;
break;
case 3:
P2 = 0;
E2 = 9;
break;
case 7:
a2 = a2.split('(');
console.log(a2);
return a2;
break;
case 8:
N2++, P2++;
E2 = 5;
break;
}
}
})('POILBI');
上面代码中,其中还有一部分可以继续加工,如:String.fromCharCode(), decodeURI() 方法。代码中 POILBI
为加密KEY,1'-$&zf%7B%7F(%20(c+: 为通过 XOR加密 加密后的数据,说完这两点想必你已经知道这段代码是做什么的了,其实这就是一段经过混淆后的加 XOR加密 代码,代码使用了 switch 的语法来改写 while 循环,解密后的代码如下:
function encrypt(src, key) {
var res = ''; // a2
var srcIndex = 0; // N2
var keyIndex = 0; // P2
while (srcIndex < src.length) {
if (keyIndex == key.length) {
keyIndex = 0;
res += String.fromCharCode(src.charCodeAt(srcIndex) ^ key.charCodeAt(keyIndex));
} else {
res += String.fromCharCode(src.charCodeAt(srcIndex) ^ key.charCodeAt(keyIndex));
}
keyIndex++;
srcIndex++;
}
return res;
}
var src = decodeURI("1'-$&zf%7B%7F(%20(c+:"); // e2
var key = 'POILBI';
console.log(encrypt(src, key));
// output: ahdhd3646dba3ds
最后
好了,关于 JS 反调试的学习,就先告一段落,以后有新东西,将会继续写。JS 反调试是一件很枯燥耗时的事情,需要你整个人投入进去,并调整好心态。
本文由 waynelone 创作,采用 知识共享署名4.0 国际许可协议进行许可。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。