Calling an exported function from an injected DLL library
As I am interested in function hooking/detouring in win32 I have read alot of articles about injecting a library into a remote process. Although none of these guides cover how to remotely call an exported function from the injected DLL. Most injectable library’s just execute their code in the DLLMain entry function.
In the past I have written a DLL that acquired the mouse using DirectInput. The initialization code in the DLLMain entry function actually made the process lockup. Microsoft doesn’t guarantee the DLLMain code to be executed successfully. Microsoft does not recommend this approach. I find creating a thread also a nasty way to initialize your code, eventhough it decreases the chance of an execution failure, creating the thread itself can still fail in theory.
This guide describes how to call a function from the injected library after injecting it.
What do you need
- Your DLL obviously should have been injected successfully.
- An open handle (called hProcess) to the remote process with the permission to use CreateRemoteThread.
- You have saved the remote DLL base address into a DWORD variable called dwBaseAddress. (Use GetExitCodeThread on the remote LoadLibrary thread to retrieve this address).
- The remote function of the injected DLL should be exported.
- The name of the export of the DLL function (entryPoint in this guide).
- The path to the DLL (c:\lib.dll in this guide).
The steps required after injection
- Load the library into the local process (injector).
- Retrieve the absolute address of the DLL function in the injector.
- Calculate the relative address using the absolute address.
- Locally unload the library.
- Calculate the absolute address of the DLL function in the remote process using adding the relative function address to the DLL base address.
- Call the function using CreateRemoteThread.
- Retrieve the remote thread exit code to determine if the remote execution was successful.
Retrieving the relative function address
FARPROC getRelativeEntryAddress(LPWSTR pwszLibrary, char* szEntryFunction) { if (GetFileAttributesW(pwszLibrary) == INVALID_FILE_ATTRIBUTES) return NULL; HINSTANCE hLibrary = LoadLibraryW(pwszLibrary); if (!hLibrary) return NULL; FARPROC pFunction = GetProcAddress(hLibrary, szEntryFunction); if (!pFunction) return NULL; return (FARPROC)((DWORD)pFunction - (DWORD)hLibrary); } |
Retrieving the absolute address of the remote function
LPVOID getAbsoluteAddress(DWORD dwBaseAddress, LPVOID pFunction) { return (LPVOID)((DWORD)pFunction + dwBaseAddress); } |
Calling the remote function by it’s absolute address
bool callRemoteFunction(HANDLE hProcess, LPVOID pFunction) { DWORD dwExitCode; HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunction, NULL, 0, NULL); if (!hThread) return false; if (WaitForSingleObject(hThread, THREAD_WAIT) != WAIT_OBJECT_0) return false; if (!GetExitCodeThread(hThread, &dwExitCode)) return false; return (dwExitCode != 0); // Assuming your function returns 0 if it does not succeed } |
Using the functions in your code
// You should have an open handle to the process, called hProcess // You also should have the base address of the DLL, called dwBaseAddress FARPROC pEntry = getRelativeEntryAddress(L"c:\\lib.dll", "entryPoint"); if (!pEntry) { // Failed to load the library into local process or retrieve the function address } LPVOID pFunction = getAbsoluteAddress(dwBaseAddress, pEntry); if (!callRemoteFunction(hProcess, pFunction)) { // Failed to call the remote function } |
If you found this article useful please leave me a comment.