Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Внедрение библиотеки через CreateRemoteThread

01.01.2007

А также исполнение своего кода в удаленном процессе через CreateRemote

////////////////////////////////////////////////////////////////////////////////
//
//  ****************************************************************************
//  * Project   : Inject/Eject Library Demo
//  * Unit Name : HookDLL
//  * Purpose   : Демонстрационный пример внедрения библиотеки через CreateRemoteThread
//  * Author    : Александр (Rouse_) Багель
//  * Version   : 1.00
//  ****************************************************************************
//   
 
Library HookDLL;

 
uses
  Windows,
  Messages,
  SysUtils;
 
procedure DLLEntryPoint(dwReason: DWORD); 
begin
  case dwReason of
    DLL_PROCESS_ATTACH:
    begin
      MessageBox(0, 'DLL_PROCESS_ATTACH', 'DLL_PROCESS_ATTACH', MB_OK);
      ExitThread(0);
    end;
  end;
end;
 
begin
  DLLProc := @DLLEntryPoint;
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.

 
 

Приложение:

////////////////////////////////////////////////////////////////////////////////
//
//  ****************************************************************************
//  * Project   : Inject/Eject Library Demo
//  * Unit Name : main
//  * Purpose   : Демонстрационный пример внедрения библиотеки через CreateRemoteThread
//  * Author    : Александр (Rouse_) Багель
//  * Version   : 1.00
//  ****************************************************************************
//
 
unit main;

 
interface
 
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
resourcestring
  BTN_INJECT = 'Inject';
  BTN_EJECT  = 'Eject';
 
const
  DLLName = 'hooklib.dll';
 
type
  TfrmMain = class(TForm)
    btnInjectEject: TButton;
    GroupBox: TGroupBox;
    lbStatus: TListBox;
    procedure btnInjectEjectClick(Sender: TObject);
  private
    function InjectLib(const ProcessID: DWORD): Boolean;
    function EjectLib(const ProcessID: DWORD): Boolean;
  end;
 
  // Декларация функций при помощи которых будет происходить выгрузка билиотеки
  TGetModuleHandle = function (lpModuleName: PChar): HMODULE; stdcall;
  TFreeLibrary = function (hLibModule: HMODULE): BOOL; stdcall;
 
  // Структура передаваемая потоковой функции при выгрузке библиотеки
  PEjectLibStruct = ^TEjectLibStruct;
  TEjectLibStruct = record
    hGetModuleHandle: TGetModuleHandle;
    hFreeLibrary: TFreeLibrary;
    lpModuleName: PChar;
  end;
 
var
  frmMain: TfrmMain;
 
implementation
 
{$R *.dfm}
 
{ TfrmMain }
 
//  Обработчик кнопки на внедрение/выгрузку библиотеки
// =============================================================================
procedure TfrmMain.btnInjectEjectClick(Sender: TObject);
begin
  TComponent(Sender).Tag := TComponent(Sender).Tag + 1;
  if (TComponent(Sender).Tag mod 2) = 1 then
  begin
    btnInjectEject.Caption := BTN_EJECT;
    if InjectLib(GetCurrentProcessID) then
      lbStatus.Items.Add('Library injected succes.')
    else
      lbStatus.Items.Add('Library injected fail.');
  end
  else
  begin
    btnInjectEject.Caption := BTN_INJECT;
    if EjectLib(GetCurrentProcessID) then
      lbStatus.Items.Add('Library ejected succes.')
    else
      lbStatus.Items.Add('Library ejected fail.');
  end;
end;
 
//  Пока наш процесс не получит отлабочные привилегии,
//  весь этот код работать не будет
// =============================================================================
function SetDebugPriv: Boolean;
var
  Token: THandle;
  tkp: TTokenPrivileges;
  ReturnLength: DWORD;
begin
  Result := false;
  // Получаем токен текущего процесса
  if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then
  begin
    // Получаем Luid привилегии
    if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), tkp.Privileges[0].Luid) then
    begin
      // Заполняем необходимые параметры
      tkp.PrivilegeCount := 1;
      tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      // Включаем привилегию
      Result := AdjustTokenPrivileges(Token, false, tkp, 0, nil, ReturnLength);
    end;
  end;
end;     
 
//  Функция внедряет библиотеку в удаленный процесс с PID равным ProcessID
//  Для успешного внедрения нужно передать адрес функции LoadLibraryA
//  и путь к загружаемой библиотеке.
//  Строку с путем необходимо разместить в алресном пространстве удаленного процесса
// =============================================================================
function TfrmMain.InjectLib(const ProcessID: DWORD): Boolean;
var
  Process: HWND;
  ThreadRtn: FARPROC;
  DllPath: String;
  RemoteDll: Pointer;
  BytesWriten: DWORD;
  Thread: DWORD;
  ThreadId: DWORD;
  ExitCode: DWORD;
begin
  // Устанавливаем отладочные привилегии для нашего процесса
  Result := SetDebugPriv;
  if not Result then Exit;
  Process := 0;
  Thread := 0;
  try
    // Открываем процесс
    Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
      PROCESS_VM_WRITE, True, ProcessID);
    if Process = 0 then Exit;
    // Выделяем в нем память под строку
    DllPath := ExtractFilePath(ParamStr(0)) + DLLName;
    RemoteDll := VirtualAllocEx(Process, nil, Length(DllPath),
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
    if RemoteDll = nil then Exit;
    // Пишем путь к длл в его адресное пространство
    if not WriteProcessMemory(Process, RemoteDll, PChar(DllPath),
      Length(DllPath), BytesWriten) then Exit;
    if BytesWriten <> DWORD(Length(DllPath)) then Exit;
    // Получаем адрес функции из Kernel32.dll
    ThreadRtn := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'LoadLibraryA');
    if ThreadRtn = nil then Exit;
    // Запускаем удаленный поток
    Thread := CreateRemoteThread(Process, nil, 0, ThreadRtn, RemoteDll, 0, ThreadId);
    if Thread = 0 then Exit;
    // Ждем пока удаленный поток отработает...
    if (WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0) then
      if GetExitCodeThread(Thread, ExitCode) then
        Result := ExitCode = 0;
  finally
    // Удаленный поток свою задачу выполнил и загрузил нашу библиотеку,
    // можно освобождать занятую память...
    if RemoteDll <> nil then
      VirtualFreeEx(Process, @RemoteDll, 0, MEM_RELEASE);
    if Thread <> 0 then CloseHandle(Thread);
    if Process <> 0 then CloseHandle(Process);  
  end;
end;
 
//  Для того чтобы выгрузить библиотеку, необходимо найти ее адрес в удаленном
//  процессе и вызвать там же FreeLibrary
//  Этим у нас будет заниматься вот такая функция
//  Для успешной ее работы необходимо передать 3 параметра.
//  1: Адреса функций GetModuleHandle и FreeLibrary;
//  2: Имя модуля, выгрузку которого мы будем производить
// =============================================================================
function RemoteFreeLibrary(lpParameter: Pointer): DWORD; stdcall;
var
  hLibModule: HMODULE;
begin
  Result := 0;
  if lpParameter = nil then Exit;
  // Получаем описатель нашей библиотеки (используем переданные параметры)
  hLibModule := TGetModuleHandle(PEjectLibStruct(lpParameter)^.hGetModuleHandle)
    (PEjectLibStruct(lpParameter)^.lpModuleName);
  if hLibModule <> 0 then
    // Выгружаем библиотеку
    Result := DWORD(TFreeLibrary(PEjectLibStruct(lpParameter)^.hFreeLibrary)(hLibModule));
end;
 
//  Данная функция запускает в удаленном процессе поток
//  с потоковой функцией RemoteFreeLibrary
//  и подготавливает для ее работы необходимые данные
// =============================================================================
function TfrmMain.EjectLib(const ProcessID: DWORD): Boolean;
var
  Process: HWND;
  BytesWriten: DWORD;
  Thread: DWORD;
  ThreadId: DWORD;
  ExitCode: DWORD;
  EjectLibStruct: TEjectLibStruct;
  EjectLibStructAddr: Pointer;
begin
  Result := False;
  Process := 0;
  Thread := 0;
  try
    // Открываем процесс
    Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
      PROCESS_VM_WRITE, True, ProcessID);
    if Process = 0 then Exit;
    // Выделяем в нем память под имя модуля
    EjectLibStruct.lpModuleName := VirtualAllocEx(Process, nil, Length(DLLName),
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
    if EjectLibStruct.lpModuleName = nil then Exit;
    // Пишем имя модуля в его адресное пространство
    if not WriteProcessMemory(Process, EjectLibStruct.lpModuleName, PChar(DLLName),
      Length(DLLName), BytesWriten) then Exit;
    if BytesWriten <> DWORD(Length(DLLName)) then Exit;
    // Получаем адрес функции FreeLibrary из Kernel32.dll
    EjectLibStruct.hFreeLibrary :=
      GetProcAddress(GetModuleHandle('Kernel32.dll'), 'FreeLibrary');
    if not Assigned(EjectLibStruct.hFreeLibrary) then Exit;
    // Получаем адрес функции GetModuleHandle из Kernel32.dll
    EjectLibStruct.hGetModuleHandle :=
      GetProcAddress(GetModuleHandle('Kernel32.dll'), 'GetModuleHandleA');
    if not Assigned(EjectLibStruct.hGetModuleHandle) then Exit;
    // Выделяем память под структуру, которая передается нашей функции
    EjectLibStructAddr := VirtualAllocEx(Process, nil, SizeOf(TEjectLibStruct),
      MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
    if EjectLibStructAddr = nil then Exit;
    // Пишем саму структуру
    if not WriteProcessMemory(Process, EjectLibStructAddr, @EjectLibStruct,
      SizeOf(TEjectLibStruct), BytesWriten) then Exit;
    if BytesWriten <> DWORD(SizeOf(TEjectLibStruct)) then Exit;
 
    // Запускаем удаленный поток
    Thread := CreateRemoteThread(Process, nil, 0, @RemoteFreeLibrary,
      EjectLibStructAddr, 0, ThreadId);
    if Thread = 0 then Exit;
    // Ждем пока удаленный поток отработает...
    if (WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0) then
      if GetExitCodeThread(Thread, ExitCode) then
        Result := BOOL(ExitCode);
  finally
    // Удаленный поток свою задачу выполнил и выгрузил нашу библиотеку,
    // можно освобождать занятую память...
    VirtualFreeEx(Process, @EjectLibStruct.lpModuleName, 0, MEM_RELEASE);
    VirtualFreeEx(Process, @EjectLibStructAddr, 0, MEM_RELEASE);
    if Thread <> 0 then CloseHandle(Thread);
    if Process <> 0 then CloseHandle(Process);
  end;
end;
 
end.

 

Взято из https://forum.sources.ru

Автор: Rouse_
 

Проект также доступен по адресу: http://rouse.front.ru/injectlib.zip