Rev 32 | 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(2000);
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;
}