Subversion Repositories WoWGM

Rev

Rev 3 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "Bootstrap.h"

//===========================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    // Check WowGM's compatibility with the client version
    CheckBuildCompatibility();

    EnableSeDebugPrivilege();

    ExtractResource(hInstance, DLL_RESOURCEID, DLL_FILENAME);

    PROCESS_INFORMATION processInformation = CreateWowProcess(GetCommandLine());
          //Sleep(10000);
    InjectDLL(processInformation.dwProcessId);

    // Wait for the client to exit and clean up...
    WaitForSingleObject(processInformation.hProcess, INFINITE);
    DeleteFile(DLL_FILENAME);
    return 0;
}

//===========================================================================
void CheckBuildCompatibility()
{
    ClientVersion wowGmVersion = {}, wowVersion = {};
    LPCSTR wowFilename = GetWowClientFileName();
    LPCSTR wowGmFilename = DLL_FILENAME;

    // Wow version checking
    DWORD hVersionInfo = 0;
    DWORD cbVersionInfo = GetFileVersionInfoSize(wowFilename, &hVersionInfo);
    if (cbVersionInfo > 0)
    {
        char* rgchVersionInfo = new char[cbVersionInfo];
        if (GetFileVersionInfo(wowFilename, hVersionInfo, cbVersionInfo, rgchVersionInfo))
        {
            UINT cbFixedFileInfo;
            VS_FIXEDFILEINFO* pffiFixedFileInfo;

            if (VerQueryValue(rgchVersionInfo, "\\", (void**)&pffiFixedFileInfo, &cbFixedFileInfo))
            {
                wowVersion.m_major = HIWORD(pffiFixedFileInfo->dwFileVersionMS);
                wowVersion.m_minor = LOWORD(pffiFixedFileInfo->dwFileVersionMS);
                wowVersion.m_revision = HIWORD(pffiFixedFileInfo->dwFileVersionLS);
                wowVersion.m_build = LOWORD(pffiFixedFileInfo->dwFileVersionLS);
            }
        }
        delete[] rgchVersionInfo;
    }

    // WowGM version checking: hardcoded in the meantime
    wowGmVersion = GetGmClientVersion();
    if (wowGmVersion.m_build == wowVersion.m_build)
        return; // WowGM is compatible with the targeted Wow client version;

    // Build the MessageBox output strings
    char szVersion[250];
    sprintf(szVersion,
        "Incompatible client version:\n"
        "Expected: %d.%d.%d (build %d)\n"
        "You have: %d.%d.%d (build %d)",
        wowVersion.m_major, wowVersion.m_minor, wowVersion.m_revision, wowVersion.m_build,
        wowGmVersion.m_major, wowGmVersion.m_minor, wowGmVersion.m_revision, wowGmVersion.m_build);

    // Display the MessageBox and exit
    MessageBox(0, szVersion, "WowGM Error", MB_OK);
    ExitProcess(420);
}

BOOL EnableSeDebugPrivilege () {
  HANDLE hToken = NULL;
  LUID luid;

  if (!OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
    return FALSE;

  if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
    return FALSE;

  TOKEN_PRIVILEGES tokenPriv = {};
  tokenPriv.PrivilegeCount = 1;
  tokenPriv.Privileges[0].Luid = luid;
  tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
    return FALSE;

  return TRUE;
}

void ExtractResource(const HINSTANCE hInstance, WORD resourceID, LPCSTR szFilename)
{
    /* Find and load the resource file: */
    /* Right now, this is hardcoded to extract DLL files... */
    HRSRC hResource = FindResource(hInstance, MAKEINTRESOURCE(resourceID), "DLL");
    if (hResource == NULL)
        return ErrorExit("FindResource");

    HGLOBAL hFileResource = LoadResource(hInstance, hResource);
    if (hFileResource == NULL)
        return ErrorExit("LoadResource");

    /* Open and map this to a disk file... */
    LPVOID lpFile = LockResource(hFileResource);
    DWORD dwSize = SizeofResource(hInstance, hResource);

    /* Open the file and filemap... */
    HANDLE hFile = CreateFile(szFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, dwSize, NULL);
    if (hFileMap == NULL)
        return ErrorExit("CreateFileMapping");

    LPVOID lpAddress = MapViewOfFile(hFileMap, FILE_MAP_WRITE, 0, 0, 0);
    if (lpAddress == NULL)
        return ErrorExit("MapViewOfFile");

    /* Write the file... */
    CopyMemory(lpAddress, lpFile, dwSize);

    /* Clean up... */
    UnmapViewOfFile(lpAddress);
    CloseHandle(hFileMap);
    CloseHandle(hFile);
}

void ErrorExit(LPSTR lpszFunction)
{
    /* Retrieve the system error message for the last error code */

    LPVOID lpMsgBuf = NULL;
    LPVOID lpDisplayBuf = NULL;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPSTR)&lpMsgBuf,
        0, NULL);

    /* Display the error message and exit the process */

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
        (strlen((LPSTR)lpMsgBuf) + strlen(lpszFunction) + 40) * sizeof(CHAR));

    StringCchPrintf((LPSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(CHAR),
        "%s failed with error %d: %s",
        lpszFunction, dw, lpMsgBuf);
    MessageBox(NULL, (LPSTR)lpDisplayBuf, "Error", MB_OK);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    DeleteFile(DLL_FILENAME);
    ExitProcess(dw);
}


PROCESS_INFORMATION CreateWowProcess(LPSTR lpCmdLine)
{
    /* Initialize memory for our new process... */
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(pi));

    /* Create the WoW process... */
    if (!CreateProcess(GetWowClientFileName(),    // Module name
        lpCmdLine,      // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi)           // Pointer to PROCESS_INFORMATION structure
        )
    {
        /* Failed to create the process: Clean up and error out */
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        ErrorExit("CreateProcess");
    }
    return pi;
}

//===========================================================================
void InjectDLL(DWORD dwid)
{
    /* Open a handle to the target process... */
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwid);

    LPCSTR dllPath = DLL_FILENAME;
    SIZE_T size = strlen(dllPath) + 1;

    /* Allocate memory for the dllpath in the target process: */
    /* length of the path = string + null terminator */
    LPVOID pPath = VirtualAllocEx(hProcess, NULL, size,
        MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    /* Write the path to the address of the memory we just allocated in the target process... */
    WriteProcessMemory(hProcess, pPath, (LPVOID)dllPath, size, NULL);

    /* Create a Remote Thread in the target process which */
    /* calls LoadLibraryA as our dllpath as an argument->program loads our dll */
    HANDLE hLoadThread = CreateRemoteThread(hProcess, NULL, 0,
        (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32.dll"),
            "LoadLibraryA"), pPath, 0, NULL);

    /* Wait for the execution of our loader thread to finish... */
    WaitForSingleObject(hLoadThread, INFINITE);

    /* Free the memory allocated for our DLL path */
    VirtualFreeEx(hProcess, pPath, size, MEM_RELEASE);
}

LPSTR GetProcessNameById(DWORD processID)
{
    CHAR szProcessName[MAX_PATH] = "<unknown>";
    LPSTR result = szProcessName;

    /* Get a handle to the process... */
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
        PROCESS_VM_READ,
        FALSE, processID);

    /* Retrieve the process name for the given PID... */
    if (NULL != hProcess)
    {
        HMODULE hMod;
        DWORD cbNeeded;

        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),
            &cbNeeded))
        {
            GetModuleBaseName(hProcess, hMod, szProcessName,
                sizeof(szProcessName) / sizeof(CHAR));
        }
    }

    /* Release the handle to the process. */
    CloseHandle(hProcess);

    result = szProcessName;
    return result;
}

HWND FindWindowByName(LPCSTR name)
{
    HWND window = NULL;
    window = FindWindowA(NULL, name);
    return window;
}