[TUTORIAL] Reversing del controlador XignCode3 - Parte 3 - Análisis de la funcion

  • Hola Invitado, si deseas saber que es lo que paso con nuestro servidor de discord, puedes ingresar al siguiente enlace Discord


195
Me Gusta
68
Temas

c0de

MOV EAX, EDX
Registrado
19 Abr 2020
Mensajes
127
Ubicación
Localhost
Mejores respuestas
0
LV
0
 
1588820688518.png
Si no ha leído la publicación anterior, puede encontrarla aquí: Parte 2: análisis de las funciones de inicio . En esta publicación, finalmente analizaremos la función Dispatcher. Recuerde que identificamos esta función en la primera publicación . Esta función tiene el objetivo principal de procesar cualquier paquete de solicitud de E/S (IRP) y, en este caso, manejar cualquier solicitud del código de función principal IRP_MJ_WRITE.

¿Por lo que pasaremos?
  1. Aprenda cómo se implementan las rutinas de Dispatcher.
  2. Para revertir el método de análisis que maneja las solicitudes IRP_MJ_WRITE.
  3. Identifique estructuras personalizadas utilizadas por el controlador y cree nuevos tipos locales en IDA.
  4. Comprenda cómo el controlador distribuye los diferentes identificadores codificados atravesando una matriz con estructuras personalizadas.
Introducción

Al invertir las cosas relacionadas con Windows, la lectura de la documentación de MS debería ser obligatoria. Por lo general, proporcionan mucha información útil que le ahorrará mucho tiempo, como las estructuras que usan, los parámetros y los ejemplos de código. Algo que me gusta hacer es examinar los ejemplos disponibles en sus repositorios y buscar códigos similares. Los desarrolladores de controladores suelen reutilizar una gran cantidad de código de esos ejemplos. Buscar patrones similares en nuestro binario podría proporcionarnos mucha información sobre el contexto y las funciones a las que se llama dentro de un fragmento de código similar. Al final de esta publicación, encontrará una lista de enlaces útiles.

fn_DriverIOCTLDispatcher (0x140004604)

Primero, tome unos minutos para analizar el código descompilado inicial aquí y el ensamblado . Un controlador puede proporcionar múltiples rutinas de despacho, en este caso, implementaron solo un código de función principal, como vimos antes.

Si quieres hacer trampa un poco, aquí está el código final .

Podemos ver que recibe dos parámetros, pero ¿sabemos cuáles son esos parámetros? Sí, la documentación de MS explica que las funciones del despachador IRP_MJ_WRITE reciben como primer parámetro un PDEVICE_OBJECT y como segundo un puntero a una estructura IRP (IDA identificará este por sí mismo).

1588820989256.png

En la línea 16, el controlador controla que la longitud del búfer de entrada es igual a 0x270 , parece que es la única longitud posible.

Tenga cuidado al analizar la siguiente línea:

C++:
v5 = a2->AssociatedIrp.MasterIrp;

Como puede ver a continuación, MasterIrp comparte el mismo desplazamiento con IrpCount y SystemBuffer dentro de una unión ( struct _IRP ):

C++:
union {
    struct _IRP     *MasterIrp;
    __volatile LONG IrpCount;
    PVOID           SystemBuffer;
  } AssociatedIrp;

En este caso, el Despachador está intentando recuperar el SystemBuffer de la solicitud de IRP; no hace referencia al puntero MasterIrp. Necesitamos arreglar eso adecuadamente. En IDA PRO, esto se puede hacer fácilmente haciendo clic derecho-> Seleccionar campo de unión:

1588821133250.png

Ahora que hemos identificado dónde se almacena el búfer de entrada, veamos cómo se analiza:

C++:
v5 = a2->AssociatedIrp.SystemBuffer;
if ( *(_DWORD *)v5 == 0x270 && *((_DWORD *)v5 + 1) == 0x345821AB )
{
sub_140001E00(v5, &v13);

Podemos ver que se espera que el primer DWORD sea igual a 0x270 (mismo valor de la longitud); Entonces, el siguiente DWORD debe tener algún tipo de valor mágico que coincida con 0x345821AB . Si se cumplen ambos requisitos, la función sub_140001E00 se llama enviando el búfer en el primer parámetro, y una referencia a una estructura aún desconocida en el segundo parámetro. Decidí llamar a esta función fn_DispatchIOCTLMethod y la analizaremos en la siguiente sección.

Después de cambiar el nombre de las variables, podemos concluir que la estructura del búfer de entrada sería algo como esto:

Código:
struct DrvInputBuffer
{
  _DWORD Size;                           // Offset 0x0
  _DWORD MagicNumber;                    // Offset 0x4
  _BYTE gap8[8];                         // Offset 0x8
  void *pvoid10;                         // Offset 0x10
};

Como todavía no estamos analizando todos los métodos de envío, pero quiero proporcionarle un análisis completo del búfer de entrada, le mostraré la estructura completa que está utilizando el controlador. La estructura final sería así:

C++:
struct DrvInputBuffer
{
  _DWORD Size;                           // Offset 0x0
  _DWORD MagicNumber;                    // Offset 0x4
  _DWORD RequestId;                      // Offset 0x8
  _DWORD FnIndex;                        // Offset 0xc
  void *pvoid10;                         // Offset 0x10
  unsigned __int8 buffer[600];           // Offset 0x18
};

Esta función hace algunas cosas más, pero ignorémoslas por ahora.

fn_DispatchIOCTLMethod (0x140001E00)

1588821221355.png

Esta función es pequeña, y veremos que después de configurar los tipos correctamente y cambiar el nombre, todo se vuelve mucho más claro.

Lo primero que deberíamos hacer es agregar la estructura previamente definida DrvInputBuffer a IDA Pro. En la subvista "Tipos locales", es posible hacer "Clic derecho-> Insertar", allí puede copiar y pegar la definición de estructura:

1588821332840.png

Siguiente paso, cambie el nombre del primer parámetro para que sea un puntero a esa estructura haciendo "clic derecho en la variable -> Convertir a estructura *".

Si ocultamos los moldes, obtendremos algo como esto:

C++:
__int64 __fastcall fn_DispatchIOCTLMethod(DrvInputBuffer *a1, __int64 a2)
{
  int v2; // er8

  v2 = 0;
  if ( !dword_14000A240 )
    return 3221225473i64;
  while ( dword_140009E40[4 * v2] != a1->FnIndex )
  {
    if ( ++v2 >= dword_14000A240 )
      return 3221225473i64;
  }
  return (*&dword_140009E40[4 * v2 + 2])(a1, a2);
}

Si ha leído las publicaciones anteriores, puede reconocer dword_14000A240. Cambiamos el nombre de esta variable en la segunda publicación, mientras analizábamos fn_InitDispatchMethodArray : esta era la variable FunctionsCount .

Lo mismo sucede con dword_140009E40, que se renombró a IOCTLFunctionArray en la misma publicación, y es una matriz que contiene múltiples estructuras DispatcherStruct :

C++:
00000000 DispatcherStruct struc ; (sizeof=0x10, mappedto_424)
00000000                                         ; XREF: .data:_IOCTLFunctionArray/r
00000000 Index           dd ?                    ; XREF: fn_InitDispatchMethodArray+1F/t
00000004 padding         db 4 dup(?)
00000008 FnPtr           dq ?
00000010 DispatcherStruct ends

En base a eso, podemos identificar el siguiente comportamiento: Primero, la aplicación valida que IOCTLFunctionArray se haya inicializado comparando FunctionsCount con NULL. Luego, itera en un ciclo while, comparando el valor del índice de cada elemento con el DWORD en el desplazamiento 0xC del búfer de entrada (definido en la estructura como FnIndex ). Aumentan el contador hasta que alcanza el valor máximo almacenado en FunctionsCount . Si hay una coincidencia entre los índices, la función almacenada en DispatcherStruct-> FnPtr es call; enviando los mismos dos parámetros de fn_DispatchIOCTLMethod: SystemBuffer y la referencia a una estructura aún desconocida.

Esta sería la función final:

C++:
__int64 __fastcall fn_DispatchIOCTLMethod(DrvInputBuffer *SystemBuffer, DrvOutputBuffer *a2)
{
  int counter; // er8

  counter = 0;
  if ( !FunctionsCount )
    return 0xC0000001i64;
  while ( IOCTLFunctionArray[counter].Index != SystemBuffer->FnIndex )
  {
    if ( ++counter >= FunctionsCount )
      return 0xC0000001i64;
  }
  return (IOCTLFunctionArray[counter].FnPtr)(SystemBuffer, a2);
}

Próximos pasos
  • Análisis de NotifyRoutines (fn_InitRegistrationNotifyAndCallbackRoutines y fn_RegisterCreateProcessNotifyRoutine)
  • Cargue estructuras de kernel con archivos .h y tipos locales
Enlaces útiles
Creditos
Niemand

Enlace de origen

Twitter
 

Adjuntos

  • 1588820679684.png
    1588820679684.png
    201,9 KB · Visitas: 0