So, after some rigorous testing, it would seem that my previous answer is something like flawless
(or even 100% functional, for that matter), and is prone to crashes. After I thought, I decided to use a completely different approach to this ... using Interprocess Communication .
Know ... this method uses code in DllMain .
Therefore, do not go overboard and do not follow safe methods in order to prevent you from falling into deadlock ...
In particular, the Win32 API offers the following two functions that prove useful:
With their help, we can simply tell our Launcher process exactly where our remote init function is located, right from the most implemented dll ...
dllmain.cpp :
< / "> Then, from our Launcher application, we will do the usual CreateProcess + VirtualAllocEx + CreateRemoteThread trick to enter our Dll , making sure to pass the pointer to the correct SECURITY_DESCRIPTOR as the third parameter to CreateProcess , and also pass the CREATE_SUSPENDED flag in the 6th parameter .
This will help ensure that your child process has the proper read and write permissions to the global shared memory namespace, although there are other ways to achieve this (or you can test without a global path at all).
The CREATE_SUSPENDED flag ensures that the dllmain entry point function will complete writing to our shared memory before loading other libraries, making it easier to connect locally later ...
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);
<h / "> After injecting the DLL into the target process, all you have to do is use the same (more or less) file mapping code from your DLL project to the Launcher project (except for the part where you set the contents of shared memory, of course )
Then calling your remote function is just a question:
// 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);
You can ResumeThread in the main thread of the target process or from your remote function.
As an added bonus ... Using this form of communication can also open several doors for our Launcher process, as it can now directly communicate with the target process.
But again, make sure you don't do too much in
DllMain and, if at all possible, just use your remote init function (where it is also safe
use named mutexes , for example) to create a separate shared memory card and continue communication from there.
Hope this helps someone! =)