warlocks-stave/bridges/stave_stub.cpp

87 lines
2.6 KiB
C++

// ============================================================================
// 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 <windows.h>
#include <string.h>
#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);
}
}
}