吃不上鱼的dj猫

明月如镜 高悬草原映照千年岁月


  • 首页

  • 技术

  • 感想

  • 笔记

  • 归档

  • 关于

  • 搜索
close

xdebug3调试原理分析及配置迁移

时间: 2022-05-15   |   分类: technical     |   阅读: 1646 字 ~4分钟

xdebug3相对于2,配置方式修改了很多,在配置的时候会给出相应提示。本文使用较大篇幅分析xdebug的调试原理,以及简单的调试。针对结合PHPSTROM进行php调试也有简单涉及。

xdebug3常用配置迁移

  • 开启方式,不再是0,1的简单设置,而是使用mode来指定xdebug处于什么模式。方便于xdebug只是加载实际需要的特性。

    xdebug.mode=debug # 开启Step Debugging
    # 其他值off 关闭,develop 开启开发辅助,coverage 开启代码覆盖率分析,gcstats 开启垃圾收集状态统计, profile 开启分析,trace 开启函数追踪特性。
    # 可以使用 xdebug_info() 查看配置
    
  • 激活命令行调试export XDEBUG_CONFIG=idekey=yourname 替换为 export XDEBUG_SESSION=xdebug_is_great

  • 自动开启调试xdebug.remote_autostart 替换为 xdebug.start_with_request

  • 调试端口默认不再是9000,而是9003(更合理,9000往往会和fpm冲突)

调试原理

原理图

  • IDE集成遵循BGDP的xdebug插件,监听9000端口,监听服务端发过来的debug信息
  • 浏览器发送带了XDEBUG_SESSION_START参数
  • 后端php收到该请求(开启xdebug),xdebug向来源客户端9000端口发送debug请求
  • 客户端相应这个请求,debug就建立了
  • 后端php已经准备好后,一行行执行代码,每执行一行,就交给xdebug处理一下
  • xdebug处理过程,会暂停代码执行,向客户端发送代码的执行情况,等待客户端的操作

上文提到的客户端、IDE,这些指代监听9000端口这一方。而后端、服务端是指php,真正执行代码一方。 现实场景有可能是:客户端(浏览器)发起http请求,nginx接受http请求,转发给fpm(服务端),执行PHP代码。

代码分析

演示代码

<?php
echo 'Hello world';  // 1
$a = 20;             // 2
$b = 40;             // 3
$c = $a + $b;        // 4
echo $c.'';          // 5
echo 'Hello world';  // 6

方便后面分析,后面注释代表行号。

简单检测

按照调试原理,可以看出,当开启了

xdebug.mode=debug
xdebug.start_with_request

执行php代码php index.php, 执行方即php, 会发送9003的请求给客户端。客户端如果依赖于ide(如phpstorm),开启右上角监听按钮即可。为了分析具体情况,可以用nc模拟监听9003端口

nc -lv 127.0.0.1 9003 
# 可以参考引用中的链接,了解nc命令

这个时候在nc命令行界面便可以看到打印的init信息

<?xml version="1.0" encoding="iso-8859-1"?>\n<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" fileuri="file:///Users/jerry/Desktop/work/phptest/index.php" language="PHP" xdebug:language_version="7.4.16" protocol_version="1.0" appid="29040"><engine version="3.0.3"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[https://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2021 by Derick Rethans]]></copyright></init>

如果想检测具体的网络协议:

tcpdump -i eth1 -nn -A port 9003

或者wireshark

tcp.port==9003 && tcp.flags.push == 1

交互测试

import base64
import binascii
import re
import socket

ip_port = ('0.0.0.0', 9003)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(10)
conn, addr = sk.accept()

while True:
    client_data = b''
    data_len = 0
    data = b''
    while True:
        client_data = conn.recv(1024)
        if not client_data:
            break
        client_data_arr = client_data.split(b'\x00')
        # 开始处为内容的长度
        if not data_len:
            data_len = client_data_arr[0]
            data += client_data_arr[1]
        else:
            data += client_data_arr[0]
        # 最后面是以\x00结尾
        if client_data_arr[len(client_data_arr) - 1] == b'':
            break

    print("[+] Raw Result: %s" % data)

    g = re.search(rb'<\!\[CDATA\[([a-z0-9=\./\+]+)\]\]>', data, re.I)
    if g:
        data = g.group(1)
        try:
            print('[+] Result: %s' % base64.b64decode(data).decode())
        except binascii.Error:
            print('[-] May be not string result...')
    else:
        print('[-] No result...')

    data = input('>> ')
    # conn.sendall('eval -i 1 -- %s\x00' % data.encode('base64'))
    conn.sendall(data.encode('utf-8') + b'\x00')

程序简单解释:

  • 监听9003端口(如果其他配置的是其他端口,自行修改程序)
  • '\x00'协议以该字节结尾,循环判断内容是否读取完毕
  • 正则提取xml里的data数据
  • 使用base64解码内容
  • 等待用户输入
  • 发送给服务端命令
  • 循环以上过程
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" fileuri="file:///Users/jerry/Desktop/work/phptest/index.php" language="PHP" xdebug:language_version="7.4.16" protocol_version="1.0" appid="27099"><engine version="3.0.3"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[https://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2021 by Derick Rethans]]></copyright></init>'
[-] May be not string result...
>> breakpoint_set -i 1 -t line -f index.php -n 3
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="1" id="270990001"></response>'
[-] No result...
>> breakpoint_get -i 1 -d 270990001
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_get" transaction_id="1"><breakpoint type="line" filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="3" state="enabled" hit_count="0" hit_value="0" id="270990001"></breakpoint></response>'
[-] No result...
>> breakpoint_list -i 1
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="1"><breakpoint type="line" filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="3" state="enabled" hit_count="0" hit_value="0" id="270990001"></breakpoint></response>'
[-] No result...
>> breakpoint_set -i 1 -t line -f index.php -n 11
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="1" id="270990002"></response>'
[-] No result...
>> breakpoint_list -i 1
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="1"><breakpoint type="line" filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="3" state="enabled" hit_count="0" hit_value="0" id="270990001"></breakpoint><breakpoint type="line" filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="11" state="enabled" hit_count="0" hit_value="0" id="270990002"></breakpoint></response>'
[-] No result...
>> run -i 1
[+] Raw Result: b'<?xml version="1.0" encoding="iso-8859-1"?>\n<response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="run" transaction_id="1" status="break" reason="ok"><xdebug:message filename="file:///Users/jerry/Desktop/work/phptest/index.php" lineno="3"></xdebug:message></response>'

以上内容为简单演示了程序,分别测试了:设置断点、获取某个断点、列出所有断点、运行。其他演示操作可以参考引用中的文档。

总结

通过程序模拟了dbgp的过程,如果感兴趣还可以通过程序发送system('ls')的命令,感受dbgp协议的流程。关于IDE的配置,主要是在配置里找到xdebug调试端口,在这里对应php配置中的xdebug.client_port。如果修改了,重启一下ide即可。根据是否开启自动调试配置,进行不同方式的触发即可。

更详细的配置,网络上很多,本文主要在于原理分析。

引用

https://xdebug.org/docs/upgrade_guide

https://www.secpulse.com/archives/115172.html

https://wsgzao.github.io/post/nc/ nc命令

https://xdebug.org/docs/dbgp dbgp协议

如何使用openssl加密大文件
aws cloudwatch logs insights分析业务数据
  • 文章目录
  • 站点概览
D&J

D&J

程序员

27 日志
3 分类
17 标签
GitHub
  • xdebug3常用配置迁移
  • 调试原理
  • 代码分析
    • 演示代码
    • 简单检测
    • 交互测试
  • 总结
  • 引用
© 2009 - 2024 吃不上鱼的dj猫
Powered by - Hugo v0.124.0
Theme by - NexT 沪ICP备14008426号-3
0%