{-----------------------------------------------------------------------------
Unit Name: RemoteInjection
Author: Jason Eric Pierce
Purpose: To cause another application to load a DLL on demand
Date: 7/24/2004
License: The code in this library is public domain. It may be included
in any program, commercial or otherwise, free of charge.
References: "Three Ways to Inject Your Code into Another Process" by Robert Kuster
"API hooking revealed" by Ivo Ivanov
Requires: This library uses CreateRemoteThread, which only exists on NT or
greater. For Windows 9x, you would need to use a system-wide
hook. The benefit to CreateRemoteThread is that it can be used
to target loading into a specific process only, rather than having
your DLL loading into the memory of every application.
Only applications that link to kernel32.dll can use this method.
However, only really hairy system-level applications don't link
to it.
Notes: Much of the code in this unit was translated into Delphi from the
excellent article by Robert Kuster. This was found at:
http://www.codeproject.com/threads/winspy.asp?df=100&forumid=16291&exp=0&select=858734
Usage: Call LoadLibraryIntoProcess with the full path to the DLL you
want to load and any window handle from the process you want to
hook into. It will return a handle to the loaded module which
you should save if you want to be able to unload the DLL
later. You do not need to close this handle manually.
When you are ready to unload the library, pass the handle to
UnloadLibraryFromProcess.
Uses: Forcing an application to load your DLL can be very useful if you
want to subclass a window in that application. This allows you
to monitor the Windows messages being processed by that window and
use them to alter its look or behavior. For example, you could
watch for any WM_PAINT messages to a certain window and follow it
with your own painting. For more information, read the articles
provided in the References section.
-----------------------------------------------------------------------------}
unit RemoteInjection;
interface
uses
Windows;
function LoadLibraryIntoProcess(LibPathAndName: string; TargetWnd: HWND): THandle;
function UnloadLibraryFromProcess(LibraryHandle: THandle; TargetWnd: HWND): Boolean;
implementation
function GetProcessHandle(Wnd: THandle): THandle;
var
processId: THandle;
begin
Result := 0;
if Wnd <> 0 then
begin
GetWindowThreadProcessID(Wnd, @processId);
if processId <> 0 then
Result := OpenProcess(PROCESS_ALL_ACCESS, False, processId);
end;
end;
function LoadLibraryIntoProcess(LibPathAndName: string; TargetWnd: HWND): THandle;
var
hThread: THandle;
dummy: THandle;
pLibRemote: Pointer; // The address (in the remote process) where
// LibPathAndName will be copied to
lpNumberOfBytesWritten: DWORD;
hProcess: THandle;
begin
Result := 0;
hProcess := GetProcessHandle(TargetWnd);
if hProcess <> 0 then
try
lpNumberOfBytesWritten := 0;
// 1. Allocate memory in the remote process for LibPathAndName
// 2. Write LibPathAndName to the allocated memory
pLibRemote := VirtualAllocEx(hProcess, nil, Length(LibPathAndName) + 1,
MEM_COMMIT, PAGE_READWRITE);
try
if pLibRemote = nil then
Exit;
WriteProcessMemory(hProcess, pLibRemote, PChar(LibPathAndName),
Length(LibPathAndName) + 1, // get the null too
lpNumberOfBytesWritten);
// Load the dll into the remote process
// (via CreateRemoteThread & LoadLibrary)
hThread := CreateRemoteThread(hProcess, nil, 0,
GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryA'),
pLibRemote, 0, dummy);
if hThread <> 0 then
try
WaitForSingleObject(hThread, INFINITE);
// Get handle of the loaded module
if not GetExitCodeThread(hThread, Result) then
Result := 0;
finally
// Clean up
CloseHandle(hThread);
end;
finally
VirtualFreeEx(hProcess, pLibRemote, Length(LibPathAndName) + 1,
MEM_RELEASE);
end;
finally
CloseHandle(hProcess);
end;
end;
function UnloadLibraryFromProcess(LibraryHandle: THandle; TargetWnd: HWND): Boolean;
var
hThread: THandle;
hProcess: THandle;
begin
Result := False;
hProcess := GetProcessHandle(TargetWnd);
if hProcess <> 0 then
try
if LibraryHandle <> 0 then
if CreateRemoteThread(hProcess, nil, 0,
GetProcAddress(GetModuleHandle('Kernel32'), 'FreeLibrary'),
Pointer(LibraryHandle), 0, hThread) <> 0 then
begin
WaitForSingleObject(hThread, INFINITE);
Result := True;
end;
finally
CloseHandle(hThread);
end;
end;
end.