POLLING SINGLE SHOT
Code:
static auto once = true;
if (once)
{
once = false;
// do work here. happens only once.
}
THE MOST GLORIOUS TEMPLATE (Credits: 34D)
Code:
template<typename RET, typename ...ARGS>
RET invoke(uintptr_t offset, ARGS ...args)
{
if (!offset) // Not sure maybe can be more specific here with something like the use of IsBadReadPtr
MessageBoxA(nullptr, "Invalid Function Address!", "Zero Address", MB_OK);
return reinterpret_cast<RET(__fastcall*)(ARGS...)>(offset)(args ...);
}
// Usage: invoke<return_type>(function_address, arg1, arg2, ...);
LAMBDAS (Shown Threaded Here)
Code:
auto L = invoke<lua_State*>(lua_state);
luaL_loadstring(L, "print('hello')");
std::thread([L]{ lua_call(L, 0, -1); }).join();
// Usage: The [] is the capture [&] is for local [=] is global and [L] is specific to capute L in this case
SOLUTION PATH
Code:
export std::string solution_dir(std::string suffix = "")
{
std::filesystem::path file_path(__FILE__);
std::filesystem::path directory = file_path.parent_path().parent_path();
directory += "\\" + suffix;
return directory.string();
}
// Notes: it can be annoying to have your module give you paths relative to the game's path, but this using __FILE__ gets you to the directory of your launcher. parent.parent is for when you are inside /x64/Release
THE SIMPLE LOADER
Code:
bool window_found;
std::mutex mutex;
std::condition_variable cv;
DWORD open()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
DWORD flags = DETACHED_PROCESS;
BOOL success = CreateProcess((app_path + app_name).c_str(), NULL, NULL, NULL, FALSE, flags, NULL, app_path.c_str(), &si, &pi);
if (!success)
printf("[LINK] Failed to Create Process!\n");
auto pid = pi.dwProcessId;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return pid;
}
BOOL CALLBACK callback(HWND hwnd, LPARAM lParam)
{
auto& window = *reinterpret_cast<std::tuple<HWND, DWORD>*>(lParam);
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
auto& [h, p] = window;
if (pid == p)
h = hwnd;
return TRUE;
}
HWND hWnd(DWORD process_id)
{
std::tuple<HWND, DWORD> window{};
auto& [hWnd, pid] = window;
pid = process_id;
EnumWindows(callback, reinterpret_cast<LPARAM>(&window));
if (hWnd)
return hWnd;
return nullptr;
}
void wait(DWORD pid)
{
while (true)
{
if (hWnd(pid))
{
std::unique_lock<std::mutex> lock(mutex);
window_found = true;
//std::this_thread::sleep_for(std::chrono::seconds(1)); // increase seconds for smoothness to wait on the game appearing
cv.notify_one();
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int load(DWORD pid, const wchar_t* path)
{
auto size = (wcslen(path) + 1) * sizeof(wchar_t);
auto process_ = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
auto dll_ = VirtualAllocEx(process_, nullptr, size, MEM_COMMIT, PAGE_READWRITE);
if (!dll_)
{
printf("[LINK] Failed Allocate DLL!\n");
return -1;
}
WriteProcessMemory(process_, dll_, path, size, nullptr);
auto kernel32_ = GetModuleHandle(L"Kernel32.dll");
if (!kernel32_)
{
printf("[LINK] Failed to Find Kernel32!\n");
return -1;
}
auto load_library_ = (LPTHREAD_START_ROUTINE)(GetProcAddress(kernel32_, "LoadLibraryW"));
if (!load_library_)
{
printf("[LINK] Failed to Find LoadLibraryW!\n");
return -1;
}
HANDLE thread_ = CreateRemoteThread(process_, nullptr, 0, load_library_, dll_, 0, nullptr);
if (!thread_)
{
printf("[LINK] Failed to Create Thread!\n");
return -1;
}
WaitForSingleObject(thread_, INFINITE);
VirtualFreeEx(process_, dll_, size, MEM_FREE);
return 0;
}
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
auto pid = open();
if (pid)
{
std::thread waiting(wait, pid);
{
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [] { return window_found; });
}
waiting.join();
load(pid, std::filesystem::current_path().append(dll_name).c_str());
}
return 0;
}
WNDPROC HOOK (Credits: lolp1)
Code:
LRESULT CALLBACK window(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static auto once = true;
if (!registered && playing())
{
registered = true;
lua_register(invoke<lua_State*>(lua_state), "CPlus", (lua_CFunction)int3); // Better to reverse LoadAddOn and do it clean with LuaBridge, but this is fine too ;)
}
if (once && wparam == VK_F11)
{
once = false;
auto L = invoke<int64_t>(lua_state);
lua_loadfile(L, solution_dir("scripts\\server.lua"));
}
if (wparam == VK_F12)
{
once = true;
}
return CallWindowProc(wndproc_, hwnd, message, wparam, lparam);
}
void set_window()
{
auto window_ = FindWindow(nullptr, L"World of Warcraft");
while (window_ != nullptr)
{
DWORD pid;
GetWindowThreadProcessId(window_, &pid);
if (pid == GetCurrentProcessId())
{
wnd_ = window_;
wndproc_ = reinterpret_cast<WNDPROC>(SetWindowLongPtr(window_, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(window)));
break;
}
window_ = FindWindowEx(nullptr, window_, nullptr, L"World of Warcraft");
}
}
// Usage: Call set_window and the hook will be active
VEH HOOK
Code:
void bypass() { ExitThread(0); } // Comment ExitThread if call is not on pipes
LONG NTAPI veh(struct _EXCEPTION_POINTERS* exception)
{
if (exception->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
{
exception->ContextRecord->Rip = (uintptr_t)test; // route your int3 to test
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (exception->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
exception->ContextRecord->Rip = TARGET_FUNCION_ADDRESS_HERE;
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (exception->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO)
{
MessageBoxA(nullptr, "DIVIDE BY ZERO", "Error", MB_OK);
exception->ContextRecord->Rip = (uintptr_t)bypass; // attempt to terminate the threaded call hitting a divide by zero
return EXCEPTION_CONTINUE_EXECUTION;
}
else
{
const auto code = exception->ExceptionRecord->ExceptionCode;
const auto code_hex = "0x" + std::to_string(code);
int choice = MessageBoxA(nullptr, "CONTINUE?", code_hex.c_str(), MB_YESNO);
if (choice == IDYES)
{
exception->ContextRecord->Rip = (uintptr_t)bypass; // attempt to bypass unknown exceptions
return EXCEPTION_CONTINUE_EXECUTION;
}
else
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_CONTINUE_SEARCH;
}
// ...
SetUnhandledExceptionFilter(veh); // Make your VEH topmost
typedef void(*MYVOIDFUNC)(int64_t); // Prototype of your desired function
auto p = (MYVOIDFUNC)0xFFF101011; // Garbage address casted to your function's typedef
p(1337); // Causes Exception
// Usage: This detour style is useless knowing you can just call the function explicitly. However, you can get creative and force exceptions that will occur inside the target function. For example pass a bad argument to something you know doesn't have the proper checking for it then catch that exception again in your VEH, and now you have more control than just pre/post. Use a combination of += -= on the ->Rip, context ripping, and extracting information, addresses, or arguments from the exception record or context. Again this is still useless if you just call it, but then I'd say you aren't exploring all creative potential here ;0
Stay frosty friends and best of luck! I thought I had more cool ideas, but this is my main bag of tricks for WoW.