chrome远程调试协议配置的分析
字数 947 2025-08-05 08:20:05

Chrome远程调试协议配置与分析教程

1. 概述

本教程详细讲解如何通过Chrome远程调试协议实现JavaScript的自动调试分析,特别是如何获取调用栈内的变量信息。教程基于对DevTools通信流量的抓包分析,提供了完整的Python实现代码。

2. 准备工作

2.1 启动Chrome远程调试

chrome.exe --remote-debugging-port=9222

2.2 安装必要Python库

pip install pychrome

3. 基础调试配置

3.1 基本连接与初始化

import pychrome

# 连接远程调试
remote_chrome = "http://127.0.0.1:9222"
browser = pychrome.Browser(url=remote_chrome)

# 新建标签页
tab = browser.new_tab()
tab.start()

# 启用必要模块
tab.Page.enable()
tab.Debugger.enable()
tab.Runtime.enable()

3.2 高级调试配置

# 增加脚本缓存大小
tab.Debugger.enable(maxScriptsCacheSize=10000000)

# 设置异步调用栈深度
tab.Debugger.setAsyncCallStackDepth(maxDepth=50)

4. 调试事件处理

4.1 暂停事件处理函数

def GetObject(objectId):
    result = tab.Runtime.getProperties(
        objectId=objectId,
        ownProperties=False,
        accessorPropertiesOnly=False,
        generatePreview=True,
        nonIndexedPropertiesOnly=False,
    )
    return result["result"]

def DebugPaused(**kw):
    callFrames = kw.get("callFrames")
    result = dict()
    
    for callFrame in callFrames:
        result[callFrame["callFrameId"]] = dict()
        
        # 遍历每一个调用栈
        # 先获得范围内的变量集合
        scopeChain = callFrame["scopeChain"]
        
        for _vars in scopeChain:
            # 这里只获取局部变量
            if _vars["type"] == "local":
                _objectId = _vars["object"]["objectId"]
                _object = GetObject(_objectId)
                result[callFrame["callFrameId"]][_objectId] = _object
    
    # 保存调试信息
    with open("result.json", "w", encoding="utf-8") as f:
        import json
        f.write(json.dumps(kw, indent=4))
    
    with open("stack.json", "w", encoding="utf-8") as f:
        import json
        f.write(json.dumps(kw, indent=4))
    
    # 恢复执行
    tab.Debugger.resume()

# 绑定调试函数
tab.Debugger.paused = DebugPaused

5. 设置断点

5.1 设置XHR/Fetch断点

# 设置XHR断点
tab.DOMDebugger.setXHRBreakpoint(url="")

5.2 导航到目标页面

# 打开网页
tab.Page.navigate(url="https://www.baidu.com/")

# 保持程序运行
while True:
    input()

6. 关键数据结构解析

6.1 Debugger.paused返回结构

  • callFrames: 调用栈帧数组,按从栈顶到栈底顺序排列
  • asyncStackTrace: 异步调用栈信息(需要额外配置)

6.2 callFrame结构

{
    "callFrameId": "唯一标识符",
    "functionName": "函数名",
    "location": {
        "scriptId": "脚本ID",
        "lineNumber": 行号,
        "columnNumber": 列号
    },
    "scopeChain": [
        {
            "type": "作用域类型",
            "object": {
                "type": "object",
                "objectId": "对象ID"
            }
        }
    ],
    "this": {
        "type": "对象类型",
        "objectId": "对象ID"
    }
}

6.3 scopeChain类型

  • local: 局部作用域
  • closure: 闭包作用域
  • catch: catch块作用域
  • block: 块级作用域
  • script: 脚本作用域
  • with: with语句作用域
  • global: 全局作用域

7. 获取变量信息的方法

通过Runtime.getProperties方法获取变量信息:

result = tab.Runtime.getProperties(
    objectId=objectId,
    ownProperties=False,
    accessorPropertiesOnly=False,
    generatePreview=True,
    nonIndexedPropertiesOnly=False,
)

8. 完整代码示例

import pychrome

# 连接远程调试
remote_chrome = "http://127.0.0.1:9222"
browser = pychrome.Browser(url=remote_chrome)

# 新建标签页
tab = browser.new_tab()
tab.start()

# 启用必要模块
tab.Page.enable()
tab.Debugger.enable()
tab.Runtime.enable()

# 高级调试配置
tab.Debugger.enable(maxScriptsCacheSize=10000000)
tab.Debugger.setAsyncCallStackDepth(maxDepth=50)

def GetObject(objectId):
    result = tab.Runtime.getProperties(
        objectId=objectId,
        ownProperties=False,
        accessorPropertiesOnly=False,
        generatePreview=True,
        nonIndexedPropertiesOnly=False,
    )
    return result["result"]

def DebugPaused(**kw):
    callFrames = kw.get("callFrames")
    result = dict()
    
    for callFrame in callFrames:
        result[callFrame["callFrameId"]] = dict()
        
        # 遍历每一个调用栈
        # 先获得范围内的变量集合
        scopeChain = callFrame["scopeChain"]
        
        for _vars in scopeChain:
            # 这里只获取局部变量
            if _vars["type"] == "local":
                _objectId = _vars["object"]["objectId"]
                _object = GetObject(_objectId)
                result[callFrame["callFrameId"]][_objectId] = _object
    
    # 保存调试信息
    with open("result.json", "w", encoding="utf-8") as f:
        import json
        f.write(json.dumps(kw, indent=4))
    
    with open("stack.json", "w", encoding="utf-8") as f:
        import json
        f.write(json.dumps(kw, indent=4))
    
    # 恢复执行
    tab.Debugger.resume()

# 绑定调试函数
tab.Debugger.paused = DebugPaused

# 设置XHR断点
tab.DOMDebugger.setXHRBreakpoint(url="")

# 打开网页
tab.Page.navigate(url="https://www.baidu.com/")

# 保持程序运行
while True:
    input()

9. 调试技巧

  1. 流量分析: 使用Wireshark抓取WebSocket通信数据包,分析DevTools实际操作
  2. 事件启用: 使用任何功能前,确保已启用相应模块的事件报告
  3. 异步调用栈: 需要显式设置setAsyncCallStackDepth才能获取异步调用栈信息
  4. 变量获取: 通过scopeChain中的objectId获取变量详细信息

10. 总结

通过分析DevTools的实际通信流量,我们可以复现DevTools中的各种调试操作。关键点包括:

  1. 正确配置调试参数(如脚本缓存大小、异步调用栈深度)
  2. 理解Debugger.paused事件返回的数据结构
  3. 通过scopeChainRuntime.getProperties获取变量信息
  4. 合理设置断点触发调试暂停

这种方法可以扩展到其他调试功能的实现,如条件断点、变量监控等。

Chrome远程调试协议配置与分析教程 1. 概述 本教程详细讲解如何通过Chrome远程调试协议实现JavaScript的自动调试分析,特别是如何获取调用栈内的变量信息。教程基于对DevTools通信流量的抓包分析,提供了完整的Python实现代码。 2. 准备工作 2.1 启动Chrome远程调试 2.2 安装必要Python库 3. 基础调试配置 3.1 基本连接与初始化 3.2 高级调试配置 4. 调试事件处理 4.1 暂停事件处理函数 5. 设置断点 5.1 设置XHR/Fetch断点 5.2 导航到目标页面 6. 关键数据结构解析 6.1 Debugger.paused返回结构 callFrames : 调用栈帧数组,按从栈顶到栈底顺序排列 asyncStackTrace : 异步调用栈信息(需要额外配置) 6.2 callFrame结构 6.3 scopeChain类型 local : 局部作用域 closure : 闭包作用域 catch : catch块作用域 block : 块级作用域 script : 脚本作用域 with : with语句作用域 global : 全局作用域 7. 获取变量信息的方法 通过 Runtime.getProperties 方法获取变量信息: 8. 完整代码示例 9. 调试技巧 流量分析 : 使用Wireshark抓取WebSocket通信数据包,分析DevTools实际操作 事件启用 : 使用任何功能前,确保已启用相应模块的事件报告 异步调用栈 : 需要显式设置 setAsyncCallStackDepth 才能获取异步调用栈信息 变量获取 : 通过 scopeChain 中的 objectId 获取变量详细信息 10. 总结 通过分析DevTools的实际通信流量,我们可以复现DevTools中的各种调试操作。关键点包括: 正确配置调试参数(如脚本缓存大小、异步调用栈深度) 理解 Debugger.paused 事件返回的数据结构 通过 scopeChain 和 Runtime.getProperties 获取变量信息 合理设置断点触发调试暂停 这种方法可以扩展到其他调试功能的实现,如条件断点、变量监控等。