用于Windows 11的类似SoftICE的内核调试器
作者:Sec-Labs | 发布时间:
项目地址
https://github.com/vitoplantamura/BugChecker
BugChecker

介绍
BugChecker 是一个类似于 SoftICE的内核和用户调试器,适用于 Windows 11(以及 Windows XP:它支持从 XP 到 11 的 Windows 版本,包括 x86 和 x64)。BugChecker 不需要第二台机器连接到正在调试的系统,就像 WinDbg 和 KD 一样。此版本的 BugChecker(与20 年前开发的原始版本不同)利用了 NTOSKRNL 中未记录的内部 KD API。KD API 允许 WinDbg/KD 执行读取/写入虚拟内存、读取/写入寄存器、在地址处放置断点等调用。
相比之下,最初的 BugChecker,就像 SoftICE 一样,过去常常通过挂接几个内核 API(包括导出的和私有的)来“接管”系统,控制 APIC,发送 IPI 等。这种方法以指数方式增加了复杂性(并且降低系统稳定性),因为实现必须与所有受支持的 Windows 版本和子版本(在功能签名级别)以及所有可能受支持的硬件配置兼容。而且,20 年后,PatchGuard 使这个解决方案成为不可能。
相比之下,这个版本的 BugChecker 通过拦截内核中对 KdSendPacket 和 KdReceivePacket 的调用,将自己呈现给被调试的机器作为运行外部内核调试器的第二个系统,但实际上,一切都发生在同一台机器上。通常,这是通过替换 KDCOM.DLL(这是在 Windows 中为 KD API 实现串行电缆通信的模块)并在内核调试模式下启动系统来实现的。这种方法(受VirtualKD启发) 降低了复杂性并增加了稳定性和兼容性(以及可移植性,例如,到 ARM - 和模块化,因为较低级别的调试器功能是在 KdXxxPacket 后面实现的,并且可以用自定义实现替换)。此外,在启动时存在内核调试器(尽管是“假的”)会使 Windows 禁用 PatchGuard。
目前,BugChecker 需要一个 PS/2 键盘作为输入,并需要一个线性帧缓冲区来写入其输出。
特征
- 支持 Windows XP 到 Windows 11、x86 和 x64,以及 SMP 内核。支持 x64 上的 WOW64 进程。
- QuickJSPP的集成,它是QuickJS到 MSVC++ 的端口。在调用 QuickJS 之前,BugChecker 保存 FPU 状态(在 x86 上)并切换到 128KB 的扩展堆栈。
- 支持 PDB 符号文件。可以手动指定 PDB 文件,或者 Symbol Loader 可以从符号服务器下载它们。
- JavaScript 代码可以调用以下异步函数:WriteReg、ReadMem、WriteMem。
- 断点可以有一个 JS 条件:如果条件计算为 0,则不会发生“中断”。这允许设置可以改变执行流程的“日志点”和断点。
- 日志窗口显示发送到内核调试器的消息(例如 DbgPrint 消息)。
- 带有语法高亮显示的 JavaScript 窗口。
- tab 键允许在给定几个数字的情况下循环显示屏幕上的所有十六进制数字,或者在给定几个字符的情况下循环显示包含这些字符的所有符号。
- EASTL 和 C++20 协同程序使创建新命令变得轻而易举。随时发送您的请求请求!
视频(YouTube)
BugChecker 在 Windows 11 22H2 上的演示,在 VirtualBox 7.0.4 中。编写了一个 JavaScript 断点条件来更改用户模式线程中的执行流程。
BugChecker 在非常受限的环境中运行:Raspberry Pi 4(4GB RAM),通过 Windows XP(512MB RAM)上的 QEMU。断点用于记录从用户模式到内核的所有 SYSENTER 调用。服务索引存储在 JavaScript 数组中。
直接在裸机上运行 BugChecker,在 HP Pavilion Dv2000 上,这是一台带有 PS/2 键盘的旧 PC。操作系统是Windows 7 Home 32bit。
安装说明
介绍
确保在安装和使用 BugChecker 时禁用安全启动。通常您可以稍后重新启用它。如果您使用的是 VMware 或 VirtualBox,则可以在虚拟机设置中禁用安全启动。
如果使用 Windows 8、10 或 11,还可以考虑启用旧版启动菜单,方法是使用以下命令:bcdedit /set "{current}" bootmenupolicy legacy。通过允许选择 BugChecker 引导选项,然后同时禁用驱动程序签名强制,它可以在引导期间提供更流畅的体验。
指示
第一步是启动 Symbol Loader:
如有必要,通过单击“禁用显示驱动程序”按钮来禁用显示驱动程序。同样的事情可以在 Windows 设备管理器中完成。禁用显示驱动程序后,即使在系统重新启动后它们仍保持禁用状态。在不使用 BugChecker 时,可以随时重新启用它们。
这里的重点是 BugChecker 需要一个格式为每像素 32 位的线性帧缓冲区来绘制其界面。当禁用显示驱动程序时,Windows 会取消绘制其 UI 的硬件加速并回退到 VGA 兼容模式。如果在裸机或 VMware 上运行,您应该禁用显示驱动程序。如果在 VirtualBox 上运行,您应该禁用显示驱动程序或在 BugChecker.dat 中设置 vm_screen 设置,如下所述。如果在 QEMU 上运行,您不需要禁用显示驱动程序,但请确保指定“-vga std”显示设备。
请注意,VGA 兼容模式可能会限制最大屏幕分辨率。VMware 的最大分辨率限制为 1152x864。带有“-vga std”显示设备的 QEMU 不受此限制。
有趣的是,如果 BugChecker 安装在具有多个显卡的系统上,则可以仅禁用一个显卡的显示驱动程序,该显卡将连接到将显示 BugChecker UI 的屏幕。第二张卡(设置为主显示器)将保留其所有 2D 和 3D 加速功能,包括 OpenGL 和 DirectX 支持(注意:在 VMware 上测试,使用 Windows 11 和 DisplayLink 显示器)。
然后单击“启动驱动程序”,然后单击“自动检测”,最后单击“保存”。“自动检测”应该能够自动确定帧缓冲区的宽度、高度、物理地址和步幅。但是,您可以手动指定这些设置(完成后不要忘记单击“保存”)。如果“Stride”为0,则在启动驱动程序时自动计算为“Width”* 4。“地址”(即帧缓冲区的物理地址)可以在 Windows 设备管理器中获取,方法是单击“资源”选项卡下显示设备的“属性”。
然后点击“KDCOM Hook Method”部分的“Callback”,然后点击“Copy/Replace Kdcom”,最后你可以重启系统。
此设置过程只需执行一次,如有必要,可以重新启用显示驱动程序。但是,当使用 BugChecker 时,如果您的配置需要,则必须再次禁用显示驱动程序。
VirtualBox 的 vm_screen 设置(实验性)
BugChecker.dat 中的 vm_screen 设置允许在 VirtualBox 中打开 BugChecker 调试器 UI,而无需提前在 Symbol Loader 中指定屏幕分辨率,也无需禁用显示驱动程序。
这个想法是直接写入 I/O 端口和虚拟显示设备的命令缓冲区,以获得当前屏幕分辨率并通知管理程序帧缓冲区中的任何更新。
该解决方案的灵感来自X.org xf86-video-vmware驱动程序。
此解决方案仅适用于 VirtualBox VM 并通过手动编辑 BugChecker.dat 文件:
- 在 Symbol Loader 中,手动将帧缓冲区的宽度和高度设置为可能的最大分辨率(即计算机屏幕的尺寸)。将步幅设置为 0。
- BugChecker.dat 文件由 Symbol Loader 在“C:\Windows\BugChecker”中创建。
- vm_screen 设置应该添加到“settings->framebuffer”下。
- 此文件中设置的层次结构由制表字符(而非空格)确定。
- 设置格式为 Command_Buffer_Start_Address(逗号) Command_Buffer_End_Address(逗号) I/O_Port_Base
- 重要提示:在 VM 设置中,在显示下,选择“VBoxSVGA”作为图形控制器并取消选中“启用 3D 加速”。
这是一项实验性功能。将来,此设置将由 Symbol Loader 自动添加。
实施的命令
命令名称和语法选择尽可能接近 NT 的原始 SoftICE:
- ?javascript-expression:评估 javascript 表达式。
- ADDR eprocess:切换到进程上下文(将控制权返回给操作系统)。
- BC列表| *:清除一个或多个断点。
- BD列表| *:禁用一个或多个断点。
- BE名单| *:启用一个或多个断点。
- BL(无参数):列出所有断点。
- BPX address [-t|-p] [WHEN js-expression] : 在执行时设置断点。
- CLS(无参数):清除日志窗口。
- DB/DW/DD/DQ [address] [-l len-in-bytes]:将内存显示为 8/16/32/64 位值。
- EB/EW/ED/EQ 地址 -v 空格分隔值:将内存编辑为 8/16/32/64 位值。
- KL EN|IT : 设置键盘布局。
- LINES [rows-num] : 显示或设置当前显示行数。
- MOD [-u|-s] [search-string] : 显示模块信息。
- P [RET] : 执行一个程序步骤。
- PAGEIN 地址:强制调入一页内存(将控制权返回给操作系统)。
- PROC [search-string] : 显示进程信息。
- R register-name -v value:更改寄存器值。
- STACK(无参数):扫描堆栈以搜索返回地址。
- T(无参数):跟踪一条指令。
- U 地址|DEST:反汇编指令。
- VER(无参数):显示版本信息。
- WD [window-size]:切换反汇编程序窗口或设置其大小。
- WIDTH [columns-num] : 显示或设置当前显示的列数。
- WR(无参数):切换寄存器窗口。
- WS [window-size]:切换脚本窗口或设置其大小。
- X(无参数):退出 BugChecker 屏幕。
构建说明
先决条件
- 视觉工作室 2019
- Windows 驱动程序工具包 7.1.0
注意:WDK 应安装在其默认位置,即 X:\WinDDK,其中 X 是保存 BugChecker 源的驱动器。
Visual Studio 项目说明
- BugChecker:这是 BugChecker 内核驱动程序,其中实现了整个调试器。“Release|x86”和“Release|x64”输出文件包含在最终包中。在初始化期间,驱动程序在“\SystemRoot\BugChecker\BugChecker.dat”加载其配置文件(所有符号文件也存储在此目录中),然后它尝试在内核空间中定位“KDCOM.dll”。如果找到,它会尝试调用其“KdSetBugCheckerCallbacks”导出函数,从而挂接 KdSendPacket 和 KdReceivePacket。
- SymLoader:这是符号加载器。最终包中仅包含“Release|x86”输出文件。Symbol Loader 用于更改 BugChecker 配置(配置写入“\SystemRoot\BugChecker\BugChecker.dat”)、下载 PDB 文件和安装自定义 KDCOM.dll 模块。
- KDCOM:这是 NTOSKRNL 在系统启动时加载的自定义 KDCOM.dll 模块。它导出驱动程序调用以挂钩 KdSendPacket 和 KdReceivePacket 的“KdSetBugCheckerCallbacks”函数。
- pdb:这是 Ghidra“pdb”项目。原始版本将 PDB 文件的内容以 xml 格式输出到标准输出。修改代码以生成 BCS 文件。
- NativeUtil:由于 Symbol Loader 是 Windows x64 中的 WOW64 应用程序,因此必须从体系结构本机图像进行的那些 API 的调用已移至此处(例如,对设备和驱动程序安装 API 的调用)。
- HttpToHttpsProxy:这是一个 ASP.NET Core 应用程序,其功能是在 Windows XP 中运行时充当 Symbol Loader 的互联网代理。由于 XP 已经过时了 TLS 支持,Symbol Loader 无法从任意符号服务器下载文件。在同一网络上的 IIS 中部署此应用程序后,可以从 Windows XP 中的符号服务器下载文件,将“http://<YOUR_IIS_SERVER_IP>/HttpToHttpsProxy/”添加到 Symbol Loader 中的服务器 URL。
贡献
- VirtualKD: BugChecker的第一个 POC 是通过修改 VirtualKD 构建的。
- BazisLib:Symbol Loader 中“Copy/Replace Kdcom + Add Boot Entry”按钮背后的代码来自 VirtualKD 并使用 BazisLib。
- EASTL:这里无法使用 MSVC++ STL。EASTL 是一个很好的选择。
- Ghidra:BugChecker 中的“pdb”项目来自 Ghidra。它被修改为生成 BCS 文件。
- Zydis:用于 BugChecker 中的反汇编程序窗口。
- ReactOS:用于 Windows KD 内部类型定义。
- SerenityOS:用于 BugChecker 内存分配器使用的低级位图操作函数。自从我看到Andreas的视频后开始使用 BugChecker (在 10 年远离 C/C++ 和任何类型的低级编程之后),我想在 BugChecker 中包含一小部分 SerenityOS。




