Hook raylib关键函数

DLL 劫持(Hook) EndDrawing 函数。

劫持窗口过程 (Hook WndProc)

不依赖 Raylib 的输入函数。直接拦截 Windows 的原始消息,这不依赖任何库的状态。

raylib主程序

主程序必须是动态链接raylib.dll,静态链接的话需要在主程序的内存里通过 特征码扫描 (Pattern Scan) 找到这些静态函数的地址。

main.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
#define RAYGUI_IMPLEMENTATION
#include "raylib.h"

#ifndef _DEBUG
#pragma comment(lib, "raylib.lib")
#pragma comment(lib, "winmm.lib")
// #pragma comment(lib, "opengl32.lib")
// #pragma comment(lib, "gdi32.lib")
// #pragma comment(lib, "shell32.lib")
// #pragma comment(lib, "user32.lib")
#endif // DEBIG

int main() {
// 纯净的 Raylib 程序,不包含任何插件加载代码
InitWindow(800, 600, "Target Process (To be Injected)");
SetTargetFPS(60);

while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(DARKBLUE); // 换个颜色,方便区分
DrawText("I am a standalone program.", 190, 200, 20, RAYWHITE);
DrawText("I have no searchbox code in my source.", 190, 230, 20, LIGHTGRAY);
EndDrawing();
}

CloseWindow();
return 0;
}

dll

dllmain.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

#include <windows.h>
extern DWORD WINAPI InjectThread(LPVOID lpParam);

// --- DLL 入口 ---
bool active = false; // 真正的定义
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
CreateThread(nullptr, 0, InjectThread, hModule, 0, nullptr);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

searchbox_dll.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

#define RAYGUI_IMPLEMENTATION
#include "raylib.h"
#include "IPlugin.h"
#include <vector>
#ifndef _DEBUG
#pragma comment(lib, "raylib.lib")
#pragma comment(lib, "winmm.lib")
#endif // DEBIG




// --- 接口实现函数 ---

void SearchOnInit() {
// 可以在这里初始化资源,比如加载搜索框专用的字体或音效
TraceLog(LOG_INFO, "[SearchBox DLL] Plugin Initialized.");
}
// 声明中转站的函数
// 1. 声明 Bridge 函数
extern void* GetRaylibFunction(const char* funcName);
extern void LogToDebugger(const char* msg);
// 2. 定义所需的远程函数指针类型
typedef void (*DrawRectangleRecPtr)(Rectangle, Color);
typedef void (*DrawRectangleLinesExPtr)(Rectangle, float, Color);
typedef void (*DrawTextPtr)(const char*, int, int, int, Color);
typedef int (*GetScreenWidthPtr)();
typedef int (*GetCharPressedPtr)();
typedef bool (*IsKeyPressedPtr)(int);
typedef int (*GetScreenWidthPtr)();

// 3. 缓冲区和状态
static char inputBuffer[65] = "\0";
static int letterCount = 0;
static char searchStatus[128] = "Ready"; // 用于显示回车后的消息
static int statusTimer = 0; // 消息显示计时器
static int framesCounter = 0; // 用于光标闪烁
extern bool active; // 由 dllmain.cpp 中的 WndProc 控制

// 在 searchbox_dll.cpp 中
void SearchOnTick() {
if (!active) return;

// 绑定函数(静态局部变量保证只找一次,性能最高)
static DrawRectangleRecPtr RemoteDrawRectangleRec = (DrawRectangleRecPtr)GetRaylibFunction("DrawRectangleRec");
static DrawTextPtr RemoteDrawText = (DrawTextPtr)GetRaylibFunction("DrawText");
static GetCharPressedPtr RemoteGetCharPressed = (GetCharPressedPtr)GetRaylibFunction("GetCharPressed");
static IsKeyPressedPtr RemoteIsKeyPressed = (IsKeyPressedPtr)GetRaylibFunction("IsKeyPressed");
static GetScreenWidthPtr RemoteGetScreenWidth = (GetScreenWidthPtr)GetRaylibFunction("GetScreenWidth");

if (!RemoteDrawRectangleRec || !RemoteDrawText) return;

// --- 输入处理 ---
int key = RemoteGetCharPressed();
while (key > 0) {
if ((key >= 32) && (key <= 125) && (letterCount < 64)) {
inputBuffer[letterCount] = (char)key;
inputBuffer[letterCount + 1] = '\0';
letterCount++;
}
key = RemoteGetCharPressed();
}

if (RemoteIsKeyPressed(KEY_BACKSPACE)) {
if (letterCount > 0) {
letterCount--;
inputBuffer[letterCount] = '\0';
}
}

// --- [核心功能] 回车键监听 ---
if (RemoteIsKeyPressed(KEY_ENTER)) {
if (letterCount > 0) {
// 1. 可以在这里执行实际功能
// 比如拼接成:Searching: [content]
strcpy(searchStatus, "Searching: ");
strcat(searchStatus, inputBuffer);
LogToDebugger("Search triggered!");
LogToDebugger(inputBuffer);
// 2. 计时器,用于在界面上显示 120 帧这个消息
statusTimer = 120;

// 3. (可选) 清空输入框并关闭搜索
letterCount = 0;
inputBuffer[0] = '\0';
active = false;
}
}

// --- UI 绘制 ---
int screenW = RemoteGetScreenWidth ? RemoteGetScreenWidth() : 800;
Rectangle box = { (float)screenW / 2.0f - 250, 40, 500, 50 };

// 绘制背景
RemoteDrawRectangleRec(box, { 0, 0, 0, 220 }); // 半透明黑

// 绘制文字内容
if (letterCount == 0) {
RemoteDrawText("Type to search...", (int)box.x + 15, (int)box.y + 15, 20, DARKGRAY);
}
else {
RemoteDrawText(inputBuffer, (int)box.x + 15, (int)box.y + 15, 20, RAYWHITE);
}

// --- 绘制回车后的反馈消息 ---
if (statusTimer > 0) {
// 在搜索框下方显示提示消息
RemoteDrawText(searchStatus, (int)box.x, (int)box.y + 60, 18, LIME);
statusTimer--;
}
}

void SearchOnUnload() {
// 清理资源
TraceLog(LOG_INFO, "[SearchBox DLL] Plugin Unloaded.");
}

// --- 唯一的导出函数:将上述函数打包交给宿主 ---

extern "C" __declspec(dllexport) PluginInterface* GetPluginAPI() {
static PluginInterface api = {
{"Global Search", "1.0"},
SearchOnInit,
SearchOnTick,
SearchOnUnload
};
return &api;
}

IPlugin.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef IPLUGIN_H
#define IPLUGIN_H


// 插件元数据
struct PluginInfo {
const char* name;
const char* version;
};
typedef struct {
PluginInfo info;
void (*OnInit)();
void (*OnTick)();
void (*OnUnload)();
} PluginInterface;

typedef PluginInterface* (*GetPluginAPI_Func)();

#endif

corehook.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <MinHook.h>

// --- 外部引用 (通过 extern 绕过头文件冲突) ---
extern bool active;
extern void SearchOnTick();

// --- WndProc 相关 ---
typedef LRESULT(CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
WNDPROC oWndProc = NULL;

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (oWndProc == NULL) return DefWindowProc(hWnd, msg, wParam, lParam);

if (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) {
if (wParam == VK_F2) {
active = !active;
// 切换时清空缓冲区(可选)
return 0;
}
}

if (active) {
// 当搜索框激活时:
// 1. 我们不拦截所有消息,而是让消息继续传递给 Raylib 内部的队列
// 2. 但我们要返回 0 阻止目标程序(EXE)处理这些按键

// 处理按键消息
if (msg == WM_KEYDOWN || msg == WM_CHAR) {
// 先手动传给原程序的消息队列更新状态(供Raylib读),但返回0拦截掉EXE的响应
CallWindowProc(oWndProc, hWnd, msg, wParam, lParam);
return 0;
}
return 0;
}

return CallWindowProc(oWndProc, hWnd, msg, wParam, lParam);
}

// --- Hook 渲染逻辑 ---
typedef void (*EndDrawingPtr)();
EndDrawingPtr pOriginalEndDrawing = nullptr;

void DetourEndDrawing() {
SearchOnTick(); // 这里的逻辑在另一个文件实现,那里包含 Raylib
pOriginalEndDrawing();
}

// --- 初始化线程 ---
DWORD WINAPI InjectThread(LPVOID lpParam) {
// 1. 先初始化渲染 Hook
if (MH_Initialize() == MH_OK) {
HMODULE hRaylib = GetModuleHandleA("raylib.dll");
if (hRaylib) {
void* targetAddr = (void*)GetProcAddress(hRaylib, "EndDrawing");
if (targetAddr) {
MH_CreateHook(targetAddr, (LPVOID)&DetourEndDrawing, (LPVOID*)&pOriginalEndDrawing);
MH_EnableHook(targetAddr);
}
}
}

// 2. 寻找并 Hook 窗口过程 (WndProc)
Sleep(1000); // 等待窗口完全加载
DWORD pid = GetCurrentProcessId();
HWND targetHWnd = NULL;
HWND hWnd = GetTopWindow(NULL);

while (hWnd) {
DWORD windowPid;
GetWindowThreadProcessId(hWnd, &windowPid);
// 确保是当前进程的可见主窗口
if (windowPid == pid && IsWindowVisible(hWnd) && GetWindow(hWnd, GW_OWNER) == NULL) {
targetHWnd = hWnd;
break;
}
hWnd = GetNextWindow(hWnd, GW_HWNDNEXT);
}

if (targetHWnd) {
// [关键] 只有在这里拿到了 targetHWnd,才能进行 SetWindowLongPtr
LONG_PTR prevProc = SetWindowLongPtr(targetHWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
if (prevProc != 0) {
oWndProc = (WNDPROC)prevProc;
}
}

return 0;
}

bridge.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>

// 获取 raylib.dll 中导出函数的地址,返回 void* 以避免类型污染
void* GetRaylibFunction(const char* funcName) {
HMODULE hRay = GetModuleHandleA("raylib.dll");
if (hRay) {
return (void*)GetProcAddress(hRay, funcName);
}
return nullptr;
}

void LogToDebugger(const char* msg) {
std::cout << msg << std::endl;
}