kennylovecode Posted June 23 Posted June 23 (edited) Here's a full D3D8 Hook Tutorial in English, including all steps from knowledge prerequisites to debugging and logging. 1. Prerequisites Before diving into D3D8 hooking, you should be familiar with the following: TopicDescription C/C++ ProgrammingKnow classes, pointers, function pointers DLL BasicsUnderstand how DLLs work and are injected Windows APIBasic Win32 programming and message loop Assembly & MemoryBasic understanding of memory layout and vtables DirectX 8 ConceptsHow Direct3D8 renders (e.g., EndScene, Reset) 2. Required Tools ToolPurposeRecommendation Visual Studio 2019/2022Build and debug C++ projects DirectX 8 SDKProvides d3d8.h, d3d8.lib, etc. DLL InjectorInject your DLL into the target process[Extreme Injector, Process Hacker, or custom one] Cheat EngineMemory inspection/debugging DebugView or file loggerFor logging without a console 3. Create the Hook DLL Project 3.1 Set up a Visual Studio Project Open Visual Studio → Create New Project → C++ Dynamic-Link Library (DLL) Name it something like D3D8Hook Set Project Properties: C/C++ > General > Additional Include Directories: Add the DirectX SDK Include path Linker > Input > Additional Dependencies: Add d3d8.lib, d3dx8.lib 3.2 Write the Hooking Code // D3D8Hook.cpp // D3D8Hook.cpp #include <Windows.h> #include <d3d8.h> #include <d3dx8.h> typedef HRESULT(APIENTRY* EndScene_t)(LPDIRECT3DDEVICE8 pDevice); EndScene_t oEndScene = nullptr; DWORD WINAPI MainThread(LPVOID); // Hook implementation HRESULT APIENTRY hkEndScene(LPDIRECT3DDEVICE8 pDevice) { static bool once = false; if (!once) { MessageBoxA(0, "D3D8 Hooked!", "Success", MB_OK); once = true; } return oEndScene(pDevice); // Call the original } void HookFunction() { IDirect3D8* pD3D = Direct3DCreate8(D3D_SDK_VERSION); if (!pD3D) return; D3DPRESENT_PARAMETERS d3dpp = {}; d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = GetForegroundWindow(); IDirect3DDevice8* pDevice = nullptr; if (SUCCEEDED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice))) { void** vtable = *(void***)pDevice; oEndScene = (EndScene_t)vtable[35]; DWORD oldProtect; VirtualProtect(&vtable[35], sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProtect); vtable[35] = (void*)&hkEndScene; VirtualProtect(&vtable[35], sizeof(void*), oldProtect, &oldProtect); pDevice->Release(); } pD3D->Release(); } DWORD WINAPI MainThread(LPVOID) { HookFunction(); return 0; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) CreateThread(nullptr, 0, MainThread, nullptr, 0, nullptr); return TRUE; } 3.3 Build the DLL Use Build → Build Solution (Ctrl + Shift + B) and find the DLL in: csharp 复制编辑 [YourProjectFolder]\x86\Debug\D3D8Hook.dll Make sure it's compiled for x86 if the target process is 32-bit. 4. Injecting the DLL Method 1: Use an Injector Tool Start the game or D3D8-based application Open an injector (e.g., Extreme Injector or Process Hacker) Select the target process and inject D3D8Hook.dll Method 2: Write Your Own Injector (optional) cpp 复制编辑 HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID); LPVOID addr = VirtualAllocEx(hProc, NULL, len, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProc, addr, dllPath, len, NULL); CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, addr, 0, NULL); 5. Debugging and Logging 5.1 Output to DebugView Use this to see logs: cpp 复制编辑 OutputDebugStringA("D3D8 Hook initialized!"); You can view logs with DebugView by Sysinternals. 5.2 Write Logs to File cpp 复制编辑 void Log(const char* msg) { FILE* f = fopen("C:\\D3D8_Hook_Log.txt", "a+"); if (f) { fprintf(f, "%s\n", msg); fclose(f); } } 5.3 Use Visual Studio Debugger Build your DLL in Debug mode Launch the target app Attach Visual Studio (Debug → Attach to Process) Set breakpoints in hkEndScene or elsewhere Common Issues & Fixes IssuePossible Cause Game crashesWrong vtable index or uninitialized pointers Nothing happensHook not applied or wrong process architecture DLL fails to injectMissing dependencies or wrong platform (x64 vs x86) Edited June 24 by kennylovecode Quote
kennylovecode Posted June 23 Author Posted June 23 (edited) And Next. how to use your D3D8 hook to render a custom UI inside the game/client. Goal: Render Custom UI Over Game Screen We’ll do this by drawing inside the hkEndScene() function, which runs every frame right before the screen is presented. Prerequisites You must have: Already hooked EndScene (as we did above) Access to the LPDIRECT3DDEVICE8 pointer Initialized DirectX 8 properly in the target context Tools and Libraries (Optional) You can either: Use raw D3D8 drawing functions (simple, less dependency) Or use libraries like: ImGui + D3D8 backend (more complex, but easier to make UIs) D3DXFont / D3DXSprite (from d3dx8.lib) Let’s start with a raw example, then show how to add ImGui. Step-by-Step: Drawing Text and Boxes in hkEndScene 1. Draw Text with D3DXFont LPD3DXFONT pFont = nullptr; HRESULT APIENTRY hkEndScene(LPDIRECT3DDEVICE8 pDevice) { if (!pFont) { D3DXCreateFont(pDevice, 20, 0, FW_NORMAL, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial", &pFont); } RECT rect = { 10, 10, 300, 300 }; pFont->DrawTextA(NULL, "Hello from Hook!", -1, &rect, DT_NOCLIP, D3DCOLOR_ARGB(255, 255, 0, 0)); return oEndScene(pDevice); } This renders “Hello from Hook!” in red text at the top-left of the screen. 2. Draw a Filled Rectangle (Box) void DrawBox(LPDIRECT3DDEVICE8 pDevice, float x, float y, float width, float height, D3DCOLOR color) { struct Vertex { float x, y, z, rhw; DWORD color; }; Vertex vertices[] = { { x, y, 0.0f, 1.0f, color }, { x + width, y, 0.0f, 1.0f, color }, { x, y + height, 0.0f, 1.0f, color }, { x + width, y + height, 0.0f, 1.0f, color }, }; pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); pDevice->SetRenderState(D3DRS_ZENABLE, FALSE); pDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); pDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertices, sizeof(Vertex)); } // Inside hkEndScene DrawBox(pDevice, 50, 50, 100, 20, D3DCOLOR_ARGB(150, 0, 255, 0)); // semi-transparent green box Bonus: Show Health Bar Above Entity Assuming you know the screen position (x, y) of the entity, you can do: float healthPercent = 0.7f; // 70% health DrawBox(pDevice, x, y - 10, 50, 5, D3DCOLOR_ARGB(150, 0, 0, 0)); // background DrawBox(pDevice, x, y - 10, 50 * healthPercent, 5, D3DCOLOR_ARGB(200, 0, 255, 0)); // foreground Optional: Use ImGui for Modern UI ImGui works with D3D8 too, with slight setup. You’ll need: ImGui D3D8 backend (use imgui_impl_dx8.cpp) Windows message handler (imgui_impl_win32.cpp) In hkEndScene: ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); ImGui::Begin("Custom UI"); ImGui::Text("Injected Overlay!"); ImGui::End(); ImGui::Render(); ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); Debug Tips Ensure EndScene is being called (log or breakpoint) Use OutputDebugString or write to file for diagnostics If the overlay doesn’t show: Make sure the render state is correct The game window must be the foreground window (for some methods) Try drawing solid rectangles first (not text) Summary FeatureMethod TextD3DXCreateFont, DrawTextA Box/RectanglesCustom vertex arrays + DrawPrimitiveUP UIImGui (with D3D8 backend) Health BarCombine rectangles and entity coordinates Edited June 24 by kennylovecode Quote
kennylovecode Posted June 23 Author Posted June 23 What I am sharing is an idea of how to do it, not a complete project. But this idea is a feasible path that I have fully verified, not a hypothesis. There is an ancient Chinese saying that "teach him how to fish is better then just give a man a fish". I think this is very important. Quote
zMagic Posted June 23 Posted June 23 Peak Hooking D3D strides/font/Endscene etc..... would give player new GUI costume improvement few months ago tried to hook D3D but i could not find D3D8 libs SDK Can you share any ref for d3d8 lib sdk Quote
kennylovecode Posted June 24 Author Posted June 24 (edited) 6 hours ago, zMagic said: Peak Hooking D3D strides/font/Endscene etc..... would give player new GUI costume improvement few months ago tried to hook D3D but i could not find D3D8 libs SDK Can you share any ref for d3d8 lib sdk you can find it from "google", or github.com or anywhere if you search! Even you can ask CHATGPT for the download link to this file, and it can provide it to you completely, which is much better than asking on a forum, waiting, waiting, waiting, and then giving up. Edited June 24 by kennylovecode Quote
Spirited Posted June 29 Posted June 29 On 6/27/2025 at 9:00 AM, Airplist said: Can't use d3d9? Depends on how old the client is. The original client was made using DX8.1. Quote
Airplist Posted June 30 Posted June 30 I tried to do these things with d3d9, which can write to the console but not to the game interface, so I used d3d8. Should we set up a module or group chat specifically for this? This way it would be easier to learn from each other. Quote
kennylovecode Posted June 30 Author Posted June 30 3 hours ago, Airplist said: I tried to do these things with d3d9, which can write to the console but not to the game interface, so I used d3d8. Should we set up a module or group chat specifically for this? This way it would be easier to learn from each other. 我用 d3d9 尝试做过这些事情,虽然能写入控制台但无法写入游戏界面,所以改用了 d3d8。我们应该专门建立一个模块或群聊来讨论这个吗?这样互相学习会更容易。 As far as I know, most 2D version game clients are basically based on D3D8. If you have the capability, it can be changed to D3D9 or higher versions through hooking, but this requires deeper research Quote
kennylovecode Posted June 30 Author Posted June 30 I just did some basic testing and successfully redrew. Quote
Airplist Posted July 1 Posted July 1 It is easy to draw, but it is somewhat difficult to change or add new functions. I will learn it next and we can communicate on the relevant topic. Quote
kennylovecode Posted July 1 Author Posted July 1 Yes, actually I am willing to discuss and exchange these technologies, just as I have made some attempts and want to share them with everyone. But it seems that not many people are interested... 5 hours ago, Airplist said: It is easy to draw, but it is somewhat difficult to change or add new functions. I will learn it next and we can communicate on the relevant topic. 绘制起来很容易,但修改或添加新功能有些困难。我接下来会学习它,我们可以就相关话题进行交流。 Quote
Airplist Posted July 2 Posted July 2 The main reason is that not many people take it seriously and just want to get what they want directly, so they are all waiting and watching. Quote
kennylovecode Posted July 2 Author Posted July 2 So the community problem with the free system is that they don't need to put in any effort to receive the fruits of your labor and share them. In fact, I used to run a points community in my country, which required sharing and earning point rewards to exchange for other people's labor achievements. I think this is the only healthy and benign community... Quote
Airplist Posted July 3 Posted July 3 Yes, that’s better. Or you need to share some tutorials yourself to get points. You can use the points to view the information shared by others. If you don’t have the ability to share, you have to buy points to buy the information shared by others. Quote
kennylovecode Posted July 4 Author Posted July 4 But I don't know why they didn't do so. It seems that sharing is an obligation, and it rarely brings something valuable because people lack motivation. Quote
Spirited Posted July 4 Posted July 4 7 hours ago, kennylovecode said: But I don't know why they didn't do so. It seems that sharing is an obligation, and it rarely brings something valuable because people lack motivation. This forum has a different mindset than the other forum, for sure. We're about open information and examples here. Showing how to do things to empower those who want to do things on their own. The mindset for the longest time was hording information in private groups. But I think there's enough people here now that recognize the strength of sharing information and getting more people involved. It doesn't mean share everything, but sharing knowledge is huge. Quote
kennylovecode Posted July 5 Author Posted July 5 I think this is the right direction, just like what open-source communities like GitHub are doing. You've actually been doing this kind of thing for a long time, open-sourcing many projects and compiling some resources, including your ConquerWiki. But you'll find that this doesn't attract much fresh blood, because the developers for this Conquer game are almost fixed, and very few people are interested in the game, let alone those who would study it. Quote
duki Posted Wednesday at 09:51 AM Posted Wednesday at 09:51 AM I used to do this few years ago, but for other purposes of the game. You can also disable some functions of the game and start rendering by your own module. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.