BugChecker es un depurador de kernel y modo usuario similar a SoftICE para Windows 11 (y también para Windows XP: soporta versiones de Windows desde XP hasta 11, tanto x86 como x64). BugChecker no requiere una segunda máquina conectada al sistema que se está depurando, como en el caso de WinDbg y KD. Esta versión de BugChecker (a diferencia de la versión original desarrollada hace 20 años) aprovecha la API KD interna y no documentada de NTOSKRNL. La API KD permite a WinDbg/KD realizar llamadas como leer/escribir memoria virtual, leer/escribir registros, colocar un punto de interrupción en una dirección, etc.
Por el contrario, el BugChecker original, al igual que SoftICE, solía "tomar el control" del sistema, enganchando varias API del kernel (tanto exportadas como privadas), tomando el control del APIC, enviando IPI, etc. Este enfoque aumenta la complejidad exponencialmente (y reduce la estabilidad del sistema), ya que la implementación debe ser compatible con todas las versiones y subversiones de Windows compatibles (a nivel de firma de funciones), así como con todas las configuraciones de hardware compatibles posibles. Además, 20 años después, PatchGuard hace que esta solución sea imposible.
Por el contrario, esta versión de BugChecker, al interceptar llamadas a KdSendPacket y KdReceivePacket en el kernel, se presenta a la máquina depurada como un segundo sistema que ejecuta un depurador de kernel externo, pero, en realidad, todo sucede en la misma máquina. Normalmente esto se logra reemplazando KDCOM.DLL (que es el módulo que implementa la comunicación por cable serie para la API KD en Windows) e iniciando el sistema en modo de depuración de kernel. Este enfoque (inspirado en VirtualKD) reduce la complejidad y aumenta la estabilidad y compatibilidad (y portabilidad, por ejemplo, a ARM - y modularidad, ya que las capacidades de depuración de bajo nivel se implementan detrás de KdXxxPacket y podrían reemplazarse con una implementación personalizada). Además, la presencia de un depurador de kernel en el arranque (aunque "falso") hace que Windows deshabilite PatchGuard.
Por el momento, BugChecker requiere un teclado PS/2 para entrada y un framebuffer lineal para escribir su salida. Tenga en cuenta que el teclado incorporado de muchos portátiles modernos sigue siendo PS/2.
Características
Soporte para Windows XP a Windows 11, x86 y x64, y kernels SMP. Soporte para procesos WOW64 en x64.
Integración de QuickJSPP, que es un puerto de QuickJS a MSVC++. Antes de llamar a QuickJS, BugChecker guarda el estado de la FPU (en x86) y cambia a una pila expandida de 128KB.
Los comandos aceptan expresiones JS. Por ejemplo, "U rip+rax*4" y "U MyJsFn(rax+2)" son comandos válidos. Se pueden definir funciones personalizadas en la Ventana de Scripts. Las variables de registro de la CPU se declaran automáticamente como variables de ámbito global por BugChecker.
Soporte para archivos de símbolos PDB. Los archivos PDB se pueden especificar manualmente o Symbol Loader puede descargarlos desde un servidor de símbolos.
El código JavaScript puede llamar a las siguientes funciones asíncronas: WriteReg, ReadMem, WriteMem.
Los puntos de interrupción pueden tener una condición JS: si la condición se evalúa como 0, no se produce "breakin". Esto permite establecer "Logpoints" y puntos de interrupción que pueden cambiar el flujo de ejecución.
La ventana de registro muestra los mensajes enviados al depurador de kernel (por ejemplo, mensajes DbgPrint).
Ventana JavaScript con resaltado de sintaxis.
La tecla de tabulación permite, dados pocos dígitos, recorrer todos los números hexadecimales en pantalla o, dados pocos caracteres, recorrer todos los símbolos que contienen esos caracteres.
EASTL y las corrutinas de C++20 hacen que crear nuevos comandos sea muy sencillo. ¡No dudes en enviar tus pull requests!
Videos (Youtube)
Demostración de BugChecker en Windows 11 22H2, dentro de VirtualBox 7.0.4. Se escribe una condición de punto de interrupción en JavaScript que cambia el flujo de ejecución en un hilo de modo usuario.
BugChecker ejecutándose en un entorno muy limitado: una Raspberry Pi 4 (4GB RAM), a través de QEMU en Windows XP (512MB RAM). Se usa un punto de interrupción para registrar todas las llamadas SYSENTER del modo usuario al kernel. El índice de servicio se almacena en un array de JavaScript.
Ejecutando BugChecker directamente sobre el hardware, en un HP Pavilion Dv2000, un PC antiguo con teclado PS/2. El sistema operativo es Windows 7 Home 32 bits.
Instrucciones de instalación
Introducción
Asegúrate de que Secure Boot esté desactivado al instalar y usar BugChecker. Normalmente puedes volver a habilitarlo más tarde. Si usas VMware o VirtualBox, Secure Boot se puede desactivar en la configuración de la máquina virtual.
Considera también habilitar el menú de arranque heredado, si usas Windows 8, 10 u 11, usando el comando: bcdedit /set "{current}" bootmenupolicy legacy. Permite una experiencia más fluida durante el arranque, permitiendo seleccionar la opción de arranque de BugChecker y deshabilitar la aplicación obligatoria de controladores al mismo tiempo.
Instrucciones
El primer paso es iniciar Symbol Loader:
Si es necesario, desactiva los controladores de pantalla haciendo clic en el botón "Disable Display Drvs". Lo mismo se puede lograr en el Administrador de dispositivos de Windows. Una vez que los controladores de pantalla se han desactivado, permanecen desactivados incluso después de reiniciar el sistema. Se pueden volver a habilitar en cualquier momento cuando no se use BugChecker.
La cuestión aquí es que BugChecker necesita un framebuffer lineal con un formato de 32 bits por píxel para dibujar su interfaz. Al desactivar los controladores de pantalla, Windows descarta la aceleración de hardware para dibujar su interfaz de usuario y vuelve al modo de compatibilidad VGA. Si se ejecuta en hardware real o VMware, se deben desactivar los controladores de pantalla. Si se ejecuta en VirtualBox, se deben desactivar los controladores de pantalla o configurar el ajuste vm_screen en BugChecker.dat, como se describe a continuación. Si se ejecuta en QEMU, no es necesario desactivar los controladores de pantalla, pero asegúrate de especificar el dispositivo de visualización "-vga std".
Ten en cuenta que el modo de compatibilidad VGA podría limitar la resolución máxima de la pantalla. VMware está limitado a una resolución máxima de 1152x864. QEMU con el dispositivo de visualización "-vga std" no sufre esta limitación.
Curiosamente, si BugChecker está instalado en un sistema con más de una tarjeta gráfica, es posible desactivar los controladores de pantalla de solo una tarjeta gráfica, que será la tarjeta conectada a la pantalla que mostrará la interfaz de BugChecker. La segunda tarjeta (configurada como pantalla principal) conservará todas sus funciones de aceleración 2D y 3D, incluido el soporte OpenGL y DirectX (NOTA: probado en VMware, con Windows 11 y una pantalla DisplayLink).
Luego haz clic en "Start Driver", luego en "Auto Detect" y finalmente en "Save". "Auto Detect" debería poder determinar automáticamente el ancho, alto, dirección física y stride del framebuffer. Sin embargo, puedes especificar estos ajustes manualmente (no olvides hacer clic en "Save" al terminar). Si "Stride" es 0, se calcula como "Width" * 4 automáticamente al iniciar el controlador. La "Address" (es decir, la dirección física del framebuffer) se puede obtener en el Administrador de dispositivos de Windows, haciendo clic en "Propiedades" del dispositivo de pantalla, en la pestaña "Recursos".
Luego haz clic en "Callback" en la sección "KDCOM Hook Method", luego en "Copy/Replace Kdcom" y finalmente puedes reiniciar el sistema.
Este proceso de configuración solo debe hacerse una vez y los controladores de pantalla se pueden volver a habilitar si es necesario. Sin embargo, al usar BugChecker, los controladores de pantalla deben desactivarse nuevamente, si tu configuración lo requiere.
Configuración vm_screen para VirtualBox (Experimental)
El ajuste vm_screen en BugChecker.dat permite abrir la interfaz de depuración de BugChecker en VirtualBox sin especificar de antemano una resolución de pantalla en Symbol Loader y sin desactivar los controladores de pantalla.
La idea es escribir directamente en los puertos de E/S y en el búfer de comandos del dispositivo de visualización virtual para obtener la resolución de pantalla actual y notificar al hipervisor cualquier actualización en el framebuffer.
Esta solución solo funciona para máquinas virtuales de VirtualBox y editando manualmente el archivo BugChecker.dat:
En Symbol Loader, establece manualmente el ancho y alto del framebuffer a la resolución máxima posible (es decir, las dimensiones de la pantalla de tu ordenador). Establece el stride a 0.
El archivo BugChecker.dat es creado por Symbol Loader en "C:\Windows\BugChecker".
El ajuste vm_screen debe añadirse bajo "settings->framebuffer".
La jerarquía de los ajustes en este archivo está determinada por los caracteres de tabulación (no espacios).
El formato del ajuste es Command_Buffer_Start_Address (coma) Command_Buffer_End_Address (coma) I/O_Port_Base
IMPORTANTE: En la configuración de la VM, en Pantalla, selecciona "VBoxSVGA" como Controlador gráfico y desmarca "Habilitar aceleración 3D".
Esta es una función experimental. En el futuro, este ajuste se agregará automáticamente mediante Symbol Loader.
Comandos implementados
El nombre y la sintaxis de los comandos se eligen para ser lo más cercanos posibles a los del SoftICE original para NT:
? expresión-javascript: Evalúa una expresión javascript.
ADDR eprocess: Cambia al contexto del proceso (devuelve el control al SO).
BC lista|*: Borra uno o más puntos de interrupción.
BD lista|*: Desactiva uno o más puntos de interrupción.
BE lista|*: Activa uno o más puntos de interrupción.
BL (sin parámetros): Lista todos los puntos de interrupción.
BPX dirección [-t|-p|-kt hilo|-kp proceso] [WHEN expresión-js]: Establece un punto de interrupción en la ejecución.
CLS (sin parámetros): Limpia la ventana de registro.
COLOR [normal bold reverse help line]|[reset]: Muestra, establece o restablece los colores de la pantalla.
DB/DW/DD/DQ [dirección] [-l len-en-bytes]: Muestra la memoria como valores de 8/16/32/64 bits.
EB/EW/ED/EQ dirección -v valores-separados-por-espacios: Edita la memoria como valores de 8/16/32/64 bits.
KL EN|IT: Establece la distribución del teclado.
LINES [número-filas]: Muestra o establece el número actual de filas de la pantalla.
MOD [-u|-s] [cadena-búsqueda]: Muestra información del módulo.
P [RET]: Ejecuta un paso de programa.
PAGEIN dirección: Fuerza a que una página de memoria sea paginada (devuelve el control al SO).
PROC [cadena-búsqueda]: Muestra información del proceso.
R nombre-registro -v valor: Cambia el valor de un registro.
STACK [puntero-pila]: Escanea la pila buscando direcciones de retorno.
T (sin parámetros): Traza una instrucción.
THREAD [-kt hilo|-kp proceso]: Muestra información del hilo.
U dirección|DEST: Desensambla instrucciones.
VER (sin parámetros): Muestra información de la versión.
WD [tamaño-ventana]: Alterna la ventana del desensamblador o establece su tamaño.
WIDTH [número-columnas]: Muestra o establece el número actual de columnas de la pantalla.
WR (sin parámetros): Alterna la ventana de registros.
WS [tamaño-ventana]: Alterna la ventana de scripts o establece su tamaño.
X (sin parámetros): Sale de la pantalla de BugChecker.
Instrucciones de compilación
Requisitos previos
Visual Studio 2019
Windows Driver Kit 7.1.0
Nota: WDK debe instalarse en su ubicación predeterminada, es decir, X:\WinDDK, donde X es la unidad donde se guardan los fuentes de BugChecker.
Hay disponible una guía paso a paso para compilar el controlador del kernel aquí.
Descripción de los proyectos de Visual Studio
BugChecker: este es el controlador del kernel de BugChecker, donde se implementa la totalidad del depurador. Los archivos de salida "Release|x86" y "Release|x64" se incluyen en el paquete final. Durante la inicialización, el controlador carga su archivo de configuración en "\SystemRoot\BugChecker\BugChecker.dat" (todos los archivos de símbolos también se almacenan en este directorio) y luego intenta localizar "KDCOM.dll" en el espacio del kernel. Si lo encuentra, intenta llamar a su función exportada "KdSetBugCheckerCallbacks", enganchando así KdSendPacket y KdReceivePacket.
SymLoader: este es el Symbol Loader. Solo el archivo de salida "Release|x86" se incluye en el paquete final. Symbol Loader se utiliza para cambiar la configuración de BugChecker (la configuración se escribe en "\SystemRoot\BugChecker\BugChecker.dat"), descargar archivos PDB e instalar el módulo KDCOM.dll personalizado.
KDCOM: este es el módulo KDCOM.dll personalizado que NTOSKRNL carga al iniciar el sistema. Exporta la función "KdSetBugCheckerCallbacks" que el controlador llama para enganchar KdSendPacket y KdReceivePacket.
pdb: este es el proyecto "pdb" de Ghidra. La versión original genera el contenido de un archivo PDB en la salida estándar en formato xml. El código se modificó para generar un archivo BCS en su lugar.
NativeUtil: dado que Symbol Loader es una aplicación WOW64 en Windows x64, las llamadas a aquellas API que deben realizarse desde imágenes nativas de la arquitectura se trasladaron aquí (por ejemplo, las llamadas a la API de instalación de dispositivos y controladores).
HttpToHttpsProxy: esta es una aplicación ASP.NET Core cuya función es actuar como proxy de internet para Symbol Loader cuando se ejecuta en Windows XP. Dado que XP tiene soporte TLS obsoleto, Symbol Loader no puede descargar archivos de un servidor de símbolos arbitrario. Después de implementar esta aplicación en un IIS en la misma red, es posible descargar archivos de un servidor de símbolos en Windows XP anteponiendo "http://<TU_DIRECCIÓN_IPSERVIDOR_IIS>/HttpToHttpsProxy/" a la URL del servidor en Symbol Loader.
Créditos
VirtualKD: el primer POC de BugChecker se construyó modificando VirtualKD.
BazisLib: el código detrás del botón "Copy/Replace Kdcom + Add Boot Entry" en Symbol Loader es de VirtualKD y usa BazisLib.
EASTL: De ninguna manera se puede usar MSVC++ STL aquí. EASTL es una excelente alternativa.
Ghidra: el proyecto "pdb" en BugChecker es de Ghidra. Se modificó para generar archivos BCS.
Zydis: para la ventana del desensamblador en BugChecker.
QuickJSPP, que es un puerto de QuickJS a MSVC++: para el motor JavaScript integrado en el controlador del kernel.
ReactOS: para las definiciones de tipos internos de KD de Windows.
SerenityOS: para las funciones de manipulación de mapas de bits de bajo nivel utilizadas por el asignador de memoria de BugChecker. Dado que comencé BugChecker después de ver un video de Andreas (después de 10 años de abstinencia de C/C++ y cualquier tipo de programación de bajo nivel), quería incluir una pequeña pieza de SerenityOS en BugChecker.