hook opengl

OpenGL 是一个状态机,程序每一帧都会调用 glFlushglFinish 或 Windows 特有的 wglSwapBuffers 来结束当前帧的绘制。 我们要做的就是:

  1. 定位目标程序调用的 wglSwapBuffers 地址。
  2. 劫持(Hook)这个地址,指向我们自己的函数。
  3. 在我们的函数里,先用 OpenGL 画一个方框,然后再调用原有的函数完成显示。

dll

dllamin.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <windows.h>
#include <GL/gl.h>
#include <wrl/client.h>
#include "imgui.h"
#include "imgui_impl_win32.h"
#include "imgui_impl_opengl3.h"
#include <MinHook.h>

// 原始函数定义
typedef BOOL(WINAPI* twglSwapBuffers)(HDC hdc);
twglSwapBuffers oSwapBuffers = nullptr;

bool g_Initialized = false;

// 绘制逻辑:画一个方框
void DrawOverlay() {
ImGui::NewFrame();

// 获取后台绘制列表,这样方框就不会被 ImGui 窗口挡住
ImDrawList* drawList = ImGui::GetBackgroundDrawList();

// 定义方框:左上角 (100, 100),右下角 (300, 300),颜色红色 (ABGR)
ImVec2 p1 = ImVec2(100, 100);
ImVec2 p2 = ImVec2(300, 300);
ImU32 color = IM_COL32(255, 0, 0, 255); // 纯红

// 绘制空心方框,线条粗细为 2.0
drawList->AddRect(p1, p2, color, 0.0f, 0, 2.0f);

// 如果你想画实心方框:
// drawList->AddRectFilled(p1, p2, IM_COL32(255, 0, 0, 100));

ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}

BOOL WINAPI hSwapBuffers(HDC hdc) {
if (!g_Initialized) {
HWND hWnd = WindowFromDC(hdc);
ImGui::CreateContext();
ImGui_ImplWin32_Init(hWnd);
ImGui_ImplOpenGL3_Init();
g_Initialized = true;
}

ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplWin32_NewFrame();

DrawOverlay();

return oSwapBuffers(hdc);
}

DWORD WINAPI MainThread(LPVOID lpReserved) {
// MinHook 通过 vcpkg 安装后,直接使用 MH_ 系列函数
if (MH_Initialize() == MH_OK) {
void* pTarget = (void*)GetProcAddress(GetModuleHandleA("opengl32.dll"), "wglSwapBuffers");
MH_CreateHook(pTarget, &hSwapBuffers, reinterpret_cast<LPVOID*>(&oSwapBuffers));
MH_EnableHook(pTarget);
}
return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
if (reason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hModule);
CloseHandle(CreateThread(nullptr, 0, MainThread, hModule, 0, nullptr));
}
return TRUE;
}

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# 【核心】禁用 vcpkg 所有的自动集成行为
set(VCPKG_MANIFEST_MODE OFF CACHE BOOL "Disable vcpkg manifest" FORCE)
set(X_VCPKG_APPLOCAL_DEPS_INSTALL OFF CACHE BOOL "Disable applocal copy" FORCE)

project(GLBoxHook LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)

# 1. 统一输出目录到 bin
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# 2. ImGui 路径 (保持不变)
set(IMGUI_DIR "C:/D/test/CCpp/ccpplib/imgui")
include_directories(${IMGUI_DIR} ${IMGUI_DIR}/backends)

set(IMGUI_SOURCES
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_widgets.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/imgui_demo.cpp
${IMGUI_DIR}/backends/imgui_impl_win32.cpp
${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp
)

# 3. 手动链接 vcpkg 下的 MinHook (硬路径)
set(VCPKG_BASE "C:/D/test/CCpp/ccpplib/vcpkg/vcpkg/installed/x64-windows-static")
include_directories("${VCPKG_BASE}/include")
link_directories("${VCPKG_BASE}/lib")

# 4. 生成 DLL
add_library(${PROJECT_NAME} SHARED dllmain.cpp ${IMGUI_SOURCES})

# 5. 链接系统库和 minhook
# 注意:如果链接报错,请检查 lib 目录下是否叫 minhook.lib 还是 libMinHook.x64.lib
target_link_libraries(${PROJECT_NAME} PRIVATE
minhook.x64.lib
opengl32
gdi32
dwmapi
)

add_definitions(-DUNICODE -D_UNICODE -D_CRT_SECURE_NO_WARNINGS)
if(MSVC)
add_compile_options("/utf-8")
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)