// ============================================================================ // x64dbg/Wine C++ Plugin Hook Module // ============================================================================ // // Forms the bridge between an x64dbg debug session (running under Wine) // and the Warlock's Stave IPC daemon. Captures step events and forwards // them as packed binary payloads over a named pipe (which Wine // automatically maps to Unix sockets on Linux). #include #include #define PLUG_SDKVERSION 5 typedef size_t CBTYPE; struct PLUG_INITSTRUCT { int pluginHandle; int sdkVersion; int pluginVersion; char pluginName[256]; }; int pluginHandle; HANDLE hPipe = INVALID_HANDLE_VALUE; struct __attribute__((packed)) WineIpcPayload { unsigned __int64 rip; unsigned int eflags; unsigned int buffer_len; unsigned char bytes[15]; }; void AttemptPipeConnection() { // Wine intercepts named pipe routing and maps them // to Unix sockets automatically on Linux. hPipe = CreateFileA( "\\\\.\\pipe\\stave_bridge_ipc", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); } extern "C" __declspec(dllexport) bool pluginit(PLUG_INITSTRUCT* initStruct) { initStruct->pluginVersion = 7; initStruct->sdkVersion = PLUG_SDKVERSION; strcpy(initStruct->pluginName, "StaveCoreWineBridge"); pluginHandle = initStruct->pluginHandle; AttemptPipeConnection(); return true; } extern "C" __declspec(dllexport) void plugstop() { if (hPipe != INVALID_HANDLE_VALUE) { CloseHandle(hPipe); hPipe = INVALID_HANDLE_VALUE; } } // Triggered automatically on every breakpoint step execution event. extern "C" __declspec(dllexport) void CBSTEPPED(CBTYPE cbType, void* info) { if (hPipe == INVALID_HANDLE_VALUE) { AttemptPipeConnection(); if (hPipe == INVALID_HANDLE_VALUE) return; } CONTEXT context; context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; HANDLE currentThread = GetCurrentThread(); if (GetThreadContext(currentThread, &context)) { WineIpcPayload payload; payload.rip = context.Rip; payload.eflags = context.EFlags; payload.buffer_len = 15; memset(payload.bytes, 0, 15); SIZE_T bytesRead = 0; ReadProcessMemory( GetCurrentProcess(), (LPCVOID)context.Rip, payload.bytes, 15, &bytesRead ); if (bytesRead > 0) { payload.buffer_len = (unsigned int)bytesRead; DWORD bytesWritten; WriteFile(hPipe, &payload, sizeof(payload), &bytesWritten, NULL); } } }