防止在当前上下文中使用输出语句观察结果。
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!");
如果在chrome中打开了开发者模式,通过debugger语句可以阻塞当前执行流程。在很多页面中我们也会看到这种用法。
console.log("See me!");
debugger;
console.log("See me!");
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!")
}
创建一个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!");
});
如果打开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检测的方法。
通过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();
通过函数的toString获取函数代码字符串。接着计算该字符串的hash值,从而来判断代码是否被重定义。对这个功能可以用来检查函数是否被重定义。
function a() {
console.log("a");
}
a.toString();
我们可以通过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对象,但在思路上有一定启发作用。即创建一个代理对象后某些函数结果或属性会发生变化,利用这些差异去进行检测。
这类检查思路就是利用不同环境里的差异进行检测。
例如检测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],...
...