Following code will inject dll and DllMain will be called. How I call specific function from DLL, not just DllMain?
DWORD pid;
HANDLE hd;
LPVOID gp, rs, proc;
gp = (LPVOID)GetProcAddress(GetModuleHandle(L"Kernel32.dll"), "LoadLibraryA");
pid = 6096;
hd = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
rs = (LPVOID)VirtualAllocEx(hd, 0, sizeof(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!WriteProcessMemory(hd, (LPVOID)rs, DLL_NAME, strlen(DLL_NAME), 0))
{
printf("WriteProcessMemory %d", GetLastError());
}
if (!CreateRemoteThread(hd, 0, 0, (LPTHREAD_START_ROUTINE)gp, rs, 0, 0))
{
printf("CreateRemoteThread %d", GetLastError());
}
When your injected DLL's DllMain
runs for the first time, call CreateThread
to create a new thread that can do whatever you like. Note that you cannot call arbitrary code from DllMain
as described in the documentation. Hence the call to CreateThread
from DllMain
.
Well, I'm using the following approach.
In the DLL that is being injected, I create a shared section, like this:
#pragma data_seg(".MyShared")
LPTHREAD_START_ROUTINE g_lpMyFunc = NULL;
#pragma data_seg()
#pragma section(".MyShared", read, write, shared)
The shared section variable g_lpMyFunc
is then initialized inside DllMain
like this:
BOOL APIENTRY DllMain(HMODULE, DWORD dwReasonForCall, LPVOID)
{
if (NULL != GetModuleHandle(_T("MyApp.exe")))
{
if (DLL_PROCESS_ATTACH == dwReasonForCall)
{
g_lpMyFunc = (LPTHREAD_START_ROUTINE)&MyFunc;
}
else if (DLL_PROCESS_DETACH == dwReasonForCall)
{
g_lpMyFunc = NULL;
}
}
return TRUE;
}
This code does the following. The function call GetModuleHandle
tries to get MyApp's executable module handle. If it succeeds, it return non-NULL value and that means that the injected DLL's DllMain
is called from the remote process. If it's the case, the address of MyFunc
is saved to g_lpMyFunc
shared variable. And if the DLL is detached from the process (when it exits, for example), I set g_lpMyFunc
to NULL in order to not be able to call a function by remote address that is not there.
I then create an external function MyFuncExtern
that calls MyFunc
in the remote process like this:
extern "C" __declspec(dllexport) bool __cdecl MyFuncExtern(HANDLE hProcess)
{
if (NULL == g_lpMyFunc)
{
return false;
}
return NULL != CreateRemoteThread(hProcess, NULL, 0, g_lpMyFunc, NULL, 0, NULL);
}
It is a very simplified version, but it shows the main concept: if g_lpMyFunc
is not NULL, it creates a remote thread in hProcess
(just like in your code) that calls a function at the address pointed to by g_lpMyFunc
.
There are some limitations on that function though since CreateRemoteThread
takes only one argument for the remote function (you can pass more, however it will need a significantly more complicated approach), and if you need a return value you will have to wait for remote thread to complete execution and get its exit code, that is a DWORD
.
This approach is good at writing Initialize / Uninitialize functions and, moreover, it perfectly works for managed C++/CLI DLLs.
And of course you can use any other cross-process data storage to save the function pointer(s). Memory mapped files are one good example.