Try this dll injector for what Warmane does with the wowo client, I don't play on a pvp server.
USE VPN and soma thrash TESTing wow account !!!
wow_launcher.c
/*
* wow_capture_launcher.exe - spawns Wow.exe suspended, injects
* wow_capture.dll via CreateRemoteThread/LoadLibraryW, resumes.
*
* 32-bit. wow.exe path is hardcoded below - edit WOW_EXE_PATH if needed.
*/
#include <windows.h>
#include <stdio.h>
static void die(const wchar_t *what, DWORD err, HANDLE proc) {
wprintf(L"[!] %s failed: %lu\n", what, err);
if (proc) TerminateProcess(proc, 1);
ExitProcess(1);
}
int main(void) {
wchar_t self_dir[MAX_PATH];
wchar_t dll_path[MAX_PATH];
wchar_t wow_path[MAX_PATH];
wchar_t wow_dir [MAX_PATH];
/* directory of this launcher */
GetModuleFileNameW(NULL, self_dir, MAX_PATH);
for (int i = (int)lstrlenW(self_dir) - 1; i >= 0; i--) {
if (self_dir[i] == L'\\' || self_dir[i] == L'/') {
self_dir[i + 1] = 0;
break;
}
}
lstrcpyW(dll_path, self_dir);
lstrcatW(dll_path, L"wow_capture.dll");
/* verify DLL exists */
DWORD attr = GetFileAttributesW(dll_path);
if (attr == INVALID_FILE_ATTRIBUTES) {
wprintf(L"[!] wow_capture.dll not found next to launcher\n %s\n",
dll_path);
return 1;
}
/* Wow.exe is expected next to the launcher. */
lstrcpyW(wow_path, self_dir);
lstrcatW(wow_path, L"Wow.exe");
/* Working directory = launcher's own directory, without trailing slash. */
lstrcpyW(wow_dir, self_dir);
int wd_len = (int)lstrlenW(wow_dir);
if (wd_len > 0 && (wow_dir[wd_len - 1] == L'\\' || wow_dir[wd_len - 1] == L'/'))
wow_dir[wd_len - 1] = 0;
/* Verify Wow.exe exists next to us. */
if (GetFileAttributesW(wow_path) == INVALID_FILE_ATTRIBUTES) {
wprintf(L"[!] Wow.exe not found next to launcher\n %s\n", wow_path);
return 1;
}
wprintf(L"[+] wow.exe = %s\n", wow_path);
wprintf(L"[+] wow_capture = %s\n", dll_path);
/* spawn suspended */
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = {0};
if (!CreateProcessW(wow_path, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, wow_dir, &si, &pi)) {
die(L"CreateProcessW", GetLastError(), NULL);
}
wprintf(L"[+] wow.exe PID=%lu (suspended)\n", pi.dwProcessId);
/* allocate remote buffer for DLL path */
SIZE_T path_bytes = (lstrlenW(dll_path) + 1) * sizeof(wchar_t);
LPVOID remote = VirtualAllocEx(pi.hProcess, NULL, path_bytes,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!remote) die(L"VirtualAllocEx", GetLastError(), pi.hProcess);
SIZE_T written = 0;
if (!WriteProcessMemory(pi.hProcess, remote, dll_path, path_bytes, &written))
die(L"WriteProcessMemory", GetLastError(), pi.hProcess);
/* kernel32 base is identical across same-bitness processes (shared),
* so LoadLibraryW's address in this process == its address in wow.exe. */
HMODULE k32 = GetModuleHandleW(L"kernel32.dll");
LPTHREAD_START_ROUTINE loadlib =
(LPTHREAD_START_ROUTINE)GetProcAddress(k32, "LoadLibraryW");
if (!loadlib) die(L"GetProcAddress(LoadLibraryW)", GetLastError(), pi.hProcess);
HANDLE th = CreateRemoteThread(pi.hProcess, NULL, 0, loadlib, remote, 0, NULL);
if (!th) die(L"CreateRemoteThread", GetLastError(), pi.hProcess);
wprintf(L"[+] waiting for LoadLibraryW in target...\n");
WaitForSingleObject(th, INFINITE);
DWORD dll_base = 0;
GetExitCodeThread(th, &dll_base);
CloseHandle(th);
if (!dll_base) {
wprintf(L"[!] LoadLibraryW returned NULL - DLL not loaded\n");
TerminateProcess(pi.hProcess, 1);
return 1;
}
wprintf(L"[+] wow_capture.dll loaded at 0x%08X\n", dll_base);
VirtualFreeEx(pi.hProcess, remote, 0, MEM_RELEASE);
wprintf(L"[+] resuming main thread\n");
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
wprintf(L"[+] done. Play normally until ban.\n"
L" Capture output: %s\n", self_dir);
return 0;
}
wow_capture.c
/*
* wow_capture.dll - RCE payload capture for Wow.exe 3.3.5.12340
*
* Injected into wow.exe at start by wow_capture_launcher.exe.
* Installs a hardware breakpoint (DR3, execute) on the .zdata entry
* (0x009D1000). When anything executes there - which is the RCE payload
* Warmane writes into .zdata - the VEH fires, dumps the full 4 KB of
* .zdata to disk with a timestamp, logs the hit, sets the Resume Flag,
* and lets execution continue normally. DR3 stays armed, so subsequent
* calls are also captured.
*
* Output files (next to the DLL):
* wow_capture_log.txt - timestamped event log
* wow_rce_dump_<ts>_hit<N>.bin - one 4 KB dump per HWBP hit
*/
#include <windows.h>
#include <tlhelp32.h>
#define ZDATA_VA 0x009D1000UL
#define ZDATA_SIZE 0x1000UL
static HMODULE g_self = NULL;
static PVOID g_veh = NULL;
static volatile LONG g_hit_count = 0;
static CRITICAL_SECTION g_cs;
/* ------------------------------------------------------------------ */
/* Paths / logging */
/* ------------------------------------------------------------------ */
static void dll_dir(wchar_t *out, DWORD cap) {
GetModuleFileNameW(g_self, out, cap);
for (int i = (int)lstrlenW(out) - 1; i >= 0; i--) {
if (out[i] == L'\\' || out[i] == L'/') { out[i + 1] = 0; return; }
}
}
static void log_line(const wchar_t *msg) {
wchar_t path[MAX_PATH];
dll_dir(path, MAX_PATH);
lstrcatW(path, L"wow_capture_log.txt");
HANDLE f = CreateFileW(path, FILE_APPEND_DATA, FILE_SHARE_READ, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (f == INVALID_HANDLE_VALUE) return;
SetFilePointer(f, 0, NULL, FILE_END);
SYSTEMTIME st; GetLocalTime(&st);
wchar_t buf[512];
int n = wsprintfW(buf,
L"[%04d-%02d-%02d %02d:%02d:%02d.%03d tid=%lu] %s\r\n",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
GetCurrentThreadId(), msg);
DWORD written;
WriteFile(f, buf, n * sizeof(wchar_t), &written, NULL);
CloseHandle(f);
}
static void dump_zdata(LONG hit_no) {
wchar_t path[MAX_PATH];
dll_dir(path, MAX_PATH);
SYSTEMTIME st; GetLocalTime(&st);
wchar_t name[96];
wsprintfW(name,
L"wow_rce_dump_%04d%02d%02d_%02d%02d%02d_%03d_hit%ld.bin",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, hit_no);
lstrcatW(path, name);
HANDLE f = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (f == INVALID_HANDLE_VALUE) return;
/* Read via SEH-safe copy just in case a future patch makes .zdata
* unreadable; on stock wow.exe .zdata is fully readable. */
BYTE tmp[ZDATA_SIZE];
__try {
for (DWORD i = 0; i < ZDATA_SIZE; i++)
tmp[i] = ((volatile BYTE *)ZDATA_VA)[i];
} __except (EXCEPTION_EXECUTE_HANDLER) {
CloseHandle(f);
return;
}
DWORD written;
WriteFile(f, tmp, ZDATA_SIZE, &written, NULL);
CloseHandle(f);
}
/* ------------------------------------------------------------------ */
/* Vectored exception handler */
/* ------------------------------------------------------------------ */
static LONG CALLBACK veh(EXCEPTION_POINTERS *ep) {
if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP)
return EXCEPTION_CONTINUE_SEARCH;
DWORD addr = (DWORD)(DWORD_PTR)ep->ExceptionRecord->ExceptionAddress;
if (addr < ZDATA_VA || addr >= ZDATA_VA + ZDATA_SIZE)
return EXCEPTION_CONTINUE_SEARCH;
EnterCriticalSection(&g_cs);
LONG n = InterlockedIncrement(&g_hit_count);
dump_zdata(n);
wchar_t msg[256];
wsprintfW(msg, L"HWBP hit #%ld @ 0x%08X (dumped .zdata 4096B)",
n, addr);
log_line(msg);
LeaveCriticalSection(&g_cs);
/* Resume Flag: CPU skips the HWBP for exactly one instruction,
* then DR3 stays armed for future hits. Shellcode executes
* normally after this single-instruction grace period. Any
* re-entry to .zdata later will trap again. */
ep->ContextRecord->EFlags |= 0x10000;
return EXCEPTION_CONTINUE_EXECUTION;
}
/* ------------------------------------------------------------------ */
/* HWBP arming */
/* ------------------------------------------------------------------ */
static void arm_thread(DWORD tid) {
HANDLE t = OpenThread(
THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME,
FALSE, tid);
if (!t) return;
SuspendThread(t);
CONTEXT ctx;
ZeroMemory(&ctx, sizeof(ctx));
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (GetThreadContext(t, &ctx)) {
if (ctx.Dr3 != ZDATA_VA) {
ctx.Dr3 = ZDATA_VA;
/* DR7:
* L3 (bit 6) = 1 enable DR3 local
* RW3 (bits 28-29) = 00 execute
* LEN3 (bits 30-31) = 00 one byte (required for exec) */
ctx.Dr7 &= ~((DWORD)0xF0000000u); /* clear RW3 + LEN3 */
ctx.Dr7 &= ~((DWORD)(1u << 7)); /* clear G3 */
ctx.Dr7 |= ((DWORD)(1u << 6)); /* set L3 */
SetThreadContext(t, &ctx);
}
}
ResumeThread(t);
CloseHandle(t);
}
static void arm_all_threads(void) {
DWORD self_tid = GetCurrentThreadId();
DWORD self_pid = GetCurrentProcessId();
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (snap == INVALID_HANDLE_VALUE) return;
THREADENTRY32 te;
te.dwSize = sizeof(te);
if (Thread32First(snap, &te)) {
do {
if (te.th32OwnerProcessID == self_pid &&
te.th32ThreadID != self_tid) {
arm_thread(te.th32ThreadID);
}
} while (Thread32Next(snap, &te));
}
CloseHandle(snap);
}
static DWORD WINAPI monitor_thread(LPVOID p) {
(void)p;
for (;;) {
arm_all_threads();
Sleep(200);
}
}
/* ------------------------------------------------------------------ */
/* DllMain */
/* ------------------------------------------------------------------ */
BOOL WINAPI DllMain(HINSTANCE h, DWORD reason, LPVOID r) {
(void)r;
if (reason != DLL_PROCESS_ATTACH) return TRUE;
g_self = h;
DisableThreadLibraryCalls(h);
InitializeCriticalSection(&g_cs);
g_veh = AddVectoredExceptionHandler(1, veh);
/* Diagnostic: snapshot .zdata page state at load time. */
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery((LPCVOID)ZDATA_VA, &mbi, sizeof(mbi))) {
wchar_t msg[256];
wsprintfW(msg,
L"loaded; .zdata: Base=0x%08X Size=0x%X Protect=0x%08X State=0x%08X",
(DWORD)(DWORD_PTR)mbi.BaseAddress,
(DWORD)mbi.RegionSize,
(DWORD)mbi.Protect,
(DWORD)mbi.State);
log_line(msg);
} else {
log_line(L"loaded; VirtualQuery(.zdata) failed");
}
/* Initial arm before launcher resumes the main thread. */
arm_all_threads();
CreateThread(NULL, 0, monitor_thread, NULL, 0, NULL);
return TRUE;
}
By
Pepa ·