Hook raylib关键函数 DLL 劫持 (Hook) EndDrawing 函数。
强行注入思路 如果你想这个搜索框注入到别人的 raylib 程序里:
需要用到 CreateRemoteThread。
需要找到主程序调用 EndDrawing 的内存地址。
需要把那个地址的指令跳转(JMP)到你的 DLL 函数地址。
raylib主程序 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" ) #endif int main () { 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 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 #define RAYGUI_IMPLEMENTATION #include <raylib.h> #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #define VC_EXTRALEAN #define NOGDI #define NOUSER #define WIN32_LEAN_AND_MEAN #undef ShowCursor #undef CloseWindow #undef Rectangle #include <windows.h> #include <MinHook.h> #ifndef _DEBUG #pragma comment(lib, "raylib.lib" ) #pragma comment(lib, "winmm.lib" ) #endif extern void SearchOnTick () ;typedef void (*EndDrawingPtr) () ;EndDrawingPtr pOriginalEndDrawing = nullptr ; void DetourEndDrawing () { SearchOnTick (); pOriginalEndDrawing (); } DWORD WINAPI InjectThread (LPVOID lpParam) { if (MH_Initialize () != MH_OK) return 1 ; HMODULE hRaylib = GetModuleHandleA ("raylib.dll" ); if (hRaylib) { void * targetAddr = (void *)GetProcAddress (hRaylib, "EndDrawing" ); MH_CreateHook (targetAddr, &DetourEndDrawing, reinterpret_cast <LPVOID*>(&pOriginalEndDrawing)); MH_EnableHook (targetAddr); } return 0 ; } 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 #include "IPlugin.h" #include <vector> static char inputText[64 ] = { 0 };static int letterCount = 0 ;static bool active = false ;void SearchOnInit () { TraceLog (LOG_INFO, "[SearchBox DLL] Plugin Initialized." ); } void SearchOnTick () { if (IsKeyPressed (KEY_F2)) active = !active; if (!active) return ; int key = GetCharPressed (); while (key > 0 ) { if (key >= 32 && key <= 125 && letterCount < 63 ) { inputText[letterCount++] = (char )key; inputText[letterCount] = '\0' ; } key = GetCharPressed (); } if (IsKeyPressed (KEY_BACKSPACE) && letterCount > 0 ) inputText[--letterCount] = '\0' ; if (IsKeyPressed (KEY_ENTER)) { if (letterCount > 0 ) { TraceLog (LOG_INFO, "[SearchBox] Searching for: %s" , inputText); letterCount = 0 ; inputText[0 ] = '\0' ; active = false ; } } Rectangle box = { GetScreenWidth () / 2.0f - 200 , 20 , 400 , 40 }; DrawRectangleRounded (box, 0.3f , 8 , Fade (BLACK, 0.8f )); DrawRectangleRoundedLines (box, 0.3f , 8 , active ? SKYBLUE : GRAY); DrawText (inputText, (int )box.x + 15 , (int )box.y + 10 , 20 , RAYWHITE); } 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 20 #ifndef IPLUGIN_H #define IPLUGIN_H #include "raylib.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
静态链接与动态链接的坑 动态链接成功,静态链接失败。
静态库版本还有一个巨大的坑:全局变量隔离 。
动态库版 :主程序和 DLL 都链接到同一个 raylib.dll,它们共享同一个键盘状态缓冲区。
静态库版 :主程序里有一套 Raylib 变量,你的 DLL 里也有一套。当你在主程序按 F2 时,主程序的那套变量变了,但 DLL 里的那套没变 ,所以 IsKeyPressed 永远返回 false。
方案 A:劫持窗口过程 (Hook WndProc) 不要依赖 Raylib 的输入函数。直接拦截 Windows 的原始消息,这不依赖任何库的状态。
方案 B:特征码搜索变量而非函数 你需要搜索的不是 EndDrawing,而是 Raylib 内部存放 Core 状态的全局指针。强行把 DLL 里的指针指向 EXE 里的内存地址。但这需要极高的逆向工程功底。