Jump to content


Photo

Crear Shellcode en delphi


  • Please log in to reply
7 replies to this topic

#1 seoane

seoane

    Advanced Member

  • Administrador
  • 1259 posts
  • LocationEspaña

Posted 06 March 2014 - 10:43 AM

Voy a mostrar como crear un Shellcode, muy sencillo, en delphi que asume que no se conoce nada del proceso en el que se va inyectar, ni siquiera la posición de las APIS de windows (kernel32, user32, etc ...).

Lo primero es crear un proyecto nuevo de Delphi y añadir esta función:


delphi
  1. procedure ShellCodeProc(P: Pointer);
  2. begin
  3.  
  4.   // Aqui va ir el codigo
  5.  
  6.   // Pie , lo utilizo para encontrar el final de la funcion
  7.   asm
  8.     NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;
  9.   end;
  10. end;



Dentro de esa función es donde meteremos nuestro código, y una vez compilada usaremos esta otra función para volcar el "código maquina" a texto.


delphi
  1. // aqui deberiamos "desensamblar" el codigo, esta es solo una solucion cutre
  2. procedure DumpCode(const Func: PAnsiChar);
  3. var
  4.   P: PAnsiChar;
  5. begin
  6.   Writeln;
  7.   Writeln;
  8.   if Func = nil then
  9.     Exit;
  10.   P:= Func;
  11.   while StrLComp(P,#$90#$90#$90#$90#$90#$90#$90#$90,2) <> 0 do
  12.   begin
  13.     Write('#$' + IntToHex(Byte(P^),2));
  14.     inc(P);
  15.   end;
  16.   inc(P,8);
  17.   while P^ <> #$C3 do
  18.   begin
  19.     Write('#$' + IntToHex(Byte(P^),2));
  20.     inc(P);
  21.   end;
  22.   Write('#$C3');
  23.   Writeln;
  24.   Writeln;
  25. end;



Una vez que tenemos nuestro "lugar" de trabajo vamos a programar:


delphi
  1. procedure ShellCodeProc(P: Pointer);
  2. var
  3.   Mem: PByte;
  4.   IDH: PImageDosHeader;
  5.   INH: PImageNtHeaders;
  6.   IED: PImageExportDirectory;
  7.   Names: PDWORD;
  8.   NameOrdinals: PWORD;
  9.   Functions: PDWORD;
  10.   Name: PAnsiChar;
  11.  
  12.  
  13.   Kernel32: HModule;
  14.   strLoadLibrary: PAnsiChar;
  15.   strGetProcAddress: PAnsiChar;
  16.   MyLoadLibrary: function (lpLibFileName: PChar): HMODULE; stdcall;
  17.   MyGetProcAddress: function (hModule: HMODULE;
  18.     lpProcName: LPCSTR): FARPROC; stdcall;
  19.   i,j: Integer;
  20.  
  21.   strUser32: PAnsiChar;
  22.   strMessageBoxA: PAnsiChar;
  23.   MyMessageBoxA: function (hWnd: HWND; lpText, lpCaption: PAnsiChar;
  24.     uType: UINT): Integer; stdcall;
  25.  
  26.   Str: PAnsiChar;
  27. begin
  28.   // Recordar que no se pueden usar cadenas de texto directamente,
  29.   // ya que delphi luego haria referencia a ellas por su posicion
  30.   // absoluta dentro del ejecutable, asi que al insertarlo en otro ejecutable
  31.   // no las encontraria. Tampoco podemos usar bloques "try .. except" ni
  32.   // funciones externas, ni siquiera las de "Sysutils",  y en general nada que delphi guarde en otra
  33.   // parte del ejecutable, ya que en el nuevo proceso no estaran en el mismo sitio
  34.  
  35.   // Empezamos  con un poquito de ensablador
  36.   asm
  37.       push eax                // Guardamos el registro eax
  38.       jmp @@Salto              // Saltamos al comienzo
  39.       db 'Hola mundo',0        // Declaramos algunas constantes
  40.       db 'MessageBoxA',0      //  hay que recordar que se tienen
  41.       db 'user32.dll',0        //  que declarar de esta manera
  42.       db 'LoadLibraryA',0      //  para que queden "incrsutadas"
  43.       db 'GetProcAddress',0    //  dentro del codigo
  44.     @@ExHandler:              // Esta rutina maneja las excepciones
  45.       push ebp                //  al leer posiciones de memoria prohibidas
  46.       mov ebp,esp
  47.       mov eax,[ebp+$10]
  48.       add [eax+$a4],$10000    // Incrementa el puntero en 64 Kb
  49.       xor eax,eax
  50.       pop ebp
  51.       ret
  52.     @@GetEIP:                // Esta funcion nos devuelve la posicion
  53.       pop eax                //  de memoria actual
  54.       push eax
  55.       ret
  56.     @@Salto:
  57.       call @@GetEIP          // Obtenemos la posicion actual
  58.       sub eax,$1c            // Calculamos la posicion de la rutina ExHandler
  59.       push eax              // La guardamos en la pila
  60.       sub eax,$0f            // Calculamos la posicion de las cadenas de texto
  61.       mov strGetProcAddress,eax
  62.       sub eax,$0d
  63.       mov strLoadLibrary,eax
  64.       sub eax,$0b
  65.       mov strUser32,eax
  66.       sub eax,$0c
  67.       mov strMessageBoxA,eax
  68.       sub eax,$0b
  69.       mov Str,eax
  70.       push dword ptr fs:[0] // Añadimos la rutina ExHandler a los manejadores
  71.       mov dword ptr fs:[0], esp  // de excepciones
  72.   end;
  73.  
  74.   // Si queremos poder hacer algo vamos a tener que poder usar las APIS de windows.
  75.   // Normalmente se suele usar el "truco" de que windows carga las dlls
  76.   // del sistema (kernel32, user32, etc ...) casi siempre en la misma posicion de memoria
  77.   // por lo que se incluye como una constante. Pero esto no es simpre cierto, depende
  78.   // de la version del sistema. Ademas en las ultimas versiones de windows se intenta
  79.   // cargar las librerias en posiciones "aleatorias" para evitar las inyecciones de codigo
  80.  
  81.   // La solucion que se me ocurrio es "escanear" la memoria del proceso para buscar
  82.   // la posicion de la libreria Kernel32 y a partir de ahi sacar lo demas
  83.   Kernel32:= 0;
  84.   MyLoadLibrary:= nil;
  85.   MyGetProcAddress:= nil;
  86.   Mem:= nil;
  87.   // Comenzxamos en la posicion 0
  88.   while (@MyGetProcAddress = nil) or (@MyLoadLibrary = nil) do
  89.   begin
  90.     // Leemos la posicion de memoria a la que apunta "Mem"
  91.     asm
  92.       push ebx
  93.       push ecx
  94.       mov ebx,Mem
  95.       mov ecx,[ebx]  // Si salta una excepcion, incrementamos el puntero 64Kb, y volvemos aprobar
  96.       mov Mem,ebx
  97.       pop ecx
  98.       pop ebx
  99.     end;
  100.  
  101.     // Si llegamos aqui es que el bloque de memoria se puede leer
  102.  
  103.     // Comprobamos si es el comienzo de una dll
  104.     if PImageDosHeader(Mem)^.e_magic = IMAGE_DOS_SIGNATURE  then
  105.     begin
  106.       IDH:= PImageDosHeader(Mem);
  107.       INH:= PImageNtHeaders(Integer(IDH) + IDH^._lfanew);
  108.       // Volvemos a comprobar un segundo numero "magico"
  109.       if INH^.Signature =  IMAGE_NT_SIGNATURE then
  110.         // y una ultima comprobacion mas
  111.         if INH^.FileHeader.Characteristics and  IMAGE_FILE_DLL = IMAGE_FILE_DLL then
  112.           if INH^.FileHeader.SizeOfOptionalHeader > 0 then
  113.             if (INH^.OptionalHeader.Magic = $010b) or (INH^.OptionalHeader.Magic = $020b) then
  114.             begin
  115.               // Ya estamos seguros que se trata de una dll
  116.               IED:= PImageExportDirectory(Cardinal(Mem) +
  117.                 INH^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  118.               Names:= PDWORD(Integer(Mem) + Integer(IED.AddressOfNames));
  119.               // Recorremos las funciones que exporta
  120.               for i:= 0 to IED^.NumberOfNames - 1 do
  121.               begin
  122.                 Name:= PAnsiChar(Cardinal(Mem) + Names^);
  123.                 j:= 0;
  124.                 // Hasta que encontramos la que nos intersa (recordar que no podemos usar StrComp
  125.                 while (strGetProcAddress[j]=Name[j]) and (strGetProcAddress[j]<>#0) do
  126.                 inc(j);
  127.                 if strGetProcAddress[j] = #0 then
  128.                 begin
  129.                   // Caundo encontramos GetProcAddress
  130.                   NameOrdinals:= PWORD(Integer(Mem) + Integer(IED.AddressOfNameOrdinals));
  131.                   inc(NameOrdinals,i);
  132.                   Functions:= PDWORD(Integer(Mem) + Integer(IED.AddressOfFunctions));
  133.                   inc(Functions,NameOrdinals^);
  134.                   Kernel32:= Cardinal(Mem);
  135.                   // Guardamos la direccion de la funcion
  136.                   @MyGetProcAddress:= PDWORD(Cardinal(Mem) + Functions^);
  137.                   // Y el handle del modulo (que se corresponde con su posicion de memoria)
  138.                   @MyLoadLibrary:= MyGetProcAddress(Kernel32,strLoadLibrary);
  139.                   // Y terminamos con el escaneo
  140.                   break;
  141.                 end;
  142.                 inc(Names);
  143.               end;
  144.             end;
  145.     end;
  146.     // Incrementamos el puntero 64Kb
  147.     inc(Mem,$10000);
  148.   end;
  149.  
  150.   // Sacamos el manejador de Excepciones que habiamos introducido antes
  151.   asm
  152.       pop dword ptr fs:[0]
  153.       pop eax
  154.       pop eax
  155.   end;             
  156.  
  157.   // Mostramos un bonito mensaje
  158.   @MyMessageBoxA:= MyGetProcAddress(MyLoadLibrary(strUser32),strMessageBoxA);
  159.   MyMessageBoxA(0,Str,Str,MB_OK or MB_TASKMODAL);
  160.  
  161.  
  162.   // Pie , lo utilizo para encontrar el final de la funcion
  163.   asm
  164.     NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;
  165.   end;
  166. end;



Para volcar la función podemos usar algo como esto:


delphi
  1. DumpCode(@ShellCodeProc);



Que nos dará como salida esto:


delphi
  1. #$55#$8B#$EC#$83#$C4#$C0#$53#$56#$57#$50#$EB#$55#$48#$6F#$6C#$61#$20#$6D#$75#$6E
  2. #$64#$6F#$00#$4D#$65#$73#$73#$61#$67#$65#$42#$6F#$78#$41#$00#$75#$73#$65#$72#$33
  3. #$32#$2E#$64#$6C#$6C#$00#$4C#$6F#$61#$64#$4C#$69#$62#$72#$61#$72#$79#$41#$00#$47
  4. #$65#$74#$50#$72#$6F#$63#$41#$64#$64#$72#$65#$73#$73#$00#$55#$89#$E5#$8B#$45#$10
  5. #$81#$80#$A4#$00#$00#$00#$00#$00#$01#$00#$31#$C0#$5D#$C3#$58#$50#$C3#$E8#$F8#$FF
  6. #$FF#$FF#$83#$E8#$1C#$50#$83#$E8#$0F#$89#$45#$FC#$83#$E8#$0D#$89#$45#$F8#$83#$E8
  7. #$0B#$89#$45#$F4#$83#$E8#$0C#$89#$45#$F0#$83#$E8#$0B#$89#$45#$EC#$64#$FF#$35#$00
  8. #$00#$00#$00#$64#$89#$25#$00#$00#$00#$00#$33#$FF#$33#$F6#$33#$C0#$89#$45#$E8#$E9
  9. #$3D#$01#$00#$00#$53#$51#$8B#$5D#$E8#$8B#$0B#$89#$5D#$E8#$59#$5B#$8B#$45#$E8#$66
  10. #$81#$38#$4D#$5A#$0F#$85#$1C#$01#$00#$00#$8B#$45#$E8#$89#$45#$E4#$8B#$45#$E4#$8B
  11. #$40#$3C#$03#$45#$E4#$89#$45#$E0#$8B#$45#$E0#$81#$38#$50#$45#$00#$00#$0F#$85#$FB
  12. #$00#$00#$00#$8B#$45#$E0#$0F#$B7#$40#$16#$66#$25#$00#$20#$66#$3D#$00#$20#$0F#$85
  13. #$E6#$00#$00#$00#$8B#$45#$E0#$66#$83#$78#$14#$00#$0F#$86#$D8#$00#$00#$00#$8B#$45
  14. #$E0#$66#$81#$78#$18#$0B#$01#$74#$0F#$8B#$45#$E0#$66#$81#$78#$18#$0B#$02#$0F#$85
  15. #$BE#$00#$00#$00#$8B#$45#$E0#$8B#$40#$78#$03#$45#$E8#$89#$45#$DC#$8B#$45#$DC#$8B
  16. #$40#$20#$03#$45#$E8#$89#$45#$D8#$8B#$45#$DC#$8B#$40#$18#$48#$85#$C0#$0F#$8C#$97
  17. #$00#$00#$00#$40#$89#$45#$C0#$C7#$45#$C4#$00#$00#$00#$00#$8B#$45#$D8#$8B#$00#$03
  18. #$45#$E8#$89#$45#$CC#$33#$DB#$EB#$01#$43#$8B#$45#$FC#$0F#$B6#$04#$18#$8B#$55#$CC
  19. #$3A#$04#$1A#$75#$09#$8B#$45#$FC#$80#$3C#$18#$00#$75#$E7#$8B#$45#$FC#$80#$3C#$18
  20. #$00#$75#$4B#$8B#$45#$DC#$8B#$40#$24#$03#$45#$E8#$89#$45#$D4#$8B#$45#$C4#$03#$C0
  21. #$01#$45#$D4#$8B#$45#$DC#$8B#$40#$1C#$03#$45#$E8#$89#$45#$D0#$8B#$45#$D4#$0F#$B7
  22. #$00#$03#$C0#$03#$C0#$01#$45#$D0#$8B#$45#$E8#$89#$45#$C8#$8B#$45#$D0#$8B#$00#$03
  23. #$45#$E8#$89#$C6#$8B#$45#$F8#$50#$8B#$45#$C8#$50#$FF#$D6#$89#$C7#$EB#$10#$83#$45
  24. #$D8#$04#$FF#$45#$C4#$FF#$4D#$C0#$0F#$85#$74#$FF#$FF#$FF#$81#$45#$E8#$00#$00#$01
  25. #$00#$85#$F6#$0F#$84#$BB#$FE#$FF#$FF#$85#$FF#$0F#$84#$B3#$FE#$FF#$FF#$64#$8F#$05
  26. #$00#$00#$00#$00#$58#$58#$8B#$45#$F0#$50#$8B#$45#$F4#$50#$FF#$D7#$50#$FF#$D6#$89
  27. #$C3#$68#$00#$20#$00#$00#$8B#$45#$EC#$50#$8B#$45#$EC#$50#$6A#$00#$FF#$D3#$5F#$5E
  28. #$5B#$8B#$E5#$5D#$C3



Este código lo podríamos inyectar directamente, con alguna de las rutinas de nuestro amigo escafandra, o aprovechando algún "exploit".

Para probarlo podemos hacer algo como esto:


delphi
  1. const
  2.   test : AnsiString =
  3. #$55#$8B#$EC#$83#$C4#$C0#$53#$56#$57#$50#$EB#$55#$48#$6F#$6C#$61#$20#$6D#$75#$6E+
  4. #$64#$6F#$00#$4D#$65#$73#$73#$61#$67#$65#$42#$6F#$78#$41#$00#$75#$73#$65#$72#$33+
  5. #$32#$2E#$64#$6C#$6C#$00#$4C#$6F#$61#$64#$4C#$69#$62#$72#$61#$72#$79#$41#$00#$47+
  6. #$65#$74#$50#$72#$6F#$63#$41#$64#$64#$72#$65#$73#$73#$00#$55#$89#$E5#$8B#$45#$10+
  7. #$81#$80#$A4#$00#$00#$00#$00#$00#$01#$00#$31#$C0#$5D#$C3#$58#$50#$C3#$E8#$F8#$FF+
  8. #$FF#$FF#$83#$E8#$1C#$50#$83#$E8#$0F#$89#$45#$FC#$83#$E8#$0D#$89#$45#$F8#$83#$E8+
  9. #$0B#$89#$45#$F4#$83#$E8#$0C#$89#$45#$F0#$83#$E8#$0B#$89#$45#$EC#$64#$FF#$35#$00+
  10. #$00#$00#$00#$64#$89#$25#$00#$00#$00#$00#$33#$FF#$33#$F6#$33#$C0#$89#$45#$E8#$E9+
  11. #$3D#$01#$00#$00#$53#$51#$8B#$5D#$E8#$8B#$0B#$89#$5D#$E8#$59#$5B#$8B#$45#$E8#$66+
  12. #$81#$38#$4D#$5A#$0F#$85#$1C#$01#$00#$00#$8B#$45#$E8#$89#$45#$E4#$8B#$45#$E4#$8B+
  13. #$40#$3C#$03#$45#$E4#$89#$45#$E0#$8B#$45#$E0#$81#$38#$50#$45#$00#$00#$0F#$85#$FB+
  14. #$00#$00#$00#$8B#$45#$E0#$0F#$B7#$40#$16#$66#$25#$00#$20#$66#$3D#$00#$20#$0F#$85+
  15. #$E6#$00#$00#$00#$8B#$45#$E0#$66#$83#$78#$14#$00#$0F#$86#$D8#$00#$00#$00#$8B#$45+
  16. #$E0#$66#$81#$78#$18#$0B#$01#$74#$0F#$8B#$45#$E0#$66#$81#$78#$18#$0B#$02#$0F#$85+
  17. #$BE#$00#$00#$00#$8B#$45#$E0#$8B#$40#$78#$03#$45#$E8#$89#$45#$DC#$8B#$45#$DC#$8B+
  18. #$40#$20#$03#$45#$E8#$89#$45#$D8#$8B#$45#$DC#$8B#$40#$18#$48#$85#$C0#$0F#$8C#$97+
  19. #$00#$00#$00#$40#$89#$45#$C0#$C7#$45#$C4#$00#$00#$00#$00#$8B#$45#$D8#$8B#$00#$03+
  20. #$45#$E8#$89#$45#$CC#$33#$DB#$EB#$01#$43#$8B#$45#$FC#$0F#$B6#$04#$18#$8B#$55#$CC+
  21. #$3A#$04#$1A#$75#$09#$8B#$45#$FC#$80#$3C#$18#$00#$75#$E7#$8B#$45#$FC#$80#$3C#$18+
  22. #$00#$75#$4B#$8B#$45#$DC#$8B#$40#$24#$03#$45#$E8#$89#$45#$D4#$8B#$45#$C4#$03#$C0+
  23. #$01#$45#$D4#$8B#$45#$DC#$8B#$40#$1C#$03#$45#$E8#$89#$45#$D0#$8B#$45#$D4#$0F#$B7+
  24. #$00#$03#$C0#$03#$C0#$01#$45#$D0#$8B#$45#$E8#$89#$45#$C8#$8B#$45#$D0#$8B#$00#$03+
  25. #$45#$E8#$89#$C6#$8B#$45#$F8#$50#$8B#$45#$C8#$50#$FF#$D6#$89#$C7#$EB#$10#$83#$45+
  26. #$D8#$04#$FF#$45#$C4#$FF#$4D#$C0#$0F#$85#$74#$FF#$FF#$FF#$81#$45#$E8#$00#$00#$01+
  27. #$00#$85#$F6#$0F#$84#$BB#$FE#$FF#$FF#$85#$FF#$0F#$84#$B3#$FE#$FF#$FF#$64#$8F#$05+
  28. #$00#$00#$00#$00#$58#$58#$8B#$45#$F0#$50#$8B#$45#$F4#$50#$FF#$D7#$50#$FF#$D6#$89+
  29. #$C3#$68#$00#$20#$00#$00#$8B#$45#$EC#$50#$8B#$45#$EC#$50#$6A#$00#$FF#$D3#$5F#$5E+
  30. #$5B#$8B#$E5#$5D#$C3;
  31.  
  32. var
  33.   Proc: Procedure(P: Pointer);
  34. begin
  35.   @Proc:= @test[1];
  36.   Proc(nil);
  37. end.



A jugar  :dmad:











  • 0

#2 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 06 March 2014 - 11:16 AM

:o  :| me da miedo ejecutar eso aquí en mi oficina  *-), lo haré en una máquina que tengo destinada para todo tipo de pruebas en mi casa :D :D :D

Saludos
  • 0

#3 seoane

seoane

    Advanced Member

  • Administrador
  • 1259 posts
  • LocationEspaña

Posted 06 March 2014 - 11:26 AM

:o  :| me da miedo ejecutar eso aquí en mi oficina  *-), lo haré en una máquina que tengo destinada para todo tipo de pruebas en mi casa :D :D :D


:D No te fías de mi !!!  :D ... esa es una decisión muy sabia  (y)

Por cierto, si lo ejecutas desde el IDE de Delphi te saltaran varios errores porque se producen muchas excepciones juntas y se le "atragantan" pero si lo compilas y lo ejecutas fuera del IDE toda va bien.
  • 0

#4 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 06 March 2014 - 12:13 PM

:D No te fías de mi !!!  :D ... esa es una decisión muy sabia  (y)

Por cierto, si lo ejecutas desde el IDE de Delphi te saltaran varios errores porque se producen muchas excepciones juntas y se le "atragantan" pero si lo compilas y lo ejecutas fuera del IDE toda va bien.


No, si sí me fío de usted estimado Domingo, del que no me fío es de mí, todo lo que toco lo hago trizas :D :D :D

Saludos
  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 06 March 2014 - 01:04 PM

Muy bueno, seoane.  (y) :ap:

Me recuerda a las precauciones que exponía en Inyección directa de código en C y en delphi y en Inyección directa de código II. En la segunda conseguía escribir el shellcode directamente en C e inyectarlo tal cual ajustando la pila al entrar y salir con ayuda de asm. Todo debe ir al espacio de memoria del proceso anfitrión, cadenas, valores apuntados por punteros, parámetros a usar... todo.

Son ejercicios muy divertidos. La única pega es que si nuestro S.O. es de 64 bits, el shellcode debe estar así compilado.


Saludos.


  • 0

#6 seoane

seoane

    Advanced Member

  • Administrador
  • 1259 posts
  • LocationEspaña

Posted 06 March 2014 - 03:11 PM

Son ejercicios muy divertidos. La única pega es que si nuestro S.O. es de 64 bits, el shellcode debe estar así compilado.


Yo lo compile en Windows XP 32 bits y lo probé en Windows 8 64 btis y todo fue bien. Eso si, lo probé dentro de un proceso de 32 bits
  • 0

#7 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 06 March 2014 - 06:01 PM

Yo lo compile en Windows XP 32 bits y lo probé en Windows 8 64 btis y todo fue bien. Eso si, lo probé dentro de un proceso de 32 bits


Claro, yo me refiero a inyectar el shellcode en un proceso ajeno de 64 bits. No quiero ni imaginar lo que sucedería con un proceso a 64bits al que se le inyecta un trozo de código de 32 bits por la técnica de suspensión de Thread, por ejemplo...  :s  Algún día lo pruebo.

Por cierto, he probado tu código en win8 64bits tal cual escribiste en tu último código, compilado con delphi7 y funciona bien.


Saludos.
  • 0

#8 FGarcia

FGarcia

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 687 posts
  • LocationMéxico

Posted 06 March 2014 - 09:36 PM

Al ver todo eso me digo: ¡Simplemente no se nada!
  • 0




IP.Board spam blocked by CleanTalk.