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],...
     ...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章