After googling and trying different solutions and then googling again and trying some more solutions I've decided I'm a bit out of my league here. Hopefully you guys can lend a hand. First this program isn't used for World of Warcraft, I don't think that will matter all that much, as it is pretty generalized. What I'm doing is have a dll called Mod.dll and inside Mod.dll I hook endScene and initialize the CEGUI with the pointer in endScene.
Code:
HRESULT WINAPI hkEndScene (LPDIRECT3DDEVICE9 pDevice) {
static bool init = true;
if (init) {
log_dll._stream << "Attempting to setup CEGUI for the first time" << std::endl;
CEGUI::Direct3D9Renderer::bootstrapSystem (pDevice);
setupGuiFluff();
CEGUI::Window* myRoot = CEGUI::WindowManager::getSingletonPtr()->loadWindowLayout ("dps.layout");
CEGUI::System::getSingletonPtr()->setGUISheet (myRoot);
init = false;
}
CEGUI::System::getSingletonPtr()->renderGUI();
/*
IDirect3DStateBlock9 *pStateBlock;
pDevice->CreateStateBlock (D3DSBT_ALL, &pStateBlock);
pStateBlock->Apply();
pStateBlock->Release();*/
__asm nop;
return oEndScene (pDevice);
}
Code:
DWORD WINAPI hookThread (LPVOID) {
DWORD vTable[1] = {0};
while (GetModuleHandle ("d3d9.dll") == NULL ) {
Sleep (250);
}
initDX (vTable);
HOOK (EndScene, vTable[0]);
return 0;
}
Code:
BOOL APIENTRY DllMain( HMODULE hInstance, DWORD dwReason, LPVOID lpReserved ) {
switch (dwReason) {
case DLL_PROCESS_ATTACH:
log_dll._stream.open ("C:\\ModDll.txt");
log_dll._stream << "CallSomething address:" << CallSomething << std::endl;
CreateThread (0, 0, hookThread, 0, 0, 0);
break;
case DLL_PROCESS_DETACH:
log_dll._stream << "Detaching from process" << std::endl;
break;
}
return TRUE;
}
I then Inject the DLL using this piece of code, I'm not sure how "safe" it is or if it's exactly the best way to do the job. I wrapped it in a class for pure convenience.
Code:
#ifndef DLLMANAGER_HPP
#define DLLMANAGER_HPP
#include <Windows.h>
#include <tlhelp32.h>
#include <Psapi.h>
#include "shlwapi.h"
#include "Logger.hpp"
class DLLManager {
public:
Logger log;
DWORD processId;
DWORD dwBaseAddress;
HANDLE hProcess;
std::string dll;
DLLManager () { log._stream.open ("C:\\DLLManager.txt"); }
~DLLManager () { log._stream.close(); }
DWORD findProcessId (const std::string &processName) {
PROCESSENTRY32 processInfo;
processInfo.dwSize = sizeof (processInfo);
HANDLE processesSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, NULL);
if (processesSnapshot == INVALID_HANDLE_VALUE) {
log._stream << "findProcessId() -> processSnapshot failed" << std::endl;
return 0;
}
Process32First (processesSnapshot, &processInfo);
if (!processName.compare (processInfo.szExeFile)) {
CloseHandle (processesSnapshot);
log._stream << "findProcessId() -> Process '" << processInfo.szExeFile << "' found and id is '" << processInfo.th32ProcessID << "'" << std::endl;
processId = processInfo.th32ProcessID;
return processInfo.th32ProcessID;
}
while (Process32Next (processesSnapshot, &processInfo)) {
if (!processName.compare (processInfo.szExeFile)) {
CloseHandle (processesSnapshot);
log._stream << "findProcessId() -> Process '" << processInfo.szExeFile << "' found and id is '" << processInfo.th32ProcessID << "'" << std::endl;
processId = processInfo.th32ProcessID;
return processInfo.th32ProcessID;
}
}
log._stream << "findProcessId() -> Failed to find process id, are you sure it's running?" << std::endl;
CloseHandle (processesSnapshot);
return 0;
}
bool injectDLL (DWORD pId, std::string dll) {
this->dll = dll;
HMODULE hLocKernel32 = GetModuleHandle ("Kernel32");
FARPROC hLocLoadLibrary = GetProcAddress (hLocKernel32, "LoadLibraryA");
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges (hToken, 0, &tkp, sizeof (tkp), NULL, NULL);
}
HANDLE hProc = OpenProcess (PROCESS_ALL_ACCESS, false, pId);
dll += '\0';
LPVOID hRemoteMem = VirtualAllocEx (hProc, NULL, dll.size(), MEM_COMMIT, PAGE_READWRITE);
DWORD numBytesWritten;
WriteProcessMemory (hProc, hRemoteMem, dll.c_str(), dll.size(), &numBytesWritten);
HANDLE hRemoteThread = CreateRemoteThread (hProc, NULL, 0, (LPTHREAD_START_ROUTINE) hLocLoadLibrary, hRemoteMem, 0, NULL);
log._stream << "hRemoteThread:" << hRemoteThread << std::endl;
bool result = false;
if (hRemoteThread)
result = (bool) WaitForSingleObject (hRemoteThread, 10000) != WAIT_TIMEOUT;
if (!GetExitCodeThread (hRemoteThread, &dwBaseAddress)) result = false;
log._stream << "DLL Successfully injected at location:" << dwBaseAddress << std::endl;
VirtualFreeEx (hProc, hRemoteMem, dll.size(), MEM_RELEASE);
hProcess = hProc;
CloseHandle (hProc);
return result;
}
bool callFunction (const std::string &function) {
HINSTANCE hLibrary = LoadLibrary (dll.c_str());
if (!hLibrary)
log._stream << "Attempted to load a dll but failed" << std::endl;
FARPROC pPrototype = GetProcAddress (hLibrary, function.c_str());
if (!pPrototype)
log._stream << "Could not find function '" << function << "' in specified library" << std::endl;
FARPROC pRelative = (FARPROC)((DWORD)pPrototype - (DWORD)hLibrary);
LPVOID pFunction = (LPVOID)((DWORD)pRelative + dwBaseAddress);
log._stream << "Attempting to call '" << function << "' at location:" << pFunction << std::endl;
DWORD dwExitCode;
//HANDLE hThread = CreateRemoteThread (hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunction, NULL, 0, NULL);
HANDLE hThread = CreateRemoteThread (GetCurrentProcess(), NULL, 0, (LPTHREAD_START_ROUTINE)pFunction, NULL, 0, NULL);
if (WaitForSingleObject (hThread, 10000) != WAIT_OBJECT_0) {
log._stream << "Failed to create thread to run function in" << std::endl;
return false;
}
if (!GetExitCodeThread (hThread, &dwExitCode)) {
log._stream << "Remote function call failed to execute" << std::endl;
return false;
}
log._stream << "Function ran with exit code:" << dwExitCode << std::endl;
return (dwExitCode != 0);
}
bool unloadDll () {
DWORD dwNeeded;
HMODULE hMods[0x400];
HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, processId);
EnumProcessModules (hProcess, hMods, 0x400, &dwNeeded);
for (int i = 0; i < (dwNeeded / sizeof (DWORD)); i++) {
char szPath[MAX_PATH] = "";
GetModuleFileNameExA (hProcess, hMods[i], szPath, MAX_PATH);
PathStripPathA (szPath);
// uncomment below line to see all modules loaded into the given process id
// log._stream << szPath << std::endl;
if (!_stricmp (szPath, "ModDll.dll")) {
log._stream << "Located dll inside of process" << std::endl;
FreeLibrary (hMods[i]);
return true;
}
}
return false;
}
};
#endif
Then in my applications main thread I do.
Code:
#pragma comment (lib, "ModDll.lib")
extern "C" __declspec (dllimport) int CallSomething();
int main (int argc, char *argv[]) {
DLLManager Manager;
Manager.injectDLL (Manager.findProcessId ("app.exe"), "C:\\Programming\\Projects\\Mod\\Debug\\ModDll.dll");
Manager.callFunction ("CallSomething");
int ret = CallSomething();
return 0;
}
The DLL seems to inject fine and I get my GUI window displayed that I want, the big issue comes when I try to call a function (defined below) from inside the application. It seems to be crashing out on the WindowManager::getSingleton() call (bad pointer?) if I use WindowManager::getSingletonPtr() it will crash out on GetWindow call I assume this is pointing to bad memory as well.
Code:
extern "C" __declspec (dllexport) int CallSomething(const char *data) {
log_dll._stream << "CallSomething()" << std::endl;
// setup variables;
CEGUI::String str ("player");
CEGUI::ListboxTextItem *add = new CEGUI::ListboxTextItem (str);
log_dll._stream << "CallSomething(): " << str << std::endl;
// crash
// CEGUI::Window *listBox = CEGUI::WindowManager::getSingleton().getWindow ("Root/testWindow/players");
// get the listbox and add the name - crash
CEGUI::Window *listBox = CEGUI::WindowManager::getSingletonPtr()->getWindow ("Root/testWindow/players");
static_cast <CEGUI::Listbox *> (listBox)->addItem (add);
log_dll._stream << "CallSomething(): complete" << std::endl;
return 1;
}
Just as an FYI CEGUI has been statically linked. I thought maybe the issue was with my DLL so I downloaded memory hacker and injected my dll through that and called the functions from there, it has no issue populating my listbox. I've included two call stacks, the first when using CEGUI::WindowManager::getSingletonPtr() and the second when using CEGUI::Window::Manager::getSingleton().
Code:
> ModDll.dll!std::_Tree<std::_Tmap_traits<CEGUI::String,CEGUI::Window *,CEGUI::String::FastLessCompare,std::allocator<std::pair<CEGUI::String const ,CEGUI::Window *> >,0> >::_Root() Line 1789 + 0x3 bytes C++
ModDll.dll!std::_Tree<std::_Tmap_traits<CEGUI::String,CEGUI::Window *,CEGUI::String::FastLessCompare,std::allocator<std::pair<CEGUI::String const ,CEGUI::Window *> >,0> >::_Lbound(const CEGUI::String & _Keyval) Line 1725 + 0x8 bytes C++
ModDll.dll!std::_Tree<std::_Tmap_traits<CEGUI::String,CEGUI::Window *,CEGUI::String::FastLessCompare,std::allocator<std::pair<CEGUI::String const ,CEGUI::Window *> >,0> >::lower_bound(const CEGUI::String & _Keyval) Line 1455 + 0x10 bytes C++
ModDll.dll!std::_Tree<std::_Tmap_traits<CEGUI::String,CEGUI::Window *,CEGUI::String::FastLessCompare,std::allocator<std::pair<CEGUI::String const ,CEGUI::Window *> >,0> >::find(const CEGUI::String & _Keyval) Line 1433 + 0x10 bytes C++
ModDll.dll!CEGUI::WindowManager::getWindow(const CEGUI::String & name) Line 252 + 0x13 bytes C++
ModDll.dll!CallSomething(const char * data) Line 124 + 0x23 bytes C++
kernel32.dll!76da3677()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
ntdll.dll!77309d42()
ntdll.dll!77309d15()
Code:
ModDll.dll!_wassert(const wchar_t * expr, const wchar_t * filename, unsigned int lineno) Line 325 C
> ModDll.dll!CEGUI::Singleton<CEGUI::WindowManager>::getSingleton() Line 79 + 0x38 bytes C++
ModDll.dll!CallSomething(const char * data) Line 124 + 0x1c bytes C++
kernel32.dll!76da3677()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
ntdll.dll!77309d42()
ntdll.dll!77309d15()
Please rip it apart, critique it, flame it, anything that will help me through this issue. I've also been thinking about moving over to HadesMem but I haven't been having much luck with Boost.Build.
Thanks, Orix
/mmowned cherry popped