首页 > 编程语言 >【C++】实现D3D9 的 Inline hook

【C++】实现D3D9 的 Inline hook

时间:2022-08-27 23:24:40浏览次数:49  
标签:Reset 函数 int C++ hook D3D9 address Inline original

【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<process.h>
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<Windows.h>
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<d3d9.h>
#include<HOOK部分代码>
#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);
check_error(g_direct3d9, "Direct3DCreate9失败");
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);
check_error(result == 0, "CreateDevice失败");
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.............

 

标签:Reset,函数,int,C++,hook,D3D9,address,Inline,original
From: https://www.cnblogs.com/water-wells/p/16619679.html

相关文章

  • 刨析一下C++构造析构函数能不能声明为虚函数的背后机理?
    以下内容为本人的著作,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16631774.html先说结论:构造函数不能声明为虚函数,析构函数可以......
  • C++ Protobuf
    Protobufprotobuf(protocolbuffer)是谷歌内部的混合语言数据标准。通过将结构化的数据进行序列化(串行化),用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展......
  • C++中的cout.setf(ios::fixed)是什么意思?
    问题描述:在阅读一段代码时,发现代码的最后一部分出现...cout.setf(ios::fixed);cout.setf(ios::showpoint);...解决:cout.setf()是通过设置格式标志来控制cout输出格......
  • C++ Primer 第五版 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/14M-yWrk2FxOFB4RVhiolQQ点击这里获取提取码这本久负盛名的 C++经典教程,时隔八年之久,终迎来史无前例的重大升级。除令全球......
  • 【c++多线程】互斥量概念、用法、死锁演示以及unique_lock
    第5节互斥量概念、用法、死锁演示及解决详解(1)互斥量(mutex)的基本概念(2)互斥量的用法(2.1)lock(),unlock()(2.2)std::lock_guard类模板(3)死锁(3.1)......
  • CCF 202109-2 非零段划分(C++)差分法
    借用岛屿情况来分析这个题。考虑p足够大的情况,所有的数都被海水淹没了,只有0个岛屿。然后,海平面逐渐下降,岛屿数量出现变化。每当一个凸峰出现,岛屿数就会多一个;每当一个凹......
  • 褶积方法制作合成地震记录c++
    地震褶积方法制作合成地震记录包括,(1)读取相模型,设置每种相的密度和速度,(2)计算反射系数,添加噪音,(3)设置子波,(4)进行褶积计算。具体的代码如下voidsyntheticSeis(conststring&......
  • C++停车场管理系统
    C++停车场管理系统停车场管理系统简介一、 问题描述设停车场是一个可停放若干辆辆汽车的狭多层平面区域,且只有一个大门可供汽车进出。若车场内已停满汽车,则后来的汽车只......
  • CCF 202112-2 序列查询新解(C++)
    该题关键点在于:分段计算先对f分段:for(inti=1;i<=n+1;i++)//以f(i)为区域划分计算在此区域内f的取值相同,值为:i-1。再对每个f值相同的区域按照g值进行分段:for(int......
  • C++基础-理解new和delete
    intmain(intargc,charconst*argv[]){ //C风格 int*p=(int*)malloc(sizeof(int)); if(p==NULL){ return-1; } *p=20;//初始化 free(p); int*q=(......