comment
IRC Chat
play_arrow
Este sitio utiliza cookies propias y de terceros. Si continúa navegando consideramos que acepta el uso de cookies. OK Más Información.

Otra forma de inyectar un ejecutable en memoria (DummySection)

  • 3 Respuestas
  • 2368 Vistas

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

Desconectado [Zero]

  • *
  • Underc0der
  • Mensajes: 7
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
    • H-Sec.org
    • Email
« en: Junio 16, 2013, 05:51:09 pm »
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 permisos para ver links. Registrate o Entra con tu 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 permisos para ver links. Registrate o Entra con tu 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
  1. #pragma comment(linker,"/NODEFAULTLIB")
  2. #pragma comment(linker,"/ENTRY:main")
  3.  
  4. #include <windows.h>
  5. #include "resource.h"
  6.  
  7. void mCopyMemory(LPVOID bEscritura,LPVOID bLectura,DWORD lenBuffer);
  8.  
  9. int main()
  10. {
  11.         //Dirección base del exe que inyectaremos
  12.         int InjectedImageBase=0x00400000;
  13.         LPBYTE lpBuffer=(LPBYTE)InjectedImageBase;
  14.  
  15.         //Cargamos el exe que inyectaremos del resource
  16.         HRSRC hResource=FindResourceA(NULL,(LPCSTR)MAKEINTRESOURCE(IDR_EXE1),"EXE");
  17.         HGLOBAL hGlob=LoadResource(NULL,hResource);
  18.         DWORD FileSize=SizeofResource(NULL,hResource);
  19.         LPBYTE lpFileMaped=(LPBYTE)LockResource(hGlob);
  20.  
  21.         PIMAGE_DOS_HEADER IDH;
  22.         PIMAGE_NT_HEADERS INTH;
  23.         PIMAGE_SECTION_HEADER ISH;
  24.  
  25.         //Obtenemos la cabecera DOS y PE
  26.         IDH=(PIMAGE_DOS_HEADER)&lpFileMaped[0];
  27.         INTH=(PIMAGE_NT_HEADERS)&lpFileMaped[IDH->e_lfanew];
  28.  
  29.         //Damos permisos de lectura, escritura y ejecución a la Dummy Section
  30.         DWORD OldProtect;
  31.         VirtualProtect(lpBuffer,0x3000,PAGE_EXECUTE_READWRITE,&OldProtect);
  32.  
  33.         //Copiamos la cabecera DOS y PE al buffer
  34.         mCopyMemory(&lpBuffer[0],&lpFileMaped[0],INTH->OptionalHeader.SizeOfHeaders);
  35.  
  36.         //Copiamos las secciones en su VirtualOffset en el buffer
  37.         for(DWORD i=0;i<INTH->FileHeader.NumberOfSections;i++)
  38.         {
  39.                 ISH=(PIMAGE_SECTION_HEADER)&lpFileMaped[IDH->e_lfanew+sizeof(IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)*i];
  40.                 mCopyMemory(&lpBuffer[ISH->VirtualAddress],&lpFileMaped[ISH->PointerToRawData],ISH->SizeOfRawData);
  41.         }
  42.  
  43.         //---------------------------------------------------------------------
  44.         /* -Cargamos la IAT a mano para que funcionen las API's importadas   */
  45.         //---------------------------------------------------------------------
  46.  
  47.         PIMAGE_THUNK_DATA ITD;
  48.         PIMAGE_IMPORT_BY_NAME IIBN;
  49.  
  50.         //Comprobamos si hay Import Data Descriptor
  51.         if (INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size>0)
  52.         {
  53.                 //Si lo hay lo obtenemos en la estructura
  54.                 PIMAGE_IMPORT_DESCRIPTOR IID=(PIMAGE_IMPORT_DESCRIPTOR)(lpBuffer+INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  55.  
  56.                 //Vamos recorriendo todas las Dll's importadas por el ejecutable
  57.                 for (;IID->Name;IID++)
  58.                 {
  59.                         //Cargamos la dll
  60.                         HMODULE hLib=LoadLibraryA((LPCSTR)(lpBuffer+IID->Name));
  61.  
  62.                         //Obtenemos la dirección al primer miembro del array Image Thunk Data's
  63.                         ITD=(PIMAGE_THUNK_DATA)((DWORD)lpBuffer+IID->FirstThunk);
  64.  
  65.                         //Vamos recorriendo las funciones importadas
  66.                         for (;ITD->u1.Ordinal;ITD++)
  67.                         {
  68.                                 //Cargamos el Image Import By Name para obtener el nombre
  69.                                 IIBN=(PIMAGE_IMPORT_BY_NAME)(lpBuffer+ITD->u1.Function);
  70.                                 //Obtenemos la dirección de la función y la guardamos en la IAT
  71.                                 ITD->u1.Function=(DWORD)GetProcAddress(hLib,(LPCSTR)&IIBN->Name);
  72.                         }
  73.                 }
  74.         }
  75.  
  76.         //Creamos el hilo de ejecución
  77.         CreateThread(0,0,(LPTHREAD_START_ROUTINE)(lpBuffer+INTH->OptionalHeader.AddressOfEntryPoint),NULL,0,0);
  78.  
  79.         MessageBoxA(0,"I'm the Loader Running!",":D",0);
  80.  
  81.         return 0;
  82. }
  83.  
  84. //Función que simula RtlCopyMemory
  85. void __declspec(naked) mCopyMemory(LPVOID bEscritura,LPVOID bLectura,DWORD lenBuffer)
  86. {
  87.         __asm
  88.         {
  89.                 pushad
  90.                         mov esi,[esp+0x28] //bLectura
  91.                 mov ecx,[esp+0x2C] //lenBuffer
  92.                 mov edi,[esp+0x24] //bEscritura
  93.                 dec ecx
  94.  
  95. bCopyMemory:
  96.                 dec ecx
  97.                         movsb
  98.                         cmp ecx,0
  99.                         jge bCopyMemory
  100.                         popad
  101.                         ret
  102.         }
  103. }
  104.  
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
  1. #pragma comment(linker,"/NODEFAULTLIB")
  2. #pragma comment(linker,"/ENTRY:main")
  3.  
  4. #include <windows.h>
  5.  
  6. int main()
  7. {
  8.         MessageBoxA(0,"I'm the Injected Exe Running!",":D",0);
  9.         return 0;
  10. }
  11.  

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
« Última modificación: Junio 16, 2013, 05:55:24 pm por [Zero] »
   
 No tienes permisos para ver links. Registrate o Entra con tu cuenta

Desconectado Arkangel

  • *
  • Underc0der
  • Mensajes: 15
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
« Respuesta #1 en: Junio 16, 2013, 05:57:57 pm »
Veo que ya te llevas la casa a otro lugar. Seguro que les gusta este aporte aunque tenga ya tiempo

Saludos

Desconectado k0ws

  • *
  • Underc0der
  • Mensajes: 145
  • Actividad:
    0%
  • Reputación 0
  • I'm Back
    • Ver Perfil
  • Skype: k0wsit0
« Respuesta #2 en: Junio 16, 2013, 06:16:23 pm »
Muy bueno!  ;D

-Saludos-

Desconectado bruxinho

  • *
  • Underc0der
  • Mensajes: 3
  • Actividad:
    0%
  • Reputación 0
    • Ver Perfil
    • Email
  • Skype: bruxinho_dark
« Respuesta #3 en: Julio 01, 2013, 03:27:50 pm »
es qual linguagem?

 

¿Te gustó el post? COMPARTILO!



Tutorial: Inyecciones de código en memoria

Iniciado por Juan

Respuestas: 4
Vistas: 2770
Último mensaje Agosto 25, 2011, 06:06:57 pm
por 3hy!