Code:
#include <iostream>
#include <string>
#include <fstream>
#include <Windows.h>
struct SFileArchive
{
int m_type;
int m_handle;
};
typedef bool (__stdcall *tSFileOpenArchive)(const char* file, int zero, int flags, SFileArchive** ppNode);
typedef int (__stdcall *tSFileSystem__AddMPQ)(SFileArchive* node, const char* prefix, int zero, int unk, SFileArchive** dest);
typedef int (__stdcall *tArray__Unk)(int unkNum);
typedef int (__stdcall *tArray__Resize)(int unkNum);
#define GetAddr(T, A) ((T)((DWORD)GetModuleHandle(NULL) + A))
extern "C"
__declspec(dllexport) unsigned long InjectFunction(LPVOID)
{
tSFileOpenArchive SFileOpenArchive = GetAddr(tSFileOpenArchive, 0x303E20);
tSFileSystem__AddMPQ SFileSystem__AddMPQ = GetAddr(tSFileSystem__AddMPQ, 0x303FA0);
tArray__Unk Array__Unk = GetAddr(tArray__Unk, 0x2BA7D0);
tArray__Resize Array__Resize = GetAddr(tArray__Resize, 0x32D0);
LPDWORD lpNumArchives = GetAddr(LPDWORD, 0x831A44);
SFileArchive*** lpArchives = GetAddr(SFileArchive***, 0x831A48);
LPDWORD lpCapacity = GetAddr(LPDWORD, 0x831A40);
LPDWORD lpGain = GetAddr(LPDWORD, 0x831A4C);
std::ifstream input("MpqFiles.txt");
if(!input.is_open())
{
std::cout << "Could not locate or open \"MpqFiles.txt\" in wow directory!" << std::endl;
ExitThread(0);
}
std::string curFile;
while(std::getline(input, curFile))
{
std::ifstream tst(curFile);
std::cout << "Loading file '" << curFile << "'..." << std::endl;
if(!tst.is_open())
{
std::cout << "file does not exist!" << std::endl;
continue;
}
tst.close();
SFileArchive* pNode = NULL;
if(!SFileOpenArchive(curFile.c_str(), 0, 0, &pNode))
{
std::cout << "SFileOpenArchive returned false!" << std::endl;
continue;
}
++(*lpNumArchives);
if(*lpNumArchives > *lpCapacity)
{
DWORD gain = *lpGain;
if(!gain)
{
DWORD v4 = *lpNumArchives;
DWORD pThis = GetAddr(DWORD, 0x831A40);
__asm
{
mov eax, v4
push eax
lea ecx, pThis
lea eax, Array__Unk
call far eax
mov gain, eax
}
}
DWORD v4 = *lpNumArchives;
if(v4 % gain)
v4 = *lpNumArchives + gain - *lpNumArchives % gain;
DWORD pThis = GetAddr(DWORD, 0x831A40);
__asm
{
mov eax, v4
push eax
mov ecx, pThis
mov eax, Array__Resize
call far eax
}
}
SFileSystem__AddMPQ(pNode, NULL, 64 + *lpNumArchives, 0, *lpArchives + *lpNumArchives);
}
ExitThread(0);
}
Exe code:
Code:
#include <iostream>
#include <cassert>
#include <string>
#include <windows.h>
#include <winternl.h>
HANDLE hProcess;
void StartupInject(HANDLE);
void AdjustDllDirectory(HANDLE);
HMODULE LoadDll(HANDLE, LPSTR);
template<typename T>
void CallFunc(HANDLE, T func, LPVOID param);
DWORD GetFuncOffset(LPSTR szDll, LPSTR szFunc);
int main(int argc, char* argv[])
{
PROCESS_INFORMATION pi;
if(argc >= 2)
{
std::string wowPath;
std::string curDir;
if(!stricmp(argv[1], "-nodelay"))
{
if(argc > 2)
{
curDir = argv[2];
wowPath = std::string(argv[2]) + "\\WoW.exe";
}
else
{
CHAR dir[MAX_PATH];
GetCurrentDirectory(MAX_PATH, dir);
curDir = dir;
wowPath = "WoW.exe";
}
STARTUPINFO startInfo;
memset(&startInfo, 0, sizeof(startInfo));
startInfo.cb = sizeof(startInfo);
memset(&pi, 0, sizeof(pi));
if(!CreateProcess(wowPath.c_str(), NULL, NULL, NULL, FALSE, CREATE_SUSPENDED | CREATE_NEW_CONSOLE, NULL, curDir.c_str(), &startInfo, &pi))
{
if(GetLastError() == ERROR_NOACCESS || GetLastError() == ERROR_DIRECTORY)
{
std::cout << "File " << wowPath << " does not exist!" << std::endl;
return 0;
}
std::cout << "Failed to launch WoW in suspended mode! (Error: " << GetLastError() << ")" << std::endl;
return 0;
}
hProcess = pi.hProcess;
StartupInject(pi.hThread);
return 0;
}
else
{
bool commandLineRecognized = false;
assert(commandLineRecognized == true);
}
}
HWND hWindow = FindWindow("GxWindowClass", "World of Warcraft");
assert(hWindow != NULL);
DWORD dwProcess = 0;
assert(GetWindowThreadProcessId(hWindow, &dwProcess) != FALSE);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcess);
assert(hProcess != NULL);
AdjustDllDirectory(hProcess);
HMODULE hDll = LoadLibrary("Mopaq.dll");
DWORD dwOffset = GetFuncOffset("Mopaq.dll", "InjectFunction");
HMODULE hRemote = LoadDll(hProcess, "Mopaq.dll");
CallFunc(hProcess, (DWORD)hRemote + dwOffset, NULL);
CallFunc(hProcess, FreeLibrary, NULL);
return 0;
}
typedef NTSTATUS (__stdcall *tNtQueryInformationProcess)(HANDLE hProcess, PROCESSINFOCLASS info, PVOID infoBuffer, ULONG infoLen, PULONG retLen);
void StartupInject(HANDLE hThread)
{
HMODULE hNtDll = LoadLibrary("ntdll.dll");
tNtQueryInformationProcess NtQueryInformationProcess = (tNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");
PROCESS_BASIC_INFORMATION pbi;
NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
PEB peb;
ReadProcessMemory(hProcess, (LPCVOID)pbi.PebBaseAddress, &peb, sizeof(peb), NULL);
DWORD dwBase = (DWORD)peb.Reserved3[1];
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
assert(GetThreadContext(hThread, &ctx) != FALSE);
int index = 0;
DWORD dwFunction = dwBase + 0x6176;
ctx.Dr0 = dwFunction;
ctx.Dr7 |= (3 << 24);
ctx.Dr7 |= 1;
assert(SetThreadContext(hThread, &ctx));
AdjustDllDirectory(hProcess);
DWORD offset = GetFuncOffset("VectoredHandler.dll", "AddHandler");
HMODULE hRemote = LoadDll(hProcess, "VectoredHandler.dll");
char name[255];
sprintf(name, "Global\\_FinishEvent_%u", GetProcessId(hProcess));
HANDLE hFinish = CreateEvent(NULL, FALSE, FALSE, name);
CallFunc(hProcess, (DWORD)hRemote + offset, NULL);
sprintf(name, "Global\\_CommMutex_%u", GetProcessId(hProcess));
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, name);
ResumeThread(hThread);
WaitForSingleObject(hEvent, INFINITE);
offset = GetFuncOffset("Mopaq.dll", "InjectFunction");
HMODULE hMpq = LoadDll(hProcess, "Mopaq.dll");
CallFunc(hProcess, (DWORD)hMpq + offset, NULL);
CallFunc(hProcess, FreeLibrary, hMpq);
SetEvent(hFinish);
CloseHandle(hFinish);
CloseHandle(hEvent);
// Wait a second to let the vectored exception handler return. Hacky, but will work
Sleep(1000);
CallFunc(hProcess, FreeLibrary, hRemote);
CloseHandle(hProcess);
CloseHandle(hThread);
}
void AdjustDllDirectory(HANDLE hProc)
{
CHAR szProc[MAX_PATH];
GetCurrentDirectory(MAX_PATH, szProc);
LPVOID dllAddr = VirtualAllocEx(hProc, NULL, strlen(szProc) + 1, MEM_COMMIT, PAGE_READWRITE);
assert(dllAddr != NULL);
DWORD dwRet = WriteProcessMemory(hProc, dllAddr, szProc, strlen(szProc) + 1, NULL);
assert(dwRet == TRUE);
HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)SetDllDirectory, dllAddr, 0, NULL);
assert(hThread != NULL);
dwRet = WaitForSingleObject(hThread, INFINITE);
assert(dwRet == WAIT_OBJECT_0);
VirtualFreeEx(hProc, dllAddr, strlen(szProc) + 1, MEM_COMMIT);
}
HMODULE LoadDll(HANDLE hProc, LPSTR szDll)
{
LPVOID dllAddr = VirtualAllocEx(hProc, NULL, strlen(szDll) + 1, MEM_COMMIT, PAGE_READWRITE);
assert(dllAddr != NULL);
DWORD dwRet = WriteProcessMemory(hProc, dllAddr, szDll, strlen(szDll) + 1, NULL);
assert(dwRet == TRUE);
HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, dllAddr, 0, NULL);
assert(hThread != NULL);
dwRet = WaitForSingleObject(hThread, INFINITE);
assert(dwRet == WAIT_OBJECT_0);
HMODULE hRemote = NULL;
dwRet = GetExitCodeThread(hThread, (LPDWORD)&hRemote);
assert(dwRet == TRUE);
assert(hRemote != NULL);
VirtualFreeEx(hProc, dllAddr, strlen(szDll) + 1, MEM_COMMIT);
return hRemote;
}
template<typename T>
void CallFunc(HANDLE hProc, T func, LPVOID param)
{
LPTHREAD_START_ROUTINE initProc = (LPTHREAD_START_ROUTINE)func;
HANDLE hThread = CreateRemoteThread(hProc, NULL, 0, initProc, param, 0, NULL);
assert(hThread != NULL);
DWORD dwRet = WaitForSingleObject(hThread, INFINITE);
assert(dwRet == WAIT_OBJECT_0);
}
DWORD GetFuncOffset(LPSTR szDll, LPSTR szFunc)
{
HMODULE hMod = LoadLibrary(szDll);
assert(hMod != NULL);
FARPROC proc = GetProcAddress(hMod, szFunc);
assert(proc != NULL);
LONG offset = (LONG)proc - (LONG)hMod;
assert(offset >= 0);
FreeLibrary(hMod);
return offset;
}
Starting it is now different: