Access violation when unloading injected DLL via CreateRemoteThread - c++

I'm trying to cleanly inject DLL into foreground window's process, call simple function from this DLL and then cleanly unload the DLL. My injection code:
HWND fgwnd = GetForegroundWindow();
DWORD cur_thread = GetCurrentThreadId();
DWORD fg_pid = 0;
DWORD fg_thread = GetWindowThreadProcessId(fgwnd, &fg_pid);
BOOL res = 0;
const char* inj_path = "C:\\Users\\pc\\source\\repos\\hothook\\x64\\Debug\\fground_injector.dll";
// Get process handle to victim
HANDLE victim = OpenProcess(PROCESS_ALL_ACCESS, FALSE, fg_pid);
// Find exact adress of LoadLibraryA function from text space of kernel32.dll loaded by the OS
// and used by victim
PVOID llib = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
PVOID flib = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "FreeLibrary");
// Allocate memory inside victim's address space
LPVOID inj_path_victim = (LPVOID)VirtualAllocEx(victim, NULL, strlen(inj_path)+1,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write inject dll's adress into victim
SIZE_T written;
res = WriteProcessMemory(victim, inj_path_victim, inj_path, strlen(inj_path)+1, &written);
// Finally, inject DLL into victim!
// Spawn thread in remote process ================================================================
HANDLE inj_llib_thread = CreateRemoteThread(
/*I*/ victim, // Handle to process where thread will be created
/*I*/ NULL, // SECURITY_ATTRIBUTES for new thread
/*I*/ 0, // Initial stacks size, bytes. 0 -> default size
/*I*/ (LPTHREAD_START_ROUTINE)llib, // User defined callback LPTHREAD_START_ROUTINE
/*I*/ inj_path_victim, // Ptr to variable to be sent as func parameter
/*I*/ 0, // Creation control flags. 0 -> immediate start
/*O|O*/ NULL); // Ptr to variable that recieves thread ID
// ===============================================================================================
// CANNOT WAIT FOR THREAD IN OTHER PROCESS.... OR CAN I?! I CAN!
// Wait for DLL to get properly injected into victim
res = WaitForSingleObject(inj_llib_thread, INFINITE);
// Get executable base address of the loaded DLL
DWORD llib_exit;
res = GetExitCodeThread(inj_llib_thread, &llib_exit);
// Free previously allocated remote memory
res = VirtualFreeEx(victim, inj_path_victim, 0, MEM_RELEASE);
// Call injected DLL's function
HMODULE fg_inj = LoadLibraryA(inj_path);
PVOID inj_t_proc = (LPVOID)GetProcAddress(fg_inj, "injectThread");
PVOID ulib = NULL;
// Spawn thread in remote process ================================================================
HANDLE inj_thread = CreateRemoteThread(
/*I*/ victim, // Handle to process where thread will be created
/*I*/ NULL, // SECURITY_ATTRIBUTES for new thread
/*I*/ 0, // Initial stacks size, bytes. 0 -> default size
/*I*/ (LPTHREAD_START_ROUTINE)inj_t_proc, // User defined callback LPTHREAD_START_ROUTINE
/*I*/ NULL, // Ptr to variable to be sent as func parameter
/*I*/ 0, // Creation control flags. 0 -> immediate start
/*O|O*/ NULL); // Ptr to variable that recieves thread ID
// ===============================================================================================
// Wait before injected DLL's thread finishes before extraction
res = WaitForSingleObject(inj_thread, INFINITE);
// Extract injected DLL from victim
// Spawn thread in remote process ================================================================
HANDLE inj_flib_thread = CreateRemoteThread(
/*I*/ victim, // Handle to process where thread will be created
/*I*/ NULL, // SECURITY_ATTRIBUTES for new thread
/*I*/ 0, // Initial stacks size, bytes. 0 -> default size
/*I*/ (LPTHREAD_START_ROUTINE)flib, // User defined callback LPTHREAD_START_ROUTINE
/*I*/ (LPVOID)llib_exit, // Ptr to variable to be sent as func parameter
/*I*/ 0, // Creation control flags. 0 -> immediate start
/*O|O*/ NULL); // Ptr to variable that recieves thread ID
// ===============================================================================================
// Wait untill injected DLL is fully extracted from the victim
res = WaitForSingleObject(inj_flib_thread, INFINITE);
DWORD flib_exit;
res = GetExitCodeThread(inj_flib_thread, &flib_exit);
// Extract injection DLL from host
FreeLibrary(fg_inj);
// ^^^ This actually does not unload DLL from host app, even if I call it 100 times in a loop...
// Clean up by closing all utilised handles
CloseHandle(victim);
CloseHandle(inj_llib_thread);
CloseHandle(inj_thread);
CloseHandle(inj_flib_thread);
My injection DLL is truly bare-bones:
BOOL APIENTRY DllMain(HMODULE hm,
DWORD call_reas,
LPVOID reserved)
{
switch(call_reas)
{
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls(hm);
// I thought that threads calling DllMain with case 2-3 cause crash
// But no, same crash with or without this call
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DWORD injectThread(LPVOID p)
{
//AllowSetForegroundWindow(ASFW_ANY);
// This is what it originally suppose to do
// Let the host "steal" foreground window status from victim
// But even commenting this out results in the same crash
return 0;
}
The crash happens after I create FreeLibrary remote thread to unload injected DLL. This is as much crash details as I could get, as it happens in the system kernel it seems:
Exception thrown at 0x00007FFE598C7170 in maudswch.exe: 0xC0000005: Access violation executing location 0x00007FFE598C7170.
00007ffe598c7170()
kernel32.dll!00007ffe9ac47034()
ntdll.dll!00007ffe9c682651()
Not Flagged 50864 0 Main Thread Main Thread win32u.dll!00007ffe99e51104
Not Flagged 47548 0 Worker Thread ntdll.dll thread ntdll.dll!00007ffe9c6d0794
Not Flagged 41096 0 Worker Thread ntdll.dll thread ntdll.dll!00007ffe9c6d0794
Not Flagged 43456 0 Worker Thread ntdll.dll thread ntdll.dll!00007ffe9c6d0794
Not Flagged > 29820 0 Worker Thread Win64 Thread 00007ffe598c7170
I tested this on many "victims". CMD, Notepad, my other custom GUI program. The result is the same. DLL gets successfully injected, DLL function gets executed, but when unloading it crashes "victim". One more detail, is that FreeLibrary remote thread takes quite long time to finish, about 1.5 seconds sometimes even 7 seconds!
I'm trying to solve this puzzle for days now, I searched all the Internet, but all other similar cases seems to be non-related... And at this point I have no idea what is going on and how to fix this. Of course, I can just bite the bullet and never try to unload my injected DLL, after all it works. But I don't want to leave useless DLLs in other processes after it finished it's job.
Edit:
Some debug prints. As you can see, hm: and func addr: is outputted in DllMain PROCESS_ATTACH. As you can see, I'm lucky to have base DLL address and function address to be exactly the same in host and victim processes. However, passing full base address to FreeLibrary external thread results in exactly the same crash, so truncated base address was not the real reason behind the crash...

Using GetExitCodeThread() to retrieve the HMODULE returned by LoadLibraryA() in the target process will work only if the victim is a 32bit process. Otherwise, the HMODULE will be too large to fit in the remote thread's exit code, so you will have to use a different mechanism to get the DLL's base address in the target process, such as using EnumProcessModules()+GetModuleFileNameEx() or CreateToolhelp32Snapshot()+Module32(First|Next)(), or even injecting stub code that calls LoadLibraryA() and saves the HMODULE into a variable that the injector allocates and can read from via ReadProcessMemory().
More importantly, the way you are calling the DLL's injectThread() function in the target process is wrong. You are using LoadLibraryA()+GetProcAddress() to get a pointer to the injectThread() function within the injector's process, and then you are assuming that the function is located at the same address in the target process. But the DLL in the target process may have been loaded at a different base address than the DLL in the injector process (especially in light of technologies like ALSR, DLL rebasing, etc).
The correct solution is to get the offset of the injectThread() function within the DLL (which the injector can calculate by subtracting its DLL's base address from the function's address), and then add that offset to the base address of the DLL in the target process.
Also, make sure your injectThread() function has the correct signature that CreateRemoteThread() is expecting. What you showed is missing a calling convention specified, so it will use whatever the compiler's default convention is, which is usually __cdecl. But CreateRemoteThread() requires __stdcall instead.

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.

RegisterWaitForSingleObject crash sometime if handle is closed immediately

I'm getting a crash sometimes in RegisterWaitForSingleObject (1 out of 10). It seems that although RegisterWaitForSingleObject returns, the internal thread pool is not yet ready.
HANDLE processHandle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, processID);
// CRASH IN INTERNAL SOMETIMES
RegisterWaitForSingleObject (&hWaitForChild_,processHandle,OnChildProcessExit, 0,INFINITE,WT_EXECUTEONLYONCE);
// If I sleep here, then it seems ok.
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
CloseHandle (processHandle);
I can replicate this with a simple sample here. 1 in 10 times, it will crash. How should I be synchronizing it properly without resorting to sleep hack.
https://filedn.com/l3TGy7Y83c247u0RDYa9fkp/temp/stackoverflow/testregister.cpp
based on your code spinet:
// THIS CRASHS HERE SOMETIMES
if (! RegisterWaitForSingleObject (
&hWaitForChild_
,processHandle
, OnChildProcessExit
, 0 //this
, INFINITE
, WT_EXECUTEONLYONCE))
{
LogDebug ("RegisterWaitForSingleObject failed");
}
// If this is enabled, then it won't crash
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
if (! CloseHandle (processHandle)) // !!!
LogDebug ("RegisterWaitForSingleObject Closehandle failed");
so you close processHandle just after you call RegisterWaitForSingleObject for this handle. however if read about RegisterWaitForSingleObject:
If this handle is closed while the wait is still pending, the
function's behavior is undefined.
if look more deep - try understand - how is RegisterWaitForSingleObject worked internally ? it pass processHandle to some worker thread. and this thread begin wait for this handle. but this is (pass handle to another thread) is asynchronous operation - say for example internally can be started new thread with this handle as argument, or it can be passed to already existing working thread via some signal. but anyway - worked thread got this handle and begin wait some later. from another side - you just close processHandle after RegisterWaitForSingleObject return control. so here race - what will be first - or worked thread begin wait on handle (in this case all will be work) or you close this handle. in case you close this handle first - worked thread will be try wait on already invalid handle and raise exception - STATUS_THREADPOOL_HANDLE_EXCEPTION.
// If this is enabled, then it won't crash
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
of course - by sleep you give time for worked thread to begin wait on handle. in this case he begin wait before you close handle.
solution - you must not close handle, until WAITORTIMERCALLBACK Callback will be not called. you need allocate some context, where place processHandle and pass this context to RegisterWaitForSingleObject. and when you callback will be called - you got pointer to your context back and here and close handle.
also note, that you not need open separate, second, handle for child process, but can use process handle returned by CreateProcess
Ok, I managed to solve it by keeping the handle around until I call Unregisterwait. It seems to be stable. Thanks to the answers.
I met the same problem like you that an exception occurred while debugging in Visual Studio. I tried many time and finally found the reason. If you close the handle of the process newly created, the program would crash. I tried to close the handles in the callback function, it works perfectly, like this:
typedef struct {
LPTSTR pszCmdLine;
HANDLE hEvent;
} THREAD_PARAM;
typedef struct {
TCHAR szCmdLine[1024];
HANDLE hWaitObject;
DWORD dwProcessId;
HANDLE hProcess;
DWORD dwThreadId;
HANDLE hThread;
} OBJECT_PARAM;
static void CALLBACK WaitObjectCallback(LPVOID lpParam, BOOLEAN TimerOrWaitFired)
{
OBJECT_PARAM *pobp = static_cast<OBJECT_PARAM *>(lpParam);
TCHAR szInfo[1024] = { 0 };
DWORD dwExitCode = 0;
GetExitCodeProcess(pobp->hProcess, &dwExitCode);
wnsprintf(szInfo, ARRAYSIZE(szInfo), _T("process %u [%s] exit: %u\n"), pobp->dwProcessId, pobp->szCmdLine, dwExitCode);
OutputDebugString(szInfo);
//
// unregister the wait object handle and close the process handle finally
//
UnregisterWait(pobp->hWaitObject);
CloseHandle(pobp->hProcess);
CloseHandle(pobp->hThread);
GlobalFree(lpParam);
}
static DWORD CALLBACK ThreadFunction(LPVOID lpParam)
{
THREAD_PARAM *pthp = static_cast<THREAD_PARAM *>(lpParam);
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
BOOL bResult;
bResult = CreateProcess(nullptr, pthp->pszCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
if (bResult)
{
OBJECT_PARAM *pobp = static_cast<OBJECT_PARAM *>(GlobalAlloc(GPTR, sizeof(OBJECT_PARAM)));
// make copy of the command line and other informations of the newly created process
lstrcpyn(pobp->szCmdLine, pthp->pszCmdLine, ARRAYSIZE(pobp->szCmdLine));
pobp->dwProcessId = pi.dwProcessId;
pobp->hProcess = pi.hProcess;
pobp->dwThreadId = pi.dwThreadId;
pobp->hThread = pi.hThread;
bResult = RegisterWaitForSingleObject(&pobp->hWaitObject, pi.hProcess, WaitObjectCallback, pobp, INFINITE, WT_EXECUTEONLYONCE);
// once it failed...
if (!bResult)
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
// Notify the thread creator that the process is created successfully
SetEvent(pthp->hEvent);
return 0;
}

Debugging .DLL Injection Issue - Breakpoint On Supposedly Executing Code Not Being Hit

I have written a program (.DLL) which is to be injected into process.exe.
DLL injector code:
Bool InjectDll(DWORD pID, const char* dllPath) {
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
return false;
}
void* LoadLibAddr = (void*)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
void* RemoteString = (void*)VirtualAllocEx(Proc, NULL, strlen(dllPath), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, dllPath, strlen(dllPath), NULL);
HANDLE ret = CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddr, (LPVOID)RemoteString, CREATE_SUSPENDED, NULL);
if (ret) {
return true;
}
}
DllMain() function of .DLL to be injected:
#include <Windows.h>
extern void vMain();
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&vMain, 0, 0, 0);
return true;
}
return false;
}
vMain:
void vMain() {
CreateConsole();
std::cout << "vMain() has executed!\n";
}
The .DLL to be injected works fine when I compile it in visual studio, but when I compile in QT Creator, vMain() never gets executed. The injector, .DLL, and target process are all 32-bit. So I have tried to debug the target process by making the .DLL injector call CreateRemoteThread() with the CREATE_SUSPENDED flag, that way I can set a breakpoint on LoadLibraryA(), resume the thread, step through execution from the breakpoint, and view the return value. However, my breakpoint on LoadLibraryA() isn't being hit.
So I debugged the .DLL injector application to make sure that the remote thread was being created. I confirmed that it is by calling GetThreadID() on the return value of CreateRemoteThread(), outputting it, and viewing that thread in the threadlist of the target process:
Keep in mind the thread is still suspended. Upon further inspection, EIP points to the first instruction in _RtlUserThreadStart(). I set a breakpoint on this instruction. I then resume the suspended thread by calling ResumeThread() from my .DLL injector program. The breakpoint is not hit.
It is noteworthy that the target application does not have any anti-breakpoint mechanism, and breakpoints have worked fine for me apart from this instance.
So how can I figure out what the issue is? Is there a reason my breakpoints are not being hit? Is there a better way to debug the problem?
When doing console output from inside a DLL, you may need to redirect stdout to the console:
// AllocConsole() instead of CreateConsole()
AllocConsole();
freopen("CONOUT$", "w", stdout); // <====
std::cout << "vMain() has executed!\n";
Additionally, It's not a good idea to create threads inside DllMain() and here's why:
https://blogs.msdn.microsoft.com/oldnewthing/20070904-00/?p=25283
https://blogs.msdn.microsoft.com/oldnewthing/20040127-00/?p=40873/
Related question:
Creating a thread in DllMain?
I remember I've had some trouble with it in the past and I stopped doing such things as creating threads / windows inside DllMain(), as recommended.
Still, there are cases where it works, but I wouldn't trust it.
That being said, if the above doesn't work, try to call your vMain() directly without a thread and see what happens.

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;
}

C++ Hooking kernel32.dll OpenProcess with detours

I am trying to hook OpenProcess from Kernel32.dll in order to prevent so called "injector" programs from injecting other dll`s into my process:
// -------------------------------------------------------------------
HANDLE WINAPI myOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)
{
//
if (dwDesiredAccess == PROCESS_ALL_ACCESS || dwDesiredAccess == PROCESS_VM_OPERATION ||
dwDesiredAccess == PROCESS_VM_READ || dwDesiredAccess == PROCESS_VM_WRITE)
{
printf("Blcoked Process ID : %d , DesiredAccess : %d ", dwProcessId, dwDesiredAccess);
return false;
}
//
return dOpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
}
What do I need to add, in order to "detect" if anybody opens the process for "injecting" ?
I do not want to "prevent", I wish to "detect" injection and decide what to do.
The diagram depicts the steps the injector usually do to inject the dll into another process. Your program should do the behavioral analysis to decide whether it is injecting or not. you need to hook other apis like VirtualAlloc \ WriteProcessMemory, CreateRemoteThread etc.
Below shows the approach to follow to analyse the injector flow and
block the execution when needed. Injector uses many techniques to
inject a dll, the below won't be sufficient to all methods.
//
//HookOpenProcess keep track of opened process handle
//
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
/*
HookVirtualAlloc Check whether the first param is openprocess handle :: Make the suspicion level 3
*/
LPVOID arg = (LPVOID)VirtualAllocEx(process, NULL, ...);
/*
HookWriteProcessMemory Check whether the first param is openprocess handle :: Make the suspicion level 2
*/
int n = WriteProcessMemory(process, .....);
/*
HookCreateRemoteThread Check whether the first param is openprocess handle :: Make the suspicion level 1 and block it from execution
*/
HANDLE threadID = CreateRemoteThread(process, .........);