domingo, abril 27, 2008

El caso del espacio en negro en Agregar o quitar programas

Uno de mis sistemas XP estaba experimentando un problema extraño: Al abrir Agregar o quitar programas noté un espacio de color negro bastante grande, con franjas de color blanco, entre dos programas. La siguiente captura de pantalla lo muestra:


Hace tiempo ya había analizado otro caso parecido. En aquella ocasión se mostraba un espacio enorme en blanco, y eso se debe a que la ruta del icono a mostrar contiene un "-1". (La función ExtractIcon devuelve el tamaño total de iconos disponibles en el ejecutable si se le pasa como índice para el icono un "-1").

Así pues, lo primero que hice fue descubrir qué aplicación era la culpable de ese espacio enorme en color negro. Lo que hice en primer lugar es anotar cuidadosamente la lista de aplicaciones que se mostraban correctamente y comparé dicha lista con la de la clave de Registro HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall. La aplicación que faltaba, y por tanto culpable de ese espacio en negro resultaba ser TI-Graph Link, perteneciente a una calculadora gráfica de Texas Instruments. Decidí investigar un poco más en detalle para desvelar el misterio.


Por diseño, la herramienta Agregar o quitar programas obtiene los iconos de las aplicaciones de la lista de dos maneras:


  • Si un valor DisplayIcon está presente en la subclave correspondiente de Uninstall, lo usará preferentemente.

  • Si no hay valor DisplayIcon, intentará obtener el icono desde la ruta del ejecutable del programa.

Se trataba del segundo caso, así que arranqué Process Monitor (http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx?PHPSESSID=d926bdd849b5aab10f7263dd7f5904f2) y establecí como filtro la ruta ejecutable del programa de la calculadora gráfica.


¿Qué tiene de especial ese ejecutable? Al examinarlo un poco, observé que se trata de un ejecutable de 16 bits. Según la documentación de MSDN, ExtractIcon no soporta la extracción de iconos desde ejecutables de 16 bits, así que empecé a sospechar.


Desde el propio shell de Windows intenté cambiar el icono de un acceso directo a la aplicación y seleccioné el icono que ocupa la posición 0 dentro del ejecutable. Aparentemente se veía correctamente, pero recordé rápidamente que Agregar o quitar programas extrae un icono pequeño (10x10) para mostrarlo en la lista. Lo que hice, pues, es cambiar la vista de la carpeta a Lista, para así forzar la extracción de un icono pequeño. ¡Bingo!, el resultado fue el de la siguiente captura de pantalla:



Al parecer, la función de extracción de iconos tiene problemas para proporcionar un icono de tamaño pequeño para el recurso que ocupa el índice 0 del ejecutable. Como quería investigar un poco más, primero me aseguré de qué función se trata. Para ello, seleccioné con el botón derecho una de las entradas del listado de Process Monitor y pulsar sobre Stack con el objetivo de visualizar la pila de llamadas del proceso Rundll32.exe encargado de abrir la herramienta Agregar o quitar programas.

La función que me llamó la atención fue ExtractIconFromEXE, así que decidí empezar a depurar desde ahí.


Al abrir el ejecutable en Windbg, establecí el correspondiente breakpoint y ejecuté. Como esa función es llamada para diferentes programas de la lista, tuve que idear una forma que me permitiera saber cuándo había llegado al punto en el que se extrae el icono del ejecutable de la calculadora. Como la función recibe un handle al ejecutable, con Process Explorer examiné la lista de handles hastá que vi por ahí el ejecutable en cuestión, tal y como se muestra en la imagen.


Cuando llegué al breakpoint, examiné la pila con el comando dd esp:


0:000> g

Breakpoint 0 hit

eax=00005a4d ebx=00000000 ecx=00000000 edx=7c91eb94 esi=7c810760 edi=10000080eip=7e3a325a esp=0007d25c ebp=0007d6cc iopl=0 nv up ei pl zr na pe nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246

USER32!ExtractIconFromEXE:7e3a325a 6a38 push 38h

0:000> dd esp

0007d25c 7e3a2f7d 000003e8 00000000 00000010

0007d26c 00000010 0007d74c 00000000 00000001

0007d27c 00000000 00000000 00000000 0007d74c

0007d28c 3df27be2 01c8a88b 00000000 011afd3c

0007d29c 0000000c 00000000 0007d74c 000003e8

0007d2ac 003a0043 0041005c 00630072 00690068

0007d2bc 006f0076 00200073 00650064 00700020

0007d2cc 006f0072 00720067 006d0061 005c0061


El primer valor, 7e3a2f7d, es la dirección de retorno; el siguiente, el primer parámetro, y así sucesivamente. Como puede ver, el tamaño del icono es 10x10, que corresponde al tercer y cuarto parámetro de la función. ¿Qué ocurriría si la función en lugar de pedir un icono 10x10 pidiese uno 20x20, por ejemplo? Según las pruebas que hice anteriormente con la función Cambiar icono, debería funcionar, pues es solo la extracción de iconos pequeños la que falla.


Para modificar el contenido de una posición de memoria, puede usar el comando del depurador ed dirección contenido. Tenga mucho cuidado, pues si modifica posiciones de memoria puede hacer que el programa que está siendo depurado no haga lo que debe.


0:000> ed esp+c 20


0:000> ed esp+10 20


0:000> dd esp


0007d25c 7e3a2f7d 000003e8 00000000 00000020


0007d26c 00000020 0007d74c 00000000 00000001


0007d27c 00000000 00000000 00000000 0007d74c


0007d28c 3df27be2 01c8a88b 00000000 011afd3c


0007d29c 0000000c 00000000 0007d74c 000003e8


0007d2ac 003a0043 0041005c 00630072 00690068


0007d2bc 006f0076 00200073 00650064 00700020


0007d2cc 006f0072 00720067 006d0061 005c0061


Una vez modificado el tamaño de icono pedido, dejé que la aplicación se ejecutara completamente y este fue el resultado obtenido:


¡Bingo! Ya pude confirmar que un icono un poco más grande es extraído correctamente.

En resumen:


  • Agregar o quitar programas tiene que extraer un icono para cada uno de los programas que conforman la lista de programas instalados.

  • La función implicada es ExtractIconEx, que, dependiendo del tipo de fichero (EXE, DLL, ICO, etc.) llama a una u otra función. En el caso de ejecutables se trata de la función ExtractIconFromEXE (no documentada).

  • La documentación nos indica que no se soporta la extracción de iconos de ejecutables NE (16 bits). En nuestro caso, la extracción del icono de índice 0 del ejecutable en tamaño pequeño (10x10) es defectuosa. Agregar o quitar programas por diseño quiere obtener un icono 10x10.

  • Al "forzar" la extracción de un icono un poco mayor (20x20), todo funciona correctamente.

Una vez desvelado el misterio, me puse en contacto con el fabricante para ver si había disponible alguna actualización para su software (que ya no fuera de 16 bits, a ser posible).


¡Caso cerrado!

domingo, abril 06, 2008

Procesos "inmortales" en Windows XP

Si ha "jugueteado" alguna vez con la pestaña Procesos de Administrador de tareas en Windows XP, probablemente haya notado que, si intenta terminar alguno de los procesos críticos del sistema (aquéllos que si finalizan inesperadamente reiniciarán automáticamente el sistema, a saber: Csrss.exe, Winlogon.exe, Smss.exe, Services.exe y Lsass.exe), le aparecerá este mensaje de error:

Éste es un proceso de sistema crítico. El Administrador de tareas no puede finalizar este proceso.

Sin embargo, si su sistema se infecta con un virus cuyo ejecutable tenga el mismo nombre de alguno de esos procesos esenciales -muchos ejecutables de virus tienen alguno de esos nombres-, tampoco podrá terminarlo desde Administrador de tareas. Mi opinión es que como Administrador de tareas es una aplicación que se diseñó hace más de 10 años, no se tuvo en cuenta la posibilidad de que el software malicioso pudiera ocultarse del usuario usando los nombres de procesos críticos del sistema, así que es probable que lo que Administrador de tareas haga es simplemente una comparación textual. De hecho, usted mismo puede hacer la prueba: Renombre un ejecutable cualquiera de su sistema a "Smss.exe" (por ejemplo), y ejecútelo. Si lo intenta matar desde Administrador de tareas, no podrá, le aparecerá el mensaje de error comentado anteriormente.

Parece ser que en Windows Vista la gente de Microsoft ha "cortado por lo sano" y ya no se hace la comprobación de si el proceso que el usuario quiere terminar es un proceso crítico del sistema o no. Se considera que Administrador de tareas es un programa usado en su mayoría por usuarios avanzados, que saben o deberían saber lo que hacen.

Esta es otra pequeña ventaja, entre muchas otras, de Process Explorer sobre Administrador de tareas. Puede descargar Process Explorer desde el sitio web de Technet: http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx.