Ir al contenido



Foto

Inyección directa de código en C y en delphi


  • Por favor identifícate para responder
17 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 23 septiembre 2009 - 11:00

En un momento dado, se me presentó la necesidad de escribir un código que liberase una librería dll de un proceso ajeno al mio. La solución mas directa que se me ocurrió fue liberarla con la misma técnica usada para inyectarla con CreateRemoteThread, pasándole como parámetros el Handle del proceso, la dirección de la API FreeLibrary y un buffer con el nombre completo de la dll. Ese buffer estaría en el espacio de direcciones del proceso en cuestión. En este punto he de aclarar que existen formas mucho mas sofisticadas de inyección que hoy no vienen al caso.

Mi sorpresa fue que no funcionó, cosa que si sucede con otras APIs como LoadLibrary o GetModuleHandle (y muchas mas). Entonces decidí realizar una inyección directa, es decir sin dlls, del código necesario para liberar la dll del proceso deseado.

Lo que aquí publico son las bases de la inyección directa de código, prescindiendo de dlls. He de aclarar que todo el código de este tutorial está escrito en C y es completamente funcional. Tenéis una descarga en delphi que he añadido a última hora, simplemente es la traducción del código expuesto en C implementado en una pequeña aplicación.

La primera cuestión a conocer son las API de manejo de memoria:
VirtualAllocEx: Nos localiza memoria en el espacio de direcciones de un proceso.
VirtualFreeEx: Libera la memoria localizada con VirtualAllocEx
WriteProcessMemory: Escribe en un bloque de memoria de otro proceso previamente localizada con VirtualAllocEx
GetProcAddress: Nos proporciona la dirección de una función exportada de una DLL
CreateRemoteThread: Crea un hilo en un proceso remoto.

Hasta aquí, es el conocimiento necesario para inyectar código, tanto con dll como de forma directa. Esto es válido tanto para C/C++ como para delphi.

Saludos.

Edito para resubir los archivos de ejemplo.

Archivos adjuntos


  • 0

#2 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 23 septiembre 2009 - 11:04

Al inyectar una dll, todo su contenido, código y variables, están en el espacio del proceso remoto, de eso se encarga el S.O. La inyección directa es mas artesanal, requiere subir al espacio de direcciones del proceso anfitrión, tanto de los datos, como del código que debe ejecutar.

El primer paso será definir una estructura de datos que debe contener todo lo necesario para que nuestro código funcione. Después se subirá al espacio de direcciones del proceso anfitrión con las conocidas APIs VirtualAllocEx y WriteProcessMemory.

Para el caso del ejemplo de este tutorial, la estructura la definiré así:


cpp
  1. struct TParamFL
  2. {
  3.     PGetModuleHandleA GetModuleHandleA; // Puntero a la API GetModuleHandleA
  4.     PFreeLibrary FreeLibrary;          // Puntero a la API FreeLibrary
  5.     char DllName[256];                  // Cadena que contendrá el nombre completo de la DLL a liberar
  6. };



Los datos de la estructura deberán ser inicializados convenientemente y copiados después en el espacio de direcciones del proceso remoto.

Ahora le toca el turno al código que queremos ejecutar:


cpp
  1. DWORD __stdcall InjFreeLibrary(TParamFL* P)
  2. {
  3.   // Retorna true cuando el módulo no existe en el proceso.
  4.   // En caso contrario, el modulo sigue cargado
  5.   HMODULE hModule = P->GetModuleHandleA(P->DllName);  // Localiza el HMODULE de la DLL
  6.   P->FreeLibrary(hModule);                            // Libera La DLL
  7.   return (P->GetModuleHandleA(P->DllName)==0);        // Si el modulo no existe, se descargó
  8. }



Esta función recibe como parámetro un puntero a nuestra estructura, y llamará a las APIs por sus direcciones contenidas en dicha estructura.

Solo falta subir el código al espacio de direcciones de nuestro proceso anfitrión. Para ello tendremos que calcular su tamaño en Bytes una vez compilado y enlazado, y su dirección de memoria. Esto se hará en tiempo de ejecución. Vamos a aprovecharnos de la función que escribiremos inmediatamente detrás para calcular el tamaño.  Si Func1 y Func2 son punteros a sendas funciones escritas consecutivamente, el tamaño binario de Fun1 es este:


cpp
  1. (UINT)Func2 - (UINT)Func1;


Pues con esto ya lo tenemos casi todo. Ni que decir tiene que esas funciones no se pueden cambiar de sitio en nuestros fuentes porque sino seria desastroso.

Saludos.
  • 0

#3 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 23 septiembre 2009 - 11:10

Vamos a ocuparnos del meollo de la cuestión. Colocar lo necesario en el espacio de direcciones del proceso remoto, ejecutarlo, recibir el resultado y limpiar los restos de la merienda. El siguiente código se encarga de todo ello:




cpp
  1. BOOL FarFreeLibrary(DWORD Pid, char* DllName)
  2. {
  3.   DWORD    ExitCode;
  4.   HANDLE  hThread = 0;
  5.   HANDLE  hProc;      // El handle del proceso en el que inyectaremos
  6.   TParamFL Param;      // El tipo de dato de la estructura
  7.   UINT    TamFun;    // El tamaño de la función a inyectar
  8.   void*    BFunc;      // Lugar de memoria donde copiaremos nuestra función
  9.  
  10.   //Metemos la dirección de las apis en la estructura
  11.   Param.FreeLibrary = (PFreeLibrary)GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "FreeLibrary");
  12.   Param.GetModuleHandleA = (PGetModuleHandleA)GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "GetModuleHandleA");
  13.   strcpy(Param.DllName, DllName);
  14.  
  15.   //Abrimos el proceso en el que nos inyectaremos
  16.   hProc = OpenProcess(PROCESS_ALL_ACCESS, false, Pid);
  17.  
  18.   //Reservamos espacio para nuestra estructura en el proceso a inyectar y la escribimos
  19.   void* BParam = VirtualAllocEx(hProc, 0, sizeof(TParamFL), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  20.   WriteProcessMemory(hProc, BParam, &Param, sizeof(TParamFL), NULL);
  21.  
  22.   //Calculamos el tamaño de la función a inyectar
  23.   TamFun = (UINT) FarFreeLibrary - (UINT)InjFreeLibrary;
  24.  
  25.   //Reservamos espacio para la función, escribimos en él y creamos un hilo
  26.   BFunc = VirtualAllocEx(hProc, 0, TamFun, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  27.   WriteProcessMemory(hProc, BFunc, InjFreeLibrary, TamFun, NULL);
  28.   hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)BFunc, BParam, 0, NULL);
  29.   if(hThread){
  30.     // Labores de limpieza...
  31.     WaitForSingleObject(hThread, INFINITE ); // Espero a que se termine de ejecutar el Thread
  32.     GetExitCodeThread(hThread, &ExitCode);  // Recojo el resultado
  33.     CloseHandle(hThread);                    // Cierro el Handle hThread
  34.     VirtualFreeEx(hProc, BParam, 0, MEM_RELEASE); // Libero memoria de parámetros
  35.     VirtualFreeEx(hProc, BFunc,  0, MEM_RELEASE); // Libero memoria del código
  36.   }
  37.  
  38.   CloseHandle(hProc);
  39.  
  40.   return (BOOL)ExitCode;
  41. }



Espero que halla sido de vuestro agrado y os sirva como base para desarrollos mas ambiciosos.

Saludos.
  • 0

#4 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 23 septiembre 2009 - 04:30

He migrado el código a delphi, está probado. Subo un ejemplo con una aplicación completa, pero sencilla. Para probarlo deberíais inyectar primero una dll a un proceso para luego liberarlo con el ejemplo. La liberacion indiscriminada de dlls a procesos puede hacerlos caer.

Creo que por la similitud de la implementación con lo expuesto en C y los comentarios, no hacen falta mas explicaciones  8-|. Pero si alguien las precisa... ;)

Saludos.

PD: Descarga en el primer mensaje.

Elimino link roto
  • 0

#5 c0lo

c0lo

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 241 mensajes
  • LocationLima-Peru

Escrito 18 marzo 2010 - 05:33

Muy bueno y super archi interesante.

Pero tengo una duda, podrias relanzar nuevamente el codigo de ejemplos que pusistes, ya que cuando descargo me sale que el archivo esta dañado.... o es problema de mi PC y conexion?
  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.812 mensajes
  • LocationMéxico

Escrito 18 marzo 2010 - 05:44

Hola, a reserva y mientras nuestro amigo escafandra pasa por aquí, tengo el archivo para Delphi, el de C++ no lo encontré.

Salud OS
  • 0

#7 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 18 marzo 2010 - 06:27

Bueno parece que los duendes hicieron de nuevo de las suyas... :p

He resubido el el primer mensaje los dos archivos, para que quede ordenado.

Saludos.
  • 0

#8 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.812 mensajes
  • LocationMéxico

Escrito 18 marzo 2010 - 06:28

Pues si, vaya joda que nos dió ésta última migración, siento mucho los problemas ocasionados :(

Salud OS
  • 0

#9 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 18 marzo 2010 - 06:51

Pues si, vaya joda que nos dió ésta última migración, siento mucho los problemas ocasionados :(


Caramba, parece que fue culpa tuya, pues no fue así, amigo. No tienes porqué disculparte.  :D

Saludos.

  • 0

#10 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.812 mensajes
  • LocationMéxico

Escrito 18 marzo 2010 - 06:58


Pues si, vaya joda que nos dió ésta última migración, siento mucho los problemas ocasionados :(


Caramba, parece que fue culpa tuya, pues no fue así, amigo. No tienes porqué disculparte.  :D

Saludos.


Bueno, es que lo que no sabes es que yo hice el backup y el restore :s :D :D :D.

Salud OS
  • 0

#11 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 18 marzo 2010 - 07:07

Bueno, un pequeño fallo lo tiene cualquiera.  :D

Saludos.
  • 0

#12 xblade2k10

xblade2k10

    Newbie

  • Miembros
  • Pip
  • 1 mensajes

Escrito 28 julio 2012 - 05:09

andaba buscando algo similar a esto, muchas gracias por la migracion a delphi.
  • 0

#13 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 28 julio 2012 - 06:47

Bienvenido xblade2k10.

Saludos.
  • 0

#14 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 02 enero 2015 - 03:08

Cinco años después de la publicación de este tutorial, me he enterado, navegando por la web, que el código que expuse en C/C++ está reproducido con pelos y señales en la web http://www.indetectables.net formando parte de un tutorial prácticamente plagiado. Si bien tienen la decencia de nombrarme, el enlace que ponen no es del todo exacto, pues apunta a la segunda parte del tutorial y no a este código concreto.

Os dejo el enlace donde lo encontré: http://www.indetecta...t=20851#p171958 así juzgáis vosotros mismos.

Un saludo.
  • 0

#15 azdin

azdin

    Member

  • Miembros
  • PipPip
  • 20 mensajes

Escrito 18 octubre 2015 - 12:38

Interesante... Pero al ejecutar el .exe y inyectar un Dll normal en el Notepad no me anda.
y al ver el codigo...


delphi
  1. WriteProcessMemory(hProc, BParam, @Param, sizeof(TParamFL), BytesWritten);

[dcc32 Error] Unit1.pas(83): E2033 Types of actual and formal var parameters must be identical


delphi
  1. WriteProcessMemory(hProc, BFunc, @InjFreeLibrary, TamFun, BytesWritten);

[dcc32 Error] Unit1.pas(90): E2033 Types of actual and formal var parameters must be identical


  • 0

#16 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 18 octubre 2015 - 03:13

¿Con que compilas?. El código de delphi es para d7 32 bits, puedes tener errores de tipo en Lazarus o compilando para 64 bits. Los punteros se asumen de 32bits. El código data de la era 32bits y nunca lo actualucé para que funcione en 64 bits.

 

Por otro lado, no podrás inyectar una dll compilada para 32bits en un proceso de 64.

 

Prueba con una versión notepad32 y compila para 32 bits.

 

 

Saludos.


  • 0

#17 azdin

azdin

    Member

  • Miembros
  • PipPip
  • 20 mensajes

Escrito 18 octubre 2015 - 03:07

Los errores se me presentan en Delphi XE3 - x64

Pero en Delphi 7 - x86 me anda normal al compilar..

 

 

 En este punto he de aclarar que existen formas mucho mas sofisticadas de inyección que hoy no vienen al caso.

Edito para resubir los archivos de ejemplo.

 

A qué tipo de inyecciones te refieres?

 


  • 0

#18 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.773 mensajes
  • LocationMadrid - España

Escrito 18 octubre 2015 - 05:48

...A qué tipo de inyecciones te refieres?

.
 
Suspensión de Thread. Lee este tema
 
Saludos.
  • 0