Revisando mis apuntes encontré esta joya que parte de dos tutoriales:
El método usado es la de inyección directa de código en memoria, es decir no se
hace a través de dll, para esto hay que ponerse al día con la API que hacen el
manejo de memoria, aquí os pongo un pequeño resumen de lo que hace cada una:
VirtualAllocEx: Localiza memoria en el espacio de direcciones de un proceso
VirtualFreeEx: Libera la memoria localizada con VirtualAllocEx
WriteProcessMemory: Permite escribir en un bloque de memoria de otro proceso que hemos localizado con VirtualAllocEx
GetProcAddress: Nos da la dirección de una función exportada de una dll
CreateRemoteThread: Crea un hilo en un proceso remoto
Como veis son muy conocidas por todos nosotros y mucho más por las compañías
de AVs que nos la marcan en muchos de nuestros RunPE
Porque todo hay que decirlo, es "casi" lo mismo que haremos, inyectar código en
memoria para ejecutarlo, pero
no vamos a inyectar todo un dll o ejecutable con
su código y variables como hacemos en nuestros crypters, no eso no
Cuando un RunPE inyecta nuestro ejecutable en memoria el Sistema Operativo se
encarga en darnos el espacio necesario para la ejecución del proceso, esto nos
facilita las cosas, pero con la inyección directa lo vamos a hacer manualmente
ya que necesita subir al espacio de direcciones del proceso anfitrión los datos
así como la del código que debemos ejecutar.
Lo primero que haremos será definir la estructura de datos que contendrá todo el
código necesario para que pueda ejecutarse.
Después lo subiremos al espacio de direcciones del proceso anfitrión con
VirtualAllocEx y WriteProcessMemory
La estructura la vamos a definir así:
Código: Seleccionar todo
struct TParamFL
{
PGetModuleHandleA GetModuleHandleA; // Puntero a la API GetModuleHandleA
PFreeLibrary FreeLibrary; // Puntero a la API FreeLibrary
char DllName[256]; // Cadena que contiene el nombre de la dll a liberar
};
Los datos de la estructura deben ser inicializados para luego copiarlos al
espacio de direcciones del proceso remoto:
Código: Seleccionar todo
DWORD __stdcall InjFreeLibrary(TParamFL* P)
{
// Devuelve true si el módulo no existe en el proceso, de lo contrario el modulo sigue cargado
HMODULE hModule = P->GetModuleHandleA(P->DllName); // Localiza el HMODULE de la dll
P->FreeLibrary(hModule); // Libera La DLL
return (P->GetModuleHandleA(P->DllName)==0); // Si el modulo no existe, se descargó
}
Esta función lo que hace es recibir como parámetro un puntero a nuestra estructura
que 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 hacer esto hay que calcular su tamaño en bytes cuando sea compilado y enlazado
y su dirección de memoria.
Todo esto lo haremos en tiempo de ejecución y para ello utilizaremos lo que habíamos
escrito antes para calcular el tamaño.
Si Func1 y Func2 son punteros a sendas funciones escritas consecutivamente, el
tamaño binario de Fun1 sería este:
Esas funciones no se pueden cambiar de sitio en nuestros fuentes porque sino
seria desastroso.
Vamos al lío. Inyectaremos el código necesario en el espacio de direcciones del
proceso remoto lo ejecutaremos y limpiaremos los restos.
El código para hacer esto sería el siguiente:
Código: Seleccionar todo
BOOL FarFreeLibrary(DWORD Pid, char* DllName)
{
DWORD ExitCode;
HANDLE hThread = 0;
HANDLE hProc; // El handle del proceso en el que inyectaremos
TParamFL Param; // El tipo de dato de la estructura
UINT TamFun; // El tamaño de la función a inyectar
void* BFunc; // Lugar de memoria donde copiaremos nuestra función
//Metemos la dirección de las apis en la estructura
Param.FreeLibrary = (PFreeLibrary)GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "FreeLibrary");
Param.GetModuleHandleA = (PGetModuleHandleA)GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "GetModuleHandleA");
strcpy(Param.DllName, DllName);
//Abrimos el proceso en el que nos inyectaremos
hProc = OpenProcess(PROCESS_ALL_ACCESS, false, Pid);
//Reservamos espacio para nuestra estructura en el proceso a inyectar y la escribimos
void* BParam = VirtualAllocEx(hProc, 0, sizeof(TParamFL), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProc, BParam, &Param, sizeof(TParamFL), NULL);
//Calculamos el tamaño de la función a inyectar
TamFun = (UINT) FarFreeLibrary - (UINT)InjFreeLibrary;
//Reservamos espacio para la función, escribimos en él y creamos un hilo
BFunc = VirtualAllocEx(hProc, 0, TamFun, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProc, BFunc, InjFreeLibrary, TamFun, NULL);
hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)BFunc, BParam, 0, NULL);
if(hThread){
// Labores de limpieza...
WaitForSingleObject(hThread, INFINITE ); // Espero a que se termine de ejecutar el Thread
GetExitCodeThread(hThread, &ExitCode); // Recojo el resultado
CloseHandle(hThread); // Cierro el Handle hThread
VirtualFreeEx(hProc, BParam, 0, MEM_RELEASE); // Libero memoria de parámetros
VirtualFreeEx(hProc, BFunc, 0, MEM_RELEASE); // Libero memoria del código
}
CloseHandle(hProc);
return (BOOL)ExitCode;
}
En resumen solo inyectamos la función que deseamos ejecutar.
Aquí buenas referencias:
De Escafandra:
[Enlace externo eliminado para invitados]
[Enlace externo eliminado para invitados]
Y de Rolandj:
[Enlace externo eliminado para invitados]
Espero que os sea de utilidad
Tengo realizada una implementación en VB6 que realicé en noviembre del año pasado
en cuanto lo encuentre os lo posteo pero en la sección de fuentes, que por cierto es
más complejo de entender pues con VB para hacer lo mismo hay que hacer muchas
más piruetas, con lo "fácil" que es con C++ , Delphi y ASM...