0

So I'm studying cyber security and a topic we've come across is DLL injection. So as a little experiment i've taken the time to create my own DLL injection on a game I have.

so syntax wise everything runs smoothly, as well with the compiler, Im doing just as the documentation says for createRemoteThread, connecting to the DLLMAIN api, I've even added a message box to alert me the DLL Attachment was successful, yet nothing. here is my source code

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH:
        MessageBoxA(NULL, "Successfully connected to DLL!", "DLL Injector", MB_OK);
        break;
    case DLL_THREAD_ATTACH:
        MessageBoxA(NULL, "it worked", "k", MB_OK);
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

int getProcId(const char* target){
    DWORD pID = 0;
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    wchar_t wideTarget[MAX_PATH];
    MultiByteToWideChar(CP_UTF8, 0, target, -1, wideTarget, MAX_PATH);

    do {
        wchar_t wideExeFile[MAX_PATH];
        MultiByteToWideChar(CP_UTF8, 0, pe32.szExeFile, -1, wideExeFile, MAX_PATH);

        if (wcscmp(wideExeFile, wideTarget) == 0) {
            CloseHandle(hSnapshot);
            pID = pe32.th32ProcessID;
            break;
        }
    } while (Process32Next(hSnapshot, &pe32));
    CloseHandle(hSnapshot);
    return pID;
}

int injectDLL(int pID, const char* dllPath) {
    HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, pID);
    if (hProcess == NULL) {
        return 1;
    }

    LPVOID pRemotePath = VirtualAllocEx(hProcess, NULL, strlen(dllPath) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (pRemotePath == NULL) {
        CloseHandle(hProcess);
        return 2;
    }

    if (!WriteProcessMemory(hProcess, pRemotePath, dllPath, strlen(dllPath) + 1, NULL)) {
        VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return 3;
    }

    HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
    FARPROC pLoadLibraryA = GetProcAddress(hKernel32, "LoadLibraryA");

    HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibraryA, pRemotePath, 0, NULL);
    if (hRemoteThread == NULL) {
        VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return 4;
    }

    WaitForSingleObject(hRemoteThread, INFINITE);

    VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
    CloseHandle(hRemoteThread);
    CloseHandle(hProcess);

    return 0;
}

int main(int argc, char* argv[]) {
    const char* process = "Left 4 dead 2 - Direct3D 9";
    const char* dllPath = "Engine.dll";

    int pID = getProcId(process);

    if (pID == 0) {
        // Process not found
        return 1;
    }

    int result = injectDLL(pID, dllPath);

    if (result == 0) {
        printf("success");// Injection succeeded
    } else {
        printf("not successful"); // Injection failed
    }

    return 0;
}
  • 1
    Welcome to Stack Overflow. Please clarify what you mean by "yet nothing"? What happens? Does it alert you that the injection was successful? – ewokx Mar 30 '23 at 02:24
  • it does not, it spawns the executable yet no message box, or console output. – SmoothBrainBoy12 Mar 30 '23 at 02:45
  • C and C++ are different languages. Which language are you using? Please remove the tag for the other language. – Barmar Mar 30 '23 at 03:09
  • Sorry usually they're clumped together on some forums, im using c++ – SmoothBrainBoy12 Mar 30 '23 at 03:28
  • No, they are not *clumped together*. They are two different languages, and are not the same because they both start with *C*, any more than a car, a carrot, and a cat are the same because they all start with *ca*. Tag spamming (using tags that do not actually apply to your post) is a good way to get questions downvoted or closed. Tags have relevance and meaning here, and should be used properly. Thanks. – Ken White Mar 30 '23 at 03:54
  • 1
    Weird to have DllMain in an EXE. Not surprising it isn't called, since it isn't in a DLL. What is is this engine.dll that you're injecting into the process? – Paul Dempsey Mar 30 '23 at 04:14
  • Per [Dynamic-Link Library Best Practices](https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices): "*You **should never** perform the following tasks from within DllMain: ... - **Call functions in User32.dll or Gdi32.dll**. Some functions load another DLL, which may not be initialized.*" `MessageBox` is in `user32.dll`. Use [`OutputDebugString()`](https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-outputdebugstringa) and a tool like [DebugView](https://learn.microsoft.com/en-us/sysinternals/downloads/debugview) to see the messages. – Remy Lebeau Mar 30 '23 at 04:16
  • 1
    Also, `injectDLL()` returning 0 only means that the remote thread was created successfully. It does not determine whether `LoadLibraryA()` itself was successful or not. If the DLL and remote process are 32bit, you can use `GetExitCodeThread()` to determine if `LoadLibraryA()` succeeded or failed (but not why). However, if they are 64bit instead, then getting that information is [much more difficult](https://stackoverflow.com/a/62666600/65863). – Remy Lebeau Mar 30 '23 at 04:24
  • Related (possible dupe): [CreateRemoteThread succeeded, but LoadLibrary failed for some target app](https://stackoverflow.com/questions/56490123/) – Remy Lebeau Mar 30 '23 at 04:34

0 Answers0