Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   API de Windows (https://www.clubdelphi.com/foros/forumdisplay.php?f=7)
-   -   Inyeccion DLL[Duda] (https://www.clubdelphi.com/foros/showthread.php?t=83821)

Jais 02-08-2013 12:53:38

Inyeccion DLL[Duda]
 
Hola

Este es mi primer post en el foro.

Estoy estudiando la inyección de DLL en un proceso.
Hasta el momento he conseguido hacer un Hook (metodo trampolin) a un MessageBox.

La duda que tengo es la siguiente.

Yo tengo un programa de este estilo, pero con mucho más código:

Código:

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils,Windows;

Var
  i: Integer;
  Cuenta: String;

begin
  { TODO -oUser -cConsole Main : Insert code here }
  Cuenta := '';
  For i:=0 To 10 Do
    Begin
      Cuenta := Cuenta + IntToStr(i);
    End;

  MessageBox(0,PAnsiChar(Cuenta),'Cuenta',64);
end.

Y lo que no se como hacer, es inyectar este programa, haciendo uso de la inyección con DLL, en un proceso como notepad.exe, calc.exe, ... (el proceso sinceramente no me importa cual sea).

Espero me puedan ayudar.

Muchísimas gracias de antemano.

Un saludo

escafandra 02-08-2013 20:10:31

En el foro tienes ejemplos de como inyectar una dll. De entrada, necesitas tener una dll que inyectar y tu código no lo es.


Saludos.

Jais 05-08-2013 14:39:07

Hola escafandra

Gracias por tu respuesta. La DLL que quiero inyectar es esta:

Código:

library Sumar;

{$APPTYPE CONSOLE}

uses
  SysUtils,Windows;

Var
  i: Integer;
  Cuenta: String;

begin
  { TODO -oUser -cConsole Main : Insert code here }
  Cuenta := '';
  For i:=0 To 10 Do
    Begin
      Cuenta := Cuenta + IntToStr(i);
    End;

  MessageBox(0,PAnsiChar(Cuenta),'Cuenta',64);
end.

Llevo tiempo leyendo tutoriales, tanto los que mencionas como otros, pero no tengo muy claro el funcionamiento.

Ahora mismo estoy trabajando con este codigo, que me funciona en Windows XP:

Código:

procedure InjectDll(PID: dword;  DLL: pChar);
var
  BytesWritten, hProcess, hThread, TID: Cardinal;
  Parameters: pointer;
  pThreadStartRoutine: Pointer;
begin
  // Abrimos el proceso
  hProcess := OpenProcess(PROCESS_ALL_ACCESS,  False,  PID);
  // Creamos espacio en el proceso
  Parameters := VirtualAllocEx( hProcess, nil, Length(DLL)+1, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
  // Escribimos en el proceso la ruta de nuestra DLL
  WriteProcessMemory(hProcess,Parameters,Pointer(DLL  ),Length(DLL)+1,BytesWritten);
  // Obtenemos la direccion de LoadLibrary con GetProcAddress
  pThreadStartRoutine := GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'LoadLibraryA');
  // Creamos un Thread en el proceso remoto que ejecute nuestra dll
  hThread := CreateRemoteThread(hProcess,  nil,  0,  pThreadStartRoutine,  Parameters,  0,  TID);
  // Cerramos el hProcess abierto
  CloseHandle(hProcess);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  InjectDll(Aqui pongo el PID del notepad o de la calculadora,PAnsiChar('C:\Sumar.dll'));
end;

He probado este codigo tanto con el PID de un notepad y con el de la calculadora y con los dos me ha funcionado.

Tengo unas dudas, ¿porque obtenemos la dirección de LoadLibrary?
He leido el algun tutorial, pero no se porque motivo es, que este codigo no funciona en Sistemas Operativos de 64 bits. ¿Por que razon no funciona? Yo no le podido probar en sistemas operativos de 64 bits porque no tengo.

Muchisimas gracias de antemano.

Saludos

escafandra 07-08-2013 21:15:52

Aclarando dudas:
Cita:

Empezado por Jais (Mensaje 465041)
¿porque obtenemos la dirección de LoadLibrary?

Estudia la API CreateRemoteThread, el 4 parámetro precisa un puntero a una función y el 5 es un puntero que se pasará a la dicha función.

LoadLibrary es la API que se usa para cargar una dll en el proceso actual y usa un parámetro que es el nombre de la dll. La inyección se basa en obligar a otro proceso a cargar una dll, CreateRemoteThread hace esa función ejecutando en el proceso anfitrión LoadLibrary con el nombre de la dll que queremos inyectar. Por eso necesitamos conocer un puntero a Loadlíbrary y reservar memoria en el espacio de direcciones del priceso anfitrión para escribir el nombre de la dll que pasaremos a LoadLibrary. El truco se basa en que las direcciones de las APIs del sistema son idénticas para todos los procesos.

Cita:

Empezado por Jais (Mensaje 465041)
...este codigo no funciona en Sistemas Operativos de 64 bits. ¿Por que razon no funciona?

Un proceso compilado para 32bits no puede usar una dll compilada para 32bits, por lo tanto
no se puede inyectar código compilado para 32bits en un proceso 64bits.


Saludos.

escafandra 09-08-2013 01:00:39

Perdón por la errata:
Cita:

Empezado por escafandra (Mensaje 465169)
Un proceso compilado para 32bits no puede usar una dll compilada para 32bits, por lo tanto
no se puede inyectar código compilado para 32bits en un proceso 64bits.

debe decir:
Un proceso compilado para 64bits no puede usar una dll compilada para 32bits, por lo tanto
no se puede inyectar código compilado para 32bits en un proceso 64bits.


Saludos.

Jais 10-08-2013 21:23:14

Hola escafandra

Referente a la API CreateRemoteThread me ha quedado todo muy claro. Ahora si lo que entiendo muy bien. Sinceramente, muchisimas gracias escafandra.

El tema de 32 bits y 64 bits también, creo , que me ha quedado claro. Esto es lo que he entendido:
- Para utilizar una DLL en 32 bits, se deberá crear esa DLL en una arquitectura 32 bits. Ejemplo: Windows Vista 32 bits,...
- Para utilizar una DLL en 64 bits, se deberá crear esa DLL en una arquitectura 64 bits. Ejemplo: Windows 7 64 bits,...

Espero haberlo entendido bien.

Una vez entendido el tema de la inyección DLL bastante bien, quería aprender el tema de Hook API porque aunque algo hecho todavía no lo entiendo del todo bien.

El código con el que he estado trabajando es el siguiente(Autor: Robert Milan ):

Aplicación Test:

Código:

procedure TForm1.Button1Click(Sender: TObject);
begin
MessageBoxA(Self.Handle,                        // Application Handle
              PAnsiChar(AnsiString(Edit1.Text)),  // Message in messagebox
              PAnsiChar(Self.Caption),            // Title of messagebox
              $00000040);                          // Information Icon
end;

Inyector:

Código:

procedure TForm1.Button1Click(Sender: TObject);
begin
InjectDLL('notepad.exe', Ruta de la DLL);
end;

function GetProcessIdByName(s : String) : Cardinal;
var
  { Process Vars }
  hProcessSnap : THandle;
  PE32        : ProcessEntry32;
begin
        { Init. Result }
          Result := 0;

          { Take a snapshot of all the processes in the system }
          hProcessSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
          if (hProcessSnap = INVALID_HANDLE_VALUE) then exit;

          { Size of the ProcessEntry32 Structure }
          PE32.dwSize := SizeOf(TProcessEntry32);

          { Unable to retreive information about the first process }
          if not (Process32First(hProcessSnap, PE32)) then
          begin
            PE32.dwSize := 0;
            CloseHandle(hProcessSnap);
            exit;
          end;

          { Iterate through the process list }
          while not (Process32Next(hProcessSnap, PE32) = false) do
          begin
          if (Lowercase(PE32.szExeFile) = Lowercase(s)) then
            begin
        Result := PE32.th32ProcessID;
              break;
            end;
          end;

  { Cleanup the ProcessEntry32 struct. }
  with PE32 do
  begin
      dwSize := 0;
      cntUsage := 0;
      th32ProcessID := 0;
      th32DefaultHeapID := 0;
      th32ModuleID := 0;
      cntThreads := 0;
      th32ParentProcessID := 0;
      pcPriClassBase := 0;
      dwFlags := 0;
      szExeFile := '';
  end;

  { Freeup allocated memory }
  CloseHandle(hProcessSnap);
end;

function InjectDLL(Process: AnsiString; Dll: AnsiString) : Integer;
var
  PID          : Cardinal; { Process ID }

  hProcess    : THandle;  { Process Object }
  hThread      : THandle;  { Remote Thread Handle }

  dwThreadID  : DWORD;    { Remote Thread ID }

  BaseAddr    : PChar;    { Memory Address }

  BytesWritten : LongWord; { Total Bytes Written }
begin
  { Search for process id }
        PID := GetProcessIdByName(Process);

  { Process wasn't found }
  if (PID = 0) then
  begin
          Result := -1;
          exit;
  end;

  { Something went wrong, we can't find the process }
  if (PID = 0) then
  begin
      Result := -1;
      exit;
  end;

  { Open the process }
  hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or { For Token, Exit code and more }
                          PROCESS_CREATE_THREAD or    { For CreateRemoteThread }
                          PROCESS_VM_OPERATION or      { For VirtualAllocEx/VirtualFreeEx }
                          PROCESS_VM_WRITE,            { For WriteProcessMemory }
                          false, PID);


  { Allocate some extra memory in the target process }
  BaseAddr := PChar(VirtualAllocEx(hProcess, nil, strlen(PChar(DLL)) + 1 * sizeof(Char), MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE));

  { Inject dll into memory }
  if not (BaseAddr = nil) then
  begin
      WriteProcessMemory(hProcess, BaseAddr, PChar(DLL), Length(DLL), BytesWritten);
  end else
  begin
      { No need to continue, we couldn't write the dll into memory }
      Result := -1;
      exit;
  end;

  { Create a thread, force the process to load the dll }
  hThread := CreateRemoteThread(hProcess, nil, 0, GetProcAddress(LoadLibrary('Kernel32.dll'), 'LoadLibraryA'), BaseAddr, 0, dwThreadID);

  { Wait for the thread to execute }
  WaitForSingleObject(hThread, INFINITE);

  { Free allocated memory }
  VirtualFreeEx(hProcess, BaseAddr, 0, MEM_RELEASE);
  CloseHandle(hProcess);

  Result := 0;
end;

DLL:

Código:

(************************************************************)
(* Win32 API Hooking Library                                *)
(* by Robert Milan (03/23/13)                              *)
(************************************************************)
(* This code is provided "as is" without express or        *)
(* implied warranty of any kind. Use it at your own risk.  *)
(************************************************************)

library prjHook;

uses
  Windows,
  SysUtils,
  StrUtils,
  Classes,
  Dialogs,
  Winsock;

var
  { Original API }
  TMessageBoxA : function (Handle : hWnd; lpText : PAnsiChar; lpCaption : PAnsiChar; uType : Cardinal) : Integer; stdcall;

{$R *.res}

{ Duplicate of the original api }
function OMessageBoxA(Handle : hWnd; lpText : PAnsiChar; lpCaption : PAnsiChar; uType : Cardinal) : Integer; stdcall;
begin

  { Here we will edit the api in any way that we want. }


  { Edit the message for the MessageBox }
  lpText := PAnsiChar('Message text edited!');

  { Change the icon type to exclamation }
  uType := $00000030;

  { Call the original api }
  Result := TMessageBoxA(Handle, lpText, lpCaption, uType);
end;

{
  This function will take a api call from a dll and create a
      unconditional JMP to the functions address in this dll.

  If the "REAL" function address is "0x00AA0F00" and the address to
      our replacement is "0x00FFFFFF" then the JMP will replace a JMP
      right before we reach the "REAL" address to the replacement address.
}

// Example: InterceptAPI('USER32.dll', 'MessageBoxA', @OMessageBoxA, @TMessageBoxA);
function InterceptAPI(lpModuleName : PAnsiChar; lpProcName: PAnsiChar; PCallBack : Pointer; var PTrampoline : Pointer) : Integer; stdcall;
var
  hMod      : HMODULE;
  FuncAddr  : Pointer;
  FuncOrg  : Pointer;
  dwProtect : DWORD;
begin
  { Dynamic Link Library }
  hMod := GetModuleHandle(lpModuleName);
  if (hMod = 0) then
  begin
      Result := 0;
      exit;
  end;

  { Address to api function }
  FuncAddr := GetProcAddress(hMod, lpProcName);
  if (FuncAddr = nil) then
  begin
      Result := 0;
      exit;
  end;

  VirtualProtect(FuncAddr, 5, PAGE_WRITECOPY, dwProtect);
  GetMem(FuncOrg, 10);
  CopyMemory(FuncOrg, FuncAddr, 5);

  { Create a unconditional JMP to the address of our replacement api}
  Byte(Pointer(DWORD(FuncOrg) + 5)^) := $E9;
  DWORD(Pointer(DWORD(FuncOrg) + 6)^) := (DWORD(FuncAddr) - (DWORD(FuncOrg) + 5));

  { Create a trampoline so that we can replace the replacement api back with the original }
  PTrampoline := FuncOrg;

  Byte(FuncAddr^) := $E9;
  DWORD(Pointer(DWORD(FuncAddr) + 1)^) := DWORD(PCallback) - (DWORD(FuncAddr) + 5);

  VirtualProtect(FuncAddr, 5, dwProtect, dwProtect);
  FlushInstructionCache(GetCurrentProcess(), Nil, 0);

  Result := 1;
end;

procedure DllMain(reason: integer);
begin
  case reason of
      DLL_PROCESS_ATTACH:  // DLL Loaded
      begin
        InterceptAPI('USER32.dll', 'MessageBoxA', @OMessageBoxA, @TMessageBoxA);
      end;

      DLL_PROCESS_DETACH:  // DLL Unloaded
      begin
        // Do something while dll is being unloaded.
      end;
  end;
end; { DllMain }

begin
  { Set the dll entry point and call it }
  DllProc := @DllMain;
  DllProc(DLL_PROCESS_ATTACH);
end.

Hace uso de la tecnica "Trampolin" que tambien utilizaste tu escafandra aqui: delphiaccess.com/forum/tutoriales/hook-a-la-api-en-delphi-(trampolin)

Mas o menos entiendo que hace el codigo y en que consiste la tecnica del trampolin.
Pero tengo unas dudas:
- Como se que $E9 hace referencia a JMP.
- Y la operación inversa. Como sacar que "codigo hexadecimal" tiene JMP.

Mirando google he visto otros codigos que hacen uso de la funcion SetWindowsHookEx, CallNextHookEx y UnhookWindowsHookEx para hacer un Hook.

Quería saber la diferencia que hay entre hacer un hook con el metodo trampolin y el hacer el hook utilizando las 3 apis de arriba. Tengo un codigo que hacer un hook del 2º tipo, pero sinceramente no lo entiendo.
Estudiando y leyendo, creo que la respuesta es que el metodo trampolin hace un hook INDIVIDUAL a una api de un UNICO proceso, mientras que con SetWindowsHookEx se hace un hook GLOBAL que es procesado por un UNICO proceso, pero sinceramente no estoy seguro de si es correcto lo que he dicho.

Muchisimas gracias escafandra por la ayuda!!!

Siento lo largo que me ha quedado el post y espero que me haya explicado con claridad.

Saludos

escafandra 19-08-2013 08:56:30

Cita:

Empezado por Jais (Mensaje 465353)
Mas o menos entiendo que hace el codigo y en que consiste la tecnica del trampolin.
Pero tengo unas dudas:
- Como se que $E9 hace referencia a JMP.
- Y la operación inversa. Como sacar que "codigo hexadecimal" tiene JMP.

E9h es el opcode de la instrucción JMP en ensamblador. Es así en la familia de microprocesadores intel desde el Z80.

Cita:

Empezado por Jais (Mensaje 465353)
Mirando google he visto otros codigos que hacen uso de la funcion SetWindowsHookEx, CallNextHookEx y UnhookWindowsHookEx para hacer un Hook.

Quería saber la diferencia que hay entre hacer un hook con el metodo trampolin y el hacer el hook utilizando las 3 apis de arriba. Tengo un codigo que hacer un hook del 2º tipo, pero sinceramente no lo entiendo.

Ese segundo tipo Hook no es a la API, sino de Windows, tienes amplia documentación: Hook Functions

Saludos.

Jais 19-08-2013 19:52:31

Ok, Muchísimas gracias Escafandra!!

¿Y donde puedo mirar o como puedo saber que JMP es E9?¿Y saber que E9 es JMP?

Un saludo

escafandra 20-08-2013 16:31:30

Cita:

Empezado por Jais (Mensaje 465773)
¿Y donde puedo mirar o como puedo saber que JMP es E9?¿Y saber que E9 es JMP?

Con un ensamblador-desensamblador. Por ejemplo con el programa de consola debug.
El desensamblador de delphi también te serviría.
También puedes consultar tablas de opcodes como esta.


Saludos.

Jais 22-08-2013 13:50:42

ok, muchísimas gracias escafandra!!

Seguro que me ayuda para entender mejor los opcodes.

Saludos


La franja horaria es GMT +2. Ahora son las 13:34:05.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi