Loading...

文章背景图

阶段七:图形渲染

a0yark a0yark
|
2025-12-03
|
0
|
-
|
- min
|

阶段七:图形渲染

📅 创建日期: 2025-01-XX
⏱️ 预计学时: 6-8 周
🎯 学习目标: 掌握 ImGui 界面库、DirectX Hook、游戏 Overlay 开发
📋 前置要求: [[阶段五:核心逆向技术]]
🔗 返回: [[逆向与驱动开发学习路径(详细版)]]


📚 本阶段内容概览

  • [[#7.1 ImGui入门|7.1 ImGui入门]]
    • [[#7.1.1 ImGui基础|ImGui基础]]
    • [[#7.1.2 常用控件|常用控件]]
    • [[#7.1.3 自定义样式|自定义样式]]
  • [[#7.2 DirectX基础|7.2 DirectX基础]]
    • [[#7.2.1 DirectX 9|DirectX 9]]
    • [[#7.2.2 DirectX 11|DirectX 11]]
  • [[#7.3 Hook渲染|7.3 Hook渲染]]
    • [[#7.3.1 D3D9 Hook|D3D9 Hook]]
    • [[#7.3.2 D3D11 Hook|D3D11 Hook]]
  • [[#7.4 Overlay技术|7.4 Overlay技术]]

7.1 ImGui入门

7.1.1 ImGui基础

📝 学习笔记

什么是 ImGui

ImGui (Immediate Mode GUI) 是一个轻量级的 C++ GUI 库,特点:

  • 无状态,每帧重新构建UI
  • 无需复杂的继承体系
  • 适合游戏内嵌界面、调试工具

基本框架

#include "imgui.h"
#include "imgui_impl_win32.h"
#include "imgui_impl_dx11.h"

// 初始化
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();

// 设置风格
ImGui::StyleColorsDark();

// 初始化后端
ImGui_ImplWin32_Init(hWnd);
ImGui_ImplDX11_Init(device, deviceContext);

// 渲染循环
while (running) {
    // 开始新帧
    ImGui_ImplDX11_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();
    
    // 构建UI
    ImGui::Begin("My Window");
    ImGui::Text("Hello, ImGui!");
    ImGui::End();
    
    // 渲染
    ImGui::Render();
    ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
}

// 清理
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();

7.1.2 常用控件

📝 学习笔记

void RenderUI() {
    ImGui::Begin("Control Panel");
    
    // 文本
    ImGui::Text("Static text");
    ImGui::TextColored(ImVec4(1,1,0,1), "Yellow text");
    
    // 按钮
    if (ImGui::Button("Click Me")) {
        // 按钮点击处理
    }
    
    // 复选框
    static bool enabled = false;
    ImGui::Checkbox("Enable Feature", &enabled);
    
    // 滑块
    static float value = 0.5f;
    ImGui::SliderFloat("Value", &value, 0.0f, 1.0f);
    
    static int intValue = 50;
    ImGui::SliderInt("Int Value", &intValue, 0, 100);
    
    // 输入框
    static char text[256] = "";
    ImGui::InputText("Name", text, sizeof(text));
    
    static float floatInput = 0.0f;
    ImGui::InputFloat("Float", &floatInput);
    
    // 颜色选择器
    static float color[4] = {1,0,0,1};
    ImGui::ColorEdit4("Color", color);
    
    // 下拉框
    static int current = 0;
    const char* items[] = {"Option 1", "Option 2", "Option 3"};
    ImGui::Combo("Select", &current, items, IM_ARRAYSIZE(items));
    
    // 列表框
    ImGui::ListBox("List", &current, items, IM_ARRAYSIZE(items));
    
    // 树节点
    if (ImGui::TreeNode("Advanced")) {
        ImGui::Text("Advanced options here");
        ImGui::TreePop();
    }
    
    // 标签页
    if (ImGui::BeginTabBar("Tabs")) {
        if (ImGui::BeginTabItem("Tab 1")) {
            ImGui::Text("Tab 1 content");
            ImGui::EndTabItem();
        }
        if (ImGui::BeginTabItem("Tab 2")) {
            ImGui::Text("Tab 2 content");
            ImGui::EndTabItem();
        }
        ImGui::EndTabBar();
    }
    
    ImGui::End();
}

常用控件速查

控件 函数 说明
文本 Text(), TextColored() 静态文本
按钮 Button(), SmallButton() 可点击按钮
复选框 Checkbox() 布尔值切换
单选按钮 RadioButton() 单选选项
滑块 SliderFloat/Int() 数值滑动条
输入框 InputText/Float/Int() 输入字段
颜色 ColorEdit3/4() 颜色选择器
下拉框 Combo() 下拉选择
列表 ListBox() 列表选择
表格 BeginTable()/EndTable() 数据表格

7.1.3 自定义样式

📝 学习笔记

void SetCustomStyle() {
    ImGuiStyle& style = ImGui::GetStyle();
    
    // 窗口
    style.WindowRounding = 5.0f;
    style.WindowBorderSize = 1.0f;
    style.WindowPadding = ImVec2(10, 10);
    
    // 控件
    style.FrameRounding = 3.0f;
    style.FramePadding = ImVec2(5, 3);
    style.ItemSpacing = ImVec2(8, 4);
    
    // 颜色
    ImVec4* colors = style.Colors;
    colors[ImGuiCol_WindowBg] = ImVec4(0.1f, 0.1f, 0.1f, 0.9f);
    colors[ImGuiCol_TitleBg] = ImVec4(0.2f, 0.2f, 0.2f, 1.0f);
    colors[ImGuiCol_TitleBgActive] = ImVec4(0.3f, 0.3f, 0.3f, 1.0f);
    colors[ImGuiCol_Button] = ImVec4(0.3f, 0.3f, 0.3f, 1.0f);
    colors[ImGuiCol_ButtonHovered] = ImVec4(0.4f, 0.4f, 0.4f, 1.0f);
    colors[ImGuiCol_ButtonActive] = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
    colors[ImGuiCol_CheckMark] = ImVec4(0.0f, 1.0f, 0.0f, 1.0f);
    colors[ImGuiCol_SliderGrab] = ImVec4(0.0f, 0.8f, 0.0f, 1.0f);
}

// 自定义字体
void LoadCustomFont() {
    ImGuiIO& io = ImGui::GetIO();
    
    // 加载字体
    io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\msyh.ttc", 16.0f,
                                  NULL, io.Fonts->GetGlyphRangesChineseFull());
    
    // 或从内存加载
    // io.Fonts->AddFontFromMemoryTTF(fontData, fontSize, 16.0f);
}

7.2 DirectX基础

7.2.1 DirectX 9

📝 学习笔记

D3D9 初始化

#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")

IDirect3D9* d3d = NULL;
IDirect3DDevice9* device = NULL;

BOOL InitD3D9(HWND hWnd) {
    // 创建D3D对象
    d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (!d3d) return FALSE;
    
    // 设置呈现参数
    D3DPRESENT_PARAMETERS d3dpp = {};
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;  // VSync
    
    // 创建设备
    HRESULT hr = d3d->CreateDevice(
        D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,
        hWnd,
        D3DCREATE_HARDWARE_VERTEXPROCESSING,
        &d3dpp,
        &device
    );
    
    return SUCCEEDED(hr);
}

void RenderFrame() {
    device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                  D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
    
    if (SUCCEEDED(device->BeginScene())) {
        // 渲染内容...
        device->EndScene();
    }
    
    device->Present(NULL, NULL, NULL, NULL);
}

void CleanupD3D9() {
    if (device) device->Release();
    if (d3d) d3d->Release();
}

D3D9 绘图函数

// 绘制线段
void DrawLine(float x1, float y1, float x2, float y2, D3DCOLOR color) {
    struct Vertex {
        float x, y, z, rhw;
        D3DCOLOR color;
    };
    
    Vertex vertices[] = {
        {x1, y1, 0, 1, color},
        {x2, y2, 0, 1, color}
    };
    
    device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
    device->DrawPrimitiveUP(D3DPT_LINELIST, 1, vertices, sizeof(Vertex));
}

// 绘制矩形
void DrawRect(float x, float y, float w, float h, D3DCOLOR color) {
    DrawLine(x, y, x + w, y, color);
    DrawLine(x + w, y, x + w, y + h, color);
    DrawLine(x + w, y + h, x, y + h, color);
    DrawLine(x, y + h, x, y, color);
}

// 绘制填充矩形
void DrawFilledRect(float x, float y, float w, float h, D3DCOLOR color) {
    struct Vertex {
        float x, y, z, rhw;
        D3DCOLOR color;
    };
    
    Vertex vertices[] = {
        {x, y, 0, 1, color},
        {x + w, y, 0, 1, color},
        {x, y + h, 0, 1, color},
        {x + w, y + h, 0, 1, color}
    };
    
    device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
    device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertices, sizeof(Vertex));
}

7.2.2 DirectX 11

📝 学习笔记

D3D11 初始化

#include <d3d11.h>
#pragma comment(lib, "d3d11.lib")

ID3D11Device* device = NULL;
ID3D11DeviceContext* context = NULL;
IDXGISwapChain* swapChain = NULL;
ID3D11RenderTargetView* renderTargetView = NULL;

BOOL InitD3D11(HWND hWnd) {
    // 交换链描述
    DXGI_SWAP_CHAIN_DESC scd = {};
    scd.BufferCount = 1;
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    scd.OutputWindow = hWnd;
    scd.SampleDesc.Count = 1;
    scd.Windowed = TRUE;
    scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    
    // 创建设备和交换链
    D3D_FEATURE_LEVEL featureLevel;
    HRESULT hr = D3D11CreateDeviceAndSwapChain(
        NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
        0, NULL, 0,
        D3D11_SDK_VERSION,
        &scd,
        &swapChain,
        &device,
        &featureLevel,
        &context
    );
    
    if (FAILED(hr)) return FALSE;
    
    // 创建渲染目标视图
    ID3D11Texture2D* backBuffer;
    swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer);
    device->CreateRenderTargetView(backBuffer, NULL, &renderTargetView);
    backBuffer->Release();
    
    context->OMSetRenderTargets(1, &renderTargetView, NULL);
    
    // 设置视口
    D3D11_VIEWPORT vp = {};
    vp.Width = 800;
    vp.Height = 600;
    vp.MaxDepth = 1.0f;
    context->RSSetViewports(1, &vp);
    
    return TRUE;
}

void RenderFrame() {
    float clearColor[4] = {0.0f, 0.2f, 0.4f, 1.0f};
    context->ClearRenderTargetView(renderTargetView, clearColor);
    
    // 渲染内容...
    
    swapChain->Present(1, 0);  // VSync
}

7.3 Hook渲染

7.3.1 D3D9 Hook

📝 学习笔记

获取 D3D9 设备虚表

// 方法1: 创建临时设备获取虚表
PVOID* GetD3D9VTable() {
    // 创建临时窗口
    HWND hWnd = CreateWindowEx(0, L"STATIC", L"", WS_POPUP, 0, 0, 1, 1,
                                NULL, NULL, NULL, NULL);
    
    IDirect3D9* d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (!d3d) return NULL;
    
    D3DPRESENT_PARAMETERS d3dpp = {};
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = hWnd;
    
    IDirect3DDevice9* device;
    d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                      &d3dpp, &device);
    
    // 获取虚表
    PVOID* vtable = *(PVOID**)device;
    
    // 复制需要的函数地址
    PVOID endScene = vtable[42];    // EndScene
    PVOID reset = vtable[16];       // Reset
    PVOID present = vtable[17];     // Present
    
    device->Release();
    d3d->Release();
    DestroyWindow(hWnd);
    
    return vtable;
}

Hook EndScene

typedef HRESULT(WINAPI* EndScene_t)(IDirect3DDevice9*);
EndScene_t oEndScene = NULL;

HRESULT WINAPI hkEndScene(IDirect3DDevice9* device) {
    // 在这里绘制自定义内容
    static bool init = false;
    if (!init) {
        // 初始化ImGui
        ImGui_ImplDX9_Init(device);
        init = true;
    }
    
    // ImGui渲染
    ImGui_ImplDX9_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();
    
    ImGui::Begin("D3D9 Overlay");
    ImGui::Text("Hello from hooked EndScene!");
    ImGui::End();
    
    ImGui::Render();
    ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
    
    return oEndScene(device);
}

// 安装Hook
void InstallD3D9Hook() {
    PVOID* vtable = GetD3D9VTable();
    
    // 使用MinHook或直接修改虚表
    MH_CreateHook(vtable[42], hkEndScene, (PVOID*)&oEndScene);
    MH_EnableHook(vtable[42]);
}

D3D9 关键虚表索引

索引 函数 用途
16 Reset 设备重置时需要重建资源
17 Present 每帧呈现
42 EndScene 渲染结束,常用Hook点

7.3.2 D3D11 Hook

📝 学习笔记

Hook Present (DXGI)

typedef HRESULT(WINAPI* Present_t)(IDXGISwapChain*, UINT, UINT);
Present_t oPresent = NULL;

ID3D11Device* g_device = NULL;
ID3D11DeviceContext* g_context = NULL;
ID3D11RenderTargetView* g_rtv = NULL;

HRESULT WINAPI hkPresent(IDXGISwapChain* swapChain, UINT syncInterval, UINT flags) {
    static bool init = false;
    
    if (!init) {
        // 获取设备和上下文
        swapChain->GetDevice(__uuidof(ID3D11Device), (void**)&g_device);
        g_device->GetImmediateContext(&g_context);
        
        // 创建渲染目标视图
        ID3D11Texture2D* backBuffer;
        swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer);
        g_device->CreateRenderTargetView(backBuffer, NULL, &g_rtv);
        backBuffer->Release();
        
        // 初始化ImGui
        ImGui_ImplDX11_Init(g_device, g_context);
        
        init = true;
    }
    
    // 设置渲染目标
    g_context->OMSetRenderTargets(1, &g_rtv, NULL);
    
    // ImGui渲染
    ImGui_ImplDX11_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();
    
    ImGui::Begin("D3D11 Overlay");
    ImGui::Text("Hello from hooked Present!");
    ImGui::End();
    
    ImGui::Render();
    ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
    
    return oPresent(swapChain, syncInterval, flags);
}

// 获取SwapChain虚表
PVOID* GetDXGIVTable() {
    // 创建临时设备获取虚表
    HWND hWnd = CreateWindowEx(0, L"STATIC", L"", WS_POPUP, 0, 0, 1, 1,
                                NULL, NULL, NULL, NULL);
    
    DXGI_SWAP_CHAIN_DESC scd = {};
    scd.BufferCount = 1;
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    scd.OutputWindow = hWnd;
    scd.SampleDesc.Count = 1;
    scd.Windowed = TRUE;
    
    IDXGISwapChain* swapChain;
    ID3D11Device* device;
    ID3D11DeviceContext* context;
    
    D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0,
                                   NULL, 0, D3D11_SDK_VERSION, &scd,
                                   &swapChain, &device, NULL, &context);
    
    PVOID* vtable = *(PVOID**)swapChain;
    
    swapChain->Release();
    device->Release();
    context->Release();
    DestroyWindow(hWnd);
    
    return vtable;
}

DXGI SwapChain 虚表索引

索引 函数 用途
8 Present 每帧呈现
13 ResizeBuffers 窗口大小改变

7.4 Overlay技术

📝 学习笔记

外部 Overlay 窗口

// 创建透明窗口
HWND CreateOverlayWindow() {
    WNDCLASSEX wc = {};
    wc.cbSize = sizeof(wc);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = OverlayWndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = L"OverlayClass";
    RegisterClassEx(&wc);
    
    // 获取目标窗口位置
    HWND targetWnd = FindWindow(NULL, L"Game Window");
    RECT rect;
    GetWindowRect(targetWnd, &rect);
    
    // 创建分层窗口
    HWND overlay = CreateWindowEx(
        WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW,
        L"OverlayClass",
        L"Overlay",
        WS_POPUP,
        rect.left, rect.top,
        rect.right - rect.left,
        rect.bottom - rect.top,
        NULL, NULL, GetModuleHandle(NULL), NULL
    );
    
    // 设置透明色
    SetLayeredWindowAttributes(overlay, RGB(0, 0, 0), 0, LWA_COLORKEY);
    
    ShowWindow(overlay, SW_SHOW);
    return overlay;
}

// 跟随目标窗口
void UpdateOverlayPosition(HWND overlay, HWND target) {
    RECT rect;
    if (GetWindowRect(target, &rect)) {
        SetWindowPos(overlay, HWND_TOPMOST,
                     rect.left, rect.top,
                     rect.right - rect.left,
                     rect.bottom - rect.top,
                     SWP_NOACTIVATE);
    }
}

GDI 绘图

// 在Overlay上绘制
void DrawOnOverlay(HDC hdc, int width, int height) {
    // 清除背景(透明色)
    HBRUSH brush = CreateSolidBrush(RGB(0, 0, 0));
    RECT rect = {0, 0, width, height};
    FillRect(hdc, &rect, brush);
    DeleteObject(brush);
    
    // 绘制矩形框
    HPEN pen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
    SelectObject(hdc, pen);
    SelectObject(hdc, GetStockObject(NULL_BRUSH));
    Rectangle(hdc, 100, 100, 200, 200);
    DeleteObject(pen);
    
    // 绘制文字
    SetTextColor(hdc, RGB(0, 255, 0));
    SetBkMode(hdc, TRANSPARENT);
    TextOut(hdc, 100, 80, L"ESP Box", 7);
}

[!tip] Overlay vs 内部 Hook

方式 优点 缺点
外部Overlay 不修改目标进程 可能被遮挡,需要同步位置
内部Hook 与游戏渲染同步 需要注入,可能被检测

✅ 阶段检查点

ImGui检查

  • [ ] 搭建ImGui开发环境
  • [ ] 掌握常用控件使用
  • [ ] 能自定义样式和字体

DirectX检查

  • [ ] 理解D3D9/D3D11初始化流程
  • [ ] 能进行基本的图形绘制
  • [ ] 了解渲染管线基础

Hook渲染检查

  • [ ] 实现D3D9 EndScene Hook
  • [ ] 实现D3D11 Present Hook
  • [ ] 在Hook中集成ImGui

Overlay检查

  • [ ] 创建透明Overlay窗口
  • [ ] 实现窗口位置跟随
  • [ ] 使用GDI或D3D在Overlay上绘制

📖 学习资料

资源类型 名称 说明
📚 文档 ImGui Wiki 官方文档
📚 文档 DirectX文档 微软官方
🔧 示例 ImGui Demo 完整示例
📹 视频 YouTube D3D教程 DirectX入门

🔗 导航

← [[阶段六:驱动开发]] | [[逆向与驱动开发学习路径(详细版)| 返回主目录]] | [[阶段八:脚本框架]] →

分享文章

未配置分享平台

请在主题设置中启用分享平台

评论