Для загрузки библиотеки можно использовать функцию LdrLoadDll из ntdll.dll.
Код:
function LdrLoadDll(szcwPath: PWideChar;
pdwLdrErr: dword;
pUniModuleName: PUnicodeString;
pResultInstance: PDWORD): NTSTATUS;
stdcall; external 'ntdll.dll';
Нас интересует параметр pUniModuleName представляющий из себя указатель на строку типа UnicodeString в которой передается имя загружаемой DLL. По указателю pResultInstance будет сохранен адрес MZ заголовка загруженной DLL (параметр hInstance).
Следующий код загружает DLL аналогично функции kernel32 LoadLibraryW:
Код:
Function MyLoadLibrary(lpLibFileName: PWideChar): HMODULE;
var
uName: TUnicodeString;
begin
RtlInitUnicodeString(@uName, lpLibFileName);
if (LdrLoadDll(nil, 0, @uName, @Result) > 0) then Result := 0;
RtlFreeUnicodeString(@uName);
end;
Для получения адреса функции cледует использовать LdrGetProcedureAddress.
Код:
function LdrGetProcedureAddress(hModule: dword;
dOrdinal: DWORD;
psName: PAnsiString;
ppProcedure: ppointer): NTStatus;
stdcall; external 'ntdll.dll';
Если необходимо обеспечить максимальную скрытность перехвата, то вообще лучше использовать во внедряемом коде только функции Native API.
Процедура копирования участка памяти в процесс:
Код:
function InjectMemory(Process: dword; Memory: pointer; Size: dword): pointer;
var
BytesWritten: dword;
begin
Result := VirtualAllocEx(Process, nil, Size, MEM_COMMIT or MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
WriteProcessMemory(Process, Result, Memory, Size, BytesWritten);
end;
Эта процедура предельно проста, она принимает хэндл открытого процесса, указатель на данные в текущем процессе и размер данных, а возвращает указатель на данные в целевом процессе.
Внедрение процедуры в целевой процесс:
Код:
program InjectCode;
uses
Windows,
advApiHook;
type
TRemoteInfo = record
LoadLibrary: function(lpLibFileName: PChar): HMODULE; stdcall;
GetProcAddress: function(hModule: HMODULE;
lpProcName: LPCSTR): FARPROC; stdcall;
Kernel32 : array[0..16] of Char;
User32 : array[0..16] of Char;
MessageBoxA : array[0..16] of Char;
nExitThread : array[0..16] of Char;
Text : array[0..16] of Char;
Title : array[0..16] of Char;
end;
{ Процедура внедряемая в процесс }
procedure RemoteThread(RemoteInfo: pointer); stdcall;
var
MessageBox: function(hWnd: HWND; lpText,
lpCaption: PChar; uType: UINT): Integer; stdcall;
ExitThread: procedure(uExitCode: UINT); stdcall;
begin
with TRemoteInfo(RemoteInfo^) do
begin
@MessageBox := GetProcAddress(LoadLibrary(User32), MessageBoxA);
@ExitThread := GetProcAddress(LoadLibrary(Kernel32), nExitThread);
MessageBox(0, Text, Title, 0);
ExitThread(0);
end;
end;
procedure RemoteThreadEnd; begin end; //метка конца кода
var
RemoteInfo: TRemoteInfo;
pInfo, CodeAdr: pointer;
TID: dword;
Process: dword;
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
begin
//Запускаем процесс
ZeroMemory(@StartInfo, SizeOf(TStartupInfo));
StartInfo.cb := SizeOf(TStartupInfo);
CreateProcess(nil, 'notepad.exe', nil, nil, False, 0,
nil, nil, StartInfo, ProcInfo);
Process := ProcInfo.hProcess;
//Заполняем структуру передаваемую внедряемому коду
lstrcpy(RemoteInfo.User32, 'user32.dll');
lstrcpy(RemoteInfo.Kernel32, 'kernel32.dll');
lstrcpy(RemoteInfo.MessageBoxA, 'MessageBoxA');
lstrcpy(RemoteInfo.nExitThread, 'ExitThread');
lstrcpy(RemoteInfo.Text, 'Hello World!');
lstrcpy(RemoteInfo.Title, 'Injected MessageBox');
//получаем адреса используемых API
@RemoteInfo.LoadLibrary := GetProcAddress(GetModuleHandle('kernel32.dll'),
'LoadLibraryA');
@RemoteInfo.GetProcAddress := GetProcAddress(GetModuleHandle('kernel32.dll'),
'GetProcAddress');
//копируем в процесс структуру с данными
pInfo := InjectMemory(Process, @RemoteInfo, SizeOf(TRemoteInfo));
//копируем в процесс внедряемый код
CodeAdr := InjectMemory(Process, @RemoteThread,
dword(@RemoteThreadEnd) - dword(@RemoteThread));
//запускаем внедренный код
CreateRemoteThread(Process, nil, 0, CodeAdr, pInfo, 0, TID);
end.
Перед внедрением кода процедуры, необходимо скопировать в память целевого процесса структуру с данными используемыми внедряемым кодом. В этой структуре необходимо передать адреса функций LoadLibary и GetProcAddress, через которые внедряемый код будет загружать используемые библиотеки и получать адреса используемых функций.
введем еще одну процедуру:
Код:
function InjectThread(Process: dword; Thread: pointer; Info: pointer;
InfoLen: dword; Results: boolean): THandle;
var
pThread, pInfo: pointer;
BytesRead, TID: dword;
begin
pInfo := InjectMemory(Process, Info, InfoLen);
pThread := InjectMemory(Process, Thread, SizeOfProc(Thread));
Result := CreateRemoteThread(Process, nil, 0, pThread, pInfo, 0, TID);
if Results then
begin
WaitForSingleObject(Result, INFINITE);
ReadProcessMemory(Process, pInfo, Info, InfoLen, BytesRead);
end;
end;
Эта процедура копирует в целевой процесс внедряемый код и структуру с данными для него, после чего запускает внедренный код.
Принимаемые параметры:
Process - хэндл открытого процесса.
Thread - указатель на внедряемый код в текущем процессе.
Info - указатель на структуру с данными.
InfoLen - размер структуры с данными.
Results - необходимость возврата результата. (если true, то функция ожидает завершения удаленного потока и копирует обратно структуру с данными) .