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

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

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

可以连接到充当主机的其他操作系统,例如 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 的角色。

一个堆栈图,显示顶部WinDbg-DbgEngEXDI-GdbServer的角色、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 配置文件配置调试器主机 (WinDbg) 。
  9. 使用命令行启动 WinDbg 以连接到 EXDI 服务器。
  10. 使用 WinDbg 调试目标 QEMU Windows 映像。

在 Windows 上下载并安装 QEMU

QEMU 是一种泛型开放源代码计算机模拟器和虚拟化器,导致动态转换。 当 QEMU 用作计算机模拟器时 - 它可以运行针对一个处理器 ((例如不同计算机上的 Arm64) )进行的 OS 和程序, (x64 PC) 。 它还可以为不同 OS (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 固件

为了获得最佳结果,请 (OVMF.fd) 下载或编译 UEFI 固件文件。 需要固件,因为默认情况下 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 中创建配置文件。 例如,在 StartQEMUx64Windows.bat QEMU 根目录下创建文件。 请参阅以下示例文件。

使用 QEMU 启动脚本启动 QEMU

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

c:\Program Files\qemu\StartQEMUx64Windows.bat

如果出现防火墙后卫提示,请向应用授予对所有类型的网络的所有权限,以便通过主机调试器计算机的 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 键组合返回到主窗口。

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

QEMU x64 Windows VM 启动脚本示例

下面是可用于 AMD64 虚拟机的示例 QEMU 配置脚本。 将指向磁盘和 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:端口对) 。

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

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

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

  • 在exdiCondifgData.xml中找到 QEMU 组件标记元素。
  • 如果调试器与 QEMU GDB 服务器的 QEMU VM) 在同一主机上运行,则设置 IP:端口号 (LocalHost:
  • 将更改保存到位于EXDI_GDBSRV_XML_CONFIG_FILE环境变量指定的路径处的exdiConfigdata.xml文件。

有关 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/exdigdbsrvsrv 中主机调试器的体系结构生成 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 调试器传输中的 EXDI PowerShell 脚本示例

通过编辑 EXDI 配置文件) 配置调试器主机 (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_GDBSRV_XML_CONFIG_FILE和EXDI_SYSTEM_REGISTERS_MAP_XML_FILE) 的相同命令提示符处,通过 exdi 接口启动 windbg 会话。

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 调试器传输中的 EXDI PowerShell 脚本示例

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

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

显示窗口标题上 exdi CLSID 的主 windbg 会话

调试器将显示成功的 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

EXDIGdbServer 控制台数据包窗口还可以显示有关 EXDI 连接状态的信息(如果 displayCommPackets=“yes”)在exdiConfigData.xml文件中设置。 有关详细信息,请参阅 配置 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 (显示内存)

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 会话所需的主配置数据,因此,如果文件位置未由EXDI_GDBSRV_XML_CONFIG_FILE环境变量设置,则 GDB 服务器客户端 不会 运行。 每个 xml 标记都允许配置特定 GDB 服务器功能集。 有关可在 XML 中修改的属性列表以及示例 XML,请参阅下面。

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

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

故障排除

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

配置 EXDI 调试器传输

.exdicmd(EXDI 命令)

自动设置 KDNET 网络内核调试

手动设置 KDNET 网络内核调试