常见反调试
常见反调试
1. 开发者工具反调试
1.1 阻止打开开发者工具
打开开发者工具一般是通过快捷键或鼠标右键打开,所以这里禁用调试就会从这两个地方下手:
1)禁用鼠标右键
-
效果
点击鼠标右键就出现提示,并且无法显示右键内容:

-
代码实现
// 监听鼠标右键事件,防止调试工具被使用 document.oncontextmenu = () => { alert('检测到非法调试,右键被管理员禁用'); return false; }document.oncontextmenu表示监听鼠标右键;return false表示禁止后续事件操作。
2)禁用 F12
-
效果
点击 F12 不出控制台,出提示:

-
代码实现
// 监听键盘按键事件,防止调试工具被使用 document.onkeydown = () => { // 键盘监听事件对象 var e = window.event || arguments[0]; // 检测按键是否是 F12 if (e.keyCode == 123) { alert("检测到非法调试,F12被管理员禁用"); // 阻止事件继续执行 return false; } }123在按键中表示F12。
解决方案
控制台打开的几种方式:
-
F12
-
ctrl+shif+i
-
鼠标右键 -》检查
-
“三点” -》更多工具 -》开发者工具

多了解几种打开的方式,这种不能用就换另一种。
注意:
并不是所有的检测到后都给提示,有的会直接跳转到其他地方,或者做其他操作。例如:
document.onkeydown = () => {
var e = window.event || arguments[0];
if (e.keyCode == 123) {
// alert("检测到非法调试,F12被管理员禁用");
// 跳转到百度
window.location.href = "https://www.baidu.com";
return false;
}
}
当按下 F12 的时候,就会跳转到百度首页。
1.2 窗口检测
窗口检测一般检测的是内外窗口的尺寸,这个时候一般是在控制台打开之后的。检测后的常见操作:
- 清空控制台
- 跳转页面
- 假数据替换
不论是那种,都是检测到后执行,后面的检测基本也是做这些操作。
-
效果
控制台清空,每秒钟控制台都会强制清空,如果要在控制台调试,前面的值都会看不到。

-
实现代码
// 设置定时器 setInterval( // 定时器执行的操作 function () { // 检测浏览器外窗口尺寸和内窗口尺寸的差值 单位 像素 if (window.outerWidth - window.innerWidth > 300 || window.outerHeight - window.innerHeight > 300) { // 清除控制台 console.clear() } }, // 定时执行的时间,每多久执行一次 ms 500 );这里主要用到了:
-
定时器:setInterval(定时任务函数,定时时间)
-
内外窗口尺寸检测
如果想实现其他效果,可以自己替换清空控制台那里的代码。
-
-
解决方案
控制台悬浮出来:点击控制台右侧三点,
停靠测部分选择第一个
控制台悬浮出来后,是不会占据浏览器窗口位置的,就不会被检测出异常差异。
1.3 格式化检测
格式化检测主要检测函数的压缩格式和格式化的格式:
-
格式化函数
var test = function () { return '666'; } -
压缩格式函数
var test = function (){return '666';}实现代码:
// 格式化检测 var test = function (){return '666';} // 设置定时器每秒检测一次函数是否被格式化 setInterval(function () { // 定义正则表达式来匹配格式化后的函数 var reg = new RegExp("\\w+ \\(\\){\\w+ ['|\"].+['|\"];}"); // 匹配到了,结果返回 true var isFormatted = reg.test(test.toString()); if (!isFormatted) { console.log("函数被格式化"); } }, 1000);实现格式化检测,主要依赖于两个:
正则表达式:匹配符合条件的格式,reg.test 表示检测是否有符合条件的字符串,有则返回 truetoString() 方法:打印函数的格式
一般格式化检测会和内存爆破结合一起使用。
内存爆破
内存爆破在调试的时候有一个明显的状态,即浏览器所消耗的内存不正常的增加,浏览器会卡死。
实现内存爆破的方式也挺简单,即无限循环的做某件事情。
例如:
// 内存爆破
var test = function () {
return '666';
}
function dbf() {
let memoryLeak = [];
// 每隔10毫秒就向数组中添加一个大的对象
setInterval(() => {
let obj = {};
// 给对象添加大量属性,以增加其占用的内存
for (let i = 0; i < 500000; i++) {
obj['key' + i] = Math.random();
}
memoryLeak.push(obj);
// 可选:输出当前数组长度,以监控内存泄漏
console.log(memoryLeak.length);
}, 1);
}
2. 无限debugger
2.1 构建 debugger 的方式
-
debugger 关键字
debugger;debugger 是 js 的关键字,写在哪就可以在哪设置断点。
-
eval
eval("debugger");eval函数可以将字符串当做代码执行,也就是说你在字符串中写运算,最后得到的也是运算后的值,而不是加法运算的字符串。 -
- Function
Function("debugger")();Function是 js 中的一个内置对象,可以用来创建函数。比如:var myFunction = new Function('a', 'b', 'return a + b;');这个函数名称是
myFunction,参数是a、b,函数体是return a + b;。而上面构建 debugger,则是创建了一个匿名函数,并且调用了。
上面构建 debugger 代码类似的还有:
(function () {}["constructor"]("debugger")());
-
function () {}是一个匿名函数 -
["constructor"]调用函数的构造函数,这里指向的就是 Function 了所以上面代码等价
Function("debugger")();
知道怎么构建 debugger 了,加上个无限就简单了。一般无限不是循环就是定时器,根据情况处理。
2.2 如何过 debugger
-
右键点击 debugger 处,点击永不在此处暂停

-
hook
hook 就是所谓的钩子函数,你们怎么理解的就怎么表达吧!
以定时器实现的无限 debugger 为例:
// 定时器实现无限 debugger setInterval(function () { debugger; }, 500);这种会在每 0.5S 就进入 debugger,根本无法正常调试。使用第一种方式可以过,但是如果类似的 debugger 比较多,就需要处理定时器而不是 debugger 了。
处理方式 - 在进入断点之前,修改掉原来的定时器方法,让它失去定时器的功能:
-
效果

-
实现代码
var _setInterval = setInterval; setInterval = function () { console.log("修改定时器"); return function(){}; }
-

浙公网安备 33010602011771号