JS 反调试的学习

in Code with 0 comment

由于工作需要,临时客串了半个前端人员(鄙人才疏学浅),协助处理一下前端混淆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一些高级写法后,接下来说一下破解手段:

  1. 使用 Fiddler 做JS拦截(俗话说的好,Fiddler 学的好的,都已经进监狱了)。
  2. 使用 ReRes 将JS替换为本地路径。

关于 Fiddler JS拦截,请查看这篇文章:Fiddler - 超好用的http抓包工具使用介绍

ReRes 的使用,请点击名称进入 Github 页面。

另外 JS 防止调试,还有一种变态的做法,就是 消耗PC资源,通过不停的调用 console.logconsole.clear 来疯狂出信息,然后清空,过一小会儿,你就会发现你的PC资源过高(当然你的 PC 强到离谱,当我没说)。

加密请求参数

经过上面的步骤后,我们基本可以正常调试 JS 了。在这先说一下,如何高效的利用 Chrome Dev Tools

  1. 通常我们抓取数据都是通过查看 Network 面板中的请求数据,通过点击 Initiator 项(在标题栏),就可以直接定位到请求代码了。
  2. 通过 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 反调试是一件很枯燥耗时的事情,需要你整个人投入进去,并调整好心态。

Comments are closed.