使用 EXDI 设置 QEMU 内核模式调试

本主题介绍如何使用 EXDI 设置 QEMU Kernel-Mode 调试。 Windows 调试器支持使用 EXDI 对 QEMU 环境进行内核调试。 本文档介绍在 ExdiGdbSrv.dll (GDB 服务器客户端) 与 QEMU GDB 服务器之间建立 GdbServer RSP 会话所需的步骤。

所述的方案使用 Windows x64 虚拟机和也在 Windows 上运行的 QEMU GDB 服务器。

可以连接到充当主机的其他操作系统,例如 Linux。 QEMU(虚拟化和计算机仿真软件)可以在许多体系结构上运行,例如 x64 和 Arm64。 ExdiGdb 调试服务器还支持其他处理器,例如,可以使用 WinDbg 调试在 Arm64 上运行的 QEMU。 这提供了多个选项来调试 Windows VM,因此可以通过连接到调试器主机 EXDI GDB 服务器客户端的可用 QEMU GDB 服务器对 Windows VM 进行 HW 调试。

有关设置 EXDI 连接配置和故障排除的常规信息,请参阅 配置 EXDI 调试器传输

注意

EXDI 是针对特定环境进行调试的高级专用形式。 使用标准 KDNET 连接更易于配置,建议使用。 若要自动设置网络调试,请参阅 自动设置 KDNET 网络内核调试

EXDI COM 服务器

EXDI 是一个接口,它允许通过添加对硬件调试器的支持来扩展 WinDbg, (例如基于 JTAG 或基于 GdbServer 的) 。 下图说明了 EXDI-GdbServer 的作用。

显示 EXDI-GdbServer 的角色的堆栈图,顶部 WinDbg-DbgEng、EXDI 接口和 EXDI COM 服务器与 GDB 服务器通信。

重要

由于 EXDI 不使用 KDNET 协议,因此连接的调试器与电脑上运行的内容有关的信息要少很多,并且许多命令的工作方式会有所不同,或者可能根本不起作用。 访问要调试的代码的专用符号可以帮助调试器更好地了解目标系统代码执行。 有关详细信息,请参阅 公共符号和专用符号

在 QEMU 上设置与 Windows 映像的调试器连接

在本主题中,我们将介绍附加到在 Windows 上运行的 QEMU 虚拟 Windows 映像的过程。

  1. 在 Windows 上下载并安装 QEMU。
  2. 将目标 QEMU 虚拟 Windows 映像配置为使用调试所需的网络和 BIOS/UEFI 设置启动。
  3. 使用配置的启动脚本启动 QEMU 环境。
  4. 在 QEMU 上启动 gdbserver。
  5. 检查网络连接,找到并记录目标映像 IP 地址。 (主机 IP 默认地址 1.2.3.4) 。
  6. 在主机系统上下载并安装 Windows 调试工具。
  7. 下载、生成、注册和配置位于 GitHub 上的 QEMU 的 EXDI 服务器。
  8. 通过编辑 EXDI 配置 XML 文件 (WinDbg) 配置调试器主机。
  9. 使用命令行启动 WinDbg 以连接到 EXDI 服务器。
  10. 使用 WinDbg 调试目标 QEMU Windows 映像。

在 Windows 上下载并安装 QEMU

QEMU 是一种通用的开放源代码计算机模拟器和虚拟化程序,可导致动态转换。 当 QEMU 用作计算机仿真器时,它可以运行针对一个处理器 ((如 arm64) )制作的操作系统和程序, (x64 电脑) 。 它还可以运行/托管不同操作系统 (Windows/Linux/Mac) 的虚拟机映像。

QEMU 可以使用其他虚拟机监控程序(如 KVM)将 CPU 扩展 (HVM) 用于虚拟化。 将 QEMU 用作虚拟化程序时,QEMU 通过在主机 CPU 上直接执行来宾代码来实现接近本机的性能。 QEMU 可以利用 OS 虚拟机监控程序功能将 CPU 和 MMU 仿真卸载到实际硬件。

下载并安装 QEMU

在本演练中,适用于 Windows x64 的 QEMU 将安装在运行 Windows 调试器的 x64 电脑上。

从 QEMU 下载页下载 QEMU: https://www.qemu.org/download/

有关安装 QEMU 的信息,请参阅 QEMU 文档: https://www.qemu.org/documentation/

配置目标虚拟磁盘

找到或创建包含要调试的软件的虚拟磁盘映像。

在此示例中,将使用 Windows x64 VHDX 虚拟机磁盘映像。 若要了解有关 Windows 虚拟机映像的详细信息,请参阅在 Windows 10 上使用 Hyper-V 创建虚拟机

将 VirtIO 驱动程序注入 Windows 映像

若要允许网络功能和合理的存储设备性能,请将 VirtIO 驱动程序注入或安装到 Windows 虚拟机磁盘映像中。 此处提供了 VirtIo 驱动程序: https://github.com/virtio-win/kvm-guest-drivers-windows

VirtIO 是一个标准化接口,允许虚拟机访问抽象硬件,例如块设备、网络适配器和控制台。 Virtio 在 QEMU 等虚拟化环境中充当硬件设备的抽象层。

将 VHDX 转换为 QEMU

此步骤不是必需的,但建议这样做,因为使用本机 QEMU QCOW 映像而不是 VHDX 时会获得更好的性能。

使用以下 qemu-img.exe 命令转换 vhdx。 此实用工具位于安装 QEMU 的位置,例如 C:\Program Files\qemu

C:\Program Files\qemu> qemu-img convert -c -p -O qcow2 MyVHDXFile.vhdx MyQEMUFile.qcow2 

下载 UEFI 固件

为获得最佳结果,请下载或编译 UEFI 固件文件 (OVMF.fd) 。 需要固件,因为默认情况下 QEMU 会模拟较旧的 BIOS 系统。

UEFI 固件的一个源是 Open Clear Linux 项目: https://clearlinux.org/

此处提供了示例 UEFI OVMF.fd 文件: https://github.com/clearlinux/common/blob/master/OVMF.fd

提取 中 C:\Program Files\qemu\Firmware下载的文件的内容。

对于 Intel AMD64 以外的平台,应从 EDK2 编译固件。 有关详细信息,请参阅 https://github.com/tianocore/tianocore.github.io/wiki/How-to-build-OVMF

配置 QEMU 启动脚本

在 QEMU 中创建配置文件。 例如,在 QEMU 根目录下创建文件 StartQEMUx64Windows.bat 。 请参阅下面的示例文件。

使用 QEMU 启动脚本启动 QEMU

执行 QEMU 启动脚本以启动 QEMU。

c:\Program Files\qemu\StartQEMUx64Windows.bat

如果出现防火墙 defender 提示,请向应用授予对所有类型的网络的所有权限,以通过主机调试器计算机的 Windows 防火墙启用 Windbg。

选中所有三个选项的“Windows Defender防火墙”对话框。

在 QEMU 环境中启动 Windows 虚拟机后,将显示 QEMU UI。

显示视图菜单选项的 QEMU 屏幕截图。

使用 CTRL+Alt+ 数字组合键进入 QEMU 监视器控制台。 此监视器也可以使用 View-compatmonitor>

键入 gdbserver 以在 QEMU 上启动前端 GDB 服务器。

QEMU 应显示 Waiting for gdb connection on device ‘tcp::1234’

使用 Ctrl+Alt+1 组合键返回到main窗口。

提示:GDB 控制台窗口支持使用“system_reset”命令快速重启仿真。 键入 GDB 控制台命令列表的帮助。

QEMU x64 Windows VM 启动脚本示例

下面是可用于 AMD64 虚拟机的示例 QEMU 配置脚本。 将指向 DISK 和 CDROM 文件的链接替换为电脑上的位置。

    REM
    REM  This script is used to run a Windows x64 VM on QEMU that is hosted by a Windows x64 host system
    REM  The Host system is a PC with Intel(R) Xeon(R) CPU.
    REM
    set EXECUTABLE=qemu-system-x86_64
    set MACHINE=-m 6G -smp 4

    REM No acceleration
    REM generic cpu emulation.
    REM to find out which CPU types are supported by the QEMU version on your system, then run:
    REM	 qemu-system-x86_64.exe -cpu help
    REM the see if your host system CPU is listed
    REM

    set CPU=-machine q35 

    REM Enables x64 UEFI-BIOS that will be used by QEMU :
    set BIOS=-bios D:\temp\firmware\OVMF.fd

    REM  Use regular GFX simulation
    set GFX=-device ramfb -device VGA 
    set USB_CTRL=-device usb-ehci,id=usbctrl
    set KEYB_MOUSE=-device usb-kbd -device usb-tablet

    REM # The following line enable the full-speed HD controller (requires separate driver)
    REM # Following line uses the AHCI controller for the Virtual Hard Disk:
    set DRIVE0=-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0

    REM
    REM This will set the Windows VM x64 disk image that will be launched by QEMU
    REM The disk image is in the qcow2 format accepted by QEMU.
    REM You get the .qcow2 image, once you get the VHDX Windows VM x64 image 
    REM and apply the script to inject the virtio x64 drivers and then run the 
    REM the QEMU tool to convert the .VHDX image to .qcow2 format
    REM 	i.e. 
    REM	qemu-img convert -c -p -O qcow2 Windows_VM_VHDX_with_injected_drivers_file.vhdx file.qcow2
    REM file : points to the specified qcow2 image path.
    REM
    set DISK0=-drive id=disk,file=D:\temp\x64_image_qcow2_for_windows\basex64Client.qcow2,if=none

    REM
    REM for kdnet on, then best option:
    REM   NETWORK0="-netdev user,id=net0,hostfwd=tcp::53389-:3389,hostfwd=tcp::50001-:50001 -device virtio-net,netdev=net0,disable-legacy=on"
    REM
    set NETHOST=-netdev user,id=net0,hostfwd=tcp::3589-:3389
    set NETGUEST=-device e1000,netdev=net0

    REM # The following line should enable the Daemon (instead of interactive)
    set DEAMON=-daemonize"
    %EXECUTABLE% %MACHINE% %CPU% %BIOS% %GFX% %USB_CTRL% %DRIVE0% %DISK0% %NETHOST% %NETGUEST%

检查网络连接

如果调试器主机会话与 QEMU VM) 不在同一台 Windows 计算机上,请确保获取 windows IP 地址 (。

如果 GDB 服务器已正确启动,则会看到 GDB 服务器将侦听的端口号,并且你将需要使用此端口在 exdiConfigData.xml) 中设置主机调试器 (IP:Port 对) 。

如果主机调试器位于托管 QEMU 来宾的同一台计算机上,则 Localhost 标识符将在 exdiconfigdata.xml 中用作 IP:端口对 (例如 LocalHost:Port:1234) 。 在此示例中,服务器和主机调试器位于同一台电脑上,将使用默认值。

在 ExdiConfigData.xml 文件中,将当前目标名称属性 (CurrentTarget) 值设置为“QEMU”。

如果在远程电脑上工作,请通过以下方式设置 GDB 服务器侦听的目标 QEMU IP <address> :端口 <number>

  • 在 exdiCondifgData.xml 中找到 QEMU 组件 Tag 元素。
  • 如果调试器 (QEMU VM) 为 QEMU GDB 服务器在同一主机上运行,请通过以下方式设置 IP:端口号:
  • 保存对 exdiConfigdata.xml 文件的更改,该文件位于EXDI_GDBSRV_XML_CONFIG_FILE环境变量指定的路径处。

有关 QEMU 网络的其他信息,请参阅 https://wiki.qemu.org/Documentation/Networking

可以在 QEMU 控制台上发出以下命令, (compatmonitor0) 显示有关网络和连接状态的信息。

info network
info usernet

在主机系统上下载并安装 Windows 调试工具

在主机系统上安装 Windows 调试工具。 有关下载和安装调试器工具的信息,请参阅 Windows 调试工具

下载、生成和注册 EXDI 服务器 DLL

从 microsoft/WinDbg-Samples、GitHub https://github.com/microsoft/WinDbg-Samples) 下载相应的 ExdiGdbSrv.dll 二进制 (EXDI COM 服务器客户端) 源代码

git clone https://github.com/microsoft/WinDbg-Samples

根据 Exdi/exdigdbsrv 中主机调试器的体系结构生成 VS 解决方案 (ExdiGdbSrv.sln) 。

找到生成生成的 ExdiGdbSrv.dll。

将 EXDI com 服务器 (ExdiGdbSrv.dll) 复制到主机,并将其复制到包含调试器的目录 .g 中。 C:\Program Files (x86)\Windows Kits\10\Debuggers\x64C:\Debuggers)

使用 regsvr32 在管理员命令提示符下注册 DLL。

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>regsvr32 ExdiGdbSrv.dll

RegSvr32 应返回一条消息, DLLRegisterServer in ExdiGdbSrv.dll succeeded指示 。

此步骤只需执行一次,但如果更改 ExdiGdbSrv.dll 的位置,则需要再次注册 COM 服务器。

另一种方法是使用示例 PowerShell 脚本安装 EXDI DLL,并在第一次启动调试器。 有关详细信息,请参阅配置 EXDI 调试器传输中的示例 EXDIPowerShell 脚本

通过编辑 EXDI 配置 XML 文件 (WinDbg) 配置调试器主机

在 中找到 WinDbg-Samples/Exdi/exdigdbsrv/ 所需的两个配置文件,并将其复制到安装调试器的主机调试器的本地位置。

  • exdiConfigData.xml
  • systemregisters.xml

EXDI_GDBSRV_XML_CONFIG_FILE – 描述 EXDI xml 配置文件的完整路径。

EXDI_SYSTEM_REGISTERS_MAP_XML_FILE – 描述 EXDI xml 系统注册映射文件的完整路径。

有关设置 EXDI 连接配置和故障排除以及 exdiConfigData.xml 标记和属性的常规信息,请参阅 配置 EXDI 调试器传输

设置环境变量EXDI_GDBSRV_XML_CONFIG_FILE,并EXDI_SYSTEM_REGISTERS_MAP_XML_FILE描述 exdi xml 配置文件的完整路径。

命令提示符

打开命令提示符并设置以下环境变量。

set EXDI_GDBSRV_XML_CONFIG_FILE="C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\exdiConfigData.xml"

set EXDI_SYSTEM_REGISTERS_MAP_XML_FILE="C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\systemregisters.xml"

键入 SET 以确认指定的路径是否可从 ExdiGdbSrvSample.dll

Powershell

打开 PowerShell 提示符并设置以下环境变量:

$env:EXDI_GDBSRV_XML_CONFIG_FILE = 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\exdiConfigData.xml'

$env:EXDI_SYSTEM_REGISTERS_MAP_XML_FILE = 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\systemregisters.xml'

键入 dir env: 以确认指定的路径是否可从 ExdiGdbSrvSample.dll

在主机系统上启动 WinDbg

在同一命令提示符下,通过 exdi 接口启动 windbg 会话,在其中设置环境变量 (EXDI_GDBSRV_XML_CONFIG_FILE 和EXDI_SYSTEM_REGISTERS_MAP_XML_FILE) 。

c:\Debuggers> windbg.exe -v -kx exdi:CLSID={29f9906e-9dbe-4d4b-b0fb-6acf7fb6d014},Kd=Guess,DataBreaks=Exdi

若要显示其他输出,可以使用 -v: 详细会话。 有关 WinDbg 选项的常规信息,请参阅 WinDbg Command-Line 选项

另一种方法是使用示例 PowerShell 脚本安装 EXDI DLL,并在第一次启动调试器。 有关详细信息,请参阅配置 EXDI 调试器传输中的示例 EXDIPowerShell 脚本

PS>.\Start-ExdiDebugger.ps1 -ExdiTarget "QEMU" -GdbPort 1234 -Architecture x64 -ExdiDropPath "C:\path\to\built\exdi\files"

调试器应启动并连接到 QEMU GdbServer。

主 WinDbg 会话在窗口标题中显示 EXDI CLSID。

调试器将显示成功的 EXDI 传输初始化。

EXDI: DbgCoInitialize returned 0x00000001
EXDI: CoCreateInstance() returned 0x00000000
EXDI: QueryInterface(IExdiServer3) returned 0x00000000
Target command response: QEMU
exdiCmd: The function: 'ExdiDbgType' was completed.
EXDI: Server::GetTargetInfo() returned 0x00000000
EXDI: Server::SetKeepaliveInterface() returned 0x00000000
EXDI: Server::GetNbCodeBpAvail() returned 0x00000000
EXDI: ExdiNotifyRunChange::Initialize() returned 0x00000000
EXDI: LiveKernelTargetInfo::Initialize() returned 0x00000000
EXDI: Target initialization succeeded

如果在 exdiConfigData.xml 文件中设置了 displayCommPackets=“yes”,则 EXDIGdbServer 控制台数据包窗口还可以显示有关 EXDI 连接状态的信息。 有关详细信息,请参阅 配置 EXDI 调试器传输中的故障排除信息。

使用 WinDbg 调试目标 QEMU Windows 映像

dbgeng.dll 使用启发式算法在中断命令发生时查找 NT 基本负载地址的位置。 如果私有符号不可用,此过程将失败。

这意味着,在许多连接序列下,中断将无法按预期方式工作。 如果你手动闯入代码,它将是 Windows 恰好在该时刻执行的随机位置。 由于目标代码的符号可能不可用,因此使用符号设置断点可能很困难。

可直接访问内存的以下命令将正常工作。

k、kb、kc、kd、kp、kP、kv(显示堆栈回溯)

r(寄存器)

d、da、db、dc、dd、dD、df、dp、dq、du、dw (Display Memory)

u(取消汇编)

可以单步执行代码。

p(步进)

还有一些命令可用于尝试查找要调试的代码。

s(搜索内存)

.imgscan(查找映像标头)

Imgscan 有助于 EDXI 调试,因为与传统的基于 KDNET 的内核调试不同,基于符号设置断点可能不可用。 查找所需的目标映像有助于使用其位置来设置内存访问断点。

.exdicmd(EXDI 命令)

.exdicmd 使用活动的 EXDI 调试连接将 EXDI 命令发送到目标系统。 有关详细信息,请参阅 .exdicmd (EXDI 命令)

EXDI XML 配置文件

EXDI GDB COM 服务器 (ExdiGdbSrv.dll) 使用两个必需的 xml 文件。

  1. exdiConfigData.xml - 此文件包含 GDB 服务器客户端与 HW 调试器 GDB 服务器目标成功建立 GDB 会话所需的main配置数据,因此,如果文件位置不是由 EXDI_GDBSRV_XML_CONFIG_FILE 环境变量设置的,GDB 服务器客户端将不会运行。 每个 xml 标记都允许配置 GDB 服务器功能的特定集。 有关可在 XML 中修改的属性列表和示例 XML,请参阅下文。

  2. Systemregister.xml - 此文件包含系统寄存器及其访问代码之间的映射。 这是必需的,因为 GDB 服务器未在 xml 文件中提供访问代码,并且调试器通过访问代码访问每个系统寄存器。

有关 XML 配置文件中定义的 GDBServer 标记和属性的详细信息和说明,请参阅 配置 EXDI 调试器传输

故障排除

请参阅 配置 EXDI 调试器传输中的故障排除信息。

另请参阅

配置 EXDI 调试器传输

.exdicmd(EXDI 命令)

自动设置 KDNET 网络内核调试

手动设置 KDNET 网络内核调试