• 【C++】实现D3D9 的 Inline hook


    【C++】实现D3D9 的 Inline hook
     
    简单介绍一下HOOK原理:
        函数调用的过程大致是 先push 参数 进去,再执行 call 函数地址 ,进入函数。此时将所调用的函数的前五个字节修改,将开头改成 jmp xxxxxxxx(地址偏移) ,则可以进入自己的函数,执行自己函数的内容,执行完自己的函数后,还原修改的函数,使原本函数的功能不受影响,完成HOOK。D3D9 的hook 就是HOOK d3d函数
     
     
    一些必备知识点:
        jmp 的硬编码是E9 ,在构造字节的时候,第一个字节为' \xe9'
        在修改内存前,应当先修改内存的属性,防止内存的属性是不可写的状态
        地址偏移的算法:自己函数的地址 - (原来函数的地址 + 字节数),此处替换5个字节,所以是自己函数的地址 - (原来函数的地址 + 5)
     
    大致思路:
      写一个DLL,在DLL里面完成HOOK,随便写一个DLL注入器注入到进程即可
     
      DLL部分:
    复制代码
    #include
    int __stdcall DllMain(void* _DllHandle, unsigned long _Reason, void*_Reserved)
    {
        if (_Reason == DLL_PROCESS_ATTACH)
        {
            _beginthreadex(nullptr, 0, initialize_d3d9, nullptr, 0, nullptr);
        }
        return 1;
    }
    // 注:
    initialize_d3d9是d3d9部分的函数
    
    
    复制代码
     
      HOOK部分:
        构造一个inline hook类,传入 被修改函数的地址 和 自己函数的地址 ,根据传入的两个参数算出偏移,保存原函数的前五个字节
        一个函数,修改原函数,将构造的字节写入到内存
        一个函数,还原原函数,将保存下来的字节写入内存
        一个函数,修改内存属性 
      HOOK部分完成

      D3D部分:
        初始化D3D9
        用上面的函数HOOK掉D3D9的函数
      D3D部分完成
     
     
    代码部分(HOOK部分):
    复制代码
    #pragma once
    #include
    constexpr int byte_length = 5; //修改函数的前五个字节,修改为jmp
    
    class inline_hook
    {
    private:
        using uchar = unsigned char;
        using dword = DWORD;
        uchar m_original_byte[byte_length];
        uchar m_self_byte[byte_length];
        int m_original_address; //原始函数的地址
        int m_self_address;//自己函数的地址
        dword motify_memory_attribute(int address, dword attribute = PAGE_EXECUTE_READWRITE)
        {
            dword old_attributes;
            VirtualProtect(reinterpret_cast<void*>(address), byte_length, attribute, &old_attributes);
            return old_attributes;
        }
    public:
        inline_hook(int original_address, int self_address) :m_original_address(original_address), m_self_address(self_address)
        {
            m_self_byte[0] = '\xe9'; //jmp的硬编码
            int offset = self_address - (original_address + byte_length);   //计算偏移
            memcpy(&m_self_byte[1], &offset, byte_length - 1); //构造字节
            dword attribute = motify_memory_attribute(original_address); //修改内存属性
            memcpy(m_original_byte, reinterpret_cast<void*>(original_address), byte_length); //将程序原来的函数代码保存到 m_original_byte 
            motify_memory_attribute(original_address, attribute); // 还原内存属性
        }
        void motify_address() //修改原来的函数
        {
            dword attribute = motify_memory_attribute(m_original_address); //修改内存属性
            //写入自己构造的字节
            memcpy(reinterpret_cast<void*>(m_original_address), m_self_byte, byte_length);// 将构造好的字节,覆盖到原来的函数的地方
            motify_memory_attribute(m_original_address, attribute); //还原内存属性
        }
        void restore_address() //恢复原来的函数
        {
            dword attribute = motify_memory_attribute(m_original_address);
            memcpy(reinterpret_cast<void*>(m_original_address), m_original_byte, byte_length);
            motify_memory_attribute(m_original_address, attribute);
        }
    };
    复制代码

     

    代码部分(D3D9部分):

    复制代码
    /*需要包含的头文件*/
    #include
    #include
    #pragma comment(lib,"d3d9.lib")
    /*一些必要的全局变量*/
    IDirect3D9 * g_direct3d9 = nullptr;
    IDirect3DDevice9 *g_direct3ddevice9 = nullptr;
    D3DPRESENT_PARAMETERS g_present;
    HWND g_hwnd = FindWindowA(nullptr, "Counter-Strike: Global Offensive - Direct3D 9");
    //HWND g_hwnd = FindWindowA("Valve001",nullptr);
    
    inline_hook*g_Reset_hook = nullptr; //hook Reset 函数
    inline_hook*g_EndScene_hook = nullptr;
    inline_hook*g_DrawIndexedPrimitive_hook = nullptr;
    
    /*如果需要劫持Reset函数,则写一个函数代替原来的Reset*/
    
    HRESULT __stdcall self_Reset(IDirect3DDevice9 *g_direct3ddevice9, D3DPRESENT_PARAMETERS* pPresentationParameters)
    {
    printf("join\n"); //自己需要实现的功能写在这里
    HRESULT result = D3D_OK;
    g_Reset_hook->restore_address();
    if (g_direct3ddevice9)
    {
    ImGui_ImplDX9_InvalidateDeviceObjects();
    HRESULT result = g_direct3ddevice9->Reset(pPresentationParameters); //调用原来的Reset函数
    ImGui_ImplDX9_CreateDeviceObjects();
    }
    g_Reset_hook->motify_address();
    return result;
    }
     
    
    /*DLL注入后执行此函数*/
    
    unsigned int __stdcall initialize_d3d9(void*data)
    {
    AllocConsole();
    freopen("CON", "w", stdout);
    g_direct3d9 = Direct3DCreate9(D3D_SDK_VERSION);
    memset(&g_present, 0, sizeof(g_present));
    g_present.Windowed = TRUE;
    g_present.SwapEffect = D3DSWAPEFFECT_DISCARD;
    g_present.BackBufferFormat = D3DFMT_UNKNOWN;
    g_present.EnableAutoDepthStencil = TRUE;
    g_present.AutoDepthStencilFormat = D3DFMT_D16;
    HRESULT result = g_direct3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_present, &g_direct3ddevice9);
    int *direct3d9_table = (int*)*(int *)g_direct3d9;
    int *direct3ddevice9_table = (int*)*(int *)g_direct3ddevice9;//这里是一个表,储存了direct的函数,通过劫持这些函数,转接到自己的函数,通过速览IDirect3DDevice9的定义可以看到函数
    g_Reset_hook = new inline_hook(direct3ddevice9_table[16], (int)self_Reset); //hook掉了reset
    g_Reset_hook->motify_address(); //还原了Reset
    //direct3ddevice9_table[下标],下标通过速览定义IDirect3DDevice9结构可知,看需要hook掉的函数在结构的第几位,减去一则是下标
    return 0;
    }
    复制代码

     

    此时以DLL编译,完成后用DLL注入器注入,则完成D3D9的inline hook,需要HOOK其他函数,则仿照Reset_hook 的写法

    g_Reset_hook = new inline_hook(direct3ddevice9_table[16], (int)self_Reset); //hook掉了reset
    g_Reset_hook->motify_address(); //还原了Reset

     HOOK 掉 DrawIndexedPrimitive举例

    先写自己的函数

    复制代码
    HRESULT __stdcall self_DrawIndexedPrimitive(IDirect3DDevice9 *g_direct3ddevice9,D3DPRIMITIVETYPE type, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount)
    {
        HRESULT result = D3D_OK;
        {
            /*自己的功能*/
        }
        g_DrawIndexedPrimitive_hook->restore_address();
    
        result = g_direct3ddevice9->DrawIndexedPrimitive(type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
    
        g_DrawIndexedPrimitive_hook->motify_address();
        
        return result;
    }
    复制代码

    在 initialize_d3d9 函数中增加

    g_DrawIndexedPrimitive_hook = new inline_hook(direct3ddevice9_table[82], (int)self_DrawIndexedPrimitive); //hook掉了DrawIndexedPrimitive
    g_DrawIndexedPrimitive_hook->motify_address();

    至此,完成对DrawIndexedPrimitive的HOOK

     

     

    ENDING.............

     

  • 相关阅读:
    [CISCN2019 华北赛区 Day1 Web1]Dropbox
    【JavaWeb - 网页编程】四 jQuery 操作
    Oracle数据库Bug:相关子查询多层嵌套报错:标识符无效
    node.js多版本管理器nvm的安装和使用
    ELK+Filebeat+Kafka+Zookeeper
    MacOS13-将数据库转为markdown,docx格式
    Unity 使用宏
    成人专升本
    java计算机毕业设计个人图集管理系统源码+mysql数据库+系统+lw文档+部署
    Lagging issues of Ubuntu 20.04 on VMWare Player(卡顿问题)
  • 原文地址:https://www.cnblogs.com/water-wells/p/16619679.html