Calling function in injected DLL - c++

I want to call a function in a remote process of an injected DLL that I've made.
I have successfully injected my DLL with:
CreateRemoteThread(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA"), pLibRemote, 0, NULL);
The DllMain is executed and the DLL is running in a stand-by mode. What I would like to do is somehow call the remotely loaded DLL in order to do some work.
I have tried exporting the function like this:
extern "C" __declspec(dllexport) void MyFunc(void)
and then executing the function like this:
CreateRemoteThread(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("mydll"), "MyFunc"), NULL, 0, NULL);
but it results in a crash.
How can I solve this?

Calling GetModuleHandle as you have will get the base of the DLL as it is mapped into your process (if at all). So what you need to do is first make sure to export the function in the DLL. You can do as you have done or create a .def file as shown here. Thereafter:
In Theory
Inject the DLL to the target process and get the base address it was loaded at
Inject the DLL to the current process. Use GetProcAddress to find the offset between the exported function and the base of the DLL.
Add this offset to the base address obtained from step 1. CreateRemoteThread at this location.
In Practice
When doing your DLL injection, it is possible for you to get the base that your DLL is loaded into the target.
HMODULE hInjected;
hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)( GetProcAddress( hMod,
"LoadLibraryW" ) ), lpAddress, 0, NULL );
// Locate address our payload was loaded
if( hThread != 0 ) {
WaitForSingleObject( hThread, INFINITE );
GetExitCodeThread( hThread, ( LPDWORD )&hInjected );
CloseHandle( hThread );
}
hInjected will be the base of the injected DLL. I then have another function:
void* GetPayloadExportAddr( LPCWSTR lpPath, HMODULE hPayloadBase, LPCSTR lpFunctionName ) {
// Load payload in our own virtual address space
HMODULE hLoaded = LoadLibrary( lpPath );
if( hLoaded == NULL ) {
return NULL;
} else {
void* lpFunc = GetProcAddress( hLoaded, lpFunctionName );
DWORD dwOffset = (char*)lpFunc - (char*)hLoaded;
FreeLibrary( hLoaded );
return (DWORD)hPayloadBase + dwOffset;
}
}
What this does is first load the payload into our own virtual address space. Afterwards,
we can use GetProcAddress to get the address of the exported function. From this, we can get the offset of the function from the base of the DLL. Adding this offset to the hInjected we got earlier will tell us where the CreateRemoteThread call should be made. So you could make a call like so:
BOOL InitPayload( HANDLE hProcess, LPCWSTR lpPath, HMODULE hPayloadBase, HWND hwndDlg ) {
void* lpInit = GetPayloadExportAddr( lpPath, hPayloadBase, "Init" );
if( lpInit == NULL ) {
return FALSE;
} else {
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0,
lpInit, hwndDlg, 0, NULL );
if( hThread == NULL ) {
return FALSE;
} else {
CloseHandle( hThread );
}
}
return TRUE;
}
This is all code that is ripped out of an old project I have. You're welcome to take the code and do whatever you want with it but I know if I were to rewrite the code now, I would do a lot of things differently.

Mike's answer works if you are injecting a 32bit DLL into a 32bit process.
If you want to inject a 64bit DLL into a 64bit process, you can't get the base address of the DLL from GetExitCodeThread since it will only give you the lower 32bits of the 64bit address.
To get the correct address in this case, you must write a block of code into the process that calls LoadLibrary (storing the result at a specific location in process memory), execute this block of code (using CreateRemoteThread), and then read back the address from that location using ReadProcessMemory.
You can find more details for this here (including PowerShell and ASM code) here:
http://clymb3r.wordpress.com/2013/05/26/implementing-remote-loadlibrary-and-remote-getprocaddress-using-powershell-and-assembly/
You can then compute the offset to your exported function the same way Mike describes, but watch out to store the difference in a 64bit value, and not in a DWORD (which is 32bit).

Related

FreeLibrary not unhooking DLL

I'm trying to hook the DLL onto a notepad process, and then unhook it. When hooked, the DLL should cause the notepad to create a hidden file whenever the user clicks "Save As" (code for this is not shown). When unhooked, that should not be the case.
However, for some reason, while I got the message "DLL unhooking from process", the DLL still is not unhooked from the notepad process, and I know this because the notepad still creates the additional file when it should not have done that.
There are no error messages on the return values whatsover (at least none that I know of), so I removed most return value checks.
Hook
HANDLE hThread;
char * pid = argv[1];
DWORD user_pid = atoi(pid);
LPCSTR Dllpath = "C:\\Users\\xxx\\Desktop....\\MyDll.dll"
LPVOID pDllPath; // Address in remote process where Dllpath will be copied to.
HMODULE hKernel32 = GetModuleHandle("Kernel32");
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, user_pid);
char * command = argv[2];
if (strcmp(command,"hook") == 0){
SIZE_T bytesWritten = 0;
//Allocate memory to target process, and write dll to the allocated memory.
pDllPath = VirtualAllocEx(hProcess, NULL,strlen(DllPath)+1, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
// Write DLL hook name
WriteProcessMemory(hProcess, pDllPath, (LPCVOID)DllPath, strlen(Dllpath)+1,&bytesWritten);
// Load Dll to remote process
hThread = CreateRemoteThread(hProcess, NULL,0,(LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA"), pDllPath,0,NULL);
WaitForSingleObject(hThread, INFINITE);
//Clean up
CloseHandle(hThread);
VirtualFreeEx(hProcess, pDllPath, strlen(DllPath+1, MEM_RELEASE);
else if (strcmp(command,"unhook")==0){
InlineUnhook(); //Call unhook inside the dll itself
}
}
Unhook (inside the dll itself)
HANDLE __stdcall InlineUnhook(){
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
LoadLibrary("C:\\Users\\xxx\\Desktop...\\MyDll.dll);
HMODULE hLibModule = GetModuleHandleA ("C:\\Users\\xxx\\Desktop...\\MyDll.dll);
HANDLE hThread = CreateRemoteThread(hProcess, NULL,0,(LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "FreeLibraryAndExitThread"), (void *)(hLibModule,0),0,NULL);
if (hThread == NULL){
OutputDebugStringA("CreateRemoteThread failed.");
return -1;
}
else{
WaitForSingleObject(hThread, INFINITE);
//Clean up
CloseHandle(hThread);
OutputDebugStringA("DLL unhooking from process...");
return 0;
}
}
Your injector is calling InlineUnhook() directly, so it will act on the instance of the DLL that is loaded in the injector process, not the hooked process.
FreeLibraryAndExitThread() is not compatible with CreateRemoteThread(), so you can't use a remote thread to call it directly, like you can with LoadLibraryA().
Inside of the DLL itself, there is no need for it to call OpenProcess(), LoadLibrary(), or CreateRemoteThread() for itself. The DLL can simply call FreeLibraryAndExitThread() directly, like any other local function.
HINSTANCE hThisInst;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
hThisInst = hinstDLL;
...
return 1;
}
void __stdcall InlineUnhook()
{
FreeLibraryAndExitThread(hThisInst, 0);
}
Your injector will have to use a remote thread to call InlineUnhook() within the context of the hooked process, rather than calling it directly. That means you need to:
export InlineUnhook() from the DLL.
find the address of the loaded DLL within the hooked process. If your DLL is 32bit being loaded into a 32bit target process, that address can be obtained from GetExitCodeThread() when CreateRemoteThread() is done calling LoadLibraryA(). Otherwise, you will have to go hunting for the loaded address afterwards, such as by EnumProcessModules() or CreateToolhelp32Snapshot(TH32CS_SNAPMODULE).
find the address of the exported InlineUnhook() within the hooked process. Use LoadLibrary() and GetProcAddress() inside the injector to calculate the offset of InlineUnhook() within the DLL, and then apply that offset to the address of the loaded DLL within the hooked process.
use CreateRemoteThread() to call InlineUnhook() at that calculated address. You will have to change the signature of InlineUnhook() to be compatible with CreateRemoteThread(), eg:
DWORD __stdcall InlineUnhook(LPVOID)
{
FreeLibraryAndExitThread(hThisInst, 0);
return 1;
}
That's because your InlineUnhook call above calls the copy of the dll that is loaded into your injection process, not the one in the target process.

DLL injection via CreateRemoteThread?

Lets assume the remote thread procedure look like this:
DWORD __stdcall ThreadProc (void *pData) {
ThreadData *p = (ThreadData*)pData; // Contains function references and strings
p->MessageBoxW(NULL, p->Message, p->Title, MB_OK);
}
Then everything works fine and p->MessageBoxW(...) shows a message box as expected. But I don't want to call GetProcAddress for every function I use in the remote thread, so I thought I could create a function export within my module (EXE file creating the remote thread), so that the remote thread just calls LoadLibraryW to load my EXE file as module into the target process's address space and GetProcAddress to get the exported function's address in order to call it.
typedef void (__stdcall *_Test) ();
extern "C" void __stdcall Test () {
return;
}
DWORD __stdcall ThreadProc (void *pData) {
ThreadData *p = (ThreadData*)pData; // Contains function references and strings
HMODULE hLib = p->LoadLibraryW(p->LibPath);
_Test pTest = (_Test)p->GetProcAddress(hLib, p->ProcName);
pTest();
p->FreeLibrary(hLib);
return NULL;
}
This still works fine. But as soon as I change the exported function to
extern "C" void __stdcall Test () {
MessageBoxW(NULL, L"Message", L"Title", MB_OK);
return;
}
the target process suddenly crashes. Doesn't LoadLibrary resolve intermodular references? Is it possible to load my module into the target process's address space so that the exported function can be coded without passing all function addresses to it?
Additional information: For everyone copying the code, I had to disable incremental linking, build as release and add a module definition file to ensure that Test is exported as Test and not as _Test#SoMeJuNk. Just prepending __declspec(dllexport) didn't work for some reason. The module definition file looks like this
EXPORTS
Test#0
The ThreadData structure looks like this
typedef struct tagThreadData {
typedef BOOL (__stdcall *_FreeLibrary) (HMODULE);
typedef FARPROC (__stdcall *_GetProcAddress) (HMODULE, PSTR);
typedef HMODULE (__stdcall *_LoadLibraryW) (LPWSTR);
typedef DWORD (__stdcall *_MessageBoxW) (HWND, LPWSTR, LPWSTR, DWORD);
_FreeLibrary FreeLibrary;
_GetProcAddress GetProcAddress;
_LoadLibraryW LoadLibraryW;
_MessageBoxW MessageBoxW;
WCHAR LibPath[100];
WCHAR Message[30];
CHAR ProcName[10];
WCHAR Title[30];
} ThreadData, *PThreadData;
I came up with a temporary solution: Putting all remote code into an actual DLL. But putting the code into a DLL isn't my target, so if someone comes up with a clever solution, where the EXE file is the injector as well as the module being injected, I will mark the new answer as right.
Even though there are many tutorials on how to inject an actual DLL into another process's address space, I still give away my solution. I wrote my original solution only for UNICODE and 64-Bit, but I tried my best to make it work for both ASCII and UNICODE and 32-bit and 64-bit. But lets get started...
First of all, an explanation of the basic steps
Obtain handle to the target process with at least the following access rights
PROCESS_CREATE_THREAD
PROCESS_QUERY_INFORMATION
PROCESS_VM_OPERATION
PROCESS_VM_WRITE
PROCESS_VM_READ
Allocate memory for the remote thread procedure and the data and function pointers needed for loading the target dll and its "entrypoint" (I don't mean the actual entrypoint DllMain, but a function designed to be called from within the remote thread)
PVOID pThread = VirtualAllocEx(hProc, NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
Copy remote thread procedure and important data over to the target process
WriteProcessMemory(hProc, pThread, ThreadProc, ThreadProcLen, NULL);
WriteProcessMemory(hProc, pParam, &data, sizeof(ThreadData), NULL);
Create remote thread. This thread will load the target dll into the target process's address space and calls its "entrypoint"
HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, (PTHREAD_START_ROUTINE)pThread, pParam, NULL, NULL);
Optional: Wait until the thread returns
WaitForSingleObject(hThread, INFINITE);
DWORD threadExitCode;
GetExitCodeThread(hThread, &threadExitCode);
Close thread handle, release memory, Close process handle
CloseHandle(hThread);
VirtualFreeEx(hProc, pThread, 4096, MEM_RELEASE);
CloseHandle(hProc);
So here's my ThreadProc and ThreadData structure. ThreadProc is the remote thread procedure being called by CreateRemoteThread and should LoadLibrary the target dll, so it can call the target dll's "entrypoint". The ThreadData structure contains the addresses of LoadLibrary, GetProcAddress and FreeLibrary, the target dll's path TargetDll and the name of the "entrypoint" DllEntry.
typedef struct {
typedef BOOL (__stdcall *_FreeLibrary) (HMODULE);
typedef FARPROC (__stdcall *_GetProcAddress) (HMODULE, LPCH);
typedef HMODULE (__stdcall *_LoadLibrary) (LPTSTR);
typedef void (__stdcall *_DllEntry) ();
_LoadLibrary LoadLibrary;
TCHAR TargetDll[MAX_PATH];
_GetProcAddress GetProcAddress;
CHAR DllEntry[50]; // Some entrypoint designed to be
// called from the remote thread
_FreeLibrary FreeLibrary;
} ThreadData, *PThreadData;
// ThreadProcLen should be smaller than 3400, because ThreadData can
// take up to 644 bytes unless you change the length of TargetDll or
// DllEntry
#define ThreadProcLen (ULONG_PTR)2048
#define SPY_ERROR_OK (DWORD)0
#define SPY_ERROR_LOAD_LIB (DWORD)1
#define SPY_ERROR_GET_PROC (DWORD)2
DWORD ThreadProc (PVOID pParam) {
DWORD err = SPY_ERROR_OK;
PThreadData p = (PThreadData)pParam;
// Load dll to be injected
HMODULE hLib = p->LoadLibrary(p->TargetDll);
if (hLib == NULL)
return SPY_ERROR_LOAD_LIB;
// Obtain "entrypoint" of dll (not DllMain)
ThreadData::_DllEntry pDllEntry = (ThreadData::_DllEntry)p->GetProcAddress(hLib, p->DllEntry);
if (pDllEntry != NULL)
// Call dll's "entrypoint"
pDllEntry();
else
err = SPY_ERROR_GET_PROC;
// Free dll
p->FreeLibrary(hLib);
return err;
}
Then there's the actual code injecting the remote thread procedure into the target process's address space
int main(int argc, char* argv[]) {
// DWORD pid = atoi(argv[1]);
// Open process
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProc != NULL) {
// Allocate memory in the target process's address space
PVOID pThread = VirtualAllocEx(hProc, NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pThread != NULL) {
PVOID pParam = (PVOID)((ULONG_PTR)pThread + ThreadProcLen);
// Initialize data to be passed to the remote thread
ThreadData data;
HMODULE hLib = LoadLibrary(TEXT("KERNEL32.DLL"));
data.LoadLibrary = (ThreadData::_LoadLibrary)GetProcAddress(hLib, "LoadLibrary");
data.GetProcAddress = (ThreadData::_GetProcAddress)GetProcAddress(hLib, "GetProcAddress");
data.FreeLibrary = (ThreadData::_FreeLibrary)GetProcAddress(hLib, "FreeLibrary");
FreeLibrary(hLib);
_tcscpy_s(data.TargetDll, TEXT("...")); // Insert path of target dll
strcpy_s(data.DllEntry, "NameOfTheDllEntry"); // Insert name of dll's "entrypoint"
// Write procedure and data into the target process's address space
WriteProcessMemory(hProc, pThread, ThreadProc, ThreadProcLen, NULL);
WriteProcessMemory(hProc, pParam, &data, sizeof(ThreadData), NULL);
// Create remote thread (ThreadProc)
HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, (PTHREAD_START_ROUTINE)pThread, pParam, NULL, NULL);
if (hThread != NULL) {
// Wait until remote thread has finished
if (WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0) {
DWORD threadExitCode;
// Evaluate exit code
if (GetExitCodeThread(hThread, &threadExitCode) != FALSE) {
// Evaluate exit code
} else {
// The thread's exit code couldn't be obtained
}
} else {
// Thread didn't finish for some unknown reason
}
// Close thread handle
CloseHandle(hThread);
}
// Deallocate memory
VirtualFreeEx(hProc, pThread, 4096, MEM_RELEASE);
} else {
// Couldn't allocate memory in the target process's address space
}
// Close process handle
CloseHandle(hProc);
}
return 0;
}
The dll being injected has a real entrypoint DllMain that is called, when LoadLibrary loads the target dll into the target process's address space, and another "entrypoint" NameOfTheDllEntry called by the remote thread procedure (if it can be located in the first place)
// Module.def:
// LIBRARY NameOfDllWithoutExtension
// EXPORTS
// NameOfTheDllEntry
__declspec(dllexport) void __stdcall NameOfTheDllEntry () {
// Because the library is actually loaded in the target process's address
// space, there's no need for obtaining pointers to every function.
// I didn't try libraries other than kernel32.dll and user32.dll, but they
// should be working as well as long as the dll itself references them
// Do stuff
return;
}
BOOL APIENTRY DllMain (HMODULE hLib, DWORD reason, PVOID) {
if (reason == DLL_PROCESS_ATTACH)
DisableThreadLibraryCalls(hLib); // Optional
return TRUE;
}

Injected DLL and calling a function using CreateRemoteThread causes "has stopped working", what happens?

I`m trying to inject a DLL in a process and call a exported function in my DLL.
The DLL is injected alright with that code:
HANDLE Proc;
char buf[50] = { 0 };
LPVOID RemoteString, LoadLibAddy;
if (!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());
printf(buf);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
// Allocate space in the process for our DLL
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write the string name of our DLL in the memory allocated
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
// Load our DLL
HANDLE hThread = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
The module of my DLL is created OK, like you see in that image of Process Hacker (BootstrapDLL.exe):
My exported functions is ok too, like you see in the list of functions exported on Process Hacker (ImplantDotNetAssembly):
The problems, I think, happens on the offset calculation to get the address of the "ImplantDotNetAssembly", because everything above is alright and when I do the calculation I get the address of the "ImplantDotNetAssembly", but when I call CreateRemoteThread again to call it, the window "Has stopped working..." of the windows is showed and the process stoped. What`s happening?
Here is the code of the calculation of the offset:
DWORD_PTR hBootstrap = GetRemoteModuleHandle(ProcId, L"BootstrapDLL.exe");
DWORD_PTR offset = GetFunctionOffset(L"C:\\Users\\Acaz\\Documents\\Visual Studio 2013\\Projects\\Contoso\\Debug\\BootstrapDLL.exe", "ImplantDotNetAssembly");
DWORD_PTR fnImplant = hBootstrap + offset;
HANDLE hThread2 = CreateRemoteThread(Proc, NULL, 0, (LPTHREAD_START_ROUTINE)fnImplant, NULL, 0, NULL);
Here are the functions GetRemoteModuleHandle and GetFunctionOffset:
DWORD_PTR GetFunctionOffset(const wstring& library, const char* functionName)
{
// load library into this process
HMODULE hLoaded = LoadLibrary(library.c_str());
// get address of function to invoke
void* lpInject = GetProcAddress(hLoaded, functionName);
// compute the distance between the base address and the function to invoke
DWORD_PTR offset = (DWORD_PTR)lpInject - (DWORD_PTR)hLoaded;
// unload library from this process
FreeLibrary(hLoaded);
// return the offset to the function
return offset;
}
DWORD_PTR GetRemoteModuleHandle(const int processId, const wchar_t* moduleName)
{
MODULEENTRY32 me32;
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
// get snapshot of all modules in the remote process
me32.dwSize = sizeof(MODULEENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId);
// can we start looking?
if (!Module32First(hSnapshot, &me32))
{
CloseHandle(hSnapshot);
return 0;
}
// enumerate all modules till we find the one we are looking for or until every one of them is checked
while (wcscmp(me32.szModule, moduleName) != 0 && Module32Next(hSnapshot, &me32));
// close the handle
CloseHandle(hSnapshot);
// check if module handle was found and return it
if (wcscmp(me32.szModule, moduleName) == 0)
return (DWORD_PTR)me32.modBaseAddr;
return 0;
}
If someone know what is happening, I'll be very grateful!
I cant`t even debug the "has stopped work.." error. When I clik in the DEBUG button on the window, the error throw again and everything stop.
Thank you.
NEVER inject managed assemblies. If for some reason you must inject code into another process, use native code with either NO C library or a STATIC C library.

Calling a function in an injected DLL?

Using C++, I have an application which creates a remote process and injects a DLL into it. Is there a way to get the remote application to execute a function exported from the DLL, from the application which created it? And is it possible to send parameters to that function? Please note that I am trying to stay away from doing anything within DllMain.
Note:
For a much better answer, please see my update posted below!
Okay so here's how I was able to accomplish this:
BOOL RemoteLibraryFunction( HANDLE hProcess, LPCSTR lpModuleName, LPCSTR lpProcName, LPVOID lpParameters, SIZE_T dwParamSize, PVOID *ppReturn )
{
LPVOID lpRemoteParams = NULL;
LPVOID lpFunctionAddress = GetProcAddress(GetModuleHandleA(lpModuleName), lpProcName);
if( !lpFunctionAddress ) lpFunctionAddress = GetProcAddress(LoadLibraryA(lpModuleName), lpProcName);
if( !lpFunctionAddress ) goto ErrorHandler;
if( lpParameters )
{
lpRemoteParams = VirtualAllocEx( hProcess, NULL, dwParamSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( !lpRemoteParams ) goto ErrorHandler;
SIZE_T dwBytesWritten = 0;
BOOL result = WriteProcessMemory( hProcess, lpRemoteParams, lpParameters, dwParamSize, &dwBytesWritten);
if( !result || dwBytesWritten < 1 ) goto ErrorHandler;
}
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFunctionAddress, lpRemoteParams, NULL, NULL );
if( !hThread ) goto ErrorHandler;
DWORD dwOut = 0;
while(GetExitCodeThread(hThread, &dwOut)) {
if(dwOut != STILL_ACTIVE) {
*ppReturn = (PVOID)dwOut;
break;
}
}
return TRUE;
ErrorHandler:
if( lpRemoteParams ) VirtualFreeEx( hProcess, lpRemoteParams, dwParamSize, MEM_RELEASE );
return FALSE;
}
//...
CStringA targetDll = "injected.dll"
// Inject the target library into the remote process
PVOID lpReturn = NULL;
RemoteLibraryFunction( hProcess, "kernel32.dll", "LoadLibraryA", targetDll.GetBuffer(MAX_PATH), targetDll.GetLength(), &lpReturn );
HMODULE hInjected = reinterpret_cast<HMODULE>( lpReturn );
// Call our exported function
lpReturn = NULL;
RemoteLibraryFunction( hProcess, targetDll, "Initialize", NULL, 0, &lpReturn );
BOOL RemoteInitialize = reinterpret_cast<BOOL>( lpReturn );
This can also be used to send parameters to a remote function via a pointer to a struct or union, and gets around having to write anything in DllMain.
So after some elaborate testing, it would seem that my previous answer is anything but foolproof(or even 100% functional, for that matter), and is prone to crashes. After giving it some thought, I've decided to take an entirely different approach to this... using Interprocess Communication.
Be aware... this method utilizes code in DllMain.
So don't go overboard, and be sure to follow safe practices when doing this, so that you don't end up in a deadlock...
Most notably, the Win32 API offers the following useful functions:
CreateFileMapping
MapViewOfFile
OpenFileMapping
With the use of these, we can simply tell our Launcher process exactly where our remote init function resides, straight from the injected dll itself...
dllmain.cpp:
// Data struct to be shared between processes
struct TSharedData
{
DWORD dwOffset = 0;
HMODULE hModule = nullptr;
LPDWORD lpInit = nullptr;
};
// Name of the exported function you wish to call from the Launcher process
#define DLL_REMOTEINIT_FUNCNAME "RemoteInit"
// Size (in bytes) of data to be shared
#define SHMEMSIZE sizeof(TSharedData)
// Name of the shared file map (NOTE: Global namespaces must have the SeCreateGlobalPrivilege privilege)
#define SHMEMNAME "Global\\InjectedDllName_SHMEM"
static HANDLE hMapFile;
static LPVOID lpMemFile;
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
TSharedData data;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
// Get a handle to our file map
hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, SHMEMSIZE, SHMEMNAME);
if (hMapFile == nullptr) {
MessageBoxA(nullptr, "Failed to create file mapping!", "DLL_PROCESS_ATTACH", MB_OK | MB_ICONERROR);
return FALSE;
}
// Get our shared memory pointer
lpMemFile = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpMemFile == nullptr) {
MessageBoxA(nullptr, "Failed to map shared memory!", "DLL_PROCESS_ATTACH", MB_OK | MB_ICONERROR);
return FALSE;
}
// Set shared memory to hold what our remote process needs
memset(lpMemFile, 0, SHMEMSIZE);
data.hModule = hModule;
data.lpInit = LPDWORD(GetProcAddress(hModule, DLL_REMOTEINIT_FUNCNAME));
data.dwOffset = DWORD(data.lpInit) - DWORD(data.hModule);
memcpy(lpMemFile, &data, sizeof(TSharedData));
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
// Tie up any loose ends
UnmapViewOfFile(lpMemFile);
CloseHandle(hMapFile);
break;
}
return TRUE;
UNREFERENCED_PARAMETER(lpReserved);
}
Then, from our Launcher application, we will do the usual CreateProcess + VirtualAllocEx + CreateRemoteThread trick to inject our Dll, making sure to pass in a pointer to a proper SECURITY_DESCRIPTOR as the 3rd parameter to CreateProcess, as well as passing the CREATE_SUSPENDED flag in the 6th parameter.
This is to help ensure that your child process will have the proper privileges to read and write to a global shared memory namespace, though there are also other ways to achieve this (or you could test without the global path altogether).
The CREATE_SUSPENDED flag will ensure that the dllmain entry point function would have finished writing to our shared memory before other libraries are loaded, which allows easier local hooking later on...
Injector.cpp:
SECURITY_ATTRIBUTES SecAttr, *pSec = nullptr;
SECURITY_DESCRIPTOR SecDesc;
if (InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION) &&
SetSecurityDescriptorDacl(&SecDesc, TRUE, PACL(nullptr), FALSE))
{
SecAttr.nLength = sizeof(SecAttr);
SecAttr.lpSecurityDescriptor = &SecDesc;
SecAttr.bInheritHandle = TRUE;
pSec = &SecAttr;
}
CreateProcessA(szTargetExe, nullptr, pSec, nullptr, FALSE, CREATE_SUSPENDED, nullptr, nullptr, &si, &pi);
After injecting the DLL into the target process, all you need to do is use the same (more or less) file mapping code from your DLL project into your Launcher project (except for the part where you set the shared memory's contents, of course).
Then, calling your remote function is just a simple matter of:
// Copy from shared memory
TSharedData data;
memcpy(&data, lpMemFile, SHMEMSIZE);
// Clean up
UnmapViewOfFile(lpMemFile);
CloseHandle(hMapFile);
// Call the remote function
DWORD dwThreadId = 0;
auto hThread = CreateRemoteThread(hProcess, nullptr, 0, LPTHREAD_START_ROUTINE(data.lpInit), nullptr, 0, &dwThreadId);
Then you can ResumeThread on the target process's main thread, or from your remote function.
As an added bonus... Using this form of communication can also open up several doors for our Launcher process, as it can now directly communicate with the target process.
But again, be sure that you don't do too much in DllMain and, if at all possible, simply use your remote init function (where it is also safe to use named mutexes, for example) to create a separate shared memory map and continue communication from there.
Hope this helps someone! =)

How to inject a DLL into a Delphi program

I have a legacy application, which contains a grid with data I need to extract.
I don't have the code for that application and it is impossible to get the data out of it with normal means (like programmatically selecting all cells and copying them into clipboard).
So I decided to use DLL injection as described in section "II. The CreateRemoteThread & LoadLibrary Technique" at
http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces
My plan is
To load a DLL into the address space of the legacy application.
Make the DLL read the data from the grid and write them out (e. g. via a named pipe).
The first step is to inject the DLL into the address space of the legacy application (step a) above).
I've written following code for that:
int InjectDll (HANDLE hProcess);
int _tmain(int argc, _TCHAR* argv[])
{
printf("DllInjector\n");
/**
* Find out PID of the legacy application (START)
*/
HWND windowHandle = FindWindowW(NULL, L"FORMSSSSS");
DWORD* processID = new DWORD;
GetWindowThreadProcessId(windowHandle, processID);
DWORD delphiAppProcessId = *processID;
/**
* Find out PID of the legacy application (END)
*/
printf("Process ID of legacy app: %lu\n", delphiAppProcessId);
// Now we need the handle of the legacy app
HANDLE hProcess = OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, delphiAppProcessId);
if (hProcess != NULL)
{
printf("Found handle, ready for injection\n");
int result = InjectDll(hProcess);
CloseHandle( hProcess );
printf("Injection complete, result=%d\n", result);
}
else
{
printf("Handle not found\n");
}
system("pause");
return 0;
}
int InjectDll( HANDLE hProcess )
{
HANDLE hThread;
const char* const szLibPath = "D:\\mycompany\\SampleDll\\Debug\\SampleDll.dll";
void* pLibRemote = 0; // the address (in the remote process) where
// szLibPath will be copied to;
DWORD hLibModule = 0; // base adress of loaded module (==HMODULE);
HMODULE hKernel32 = ::GetModuleHandle(L"Kernel32");
// 1. Allocate memory in the remote process for szLibPath
// 2. Write szLibPath to the allocated memory
pLibRemote = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE );
if( pLibRemote == NULL )
return false;
::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,sizeof(szLibPath),NULL);
// Load "LibSpy.dll" into the remote process
// (via CreateRemoteThread & LoadLibrary)
hThread = ::CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryA"),
pLibRemote, 0, NULL );
if( hThread == NULL )
goto JUMP;
::WaitForSingleObject( hThread, INFINITE );
// Get handle of loaded module
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
JUMP:
::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
if( hLibModule == NULL ) // (1)
return false;
// Unload "LibSpy.dll" from the remote process
// (via CreateRemoteThread & FreeLibrary)
hThread = ::CreateRemoteThread( hProcess,
NULL, 0,
(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"FreeLibrary"),
(void*)hLibModule,
0, NULL );
if( hThread == NULL ) // failed to unload
return false;
::WaitForSingleObject( hThread, INFINITE );
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
// return value of remote FreeLibrary (=nonzero on success)
return hLibModule;
}
Some comments:
The legacy program has the title "FORMSSSSS".
The sample DLL has following DllMain method:
-
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
{
OutputDebugStringA("DllMain called: ");
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
OutputDebugStringA("DLL_PROCESS_ATTACH\n");
case DLL_THREAD_ATTACH:
OutputDebugStringA("DLL_THREAD_ATTACH\n");
case DLL_THREAD_DETACH:
OutputDebugStringA("DLL_THREAD_DETACH\n");
case DLL_PROCESS_DETACH:
OutputDebugStringA("DLL_PROCESS_DETACH\n");
break;
}
return TRUE;
}
When it is called, a text is written into the standard output of the application.
When I run the program above (the one with _tmain method), I expect to see the text
DllMain called: DLL_PROCESS_ATTACH
in the console output (it means that the DLL injection was successful).
But it doesn't happen.
One potential cause is that the PID of the legacy application is determined incorrectly:
HWND windowHandle = FindWindowW(NULL, L"FORMSSSSS");
DWORD* processID = new DWORD;
GetWindowThreadProcessId(windowHandle, processID);
DWORD delphiAppProcessId = *processID;
But the value delphiAppProcessId is the same as the PID displayed in the task manager, so I can exclude this potential bug.
Using the debugger I found out that the execution stops at the line with comment (1):
JUMP:
::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
if( hLibModule == NULL ) // (1)
return false;
What do I need to change in order for the sample DLL to be injected into the address space of the application with title "FORMSSSSS" ?
Update, 16.09.2012:
I replaced all occurrences of
sizeof(szLibPath)
by pathLength, where
const int pathLength = strlen(szLibPath)+1;
Now, in
::WaitForSingleObject( hThread, INFINITE );
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
// return value of remote FreeLibrary (=nonzero on success)
return hLibModule;
}
hLibModule is nonzero, which means that the injection was successful.
But I still can't see the log output of the sample DLL in the output of the program.
Update, 16.09.2012 (2):
When I
a) add a call to AllocConsole() in DllMain of the sample DLL,
b) rebuild it and
c) execute the injecting program,
then a console window appears, which has the same icon as the Delphi application.
When I remove AllocConsole from the DllMain function, and execute the injecting application, the console window does not appear.
So the injection might actually work.
The biggest problem that I can see is that sizeof(szLibPath) evaluates to the size of a pointer. Use strlen(szLibPath)+1 instead.
For sure that means that your injection will fail because the path that LoadLibraryA receives will be truncated. There may be other problems, but that's the place to start.