Tutorial sobre Windbg [Parte II]

En la primera parte de esta serie de artículos aprendió a instalar Windbg y a configurar un aspecto básico, los símbolos de depuración. En este artículo veremos cómo configurar otros aspectos menores de Windbg, pero que le pueden resultar necesarios, y depuraremos la primera aplicación en modo usuario.

Configurar la ruta de código fuente

Si está depurando una aplicación que no haya desarrollado, es probable que no disponga del código fuente de la misma; sin embargo, si estuviera depurando una aplicación de la que dispone el código fuente, es muy buena idea configurar Windbg para que sea capaz de usar toda esa información y mostrar la ejecución paso a paso en formato de instrucciones de código fuente, no instrucciones máquina. Para configurar este aspecto, despliegue el menú File, Source File Path (o pulse Ctrl+P). También puede usar el comando .srcpath <Ruta_código_fuente>

Para que el depurador muestre instrucciones de código fuente y no instrucciones máquina es necesario además que los símbolos de depuración contengan información acerca del fichero fuente y número de línea que se corresponde con un determinado símbolo. Estos símbolos, denominados normalmente símbolos privados, no suelen estar a disposición de los usuarios ajenos a la empresa creadora del software en cuestión.

Configurar la ruta de los módulos

En la mayoría de ocasiones, Windbg es capaz por sí solo de encontrar las imágenes de los ejecutables implicados en una sesión de depuración. En determinados casos, como por ejemplo cuando se está depurando un volcado de memoria pequeño o minidump (la depuración de volcados de memoria se tratará en un posterior artículo), es necesario indicarle al depurador dónde debe buscar los módulos (.exe, .dll, .sys, etc.). Para ello, abra File, Image File Path (o pulse Ctrl+I). Como siempre, si desea lograr esto mediante un comando de Windbg, ejecute .exepath <Ruta_ejecutables>

Ejecutar una aplicación dentro del depurador

Ya está en condiciones de depurar su primera aplicación en Windbg y para ello vamos a ejecutar la calculadora de Windows dentro de Windbg.

Abra File, Open Executable (o pulse Ctrl+E) y busque el ejecutable Calc.exe dentro del directorio \Windows\system32\. En este caso deje desmarcada la casilla Debug child processes also, que sirve para depurar no solo el proceso principal que cree ese ejecutable sino sus procesos hijos también. Haga clic sobre Abrir.

La pantalla de Windbg se rellenará con un texto similar al siguiente:

Microsoft (R) Windows Debugger Version 6.11.0001.404 X86
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: C:\WINDOWS\system32\calc.exe
Symbol search path is: SRV*c:\websymbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
ModLoad: 01000000 0101f000   calc.exe
ModLoad: 7c910000 7c9c5000   ntdll.dll
ModLoad: 7c800000 7c903000   C:\WINDOWS\system32\kernel32.dll
ModLoad: 7e6a0000 7eec1000   C:\WINDOWS\system32\SHELL32.dll
ModLoad: 77da0000 77e4c000   C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 77e50000 77ee2000   C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 77fc0000 77fd1000   C:\WINDOWS\system32\Secur32.dll
ModLoad: 77ef0000 77f39000   C:\WINDOWS\system32\GDI32.dll
ModLoad: 7e390000 7e421000   C:\WINDOWS\system32\USER32.dll
ModLoad: 77be0000 77c38000   C:\WINDOWS\system32\msvcrt.dll
ModLoad: 77f40000 77fb6000   C:\WINDOWS\system32\SHLWAPI.dll
(23c.24c): Break instruction exception - code 80000003 (first chance)
eax=001a1eb4 ebx=7ffdb000 ecx=00000007 edx=00000080 esi=001a1f48 edi=001a1eb4
eip=7c91120e esp=0007fb20 ebp=0007fc94 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!DbgBreakPoint:
7c91120e cc              int     3

Analicemos detalladamente toda esta información:

La línea CommandLine nos está indicando el archivo que vamos a ejecutar dentro de Windbg, en este caso la calculadora de Windows. A continuación se muestra la ruta establecida para los símbolos y la ruta de búsqueda de módulos ejecutables, que en este caso está vacía porque no la hemos establecido desde la opción File, Image File Path. Seguidamente el depurador ha registrado información sobre la carga de una serie de módulos de los que depende la calculadora de Windows. Para ver las dependencias de un módulo yo recomiendo usar la herramienta Dependency Walker (http://www.dependencywalker.com/).

La siguiente línea, (23c.24c): Break instruction exception – code 80000003 (first chance), da pie a comentar bastantes cosas:

La sintaxis (23c.24c) la va a encontrar no pocas veces en Windbg. Hace referencia a un hilo dentro de un proceso. 23c es el identificador de proceso (PID), en formato hexadecimal. En este caso es el PID del proceso Calc.exe. 24c hace referencia al identificador de hilo (TID), en formato hexadecimal también. La excepción recibida en este caso es “Break instruction” (STATUS_BREAKPOINT), identificada por el código hexadecimal 0x80000003. Vamos a ver qué ocurre “por lo bajo” para explicar por qué ha ocurrido esto:

Cuando hemos seleccionado el ejecutable Calc.exe y hemos hecho clic sobre Abrir, Windbg ha llamado a la API CreateProcess con el sexto parámetro establecido a DEBUG_PROCESS. Esto permite crear un proceso e indicarle a Windows que deseamos depurarlo. Pero depurar un proceso requiere de algo más. Requiere que el programa depurador reciba una serie de eventos procedentes de la ejecución de la aplicación y los muestre al usuario o los trate de manera conveniente. Lo que ocurre durante una sesión de depuración se puede entender como un bucle en el cual el depurador espera eventos de depuración mediante la API WaitForDebugEvent, los trata de manera conveniente, y continua la ejecución del programa mediante la API ContinueDebugEvent. Este bucle se repite indefinidamente hasta que o bien la aplicación que está siendo depurada desaparece de la memoria, o bien finaliza correctamente su ejecución, o bien desacoplamos el depurador mediante el comando Debug, Detach Debugee.

La frase (first chance) hace referencia al comportamiento de las excepciones. Cuando una aplicación genera una excepción y está siendo depurada, el depurador recibe una excepción de primera oportunidad (first chance) y le da la opción de tratarla. En este caso, el depurador trata la excepción STATUS_BREAKPOINT deteniendo la ejecución de la aplicación permitiendo que el usuario introduzca comandos o examine el estado de la imagen de memoria del proceso y el estado del procesador. Si el depurador no capturase la excepción, se comprueba si el código de la aplicación la capturara. Este procedimiento implica verificar en la pila de ejecución si hay algún código manejador de excepciones, desde el marco de activación más reciente hasta al más antiguo. Este procedimiento recibe técnicamente el nombre de stack unwinding. No se preocupe, en posteriores artículos se va a tratar la estructura de datos conocida como pila, pues es de capital importancia a la hora de entender buena parte de la información que nos proporcione Windbg. En caso de que el código no capturase la excepción, se lanza al depurador una excepción de segunda oportunidad (second chance) y se vuelve a comprobar si el código captura la excepción.

Lo que aparece a continuación en la pantalla de Windbg es el estado de los registros del procesador. Para entender esta parte de la salida es necesario disponer de ciertos conocimientos específicos de la máquina que está siendo depurada. En este caso se trata de la arquitectura x86, por lo que la referencia obligada es este documento: http://download.intel.com/design/PentiumII/manuals/24319102.PDF. Cuando veamos algunos casos de estudio verá cómo aplicar la información sobre los registros de la máquina a un caso real.

Para finalizar nos aparece la última instrucción ejecutada en el procesador antes de que se pasara el control al depurador. En este caso se trata de una instrucción dentro de la función DbgBreakPoint dentro del módulo Ntdll.dll. La instrucción en cuestión es la instrucción int 3, identificada mediante el código hexadecimal CC. Esta instrucción lanza una interrupción software. El parámetro 3 indica que ejecutaremos la posición 3 del vector de interrupciones y básicamente se enviará la excepción STATUS_BREAKPOINT al depurador, para que haga con ella lo que considere oportuno. La dirección de memoria que contiene esa instrucción es la 7c91120e (en este ejemplo particular).

Para concluir, puede configurar Windbg para que no informe de ciertos eventos (tales como la finalización de un proceso, la carga de una DLL, etc.). Para ello puede ir al menú Debug, Event Filters.

Cuadro de diálogo Event Filter

Si desea hacer uso de la línea de comandos de Windbg, el comando en cuestión es sx y sus derivados sxe, sxd, sxi, sxn. En la documentación de Windbg (Help, About) puede obtener información adicional sobre el uso de estos comandos.

En este artículo hemos aprendido a configurar Windbg para comenzar una sesión de depuración y hemos ejecutado nuestra primera aplicación dentro del depurador. También hemos aprendido qué quiere decir la información que aparece en pantalla y en qué consiste “por lo bajo” la depuración de aplicaciones y el manejo de excepciones. En la siguiente parte veremos algunos comandos para examinar el estado de la máquina y del proceso que está siendo depurado. Se detallarán también algunos aspectos de la arquitectura interna de Windows que son importantes para saber realmente lo que está pasando.

5 thoughts on “Tutorial sobre Windbg [Parte II]

  1. Hola gracias por tus ayuda.

    Se ve muy bueno, aunque ay algunas cosas que no entiendo bien digamos sobre dependencias (software adicional o requerido para un optimo funcionamiento), o excepciones (detalles o instrucciones no disponibles ?).

    Bueno creo q se debe por mis primeros pasos en la universidad 🙂

    Saludos

Leave a Reply to Neo Cancel reply

Your email address will not be published. Required fields are marked *