Random IRC quote :      <garbanzosf> a mi papa no le huele el culo a curry

¿Por que son los handles de Windows multiplo de cuatro?

Voy a tratar de despejar esta incoginta, esta pregunta que desde el albor de los tiempos persigue al ser humano, y lo llena de dudas e inseguridad. Los mas grandes pensadores, desde Platon a Schopenhauer, han intentado arrojar algo de luz sobre el asunto, pero sin sin obtener exito alguno. Aqui y ahora intentare abordar una vez mas este problema. Intentare, de una vez por toda, solventar esta duestion que oprime nuestros corazones y agita nuestras almas.

Si tuviesemos que dar una respueta rapida, la respuesta seria que los handles de Windows no son siempre multiplo de cuatro. Un ejemplo evidente son los llamados pseudohandles. Con pseudohandles me refiero a los handles virtuales que representan el proceso actual y el hilo actual, que se pueden obtener en user mode con las llamadas a las funciones GetCurrentProcess y GetCurrentThread, y que son respectivamente -1 y -2. Estos pseudohandles son validos desde el punto de vista de Windows y es el propio Objet Manager el que tiene constancia su existencia y los gestiona adecuadamente. Con esto quiero decir que estos pseudohandles son validos y se pueden usar en llamada a funciones del kernel tales como ObReferenceObjectByHandle.

Hay que diferenciar estos pseudohandles de otros handles virtuales como los que sirven por ejemplo para representar la entrada o la salida estandar. Este tipo de pseudohanles existen solo como parte de una implementación concreta y deben ser transformados en handles reales para poder interactuar con el sistema operativo (Con sistema operativo me estoy refiriendo en este caso «De la ntdll pa’bajo»)

Bien. Existen los pseudohandles y no son multiplo de cuatro. Pero, hay handles «reales», que en esencia son una entrada en una tabla de handles asociada al proceso (O al kernel, que tambien tiene su propia tabla ), y todos parecen ser multiplo de cuatro, como por ejemplo 0x4f4. ¿Por qué? Pues la respuesta es sencilla. Esta caracteristica se debe a una decision de implementacion.
Tabla de Handles de Windows
Si revisamos la implementacion de la tabla de handles de Windows veremos que se trata de una tabla con tres niveldes de indentación, en los que se usa 8 bits por nivel. Esto le da 24 bits para reprsentar handles. O lo que es lo mismo, el numero de handles de un proceso esta limitado a 16 millones. De esos ocho bits restantes del handle, dos de ellos quedan definidos para ser usados por los usuarios, y los otros seis permanecen indefinidos. Daros cuenta que en el primer caso es una decision de diseño, mientras en el segundo caso es una decision de implementacion. Pero, hay una excepcion. Uno de esos bits indefinidos, que se corresponde con el de mayor preso del handle, tiene un significado especial, puesto que indica si el handle pertenece a la tabla de handles del proceso, o la tabla de handles del Kernel. Este hecho es transparente para la implementación de la tabla de Handles en si misma, pero tiene implicaciones importantes para el Object Manager. Donde estan situados los siete bits restantes (2 reservados para el usuario mas cinco indefinidos): Los dos reservados para el usuario son los dos bits de menor peso del handle, mientras el resto de bits sin usar son los bits de mayor peso del handle exceputando el bit 31, cuyo significado he comentado antes.

Lo cierto es que la mayor parte de los sistemas de Windows que usan Handles no necesitan usar estos flags presentes en el Handle, por lo que estos bits se suelen dejar a 0, obteniendo los tipicos handles multiplo de cuatro. Hay excepciones como por ejemplo el registro de Windows, donde si se usan estos bits. Concretamente la parte del Registro implementada en User Mode usa el bit 0 para indicar si la clave hace referencia al registro local o a un registro de una maquina remota, y usa el bit 1 para indicar si se trata de una clave asociada a HKCR (Recordad que tanto el acceso remoto a claves como la entra HKCR están implementados en User Mode. Quizas este segundo punto no sea muy conocido. HKCR es una «clave virtual» que nos muestra de forma unificada información que se encuentra presente en diversos puntos del registro). Notad tambien que la gestión de estos flags hace necesaria una funcion especifica de cierre (RegCloseKey en vez de CloseHandle), y requiere, por claridad, de la definicion de un «handle de registro», HKEY, pero que en esencia no es mas que un handle.
Y esto es to to todo amigos. Espero que vuestra curiosidad haya sido saciada!

5 Comentarios para “¿Por que son los handles de Windows multiplo de cuatro?”

  1. Comment por Karcrack | 08/26/10 at 7:22 am

    Interesantisimo, como siempre (:

  2. Comment por Ruben | 08/26/10 at 8:07 am

    Estoy con Karcrack, como siempre muy interesante.

  3. Comment por matalaz | 08/26/10 at 8:13 am

    Muy buena barbudo!

  4. Comment por José Antonio | 08/27/10 at 11:10 am

    Hace tiempo que sali de la escuela y me costo entender el articulo. Me acorde de mis clases de sistema operativo. Muy buen articulo y tambien muy buen blog, desde hace tiempo lo tengo en el morning coffe de firefox.

  5. Comment por inocraM | 08/29/10 at 6:43 am

    /*++

    Bueno, gracias por los comentarios. Pero no se si os habeis parado a pensar las implicaciones de lo que explico en esta entrada. Algunas de las implicaciones son solo visibles en Kernel Mode, pero para otras es de espera esperar que tengan un impacto directo en User Mode. Pensemos que tenemos dos bits que son reservados para el usuario. Si para el handle que representa un tipo de objeto concreto no se usan esos bits, ¿Deberian validar que esten a 0? Puede que desde el punto de vista de la seguridad (y de la corrección explicita) si se debería validar. Pero desde el punto de vista de la escalabilidad es mejor no validarlos (Aunque a mi juicio si deberia documentarse esta circunstancia). Si miramos este trozo de código:

      Event = CreateEvent(NULL, FALSE, FALSE, NULL);
      if(Event != NULL)
      {
        Event = (HANDLE)((ULONG_PTR)Event + 1);
        WaitForSingleObject(Event, INFINITE);
        CloseHandle(Event);
      }
    

    ¿La llamada al WaitForSingleObject tendra exito?

    Ahora mismo me estoy acordando el magnifico exploit de Ruben Santamarta en el que intentaba conseguir un hande valido por fuerza bruta. Lo bueno es que si estamos en esa tesitura, dependiendo del tipo de handle que necesitemos, ni siquiera estamos buscando un handle «estrictamente valido».
    Y en Kernel mode tenemos una situacion aun mas ventajosa para estos chicos malos :o)
    –*/

Se han cerrado los comentarios