MinHook--CCKa_max 的Directx-11-example(64)

一、参考链接

https://www.cnblogs.com/iBinary/p/10805200.html
https://www.bilibili.com/video/BV1XyHLeyEgU/

二、MinHook介绍

1、编译MinHook库
vs2022对应vc17,分别x86,64编译
把libMinHook.x64.lib、libMinHook.x86.lib、MinHook.h放到程序目录(dllmain.cpp同级)

2、使用MinHook库

if defined _M_X64

pragma comment(lib, "libMinHook.x64.lib")

elif defined _M_IX86

pragma comment(lib, "libMinHook.x86.lib")

endif

3、MinHook函数介绍

MH_STATUS WINAPI MH_Initialize(VOID);   //初始化HOOK引擎
MH_STATUS WINAPI MH_Uninitialize(VOID); //反初始化
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);//创建HOOK跳板
MH_STATUS WINAPI MH_CreateHookApi(                                                 //创建APIhook跳板
      LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
MH_STATUS WINAPI MH_CreateHookApiEx(                                                
      LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);                                  //删除HOOK
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);                                  //启动HOOK
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);                                 //结束HOOK
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
MH_STATUS WINAPI MH_ApplyQueued(VOID);
const char * WINAPI MH_StatusToString(MH_STATUS status);

4、MinHook使用步骤
1.初始化HOOK引擎
2.创建HOOK跳板函数
3.启用HOOK
4.结束HOOK
5.删除HOOK
6.反初始化HOOK引擎

特别注意创建HOOK跳板函数.我们可以用的接口有 MB_CreateHook MB_CreateHookApi MB_CreateHookApiEx
以第一个为例: 参数1: 你要HOOK的函数的函数指针(&LoadLibraryExW) 参数2:你自定义的函数 (&MyLoadLibraryExW) 参数3:跳板函数指针

参数3的意思就是 我们的函数内部调用参数3.相当于调用原函数.

三、Directx-11-example 解释

1、目标函数

通过HOOK 游戏的渲染函数 即Present函数,以达到在游戏内绘制的效果

函数原型如下

virtual HRESULT STDMETHODCALLTYPE Present( 
/* [in] */ UINT SyncInterval,
 /* [in] */ UINT Flags);

很明显Present函数是一个虚函数,那么既然是虚函数我们就可以通过虚函数表来获取Present函数的地址

Present函数虚表下的定义如下

        DECLSPEC_XFGVIRT(IDXGISwapChain, GetDesc)
        HRESULT ( STDMETHODCALLTYPE *GetDesc )( 
            IDXGISwapChain * This,
            /* [annotation][out] */ 
            _Out_  DXGI_SWAP_CHAIN_DESC *pDesc);

我们知道在内存下的有虚表对象的内存如下

虚表 -> 指针
变量
变量
变量

好那我们要获得虚表就先得获得IDXGISwapChain的地址以拿到他的虚表

那我们怎么获得呢?

在Windows下dx11提供了一个函数D3D11CreateDeviceAndSwapChain他可以帮助我们获得IDXGISwapChain地址

其获取方法如下

//在这里其实不用过于去纠结参数里面的内容,感兴趣可以直接去Windows官方文档里面查看    
DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));
    sd.BufferCount = 2;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = GetForegroundWindow();
    sd.SampleDesc.Count = 1;
    sd.Windowed = TRUE;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    ID3D11Device* device = nullptr;
    IDXGISwapChain* sc = nullptr;
    const D3D_FEATURE_LEVEL level[] = { D3D_FEATURE_LEVEL_10_0,D3D_FEATURE_LEVEL_11_0 };
    if (D3D11CreateDeviceAndSwapChain(
        0,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        0,
        level,
        2,
        D3D11_SDK_VERSION,
        &sd,
        &sc,
        &device,
        nullptr,nullptr) == S_OK) {


        void** vtable = *reinterpret_cast<void***>(sc);//获得虚表 sc存着IDXGISwapChain本体指针 (指针后前8个字节) 存着虚表
        sc->Release();//释放
        device->Release();//释放
        *Pointer = (PVOID)vtable[8];//虚表下的第9个元素就是Present函数

2、MinHook

好那我们获得了Present地址我们地址了,那下一步我们就要HOOK了,怎么Hook呢,在Github上有一个功能强大的项目MinHook

他可以帮助我们方便的进行Inline Hook操作,这样我们就不用自己写Hook函数啦

3、ImGui

Hook了之后我们需要获得一些必须的数据来初始化我们的ImGui

需要的数据有:
目标渲染窗口句柄
目标渲染视图
和Context Device

我们ImGui的初始化代码如下

ImGui::CreateContext();
ImGui::StyleColorsDark();
ImGui_ImplWin32_Init(m_hwnd);//FindWindow
ImGui_ImplDX11_Init(device, context);

当然了这些数据都可以通过IDXGISwapChain和WindowsApi来获得

4、获取绘图上下文、句柄

下面就一 一讲解下怎么去获得这些需要的数据:

获得目标渲染窗口句柄我们可以通过FindWindow来获得

获得目标渲染视图这个比较重要(因为它关乎着我们是否能正确的渲染到游戏中),那要怎么获得呢,我们可以通过获得后备缓冲区来获得

     ID3D11Texture2D* pBackBuffer;
    dx->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    device->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView);
    pBackBuffer->Release();

好那么下一步我们该如何获得Context和Device呢 其实通过IDXGISwapChain里面的成员函数就可以获得

ID3D11Device* device;
ID3D11DeviceContext* context;
dx->GetDevice(__uuidof(ID3D11Device), (void**)&device);
device->GetImmediateContext(&context);

好那么我们现在已经获取了我们需要的所有数据

发表新评论