diff --git a/ImGui/impls/linux/imgui_impl_x11.cpp b/ImGui/impls/linux/imgui_impl_x11.cpp new file mode 100644 index 0000000..1065ae4 --- /dev/null +++ b/ImGui/impls/linux/imgui_impl_x11.cpp @@ -0,0 +1,302 @@ +// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) + +// Implemented features: +// [?] Platform: Clipboard support +// [?] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [?] Platform: Keyboard arrays indexed using +// [?] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + +#include "imgui.h" +#include "imgui_impl_x11.h" + +#include +#include +#include +#include + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2019-08-31: Initial X11 implementation + +// X11 Data +static Display* g_Display = nullptr; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT; +static bool g_HasGamepad = false; +static bool g_WantUpdateHasGamepad = true; + +// Functions +bool ImGui_ImplX11_Init(void *display) +{ + //if (!::QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) + // return false; + //if (!::QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) + // return false; + + // Setup back-end capabilities flags + g_Display = reinterpret_cast(display); + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = "imgui_impl_x11"; + io.ImeWindowHandle = nullptr; + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. + io.KeyMap[ImGuiKey_Tab] = -1; + io.KeyMap[ImGuiKey_LeftArrow] = -1; + io.KeyMap[ImGuiKey_RightArrow] = -1; + io.KeyMap[ImGuiKey_UpArrow] = -1; + io.KeyMap[ImGuiKey_DownArrow] = -1; + io.KeyMap[ImGuiKey_PageUp] = -1; + io.KeyMap[ImGuiKey_PageDown] = -1; + io.KeyMap[ImGuiKey_Home] = -1; + io.KeyMap[ImGuiKey_End] = -1; + io.KeyMap[ImGuiKey_Insert] = -1; + io.KeyMap[ImGuiKey_Delete] = -1; + io.KeyMap[ImGuiKey_Backspace] = -1; + io.KeyMap[ImGuiKey_Space] = -1; + io.KeyMap[ImGuiKey_Enter] = -1; + io.KeyMap[ImGuiKey_Escape] = -1; + io.KeyMap[ImGuiKey_A] = -1; + io.KeyMap[ImGuiKey_C] = -1; + io.KeyMap[ImGuiKey_V] = -1; + io.KeyMap[ImGuiKey_X] = -1; + io.KeyMap[ImGuiKey_Y] = -1; + io.KeyMap[ImGuiKey_Z] = -1; + return true; +} + +void ImGui_ImplX11_Shutdown() +{ + g_Display = nullptr; +} + +static bool ImGui_ImplWin32_UpdateMouseCursor() +{ + /* + ImGuiIO& io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) + return false; + + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + ::SetCursor(NULL); + } + else + { + // Show OS mouse cursor + LPTSTR win32_cursor = IDC_ARROW; + switch (imgui_cursor) + { + case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break; + case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break; + case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break; + case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break; + case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break; + case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break; + case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; + case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break; + } + ::SetCursor(::LoadCursor(NULL, win32_cursor)); + } + */ + return true; +} + +static void ImGui_ImplWin32_UpdateMousePos() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + //if (io.WantSetMousePos) + //{ + // POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; + // ::ClientToScreen(g_hWnd, &pos); + // ::SetCursorPos(pos.x, pos.y); + //} + + // Set mouse position + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + + +} + +/* TODO: support linux gamepad ? +#ifdef _MSC_VER +#pragma comment(lib, "xinput") +#endif + +// Gamepad navigation mapping +static void ImGui_ImplWin32_UpdateGamepads() +{ + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. + // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. + if (g_WantUpdateHasGamepad) + { + XINPUT_CAPABILITIES caps; + g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS); + g_WantUpdateHasGamepad = false; + } + + XINPUT_STATE xinput_state; + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS) + { + const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + + #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } + #define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } + MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); + #undef MAP_BUTTON + #undef MAP_ANALOG + } +} +*/ + +void ImGui_ImplX11_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + + // Setup display size (every frame to accommodate for window resizing) + Window rootWnd = DefaultRootWindow(g_Display); + + // Todo: use X11 to get this value + GLint m_viewport[4]; + glGetIntegerv( GL_VIEWPORT, m_viewport ); + io.DisplaySize.x = m_viewport[2]; + io.DisplaySize.y = m_viewport[3]; + + + /* + io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + + // Setup time step + INT64 current_time; + ::QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); + io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond; + g_Time = current_time; + + // Read keyboard modifiers inputs + io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0; + io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0; + io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0; + io.KeySuper = false; + // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below. + + // Update OS mouse position + ImGui_ImplWin32_UpdateMousePos(); + + // Update OS mouse cursor with the cursor requested by imgui + ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (g_LastMouseCursor != mouse_cursor) + { + g_LastMouseCursor = mouse_cursor; + ImGui_ImplWin32_UpdateMouseCursor(); + } + */ + + // Update game controllers (if enabled and available) + //ImGui_ImplWin32_UpdateGamepads(); +} + +// Process Win32 mouse/keyboard inputs. +// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. +// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. +// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. +// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. +IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent &event) +{ + if (ImGui::GetCurrentContext() == NULL) + return 0; + + ImGuiIO& io = ImGui::GetIO(); + switch (event.type) + { + case ButtonPress: + switch(event.xbutton.button ) + { + case Button1: case Button2: case Button3: + io.MouseDown[event.xbutton.button-1] = true; + break; + + case Button4: // Mouse wheel up + event.xbutton.button = Button4; + //io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + + case Button5: // Mouse wheel down + event.xbutton.button = Button5; + //io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + } + + break; + + case ButtonRelease: + switch(event.xbutton.button ) + { + case Button1: case Button2: case Button3: + io.MouseDown[event.xbutton.button-1] = false; + break; + } + break; + + case KeyPress: + case KeyRelease: + break; + + case MotionNotify: + io.MousePos.x = event.xmotion.x; + io.MousePos.y = event.xmotion.y; + break; + } + /* + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (wParam < 256) + io.KeysDown[wParam] = 1; + return 0; + case WM_KEYUP: + case WM_SYSKEYUP: + if (wParam < 256) + io.KeysDown[wParam] = 0; + return 0; + case WM_CHAR: + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + io.AddInputCharacter((unsigned int)wParam); + return 0; + case WM_DEVICECHANGE: + if ((UINT)wParam == DBT_DEVNODES_CHANGED) + g_WantUpdateHasGamepad = true; + return 0; + } + */ + return 0; +} + diff --git a/ImGui/impls/linux/imgui_impl_x11.h b/ImGui/impls/linux/imgui_impl_x11.h new file mode 100644 index 0000000..387609a --- /dev/null +++ b/ImGui/impls/linux/imgui_impl_x11.h @@ -0,0 +1,21 @@ +// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) + +// Implemented features: +// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui) +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + +#pragma once + +IMGUI_IMPL_API bool ImGui_ImplX11_Init(void* display); +IMGUI_IMPL_API void ImGui_ImplX11_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplX11_NewFrame(); + +// Handler for Win32 messages, update mouse/keyboard data. +// You may or not need this for your implementation, but it can serve as reference for handling inputs. +// Intentionally commented out to avoid dragging dependencies on types. You can COPY this line into your .cpp code instead. +/* +IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent *event); +*/ diff --git a/ImGui/impls/windows/imgui_impl_dx10.cpp b/ImGui/impls/windows/imgui_impl_dx10.cpp index 6eef767..ee8b3d6 100644 --- a/ImGui/impls/windows/imgui_impl_dx10.cpp +++ b/ImGui/impls/windows/imgui_impl_dx10.cpp @@ -23,7 +23,7 @@ // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. // 2016-05-07: DirectX10: Disabling depth-write. -#include "../imgui.h" +#include "../../imgui.h" #include "imgui_impl_dx10.h" // DirectX @@ -31,7 +31,7 @@ #include #include -#include "../../overlay_experimental/ImGui_ShaderBlobs.h" +#include "../../../overlay_experimental/windows/ImGui_ShaderBlobs.h" #ifdef USE_D3DCOMPILE static ID3DBlob* g_pVertexShaderBlob = NULL; diff --git a/ImGui/impls/windows/imgui_impl_dx11.cpp b/ImGui/impls/windows/imgui_impl_dx11.cpp index 624eff0..641d4c8 100644 --- a/ImGui/impls/windows/imgui_impl_dx11.cpp +++ b/ImGui/impls/windows/imgui_impl_dx11.cpp @@ -23,14 +23,14 @@ // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. // 2016-05-07: DirectX11: Disabling depth-write. -#include "../imgui.h" +#include "../../imgui.h" #include "imgui_impl_dx11.h" // DirectX #include #include -#include "../../overlay_experimental/ImGui_ShaderBlobs.h" +#include "../../../overlay_experimental/windows/ImGui_ShaderBlobs.h" #ifdef USE_D3DCOMPILE static ID3DBlob* g_pVertexShaderBlob = NULL; diff --git a/ImGui/impls/windows/imgui_impl_dx12.cpp b/ImGui/impls/windows/imgui_impl_dx12.cpp index 9f77668..c529a25 100644 --- a/ImGui/impls/windows/imgui_impl_dx12.cpp +++ b/ImGui/impls/windows/imgui_impl_dx12.cpp @@ -23,14 +23,14 @@ // 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport). // 2018-02-22: Merged into master with all Win32 code synchronized to other examples. -#include "../imgui.h" +#include "../../imgui.h" #include "imgui_impl_dx12.h" // DirectX #include #include -#include "../../overlay_experimental/ImGui_ShaderBlobs.h" +#include "../../../overlay_experimental/windows/ImGui_ShaderBlobs.h" #ifdef USE_D3DCOMPILE static ID3DBlob* g_pVertexShaderBlob = NULL; diff --git a/ImGui/impls/windows/imgui_impl_dx9.cpp b/ImGui/impls/windows/imgui_impl_dx9.cpp index 16102ed..99c497e 100644 --- a/ImGui/impls/windows/imgui_impl_dx9.cpp +++ b/ImGui/impls/windows/imgui_impl_dx9.cpp @@ -22,7 +22,7 @@ // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. -#include "../imgui.h" +#include "../../imgui.h" #include "imgui_impl_dx9.h" // DirectX diff --git a/ImGui/impls/windows/imgui_impl_win32.cpp b/ImGui/impls/windows/imgui_impl_win32.cpp index 3e2f72d..423b918 100644 --- a/ImGui/impls/windows/imgui_impl_win32.cpp +++ b/ImGui/impls/windows/imgui_impl_win32.cpp @@ -7,7 +7,7 @@ // [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -#include "imgui.h" +#include "../../imgui.h" #include "imgui_impl_win32.h" #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN diff --git a/overlay_experimental/Base_Hook.cpp b/overlay_experimental/Base_Hook.cpp index c04b39d..a9889c0 100644 --- a/overlay_experimental/Base_Hook.cpp +++ b/overlay_experimental/Base_Hook.cpp @@ -8,68 +8,20 @@ #include "../detours/detours.h" -void Base_Hook::BeginHook() -{ - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); -} +#define DETOUR_HOOKBEGIN DetourTransactionBegin +#define DETOUR_UPDATETHREAD() DetourUpdateThread(GetCurrentThread()) +#define DETOUR_ENDHOOK DetourTransactionCommit +#define DETOUR_HOOK DetourAttach +#define DETOUR_UNHOOK DetourDetach -void Base_Hook::EndHook() -{ - DetourTransactionCommit(); -} - -void Base_Hook::HookFunc(std::pair hook) -{ - if( DetourAttach(hook.first, hook.second) == 0 ) - _hooked_funcs.emplace_back(hook); -} - -void Base_Hook::UnhookAll() -{ - if (_hooked_funcs.size()) - { - BeginHook(); - std::for_each(_hooked_funcs.begin(), _hooked_funcs.end(), [](std::pair& hook) { - DetourDetach(hook.first, hook.second); - }); - EndHook(); - _hooked_funcs.clear(); - } -} - -#else +#elif defined(__LINUX__) #include "linux/Linux_Detour.h" -void Base_Hook::BeginHook() -{ - Linux_Detour::transaction_begin(); - Linux_Detour::update_thread(pthread_self()); -} - -void Base_Hook::EndHook() -{ - Linux_Detour::transaction_commit(); -} - -void Base_Hook::HookFunc(std::pair hook) -{ - if( Linux_Detour::hook_func(hook.first, hook.second) == 0 ) - _hooked_funcs.emplace_back(hook); -} - -void Base_Hook::UnhookAll() -{ - if (_hooked_funcs.size()) - { - BeginHook(); - std::for_each(_hooked_funcs.begin(), _hooked_funcs.end(), [](std::pair& hook) { - Linux_Detour::unhook_func(hook.first, hook.second); - }); - EndHook(); - _hooked_funcs.clear(); - } -} +#define DETOUR_HOOKBEGIN Linux_Detour::transaction_begin +#define DETOUR_UPDATETHREAD() Linux_Detour::update_thread(pthread_self()) +#define DETOUR_ENDHOOK Linux_Detour::transaction_commit +#define DETOUR_HOOK Linux_Detour::hook_func +#define DETOUR_UNHOOK Linux_Detour::unhook_func #endif @@ -87,4 +39,34 @@ const char* Base_Hook::get_lib_name() const return ""; } +void Base_Hook::BeginHook() +{ + DETOUR_HOOKBEGIN(); + DETOUR_UPDATETHREAD(); +} + +void Base_Hook::EndHook() +{ + DETOUR_ENDHOOK(); +} + +void Base_Hook::HookFunc(std::pair hook) +{ + if( DETOUR_HOOK(hook.first, hook.second) == 0 ) + _hooked_funcs.emplace_back(hook); +} + +void Base_Hook::UnhookAll() +{ + if (_hooked_funcs.size()) + { + BeginHook(); + std::for_each(_hooked_funcs.begin(), _hooked_funcs.end(), [](std::pair& hook) { + DETOUR_UNHOOK(hook.first, hook.second); + }); + EndHook(); + _hooked_funcs.clear(); + } +} + #endif//NO_OVERLAY diff --git a/overlay_experimental/Renderer_Detector.cpp b/overlay_experimental/Renderer_Detector.cpp index 8a429d0..30a6ff2 100644 --- a/overlay_experimental/Renderer_Detector.cpp +++ b/overlay_experimental/Renderer_Detector.cpp @@ -6,12 +6,12 @@ constexpr int max_hook_retries = 500; #ifdef STEAM_WIN32 -#include "DX12_Hook.h" -#include "DX11_Hook.h" -#include "DX10_Hook.h" -#include "DX9_Hook.h" -#include "OpenGL_Hook.h" -#include "Windows_Hook.h" +#include "windows/DX12_Hook.h" +#include "windows/DX11_Hook.h" +#include "windows/DX10_Hook.h" +#include "windows/DX9_Hook.h" +#include "windows/OpenGL_Hook.h" +#include "windows/Windows_Hook.h" static decltype(&IDXGISwapChain::Present) _IDXGISwapChain_Present = nullptr; static decltype(&IDirect3DDevice9::Present) _IDirect3DDevice9_Present = nullptr; diff --git a/overlay_experimental/linux/Linux_Detour.cpp b/overlay_experimental/linux/Linux_Detour.cpp new file mode 100644 index 0000000..984e815 --- /dev/null +++ b/overlay_experimental/linux/Linux_Detour.cpp @@ -0,0 +1,637 @@ +#include "Linux_Detour.h" + +#include +#include + +#include + +#include +#include +#include +#include + +//------------------------------------------------------------------------------// +// Helper funcs +//------------------------------------------------------------------------------// +constexpr static auto relative_jump_size = 5; +constexpr static auto relative_addr_jump_size = sizeof(int32_t); +constexpr static auto absolute_jump_size = 6; + +struct +{ + bool has_r_m; + uint8_t base_size; +} s_opcodes[256] = +{ + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 0 - 7 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 8 - 15 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 16 - 23 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 24 - 31 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 32 - 39 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 40 - 47 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 48 - 55 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 56 - 63 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 64 - 71 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 72 - 79 + // PUSH ... + {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, // 80 - 87 + // POP ... + {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, // 88 - 95 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 96 - 103 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 104 - 111 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 112 - 129 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 120 - 127 + // MOV, ADD, ... R8 <- IMM8 TEST_8 TEST XCHG_8 XCHG + {true , 3}, {true , 6}, {true , 3}, {true , 3}, {true , 2}, {true , 2}, {true , 2}, {true , 2}, // 128 - 135 + // MOV_8 MOV MOV_R8_B MOV_R32_D MOV_32_ES LEA MOV_ES_32 POP + {true , 2}, {true , 2}, {true , 2}, {true , 2}, {true , 2}, {true , 2}, {true , 2}, {false, 2}, // 136 - 143 + // NOP + {false, 1}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 144 - 151 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 152 - 159 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 160 - 167 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 168 - 175 + // MOV_AL MOV_CL MOV_DL MOV_BL MOV_AH MOV_CH MOV_DH MOV_BH + {false, 2}, {false, 2}, {false, 2}, {false, 2}, {false, 2}, {false, 2}, {false, 2}, {false, 2}, // 176 - 183 + // MOV_EAX MOV_ECX MOV_EDX MOV_EBX MOV_ESP MOV_EBP MOV_ESI MOV_EDI, + {false, 5}, {false, 5}, {false, 5}, {false, 5}, {false, 5}, {false, 5}, {false, 5}, {false, 5}, // 184 - 191 + // RETN_IMM16 RETN + {false, 0}, {false, 0}, {false, 3}, {false, 1}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 192 - 199 + // LEAVE RETF_IMM16 RETF INT INT_IMM8 INTO + {false, 0}, {false, 1}, {false, 3}, {false, 1}, {false, 1}, {false, 1}, {false, 1}, {false, 0}, // 200 - 207 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 208 - 215 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 216 - 223 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 224 - 231 + // CALL JMP LJMP SHORT_JMP + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 232 - 239 + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, // 240 - 247 + // EXTENDED + {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 0}, {false, 6}, // 248 - 255 +}; + +static constexpr auto mod_mask = 0xC0; +static constexpr auto register_addressing_mode = 0xC0; +static constexpr auto four_bytes_signed_displacement = 0x80; +static constexpr auto one_byte_signed_displacement = 0x40; + +static constexpr auto rm_mask = 0x05; +static constexpr auto displacement_only_addressing = 0x05; +static constexpr auto sib_with_no_displacement = 0x04; +static constexpr auto register_indirect_addressing_mode = 0x00; + +enum opcodes_e // Commonly used opcode in the beginning of functions +{ + PUSH_EAX = 0x50, PUSH_ECX, PUSH_EDX, PUSH_EBX, PUSH_ESP, PUSH_EBP, PUSH_ESI, PUSH_EDI, + POP_EAX , POP_ECX , POP_EDX , POP_EBX , POP_ESP , POP_EBP , POP_ESI , POP_EDI , + + R8_IMM8 = 0x80, R32_IMM32, R8_IMM8_2, R32_IMM8, + TEST_8, TEST, + XCHG_8, XCHG, + MOV_8 , MOV, + MOV_8_B, MOV_32_D, MOV_32_ES, + LEA, + MOV_ES_32, POP, + NOP, + MOV_AL = 0xB0, MOV_CL, MOV_DL, MOV_BL, MOV_AH, MOV_CH, MOV_DH, MOV_BH, + MOV_EAX, MOV_ECX, MOV_EDX, MOV_EBX, MOV_ESP, MOV_EBP, MOV_ESI, MOV_EDI, + RETN_IMM16 = 0xC2, RETN, + LEAVE = 0xC9, RETF_IMM16, RETF, INT, INT_IMM8, INTO, + CALL = 0xE8, // 5 bytes don't process + JMP, // 5 bytes don't process + LJMP, // 7 bytes, don't process + SHORT_JMP, // 2 bytes don't process + EXTENDED = 0xFF, +}; + +const char* opcode_name(uint8_t opcode) +{ +#define NAME(opcode_name) case opcode_name: return #opcode_name + switch( opcode ) + { + NAME(PUSH_EAX); NAME(PUSH_ECX); NAME(PUSH_EDX); NAME(PUSH_EBX); + NAME(PUSH_ESP); NAME(PUSH_EBP); NAME(PUSH_ESI); NAME(PUSH_EDI); + NAME(POP_EAX); NAME(POP_ECX); NAME(POP_EDX); NAME(POP_EBX); + NAME(POP_ESP); NAME(POP_EBP); NAME(POP_ESI); NAME(POP_EDI); + NAME(R8_IMM8); NAME(R32_IMM32); NAME(R8_IMM8_2); NAME(R32_IMM8); + NAME(TEST_8); NAME(TEST); NAME(XCHG_8); NAME(XCHG); NAME(MOV_8); NAME(MOV); + NAME(MOV_8_B); NAME(MOV_32_D); NAME(MOV_32_ES); + NAME(LEA); + NAME(MOV_ES_32); NAME(POP); + NAME(NOP); + NAME(MOV_AL) ; NAME(MOV_CL) ; NAME(MOV_DL) ; NAME(MOV_BL) ; NAME(MOV_AH) ; NAME(MOV_CH) ; NAME(MOV_DH) ; NAME(MOV_BH) ; + NAME(MOV_EAX); NAME(MOV_ECX); NAME(MOV_EDX); NAME(MOV_EBX); NAME(MOV_ESP); NAME(MOV_EBP); NAME(MOV_ESI); NAME(MOV_EDI); + NAME(RETN_IMM16); NAME(RETN); NAME(LEAVE); NAME(RETF_IMM16); NAME(RETF); + NAME(INT); NAME(INT_IMM8); NAME(INTO); NAME(CALL); NAME(JMP); NAME(LJMP); NAME(SHORT_JMP); + NAME(EXTENDED); + } +#undef NAME + return "no registered"; +} + +#pragma pack(push, 1) + +struct trampoline_x86_t +{ + uint8_t trampolineBytes[16+relative_jump_size]; // trampoline + original function opcodes + uint8_t hookJump[relative_jump_size]; // jump to hook addr, needed because of relative jump overflow + uint8_t nOriginalBytes; // number of original function bytes bkp + uint8_t originalBytes[16]; // original function bytes +}; + +typedef trampoline_x86_t trampoline_t; + +struct trampoline_region_t +{ + uint32_t header; + uint8_t numTrampolines; // current trampolines allocated + trampoline_t *trampolines_start; // start pointer of current region trampolines + trampoline_t *next_free_trampoline; // next free trampoline in region +}; + +#pragma pack(pop) + +struct transaction_t +{ + bool detach; + void** ppOriginalFunc; + trampoline_t *trampoline; +}; + +static std::list trampoline_regions; + +static bool transaction_started = false; +static std::list cur_transaction; + +inline size_t page_size() +{ + static size_t _page_size = sysconf(_SC_PAGESIZE); + return _page_size; +} + +inline size_t region_size() +{ + return page_size(); +} + +static uint8_t max_trampolines_in_region = region_size() / sizeof(trampoline_t); + +inline void* library_address_by_handle(void *library) +{ + return (library == nullptr ? nullptr : *reinterpret_cast(library)); +} + +inline size_t page_align(size_t size, size_t page_size) +{ + return (size+(page_size-1)) & (((size_t)-1)^(page_size-1)); +} + +inline void* page_addr(void* addr, size_t page_size) +{ + return reinterpret_cast(reinterpret_cast(addr) & (((size_t)-1)^(page_size-1))); +} + +//////////////////////////////////////////////////// +/// Tiny disasm + +bool is_opcode_terminating_function(uint8_t* pCode) +{ + switch( *pCode ) + { + case LEAVE: + case RETN: case RETN_IMM16: + case RETF: case RETF_IMM16: + case INT: case INT_IMM8: case INTO: + return true; + } + return false; +} + +int find_space_for_trampoline(uint8_t* func, int bytes_needed) +{ + if( func == nullptr ) + return -1; + + int code_len = -1; + bool search = true; + uint8_t *startCode = reinterpret_cast(func); + uint8_t *pCode = startCode; + while( search ) // Find opcodes size and try to find at least 5 bytes for our JMP + { + if( is_opcode_terminating_function(pCode) ) + break; + + if( s_opcodes[*pCode].has_r_m ) + { // MOD-REG-R/M Byte + // 7 6 5 4 3 2 1 0 - bits + //[ MOD ][ REG ][ R/M ] + switch( pCode[1] & mod_mask ) // Check MOD to know how many bytes we have after this opcode + { + case register_addressing_mode : pCode += s_opcodes[*pCode].base_size ; break;// register addressing mode [opcode] [R/M] [XX] + case four_bytes_signed_displacement: pCode += s_opcodes[*pCode].base_size+5; break;// address mode byte + 4 bytes displacement + case one_byte_signed_displacement : pCode += s_opcodes[*pCode].base_size+2; break;// address mode byte + 1 byte displacement + case 0x00: + switch( pCode[1] & rm_mask ) + { + case sib_with_no_displacement : pCode += s_opcodes[*pCode].base_size+1; break;// SIB with no displacement + case displacement_only_addressing : pCode += s_opcodes[*pCode].base_size+4; break;// 4 bytes Displacement only addressing mode + case register_indirect_addressing_mode: pCode += s_opcodes[*pCode].base_size; // Register indirect addressing mode + } + } + } + else if( s_opcodes[*pCode].base_size ) + { + pCode += s_opcodes[*pCode].base_size; + } + else + { + switch( *pCode ) + { + case CALL: case JMP: case LJMP: case SHORT_JMP: + //std::cerr << "CALL and JMP are not supported for trampolines." << std::endl; + search = false; + break; + + case EXTENDED: + //std::cerr << "IMPORT_JUMP is not handled" << std::endl; + if (pCode[1] == 0x25) // This is an imported function + { // Get the true function call + //pCode = (uint8_t*)*(pCode+2); + //startCode = pCode; + // For now disable this case + search = false; + } + else + { + search = false; + } + break; + + default: + //std::cerr << "opcode " << std::hex << (uint32_t)*pCode << " no registered" << std::endl; + search = false; + } + } + + if( (pCode - startCode) >= bytes_needed && search ) + { + search = false; + code_len = pCode-startCode; + } + } + return code_len; +} + +/////////////////////////////////////////// +// Tiny asm + +inline uint8_t* gen_immediate_addr(uint8_t* opcode_addr, uint8_t* dest) +{ + *reinterpret_cast(opcode_addr) = (dest - (opcode_addr + relative_addr_jump_size)); + return opcode_addr + relative_addr_jump_size; +} + +inline uint8_t* gen_immediate_jump(uint8_t* opcode_addr, uint8_t* dest) +{ + *opcode_addr++ = JMP; + return gen_immediate_addr(opcode_addr, dest); +} + +inline uint8_t* gen_immediate_call(uint8_t* opcode_addr, uint8_t* dest) +{ + *opcode_addr++ = CALL; + return gen_immediate_addr(opcode_addr, dest); +} + +uint8_t* relative_addr_to_absolute(int32_t rel_addr, uint8_t *code_addr) +{ + return code_addr + rel_addr + relative_jump_size; +} + +void alloc_new_trampoline_region() +{ + trampoline_region_t region; + + region.numTrampolines = 0; + // allocate new trampoline right in the middle of memory so relative jump can access any function + region.trampolines_start = reinterpret_cast(mmap((void*)std::numeric_limits::max(), // allocate the page near the half of memory addressing + region_size(), // size + PROT_EXEC|PROT_WRITE|PROT_READ, // protection + MAP_PRIVATE|MAP_32BIT|MAP_ANONYMOUS, // don't map a file but memory + -1, // fd = -1 + 0) // offset + ); + // Fill the region with 0 + std::fill(reinterpret_cast(region.trampolines_start), reinterpret_cast(region.trampolines_start)+region_size(), 0); + region.next_free_trampoline = region.trampolines_start; + // Protect trampoline region memory + mprotect((void*)region.trampolines_start, region_size(), PROT_READ|PROT_EXEC); + + trampoline_regions.push_back(region); +} + +trampoline_t* get_free_trampoline() +{ + if (!transaction_started) + return nullptr; + + trampoline_t *res = nullptr; + auto it = std::find_if(trampoline_regions.begin(), trampoline_regions.end(), [&res](trampoline_region_t ®ion){ + if( region.numTrampolines == max_trampolines_in_region ) + return false; + return true; + }); + + if( it == trampoline_regions.end() ) + { + alloc_new_trampoline_region(); + it = --trampoline_regions.end(); + } + res = it->next_free_trampoline; + + trampoline_t *next_new_trampoline = res+1; + if( it->numTrampolines != max_trampolines_in_region ) + { + while( next_new_trampoline->nOriginalBytes != 0 ) + { + ++next_new_trampoline; + } + } + else + { + next_new_trampoline = nullptr; + } + it->next_free_trampoline = next_new_trampoline; + + ++it->numTrampolines; + + return res; +} + +void clear_trampoline(trampoline_region_t& region, trampoline_t *trampoline) +{ + --region.numTrampolines; + + std::fill(reinterpret_cast(trampoline), reinterpret_cast(trampoline+1), 0); + if( region.next_free_trampoline == nullptr || region.next_free_trampoline > trampoline ) + region.next_free_trampoline = trampoline; +} + +inline bool is_page_inside_region(void *page, trampoline_region_t& region) +{ + if( page >= region.trampolines_start && page <= (region.trampolines_start+region_size()) ) + return true; + return false; +} + +//------------------------------------------------------------------------------// + +/* +#include +#include + +static pid_t tid = 0; + +struct dism_pthread_t +{ + uint32_t d0; + uint32_t d4; + uint32_t d8; + uint32_t dc; + uint32_t d10; + uint32_t d14; + uint32_t d18; + uint32_t d1c; + uint32_t d20; + uint32_t d24; + uint32_t d28; + uint32_t d2c; + uint32_t d30; + uint32_t d34; + uint32_t d38; + uint32_t d3c; + uint32_t d40; + uint32_t d44; + uint32_t d48; + uint32_t d4c; + uint32_t d50; + uint32_t d54; + uint32_t d58; + uint32_t d5c; + uint32_t d60; + uint32_t d64; + pid_t task_id; +}; +*/ + +int Linux_Detour::update_thread(pthread_t thread_id) +{ + //dism_pthread_t *dt = (dism_pthread_t*)thread_id; + + // dt->task_id == syscall(SYS_gettid); + + + return 0; +} + +int Linux_Detour::transaction_begin() +{ + if( transaction_started ) + return -1; + + transaction_started = true; + + return 0; +} + +int Linux_Detour::transaction_abort() +{ + if(!transaction_started) + return -1; + + for( auto &i : cur_transaction ) + { + trampoline_t *trampoline = i.trampoline; + void *page_start = page_addr(reinterpret_cast(trampoline), page_size()); + auto it = std::find_if(trampoline_regions.begin(), trampoline_regions.end(), [page_start](trampoline_region_t ®ion){ + if( is_page_inside_region(page_start, region) ) + return true; + return false; + }); + if( it != trampoline_regions.end() ) + { + clear_trampoline(*it, trampoline); + } + } + cur_transaction.clear(); + transaction_started = false; + + return 0; +} + +int Linux_Detour::transaction_commit() +{ + if (!transaction_started ) + return -1; + + for( auto &i : cur_transaction) + { + trampoline_t *trampoline = i.trampoline; + void **ppOriginalFunc = i.ppOriginalFunc; + + int res; + + if( i.detach ) + { + void* trampoline_page = page_addr(reinterpret_cast(trampoline), page_size()); + + *ppOriginalFunc = (void*)(relative_addr_to_absolute(*reinterpret_cast(trampoline->trampolineBytes+trampoline->nOriginalBytes+1), + trampoline->trampolineBytes)); + + void* originalFunctionPage = page_addr(*ppOriginalFunc, page_size()); + + // Allow write on the original func + res = mprotect(originalFunctionPage, page_size()*2, PROT_READ|PROT_WRITE|PROT_EXEC); + + // Write the original opcodes + std::copy(trampoline->originalBytes, trampoline->originalBytes+trampoline->nOriginalBytes, + reinterpret_cast(*ppOriginalFunc)); + + // Remove write permission + res = mprotect(originalFunctionPage, page_size()*2, PROT_READ|PROT_EXEC); + + // Allow write on trampoline page + res = mprotect(trampoline_page, page_size()*2, PROT_READ|PROT_WRITE|PROT_EXEC); + + clear_trampoline(*reinterpret_cast(trampoline_page), trampoline); + + // Remove write permission + res = mprotect(trampoline_page, page_size()*2, PROT_READ|PROT_EXEC); + } + else + { + void* originalFunctionPage = page_addr(*ppOriginalFunc, page_size()); + + // Allow write on the original func + res = mprotect(originalFunctionPage, page_size()*2, PROT_READ|PROT_WRITE|PROT_EXEC); + + // Write the jump to trampoline + gen_immediate_jump(reinterpret_cast(*ppOriginalFunc), trampoline->hookJump); + + // Remove write permission + res = mprotect(originalFunctionPage, page_size()*2, PROT_READ|PROT_EXEC); + + *ppOriginalFunc = (void*)(trampoline->trampolineBytes); + } + } + cur_transaction.clear(); + transaction_started = false; + + return 0; +} + +int Linux_Detour::unhook_func(void** ppOriginalFunc, void* _hook) +{ + if( !transaction_started ) + return -EPERM; + + if( ppOriginalFunc == nullptr || _hook == nullptr || *ppOriginalFunc == nullptr ) + return -EINVAL; + + trampoline_t *trampoline = reinterpret_cast(*ppOriginalFunc); + void *page_start = page_addr(reinterpret_cast(trampoline), page_size()); + auto it = std::find_if(trampoline_regions.begin(), trampoline_regions.end(), [page_start](trampoline_region_t ®ion){ + if( is_page_inside_region(page_start, region) ) + return true; + return false; + }); + if( it != trampoline_regions.end() ) + { + cur_transaction.push_back({true, ppOriginalFunc, trampoline}); + } + + return -EINVAL; +} + +int Linux_Detour::hook_func(void** ppOriginalFunc, void* _hook) +{ + if( !transaction_started ) + return -EPERM; + + if( ppOriginalFunc == nullptr || _hook == nullptr || *ppOriginalFunc == nullptr ) + return -EINVAL; + + uint8_t* hook = reinterpret_cast(_hook); + uint8_t* pOriginalFunc = reinterpret_cast(*ppOriginalFunc); + int code_len = find_space_for_trampoline(pOriginalFunc, relative_jump_size); + + if( code_len < relative_jump_size ) + return -ENOSPC; + + // Allocate the trampoline, try to put it right in the middle of the mem, so a relative jump can access any function in the app (+/-2GB) + // + // Our hook is a 5 bytes JMP (1 bytes for opcode, 4 for RELATIVE jump) + // /!\ TODO: Add checks on JMP overflow + + trampoline_t *trampoline = get_free_trampoline(); + uint8_t *pTrampolineCode = trampoline->trampolineBytes; + + void* trampoline_page = page_addr(reinterpret_cast(trampoline), page_size()); + + // Enable write to the trampoline region + mprotect(trampoline_page, page_size()*2, PROT_READ|PROT_WRITE|PROT_EXEC); + // Create relative jmp to hook + gen_immediate_jump(trampoline->hookJump, hook); + // Copy original opcodes + trampoline->nOriginalBytes = code_len; + std::copy((uint8_t*)pOriginalFunc, ((uint8_t*)pOriginalFunc)+code_len, trampoline->originalBytes); + std::copy((uint8_t*)pOriginalFunc, ((uint8_t*)pOriginalFunc)+code_len, pTrampolineCode); + pTrampolineCode += code_len; + // Create the relative jmp to original (function + backed up opcodes) + pTrampolineCode = gen_immediate_jump(pTrampolineCode, pOriginalFunc+code_len); + pTrampolineCode += relative_addr_jump_size; + + // Disable trampoline region write + mprotect(trampoline_page, page_size()*2, PROT_READ|PROT_EXEC); + + cur_transaction.push_back({false, ppOriginalFunc, trampoline}); + + return 0; +} + +/* ------ DOCUMENTATION ------ +http://www.c-jump.com/CIS77/CPU/x86/lecture.html <- some help to understand [MOD][REG][R/M] (see paragraph #6) +http://shell-storm.org/online/Online-Assembler-and-Disassembler <- online assembler +http://ref.x86asm.net/coder32.html <- opcodes reference + +X86 + +push ebx : 0x53 +sub esp ?? : 0x83 0xEC 0x?? +call ????????: 0xE8 0x?? 0x?? 0x?? 0x?? + + +// relative jmp: ???????? = dst_addr - curr_addr - 5 +jmp ???????? : 0xe9 0x?? 0x?? 0x?? 0x?? +destination = 0x8dba8 +jmp location: 0x91995 - opcodes: e9 0e c2 ff ff +0e c2 ff ff = 0x8dba8 - 0x91995 - 5 + +// short jmp: ?? = dst_addr - curr_addr - 2 +jmp short ??: 0xeb 0x?? +destination = 0x91964 +jmp location: 0x9198f - opcodes: 0xeb 0xd3 +d3 = 0x91964 - 0x9198f - 2 + +X64 + +TODO: + Hint: make relative jump to near (+/-2Gb) code : 5 bytes + load absolute addr into R11 and call a jmp on register R11 : 13 bytes + Or + Reuse x86 relative jmp method + +Example: +mov r11, 0x0123456789abcdef -> 0x49 0xbb 0xef 0xcd 0xab 0x89 0x67 0x45 0x23 0x01 +jmp r11 -> 0x41 0xff 0xe3 + + +*/ diff --git a/overlay_experimental/linux/Linux_Detour.h b/overlay_experimental/linux/Linux_Detour.h new file mode 100644 index 0000000..731d426 --- /dev/null +++ b/overlay_experimental/linux/Linux_Detour.h @@ -0,0 +1,32 @@ +#ifndef LINUX_DETOUR_H +#define LINUX_DETOUR_H + +#include +#include +#include +#include + +class Linux_Detour +{ + public: + static int update_thread(pthread_t thread_id); + static int transaction_begin(); + static int transaction_abort(); + static int transaction_commit(); + static int hook_func(void** ppOriginalFunc, void* _hook); + static int unhook_func(void** ppOriginalFunc, void* _hook); + + private: + static int hook_func_abs(void** ppOriginalFunc, void* _hook); + static int hook_func_rel(void** ppOriginalFunc, void* _hook); + + Linux_Detour() = delete; + Linux_Detour(Linux_Detour const&) = delete; + Linux_Detour(Linux_Detour &&) = delete; + Linux_Detour& operator=(Linux_Detour const&) = delete; + Linux_Detour& operator=(Linux_Detour &&) = delete; +}; + +extern "C" void *elf_hook(char const *library_filename, void const *library_address, char const *function_name, void const *substitution_address); + +#endif // LINUX_DETOUR_H diff --git a/overlay_experimental/linux/OpenGLX_Hook.cpp b/overlay_experimental/linux/OpenGLX_Hook.cpp new file mode 100644 index 0000000..bc6f114 --- /dev/null +++ b/overlay_experimental/linux/OpenGLX_Hook.cpp @@ -0,0 +1,152 @@ +#include "OpenGLX_Hook.h" +#include "X11_Hook.h" +#include "../Renderer_Detector.h" +#include "../dll/dll.h" + +#ifdef __LINUX__ +#ifndef NO_OVERLAY + +#include +#include + +#include "../steam_overlay.h" + +OpenGLX_Hook* OpenGLX_Hook::_inst = nullptr; + +bool OpenGLX_Hook::start_hook() +{ + bool res = true; + if (!hooked) + { + if (!X11_Hook::Inst()->start_hook()) + return false; + + GLenum err = glewInit(); + + if (err == GLEW_OK) + { + PRINT_DEBUG("Hooked OpenGLX\n"); + + hooked = true; + Renderer_Detector::Inst().renderer_found(this); + + UnhookAll(); + BeginHook(); + HookFuncs( + std::make_pair(&(void*&)_glXSwapBuffers, (void*)&OpenGLX_Hook::MyglXSwapBuffers) + ); + EndHook(); + + get_steam_client()->steam_overlay->HookReady(); + } + else + { + PRINT_DEBUG("Failed to hook OpenGLX\n"); + /* Problem: glewInit failed, something is seriously wrong. */ + PRINT_DEBUG("Error: %s\n", glewGetErrorString(err)); + res = false; + } + } + return true; +} + +void OpenGLX_Hook::resetRenderState() +{ + if (initialized) + { + ImGui_ImplOpenGL3_Shutdown(); + //X11_Hook::Inst()->resetRenderState(); + ImGui::DestroyContext(); + + initialized = false; + } +} + +// Try to make this function and overlay's proc as short as possible or it might affect game's fps. +void OpenGLX_Hook::prepareForOverlay(Display* display) +{ + PRINT_DEBUG("Called SwapBuffer hook"); + + if( ! initialized ) + { + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = NULL; + + ImGui_ImplOpenGL3_Init(); + initialized = true; + } + + if( initialized ) + { + ImGuiIO& io = ImGui::GetIO(); + + GLint m_viewport[4]; + glGetIntegerv( GL_VIEWPORT, m_viewport ); + int width = m_viewport[2]; + int height = m_viewport[3]; + + ImGui_ImplOpenGL3_NewFrame(); + X11_Hook::Inst()->prepareForOverlay(display); + + ImGui::NewFrame(); + + get_steam_client()->steam_overlay->OverlayProc(width, height); + + ImGui::EndFrame(); + + ImGui::Render(); + + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + } +} + +void OpenGLX_Hook::MyglXSwapBuffers(Display* display, GLXDrawable drawable) +{ + OpenGLX_Hook::Inst()->prepareForOverlay(display); + OpenGLX_Hook::Inst()->_glXSwapBuffers(display, drawable); +} + +OpenGLX_Hook::OpenGLX_Hook(): + initialized(false), + hooked(false), + _glXSwapBuffers(nullptr) +{ + //_library = dlopen(DLL_NAME); +} + +OpenGLX_Hook::~OpenGLX_Hook() +{ + PRINT_DEBUG("OpenGLX Hook removed\n"); + + if (initialized) + { + ImGui_ImplOpenGL3_Shutdown(); + ImGui::DestroyContext(); + } + + //dlclose(_library); + + _inst = nullptr; +} + +OpenGLX_Hook* OpenGLX_Hook::Inst() +{ + if (_inst == nullptr) + _inst = new OpenGLX_Hook; + + return _inst; +} + +const char* OpenGLX_Hook::get_lib_name() const +{ + return DLL_NAME; +} + +void OpenGLX_Hook::loadFunctions(decltype(glXSwapBuffers)* pfnglXSwapBuffers) +{ + _glXSwapBuffers = pfnglXSwapBuffers; +} + +#endif//NO_OVERLAY +#endif//__LINUX__ diff --git a/overlay_experimental/linux/OpenGLX_Hook.h b/overlay_experimental/linux/OpenGLX_Hook.h new file mode 100644 index 0000000..0a204c4 --- /dev/null +++ b/overlay_experimental/linux/OpenGLX_Hook.h @@ -0,0 +1,45 @@ +#ifndef __INCLUDED_OPENGLX_HOOK_H__ +#define __INCLUDED_OPENGLX_HOOK_H__ + +#include "../Base_Hook.h" + +#ifdef __LINUX__ +#ifndef NO_OVERLAY +#include +#include + +class OpenGLX_Hook : public Base_Hook +{ +public: + static constexpr const char *DLL_NAME = "libGLX.so"; + +private: + static OpenGLX_Hook* _inst; + + // Variables + bool hooked; + bool initialized; + + // Functions + OpenGLX_Hook(); + + void resetRenderState(); + void prepareForOverlay(Display* display); + + // Hook to render functions + static void MyglXSwapBuffers(Display* display, GLXDrawable drawable); + + decltype(glXSwapBuffers)* _glXSwapBuffers; + +public: + virtual ~OpenGLX_Hook(); + + bool start_hook(); + static OpenGLX_Hook* Inst(); + virtual const char* get_lib_name() const; + void loadFunctions(decltype(glXSwapBuffers)* pfnglXSwapBuffers); +}; + +#endif//NO_OVERLAY +#endif//__LINUX__ +#endif//__INCLUDED_OPENGLX_HOOK_H__ diff --git a/overlay_experimental/linux/X11_Hook.cpp b/overlay_experimental/linux/X11_Hook.cpp new file mode 100644 index 0000000..dbb9a83 --- /dev/null +++ b/overlay_experimental/linux/X11_Hook.cpp @@ -0,0 +1,216 @@ +#include "X11_Hook.h" +#include "../Renderer_Detector.h" +#include "../dll/dll.h" + +#ifdef __LINUX__ +#ifndef NO_OVERLAY + +#include +#include + +#include +#include +#include + +extern int ImGui_ImplX11_EventHandler(XEvent &event); + +X11_Hook* X11_Hook::_inst = nullptr; + +bool X11_Hook::start_hook() +{ + bool res = true; + if (!hooked) + { + res = false; + std::ifstream flibrary("/proc/self/maps"); + std::string line; + while( std::getline(flibrary, line) ) + { + if( strcasestr(line.c_str(), DLL_NAME) != nullptr ) + { + _library = dlopen(line.substr(line.find('/')).c_str(), RTLD_NOW); + + if( _library != nullptr ) + { + // Hook only this + _XEventsQueued = (decltype(_XEventsQueued))dlsym(_library, "XEventsQueued"); + // Thoses are needed to ignore some events when overlay is on + _XPeekEvent = (decltype(_XPeekEvent))dlsym(_library, "XPeekEvent"); + _XNextEvent = (decltype(_XNextEvent))dlsym(_library, "XNextEvent"); + _XKeysymToKeycode = (decltype(_XKeysymToKeycode))dlsym(_library, "XKeysymToKeycode"); + _XLookupKeysym = (decltype(_XLookupKeysym))dlsym(_library, "XLookupKeysym"); + + if( _XEventsQueued != nullptr && _XPeekEvent != nullptr + && _XNextEvent != nullptr && _XKeysymToKeycode != nullptr + && _XLookupKeysym != nullptr ) + { + PRINT_DEBUG("Hooked X11\n"); + hooked = true; + + BeginHook(); + HookFuncs( + std::make_pair(&(void*&)_XEventsQueued, (void*)&X11_Hook::MyXEventsQueued) + ); + + EndHook(); + break; + } + dlclose(_library); + } + } + } + } + return res; +} + +void X11_Hook::resetRenderState() +{ + if (initialized) + { + initialized = false; + ImGui_ImplX11_Shutdown(); + } +} + +void X11_Hook::prepareForOverlay(Display *display) +{ + if (!initialized) + { + ImGui_ImplX11_Init(display); + + ImGuiIO &io = ImGui::GetIO(); + io.KeyMap[ImGuiKey_Tab] = _XKeysymToKeycode(display, XK_Tab); + io.KeyMap[ImGuiKey_LeftArrow] = _XKeysymToKeycode(display, XK_Left); + io.KeyMap[ImGuiKey_RightArrow] = _XKeysymToKeycode(display, XK_Right); + io.KeyMap[ImGuiKey_UpArrow] = _XKeysymToKeycode(display, XK_Up); + io.KeyMap[ImGuiKey_DownArrow] = _XKeysymToKeycode(display, XK_Down); + io.KeyMap[ImGuiKey_PageUp] = _XKeysymToKeycode(display, XK_Prior); + io.KeyMap[ImGuiKey_PageDown] = _XKeysymToKeycode(display, XK_Next); + io.KeyMap[ImGuiKey_Home] = _XKeysymToKeycode(display, XK_Home); + io.KeyMap[ImGuiKey_End] = _XKeysymToKeycode(display, XK_End); + io.KeyMap[ImGuiKey_Insert] = _XKeysymToKeycode(display, XK_Insert); + io.KeyMap[ImGuiKey_Delete] = _XKeysymToKeycode(display, XK_Delete); + io.KeyMap[ImGuiKey_Backspace] = _XKeysymToKeycode(display, XK_BackSpace); + io.KeyMap[ImGuiKey_Space] = _XKeysymToKeycode(display, XK_space); + io.KeyMap[ImGuiKey_Enter] = _XKeysymToKeycode(display, XK_Return); + io.KeyMap[ImGuiKey_Escape] = _XKeysymToKeycode(display, XK_Escape); + io.KeyMap[ImGuiKey_A] = _XKeysymToKeycode(display, XK_A); + io.KeyMap[ImGuiKey_C] = _XKeysymToKeycode(display, XK_C); + io.KeyMap[ImGuiKey_V] = _XKeysymToKeycode(display, XK_V); + io.KeyMap[ImGuiKey_X] = _XKeysymToKeycode(display, XK_X); + io.KeyMap[ImGuiKey_Y] = _XKeysymToKeycode(display, XK_Y); + io.KeyMap[ImGuiKey_Z] = _XKeysymToKeycode(display, XK_Z); + + initialized = true; + } + + ImGui_ImplX11_NewFrame(); +} + +///////////////////////////////////////////////////////////////////////////////////// +// X11 window hooks +bool IgnoreEvent(XEvent &event) +{ + switch(event.type) + { + // Keyboard + case KeyPress: case KeyRelease: + // MouseButton + case ButtonPress: case ButtonRelease: + // Mouse move + case MotionNotify: + return true; + } + return false; +} + +int X11_Hook::MyXEventsQueued(Display *display, int mode) +{ + static Time prev_time = {}; + X11_Hook* inst = X11_Hook::Inst(); + XEvent event = {}; + + int res = inst->_XEventsQueued(display, mode); + + if( res > 0 ) + { + /// The XPeekEvent function returns the first event from the event queue, + /// but it does not remove the event from the queue. If the queue is + /// empty, XPeekEvent flushes the output buffer and blocks until an event + /// is received. + inst->_XPeekEvent(display, &event); + Steam_Overlay* overlay = get_steam_client()->steam_overlay; + bool show = overlay->ShowOverlay(); + // Is the event is a key press + if (event.type == KeyPress) + { + // Tab is pressed and was not pressed before + if (event.xkey.keycode == inst->_XKeysymToKeycode(display, XK_Tab) && event.xkey.state & ShiftMask) + { + // if key TAB is help, don't make the overlay flicker :p + if( event.xkey.time != prev_time) + { + overlay->ShowOverlay(!overlay->ShowOverlay()); + + if (overlay->ShowOverlay()) + show = true; + } + } + } + else if(event.type == KeyRelease && event.xkey.keycode == inst->_XKeysymToKeycode(display, XK_Tab)) + { + prev_time = event.xkey.time; + } + + if (show) + { + ImGui_ImplX11_EventHandler(event); + + if (IgnoreEvent(event)) + { + inst->_XNextEvent(display, &event); + res = 0; + } + } + } + // XEventsQueued returns the num of events available. + // Usually, games tend to read all events queued before calling again XEventsQueued + // making us unavailable to intercept undesired events + return res; +} + +///////////////////////////////////////////////////////////////////////////////////// + +X11_Hook::X11_Hook() : + initialized(false), + hooked(false) +{ + //_library = dlopen(DLL_NAME, RTLD_NOW); +} + +X11_Hook::~X11_Hook() +{ + PRINT_DEBUG("X11 Hook removed\n"); + + resetRenderState(); + + //dlclose(_library); + + _inst = nullptr; +} + +X11_Hook* X11_Hook::Inst() +{ + if (_inst == nullptr) + _inst = new X11_Hook; + + return _inst; +} + +const char* X11_Hook::get_lib_name() const +{ + return DLL_NAME; +} + +#endif//NO_OVERLAY +#endif//#__LINUX__ diff --git a/overlay_experimental/linux/X11_Hook.h b/overlay_experimental/linux/X11_Hook.h new file mode 100644 index 0000000..e4692de --- /dev/null +++ b/overlay_experimental/linux/X11_Hook.h @@ -0,0 +1,50 @@ +#ifndef __INCLUDED_X11_HOOK_H__ +#define __INCLUDED_X11_HOOK_H__ + +#include "../Base_Hook.h" + +#ifdef __LINUX__ +#ifndef NO_OVERLAY + +#include // XEvent types +#include // XEvent structure + +class X11_Hook : public Base_Hook +{ +public: + static constexpr const char* DLL_NAME = "libX11.so"; + +private: + static X11_Hook* _inst; + + // Variables + bool hooked; + bool initialized; + + // Functions + X11_Hook(); + + // Hook to X11 window messages + static int MyXEventsQueued(Display * display, int mode); + + decltype(XEventsQueued)* _XEventsQueued; + + decltype(XPeekEvent)* _XPeekEvent; + decltype(XNextEvent)* _XNextEvent; + decltype(XKeysymToKeycode)* _XKeysymToKeycode; + decltype(XLookupKeysym)* _XLookupKeysym; + +public: + virtual ~X11_Hook(); + + void resetRenderState(); + void prepareForOverlay(Display *display); + + bool start_hook(); + static X11_Hook* Inst(); + virtual const char* get_lib_name() const; +}; + +#endif//NO_OVERLAY +#endif//__LINUX__ +#endif//__INCLUDED_X11_HOOK_H__ diff --git a/overlay_experimental/windows/DX10_Hook.cpp b/overlay_experimental/windows/DX10_Hook.cpp index 3f0fd96..c01864f 100644 --- a/overlay_experimental/windows/DX10_Hook.cpp +++ b/overlay_experimental/windows/DX10_Hook.cpp @@ -1,12 +1,12 @@ #include "DX10_Hook.h" #include "Windows_Hook.h" -#include "Renderer_Detector.h" -#include "../dll/dll.h" +#include "../Renderer_Detector.h" +#include "../../dll/dll.h" #ifndef NO_OVERLAY #include -#include +#include DX10_Hook* DX10_Hook::_inst = nullptr; diff --git a/overlay_experimental/windows/DX10_Hook.h b/overlay_experimental/windows/DX10_Hook.h index 63921ff..ddfaffa 100644 --- a/overlay_experimental/windows/DX10_Hook.h +++ b/overlay_experimental/windows/DX10_Hook.h @@ -1,7 +1,7 @@ #ifndef __INCLUDED_DX10_HOOK_H__ #define __INCLUDED_DX10_HOOK_H__ -#include "Base_Hook.h" +#include "../Base_Hook.h" #ifndef NO_OVERLAY #include @@ -42,10 +42,10 @@ public: bool start_hook(); static DX10_Hook* Inst(); virtual const char* get_lib_name() const; - + void loadFunctions(IDXGISwapChain *pSwapChain); }; #endif//NO_OVERLAY -#endif//__INCLUDED_DX10_HOOK_H__ \ No newline at end of file +#endif//__INCLUDED_DX10_HOOK_H__ diff --git a/overlay_experimental/windows/DX11_Hook.cpp b/overlay_experimental/windows/DX11_Hook.cpp index 6ec6017..21ad917 100644 --- a/overlay_experimental/windows/DX11_Hook.cpp +++ b/overlay_experimental/windows/DX11_Hook.cpp @@ -1,12 +1,12 @@ #include "DX11_Hook.h" #include "Windows_Hook.h" -#include "Renderer_Detector.h" -#include "../dll/dll.h" +#include "../Renderer_Detector.h" +#include "../../dll/dll.h" #ifndef NO_OVERLAY #include -#include +#include DX11_Hook* DX11_Hook::_inst = nullptr; diff --git a/overlay_experimental/windows/DX11_Hook.h b/overlay_experimental/windows/DX11_Hook.h index bf2074d..f8025c9 100644 --- a/overlay_experimental/windows/DX11_Hook.h +++ b/overlay_experimental/windows/DX11_Hook.h @@ -1,7 +1,7 @@ #ifndef __INCLUDED_DX11_HOOK_H__ #define __INCLUDED_DX11_HOOK_H__ -#include "Base_Hook.h" +#include "../Base_Hook.h" #ifndef NO_OVERLAY #include @@ -19,7 +19,7 @@ private: bool hooked; bool initialized; ID3D11DeviceContext* pContext; - ID3D11RenderTargetView* mainRenderTargetView; + ID3D11RenderTargetView* mainRenderTargetView; // Functions DX11_Hook(); @@ -42,10 +42,10 @@ public: bool start_hook(); static DX11_Hook* Inst(); virtual const char* get_lib_name() const; - + void loadFunctions(IDXGISwapChain *pSwapChain); }; #endif//NO_OVERLAY -#endif//__INCLUDED_DX11_HOOK_H__ \ No newline at end of file +#endif//__INCLUDED_DX11_HOOK_H__ diff --git a/overlay_experimental/windows/DX12_Hook.cpp b/overlay_experimental/windows/DX12_Hook.cpp index 5c8981b..a3d52f6 100644 --- a/overlay_experimental/windows/DX12_Hook.cpp +++ b/overlay_experimental/windows/DX12_Hook.cpp @@ -1,12 +1,12 @@ #include "DX12_Hook.h" #include "Windows_Hook.h" -#include "Renderer_Detector.h" -#include "../dll/dll.h" +#include "../Renderer_Detector.h" +#include "../../dll/dll.h" #ifndef NO_OVERLAY #include -#include +#include #include diff --git a/overlay_experimental/windows/DX12_Hook.h b/overlay_experimental/windows/DX12_Hook.h index 5cfb7ee..d8e82f2 100644 --- a/overlay_experimental/windows/DX12_Hook.h +++ b/overlay_experimental/windows/DX12_Hook.h @@ -1,7 +1,7 @@ #ifndef __INCLUDED_DX12_HOOK_H__ #define __INCLUDED_DX12_HOOK_H__ -#include "Base_Hook.h" +#include "../Base_Hook.h" #ifndef NO_OVERLAY #include @@ -48,9 +48,9 @@ public: bool start_hook(); static DX12_Hook* Inst(); virtual const char* get_lib_name() const; - + void loadFunctions(ID3D12CommandQueue* pCommandQueue, ID3D12GraphicsCommandList* pCommandList, IDXGISwapChain* pSwapChain); }; #endif//NO_OVERLAY -#endif//__INCLUDED_DX12_HOOK_H__ \ No newline at end of file +#endif//__INCLUDED_DX12_HOOK_H__ diff --git a/overlay_experimental/windows/DX9_Hook.cpp b/overlay_experimental/windows/DX9_Hook.cpp index 0f1e14f..ef184d3 100644 --- a/overlay_experimental/windows/DX9_Hook.cpp +++ b/overlay_experimental/windows/DX9_Hook.cpp @@ -1,14 +1,12 @@ #include "DX9_Hook.h" #include "Windows_Hook.h" -#include "Renderer_Detector.h" -#include "../dll/dll.h" +#include "../Renderer_Detector.h" +#include "../../dll/dll.h" #ifndef NO_OVERLAY #include -#include - -#include "steam_overlay.h" +#include DX9_Hook* DX9_Hook::_inst = nullptr; diff --git a/overlay_experimental/windows/DX9_Hook.h b/overlay_experimental/windows/DX9_Hook.h index 974c8c8..3e42b99 100644 --- a/overlay_experimental/windows/DX9_Hook.h +++ b/overlay_experimental/windows/DX9_Hook.h @@ -1,7 +1,7 @@ #ifndef __INCLUDED_DX9_HOOK_H__ #define __INCLUDED_DX9_HOOK_H__ -#include "Base_Hook.h" +#include "../Base_Hook.h" #ifndef NO_OVERLAY #include @@ -43,10 +43,10 @@ public: bool start_hook(); static DX9_Hook* Inst(); virtual const char* get_lib_name() const; - + void loadFunctions(IDirect3DDevice9 *pDevice, bool ex); }; #endif//NO_OVERLAY -#endif//__INCLUDED_DX9_HOOK_H__ \ No newline at end of file +#endif//__INCLUDED_DX9_HOOK_H__ diff --git a/overlay_experimental/windows/OpenGL_Hook.cpp b/overlay_experimental/windows/OpenGL_Hook.cpp index 0e706d8..1e1026d 100644 --- a/overlay_experimental/windows/OpenGL_Hook.cpp +++ b/overlay_experimental/windows/OpenGL_Hook.cpp @@ -1,7 +1,7 @@ #include "OpenGL_Hook.h" #include "Windows_Hook.h" -#include "Renderer_Detector.h" -#include "../dll/dll.h" +#include "../Renderer_Detector.h" +#include "../../dll/dll.h" #ifndef NO_OVERLAY @@ -10,7 +10,7 @@ #include -#include "steam_overlay.h" +#include "../steam_overlay.h" OpenGL_Hook* OpenGL_Hook::_inst = nullptr; diff --git a/overlay_experimental/windows/OpenGL_Hook.h b/overlay_experimental/windows/OpenGL_Hook.h index b0d8a45..a2c9c7f 100644 --- a/overlay_experimental/windows/OpenGL_Hook.h +++ b/overlay_experimental/windows/OpenGL_Hook.h @@ -1,14 +1,14 @@ #ifndef __INCLUDED_OPENGL_HOOK_H__ #define __INCLUDED_OPENGL_HOOK_H__ -#include "Base_Hook.h" +#include "../Base_Hook.h" #ifndef NO_OVERLAY class OpenGL_Hook : public Base_Hook { public: static constexpr const char *DLL_NAME = "opengl32.dll"; - + using wglSwapBuffers_t = BOOL(WINAPI*)(HDC); private: @@ -39,4 +39,4 @@ public: }; #endif//NO_OVERLAY -#endif//__INCLUDED_OPENGL_HOOK_H__ \ No newline at end of file +#endif//__INCLUDED_OPENGL_HOOK_H__ diff --git a/overlay_experimental/windows/Windows_Hook.cpp b/overlay_experimental/windows/Windows_Hook.cpp index 4ccff4a..2d98f28 100644 --- a/overlay_experimental/windows/Windows_Hook.cpp +++ b/overlay_experimental/windows/Windows_Hook.cpp @@ -1,11 +1,11 @@ #include "Windows_Hook.h" -#include "Renderer_Detector.h" -#include "../dll/dll.h" +#include "../Renderer_Detector.h" +#include "../../dll/dll.h" #ifndef NO_OVERLAY #include -#include +#include extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);