Skip to content

无限debugger

更新: 2025/2/24 字数: 0 字 时长: 0 分钟

在前面一节的实战当中,有一道题目,打开开发者工具就自动进入了 debugger 状态,当我们点击继续运行后,它永远的跳转到下一个 debugger 那去,其原因是网站在网站代码中添加 debugger 调试代码,当进入网站打开开发者工具后就会频繁的去执行 debugger 逻辑,目的就是为了阻断爬虫工程师的调试,这样的反爬方式就称之为“无限debugger”。

20220313033406

实现原理

**虽然“无限debugger”名字中带有“无限”两个字,但是无限 debugger 不可能无限,否则浏览器会卡死。简单说,就是很频繁的去执行 debugger 逻辑,而不是真正的死循环。**实现 debugger 的方法有很多,例如关键字、eval 制作虚拟机、Function 函数等:

javascript
// 不可混淆
debugger;

// 可混淆
eval("debugger;")

// 可重度混淆
Function("debugger").call()/apply()或赋值bind()
XXX.constructor("debugger").call("action")
Function.constructor("debugger").call("action")
(function() {return !![];}["constructor"]("debugger")["call"]("action"))

任何可以循环的代码都可以实现无限 debugger,例如使用 setInterval 定时器来实现一个每 0.5 秒触发的无限 debugger:

html
<!-- 每0.5秒触发的无限debugger -->
<script>
    function a(){
        debugger;
    }
    setInterval(a, 500);
</script>

绕过方案

无限 debugger 一般出现在加密逻辑之前,因此想要通过调试找到函数入口,必须绕过无限 debugger。

覆盖替换

覆盖替换,用 Chrome 的 overrides 替换源 JS 文件,修改 debugger 关键字,或者用 Fiddler 等工具替换 Autoresponse 中 debugger 关键字。

无视跳过

无视跳过,遇到 debugger,可以在对应行的左侧右键点击选择 Nerver pause here 永远不停留这里来过掉,不过这样的处理方式方式只能处理小部分“无限 debugger”。

20220128024537

条件断点

条件断点,在 debugger 所在行设置断点,点击鼠标右键蓝色断点位置,选择 Edit breakpoint 选项编辑断点:

20210926175109

输入条件为 false 属性:

20210926175250

保存后断点变黄:

20210926175305

代码注入

代码注入,针对真动态文件或 Autoresponse 失效或删掉 debugger 逻辑很繁琐的情况下。

  1. 通过 Function 关键字启动的 debugger,可以注入以下代码重写函数构造器:

    javascript
    (()=>{
    Function.prototype.__constructor = Function;
    Function = function (){
    if (arguments && typeof arguments[0] === 'string'){
        if ("debugger" === arguments[0]){
      	  return
        }
      	  return Function.apply(this, arguments);
        }
        }
    })()
  2. 通过 constructor 关键字启动的 debugger,可以注入代码进行绕过:

    javascript
    (()=>{
    Function.prototype.__constructor = Function.prototype.constructor;
    Function.prototype.constructor = function (){
    if (arguments && typeof arguments[0] === 'string'){
      	  if ("debugger" === arguments[0]){
      	  return
      	  }
      	  return Function.prototype.constructor.apply(this, arguments);
      	  }
        }
    })()
  3. 通过 eval 函数启动的 debugger,可以注入以下代码重构 eval 函数:

    javascript
    eval_bc = eval
    eval = function(a) {
    if (a === '(function() {var a = new Date(); debugger; return new Date() - a > 100;}())') {}
    else {
        return eval_bc(a)
    }
    }
  4. 通过 setInterval 定时器启动的 debugger,可以替换 setInterval 或者清除定时器,在该函数被调用前重写该函数并生效:

    javascript
    setInterval_back = setInterval
    // 只要定时器里面的参数不包含了'debugger'就执行
    setInterval = function(a, b){
        if(a.toString().indexOf('debugger') == -1){
            return setInterval_back(a, b)
        }
    }
    
    // 如果业务代码里面是不重要的代码,我们也可以直接置空它
    setInterval = function(){}