I am doing the DLL injection job recently, so I have did some research into it
on google. Now I know use CreateRemoteThread is a good way.
The ASLR(Address space layout randomization, since Windows Vista) makes the
address of kernel32.dll is random, but this does not affect the whole, because
in a session the base address of kernel32.dll in all processes is just the
same - until the Operating System reset.
So this code may be safe normally:
void launchAndInject(const char* app, const char* dll)
{
STARTUPINFOA si = {0};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {0};
if (CreateProcessA(app, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
{
LPVOID loadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
if (loadLibrary == NULL) {
return;
}
SIZE_T len = ::strlen(dll) + 1;
LPVOID addr = VirtualAllocEx(pi.hProcess, NULL, len, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (addr == NULL) {
return;
}
if (!WriteProcessMemory(pi.hProcess, addr, dll, len, NULL)) {
return;
}
HANDLE th = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibrary, addr, 0, NULL);
WaitForSingleObject(th, INFINITE);
DWORD ret = 0;
GetExitCodeThread(th, &ret);
CloseHandle(th);
ResumeThread(pi.hThread);
}
}
The exit code of the injecting thread is just the returned value by
LoadLibrary, so ret is just the HMODULE of loaded DLL(in child process of
course), it works like a magic, so far so good.
I have read many projects about DLL injection, they use DLLMain to do lots of
jobs - like creating thread, or hook APIs, and so on. They must be very
carefully to do these things, refers to the document "Best Practices for
Creating DLLs" of Microsoft, behaviors such as creating thread might cause
dead-lock, "The ideal DllMain would be just an empty stub", so I don't think
this is a very good way.
So, get the HMODULE of the loaded DLL is important. With this handle, you can
use CreateRemoteThread to call a export function of injected DLL, do whatever
you want, no need to worry about the loader-lock things.
Unfortunately, the code above only works with 32bit processes, this is because
the type of thread's exit code is DWORD - a 32bit unsigned integer, but
HMODULE is a pointer, it can be 64bit. So in 64bit process, you may get a
DWORD value 0xeb390000 from GetExitCodeThread, but in fact the HMODULE
returned by LoadLibrary is 0x7feeb390000. 0xeb390000 is just a truncated 64bit
pointer.
How can we fix this issue ?
See Question&Answers more detail:
os