JavaScript反调试小技巧

1.函数重定义

防止在当前上下文中使用输出语句观察结果。

console.log("Hello World");
var fake = function() {};
window['console']['log'] = fake;
console.log("You can't see me!");
console.log("Normal function");
// 
var original = window['console']['log'];
// 
var fake = function(argument) {
    if (argument === "Ka0labs") {
        original("Spoofed!");
    } else {
        original(argument);
    }
}
window['console']['log'] = fake;
console.log("This is unaltered");
console.log("Ka0labs");
console.log("Bye bye!");

2.使用debugger语句

如果在chrome中打开了开发者模式,通过debugger语句可以阻塞当前执行流程。在很多页面中我们也会看到这种用法。

console.log("See me!");
debugger;
console.log("See me!");

3.利用时间差判断是否处于调试状态

performance对象可以用来进行性能分析。performance.now() 方法返回从页面初始化到调用该方法时的毫秒数。

函数输出的是相对于performance.timing.navigationStart的时间。当在开发者模式(DevTools)下执行时,执行时间会显著增加。因此可以用来判断是否处于开发者模式下。

setInterval(function(){
  var startTime = performance.now(), check, diff;
  for (check = 0; check < 1000; check++){
    console.log(check);
    console.clear();
  }
  diff = performance.now() - startTime;
  if (diff > 200){
    alert("Debugger detected!");
  }
}, 500);

其次结合debugger,来判断两点的时间。

var startTime = performance.now();
debugger;
var stopTime = performance.now();
if ((stopTime - startTime) > 1000) {
    alert("Debugger detected!")
}

4.自定义div的getter方法进行Devtools环境检测

创建一个div,并定义该div id的属性描述对象。当在devtools环境下通过console.log输出div对象时,浏览器会自动尝试获取div的id。那么这时自定义的get方法会被调用。因此检测出devtools环境。

let div = document.createElement('div');
let loop = setInterval(() => {
    console.log(div);
    console.clear();
});

Object.defineProperty(div, "id", {get: () => { 
    clearInterval(loop);
    alert("Dev Tools detected!");
});

5.检测窗口大小变化

如果打开Devtools,window.outerWidth/Height和window.innerWidth/Height
将会变化,因此可以在一个循环中尝试检测。

const widthThreshold = window.outerWidth - window.innerWidth > threshold;
const heightThreshold = window.outerHeight - window.innerHeight > threshold;
const orientation = widthThreshold ? 'vertical' : 'horizontal';

https://github.com/sindresorhus/devtools-detect 项目提供了devtools检测的方法。

6. 函数调用踪迹识别

通过arguments.callee.caller可以获取调用踪迹。并通过获取的踪迹生成一个哈希值,并以该hash值为key对加密的代码揭秘。一个加密的代码有多部分组成,后一部分的加密代码通过前一部分的代码生成的key揭秘得到并执行。如果代码被修改后续揭秘会发生错误。随后我们可以捕获异常,并将执行流程重定向到一个错误的错误的路径上。

function getCallStack() {
    var stack = "#", total = 0, fn = arguments.callee;
    while ( (fn = fn.caller) ) {
        stack = stack + "" +fn.name;
        total++
    }
    return stack
}
function test1() {
    console.log(getCallStack());
}
function test2() {
    test1();
}
function test3() {
    test2();
}
function test4() {
    test3();
}
test4();

7.计算函数哈希值

通过函数的toString获取函数代码字符串。接着计算该字符串的hash值,从而来判断代码是否被重定义。对这个功能可以用来检查函数是否被重定义。

function a() {
    console.log("a");
}

a.toString();

8.代理对象

我们可以通过toString length属性检测代理对象的使用。

chrome下document.createElement.toString().length 
结果为 42

当我们创建一个代理时,这个值会发生变化。

const handler = {
    apply: function(target, thisArg, args) {
        console.log("Intercepted call");
        return target.apply(thisArg, args);
    }
}

document.createElement = new Proxy(document.createElement, handler);
document.createElement.toString().length
返回结果为29

因此可以进行检测。

if (document.createElement.toString().length < 30) {
    console.log("I saw your proxy");
}
else {
    console.log("Not a proxy");
}

该方法不能用于window对象,但在思路上有一定启发作用。即创建一个代理对象后某些函数结果或属性会发生变化,利用这些差异去进行检测。

9.环境检测

这类检查思路就是利用不同环境里的差异进行检测。

例如检测hostname


if (location.hostname === "localhost" || location.hostname === "127.0.0.1" || location.hostname === "") {
    console.log("Don't run me here!")
}


 
NodeJS detected!!!!

window对象检测


   try { 
..   console.log(window); 
   } catch(e){ 
..      console.log("NodeJS detected!!!!"); 
   }

nodejs 环境检测


//Under the browser
console.log(global)
VM104:1 Uncaught ReferenceError: global is not defined
    at <anonymous>:1:13

//Under NodeJS
  console.log(global)
{ console: 
   Console {
     log: [Function: bound log],...
     ...

你可能感兴趣的:(爬虫与反爬虫,js相关)