Search code examples
c++dlldll-injection

Running code inside injected Dll's DllMain causes injection to timeout


So I'm trying to inject a dll into a process, so far I've managed to inject the dll into the process, but I'm having trouble getting any code to run inside of DllMain of the injected dll, when DllMain looks like the code below it seems to work as the target application runs and Process Explorer shows that the dll has been loaded.

BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
{
    switch (dwReason)
    {
        case DLL_PROCESS_ATTACH:
            break;
        case DLL_PROCESS_DETACH:
            break;
    };

    return TRUE;
}

However when I add any code beneath DLL_PROCESS_ATTACH, it causes the injection to timeout. Here what I've been trying to load:

extern "C" {
    BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
    {
        switch (dwReason)
        {
            case DLL_PROCESS_ATTACH:
                MessageBox(0, "Hello, world!", "Hello!", 0);
                break;
            case DLL_PROCESS_DETACH:
                break;
         };

         return TRUE;
    }
}

And here's how I'm injecting the dll:

bool InjectDLL(PROCESS_INFORMATION* pInfo, const char* dllPath) {
    bool result = false;
    HANDLE nmsProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pInfo->dwProcessId);
    if (nmsProcess) {
        LPVOID baseAddress = VirtualAllocEx(nmsProcess, NULL, strlen(dllPath) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if (baseAddress) {
            LPVOID loadLibraryAddress = (LPVOID)GetProcAddress(LoadLibraryA("kernel32.dll"), "LoadLibraryA");
            WriteProcessMemory(nmsProcess, baseAddress, dllPath, strlen(dllPath) + 1, NULL);
            HANDLE thread = CreateRemoteThread(nmsProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddress, baseAddress, 0, 0);
            if (thread != NULL) {
                switch (WaitForSingleObject(thread, 5000)) {
                    case WAIT_OBJECT_0:
                        cout << "Injected" << endl;
                        result = TRUE;
                        break;
                    case WAIT_ABANDONED:
                        cout << "Abandoned" << endl;
                        break;
                    case WAIT_TIMEOUT:
                        cout << "Timed out" << endl;
                        break;
                    case WAIT_FAILED:
                        cout << "Failed"<< endl;
                        break;
                }
            }
            else {

                cout << "Error: \n" << GetLastError() << endl;
            }
            CloseHandle(thread);

        }
        else {
            cout << "Error: \n" << GetLastError() << endl;
        }
        VirtualFreeEx(nmsProcess, baseAddress, 0, MEM_RELEASE);
        CloseHandle(nmsProcess);
    }
    return result;
}

I'm fairly new to Dll injection so I've probably made a mistake in the injection somewhere, any help would be greatly appreciated.

Edit:

I've also tried placing the call to MessageBox in another function, but that had the same results:

extern "C" {
    void Init(void) {
        MessageBox(0, "Hello, world!", "Hello!", 0);
    }

    BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
    {
        switch (dwReason)
        {
        case DLL_PROCESS_ATTACH:
            Init();
            break;
        case DLL_PROCESS_DETACH:
            break;
        };

        return TRUE;
    }
}

Solution

  • Turns out that the solution (thanks to Hans Passant and Christian.K) was to call the function in a new thread like so:

    extern "C" {
        void Init() {
            MessageBox(0, "Hello, world!", "Hello!", 0);
        }
    
        BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
        {
            switch (dwReason)
            {
            case DLL_PROCESS_ATTACH:
                CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Init, NULL, 0, NULL);
                break;
            case DLL_PROCESS_DETACH:
                break;
            };
    
            return TRUE;
       }
    }