C++ 挂钩/绕行d3d9(当前/结束场景)-似乎调用了我的函数,然后崩溃

C++ 挂钩/绕行d3d9(当前/结束场景)-似乎调用了我的函数,然后崩溃,c++,hook,directx-9,vtable,detours,C++,Hook,Directx 9,Vtable,Detours,正如标题所说,我正在尝试钩住DirectX 9并在屏幕上显示一些信息,我已经研究了几天的迂回和钩住,我认为我已经相当了解它,但现在我不太确定如何调试这个问题 我的钩子正在调用另一个函数ShowMsg(),它最终将成为一个draw函数,但现在它只显示一个消息框 调用了MyShowMsg()函数,但随后程序崩溃 我正在使用2010年2月的DirectX“SimpleSample”应用程序 // dllmain.cpp : Defines the entry point for the DLL app

正如标题所说,我正在尝试钩住DirectX 9并在屏幕上显示一些信息,我已经研究了几天的迂回和钩住,我认为我已经相当了解它,但现在我不太确定如何调试这个问题

我的钩子正在调用另一个函数
ShowMsg()
,它最终将成为一个draw函数,但现在它只显示一个消息框

调用了My
ShowMsg()
函数,但随后程序崩溃

我正在使用2010年2月的DirectX“SimpleSample”应用程序

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include "VirtualTable.h"
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")
#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
#include <detours.h>
#pragma comment(lib, "detours.lib")

using namespace std;

typedef void(__thiscall* Present)(IDirect3DDevice9* device);
Present g_org_Present;

void ShowMsg()
{
    MessageBoxA(0, "This function was called.", "", 0);
}

void __fastcall hk_Present(IDirect3DDevice9* device)
{
    ShowMsg();
    //call the original function
    g_org_Present(device);
}

void InitiateHooks()
{
    HWND game_window = FindWindowA(NULL, "SimpleSample");

    auto d3dpp = D3DPRESENT_PARAMETERS{};

    auto d3d = Direct3DCreate9(D3D_SDK_VERSION);

    IDirect3DDevice9* device;

    d3dpp.BackBufferCount = 1;
    d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = game_window;
    d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    d3dpp.BackBufferFormat = D3DFMT_R5G6B5;
    d3dpp.Windowed = TRUE;
    if (SUCCEEDED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, game_window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &device)))
    {
        void** vmt = *(void***)device;
        DWORD oldProtection;
        VirtualProtect(&vmt[17], 4, PAGE_EXECUTE_READWRITE, &oldProtection);
        g_org_Present = (Present)vmt[17];
        vmt[17] = &hk_Present;
        VirtualProtect(&vmt[17], 4, oldProtection, 0);

        device->Present(NULL, NULL, NULL, NULL);
    }

//  VirtualTable* myTable = new VirtualTable();

    //get the pointer to the actual virtual method table from our pointer to our class instance
//  void** base = *(void***)myTable;

//  DWORD oldProtection;
    //one way to remove page protection(not the best but this is an example only)
//  VirtualProtect(&base[1], 4, PAGE_EXECUTE_READWRITE, &oldProtection);
    //save the original function
//  g_org_VirtualFunction01 = (VirtualFunction01_t)base[1];
    //overwrite
//  base[1] = &hk_VirtualFunction01;
    //restore page protection
//  VirtualProtect(&base[1], 4, oldProtection, 0);

    //call the virtual function (now hooked) from our class instance
//  myTable->VirtualFunction01();
}
#pragma endregion

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CreateThread(0, 0x1000, (LPTHREAD_START_ROUTINE)InitiateHooks, 0, 0, NULL);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
这是我的代码,注释的部分来自上一次从另一个测试应用程序挂接函数的测试

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include "VirtualTable.h"
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")
#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
#include <detours.h>
#pragma comment(lib, "detours.lib")

using namespace std;

typedef void(__thiscall* Present)(IDirect3DDevice9* device);
Present g_org_Present;

void ShowMsg()
{
    MessageBoxA(0, "This function was called.", "", 0);
}

void __fastcall hk_Present(IDirect3DDevice9* device)
{
    ShowMsg();
    //call the original function
    g_org_Present(device);
}

void InitiateHooks()
{
    HWND game_window = FindWindowA(NULL, "SimpleSample");

    auto d3dpp = D3DPRESENT_PARAMETERS{};

    auto d3d = Direct3DCreate9(D3D_SDK_VERSION);

    IDirect3DDevice9* device;

    d3dpp.BackBufferCount = 1;
    d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = game_window;
    d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    d3dpp.BackBufferFormat = D3DFMT_R5G6B5;
    d3dpp.Windowed = TRUE;
    if (SUCCEEDED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, game_window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &device)))
    {
        void** vmt = *(void***)device;
        DWORD oldProtection;
        VirtualProtect(&vmt[17], 4, PAGE_EXECUTE_READWRITE, &oldProtection);
        g_org_Present = (Present)vmt[17];
        vmt[17] = &hk_Present;
        VirtualProtect(&vmt[17], 4, oldProtection, 0);

        device->Present(NULL, NULL, NULL, NULL);
    }

//  VirtualTable* myTable = new VirtualTable();

    //get the pointer to the actual virtual method table from our pointer to our class instance
//  void** base = *(void***)myTable;

//  DWORD oldProtection;
    //one way to remove page protection(not the best but this is an example only)
//  VirtualProtect(&base[1], 4, PAGE_EXECUTE_READWRITE, &oldProtection);
    //save the original function
//  g_org_VirtualFunction01 = (VirtualFunction01_t)base[1];
    //overwrite
//  base[1] = &hk_VirtualFunction01;
    //restore page protection
//  VirtualProtect(&base[1], 4, oldProtection, 0);

    //call the virtual function (now hooked) from our class instance
//  myTable->VirtualFunction01();
}
#pragma endregion

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CreateThread(0, 0x1000, (LPTHREAD_START_ROUTINE)InitiateHooks, 0, 0, NULL);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
//dllmain.cpp:定义DLL应用程序的入口点。
#包括“stdafx.h”
#包括
#包括
#包括“VirtualTable.h”
#包括
#pragma注释(lib,“d3d9.lib”)
#包括
#pragma注释(lib,“d3dx9.lib”)
#包括
#pragma注释(lib,“detours.lib”)
使用名称空间std;
typedef void(u_thiscall*存在)(IDirect3DDevice9*设备);
出席g_组织会议;
void ShowMsg()
{
MessageBoxA(0,“调用了此函数。”,“”,0);
}
无效u快速呼叫香港u当前(IDirect3DDevice9*设备)
{
ShowMsg();
//调用原始函数
g_组织_存在(设备);
}
void InitiateHooks()
{
HWND game_window=FindWindowA(NULL,“SimpleSample”);
自动d3dpp=D3DPRESENT_参数{};
自动d3d=Direct3DCreate9(d3d\U SDK\U版本);
IDirect3DDevice9*设备;
d3dpp.BackBufferCount=1;
d3dpp.MultiSampleType=D3DMULTISAMPLE\u无;
d3dpp.SwapEffect=d3dswapeeffect_DISCARD;
d3dpp.hDeviceWindow=游戏窗口;
d3dpp.FullScreen\u RefreshRateInHz=D3DPRESENT\u RATE\u默认值;
d3dpp.PresentationInterval=D3DPRESENT\u INTERVAL\u IMMEDIATE;
d3dpp.BackBufferFormat=D3DFMT_R5G6B5;
d3dpp.Windowed=TRUE;
如果(成功(d3d->CreateDevice(D3DADAPTER\u默认值、D3DDEVTYPE\u HAL、游戏窗口、D3DCREATE\u硬件\u VERTEXPROCESSING、d3dpp和设备)))
{
void**vmt=*(void***)设备;
德沃德保护;
VirtualProtect(&vmt[17],第4页,执行、读写和旧保护);
g_org_Present=(Present)vmt[17];
vmt[17]=&香港大学现在;
VirtualProtect(&vmt[17],4,oldProtection,0);
设备->存在(空,空,空,空);
}
//VirtualTable*myTable=新的VirtualTable();
//从指向类实例的指针获取指向实际虚拟方法表的指针
//void**base=*(void***)myTable;
//德沃德保护;
//一种删除页面保护的方法(不是最好的,但这只是一个示例)
//VirtualProtect(&base[1],第4页,执行页,读写页和旧保护);
//保存原始函数
//g_org_VirtualFunction01=(VirtualFunction01_t)base[1];
//覆盖
//base[1]=&hk_VirtualFunction01;
//恢复页面保护
//VirtualProtect(&base[1],4,oldProtection,0);
//从我们的类实例调用虚拟函数(现在已钩住)
//myTable->VirtualFunction01();
}
#布拉格端区
BOOL APICENT DllMain(模块HMODULE,
德沃德·乌尔打电话的理由,
LPVOID lpReserved
)
{
开关(ul\u呼叫原因\u)
{
案例DLL\u进程\u附加:
CreateThread(0,0x1000,(LPTHREAD\u START\u例程)initialehooks,0,0,NULL);
打破
案例DLL\u线程\u连接:
案例DLL\u线程\u分离:
案例DLL\u进程\u分离:
打破
}
返回TRUE;
}
有没有人能告诉我,我在这里可能做错了什么,这样我就可以解决这个问题,供将来参考

这是更新的代码,我意识到我不应该直接调用函数,所以我改变了它,也改变了它,尝试hook/detour EndScene,也使用MS Detours,而不是我认为是V-Table补丁的另一种方法,似乎调用了我的EndScene hook,因为MessageBox不断被调用。但是,如果我注释掉MessageBox,程序仍然会崩溃

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <intrin.h>  
#include <tchar.h>
#include <tlhelp32.h>
#include <Psapi.h>
#include <winsock2.h>
#include <vector>
#include <ws2tcpip.h>
#pragma comment( lib, "Ws2_32.lib" )
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")
#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
#include <detours.h>
#pragma comment(lib, "detours.lib")

using namespace std;

D3DCOLOR RED = D3DCOLOR_ARGB(255, 255, 0, 0);

typedef HRESULT(__stdcall* EndScene) (IDirect3DDevice9*);
EndScene EndScene_orig;

HRESULT __stdcall EndScene_hook(IDirect3DDevice9* pDevice)
{
//  D3DRECT rec = { 100,100,200,200 };
//  pDevice->Clear(1, &rec, D3DCLEAR_TARGET, RED, 0, 0);
//  MessageBoxA(0, "We made it here...2", "", 0); //    <<<<----- This function is called over and over when not commented.
    return EndScene_orig(pDevice);
}

void InitHook()
{

    HWND game_window = FindWindow(NULL, _T("Skinned Mesh"));

    auto d3dpp = D3DPRESENT_PARAMETERS{};
    auto d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (d3d)
    {
        d3dpp.BackBufferCount = 1;
        d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
        d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
        d3dpp.hDeviceWindow = game_window;
        d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
        d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
        d3dpp.BackBufferFormat = D3DFMT_R5G6B5;
        d3dpp.Windowed = TRUE;
        IDirect3DDevice9* Device;
        if (SUCCEEDED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, game_window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &Device)))
        {
//          MessageBoxA(0, "We made it here...", "", 0);

            DWORD* pVTable = *reinterpret_cast<DWORD**>(Device);

            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());

            EndScene_orig = (EndScene)pVTable[42];

            DetourAttach(&(LPVOID&)pVTable[42], (PBYTE)EndScene_hook);

            DetourTransactionCommit();
        }
    }

}


void SetupConsole()
{
    AllocConsole();
    freopen("CONOUT$", "wb", stdout);
    freopen("CONOUT$", "wb", stderr);
    freopen("CONIN$", "rb", stdin);
    SetConsoleTitle("CSGOHAX");
}


BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        SetupConsole();
        CreateThread(0, 0, (LPTHREAD_START_ROUTINE)InitHook, 0, 0, NULL);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
#包括“stdafx.h”
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#pragma注释(lib,“Ws2_32.lib”)
#包括
#pragma注释(lib,“d3d9.lib”)
#包括
#pragma注释(lib,“d3dx9.lib”)
#包括
#pragma注释(lib,“detours.lib”)
使用名称空间std;
D3DCOLOR RED=D3DCOLOR_ARGB(255,255,0,0);
typedef HRESULT(u stdcall*EndScene)(IDirect3DDevice9*);
尾声尾声;
HRESULT_uustdcall EndScene_u钩子(IDirect3DDevice9*pDevice)
{
//D3DRECT rec={10010000200};
//pDevice->Clear(1,&rec,D3DCLEAR\u目标,红色,0,0);

//MessageBoxA(0,“我们在这里创建了…2”,“”,0);//我找到了它,在IDA中反转了二进制,找到了模块地址和EndScene函数以及它的地址,计算了偏移量。然后使用ollydbg再次找到函数,从中创建了一个签名,现在我可以使用签名扫描函数动态地找到它

所以我可以用这个签名得到函数地址

DWORD dwEndScene = FindPattern("d3d9.dll",
    "\x6A\x18\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x8B\x7D\x08\x8B\xDF\x8D\x47\x04\xF7\xDB\x1B\xDB\x23\xD8\x89\x5D\xE0\x33\xF6\x89\x75\xE4\x39\x73\x18\x75\x73",
    "xxx????x????xxxxxxxxxxxxxxxxxxxxxxxxxxx");
然后我只是绕道函数

DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
EndScene_orig = (oEndScene)(dwEndScene);
DetourAttach(&(LPVOID&)EndScene_orig, EndScene_hook);

这比我以前使用虚拟设备在V表中查找函数要容易得多。

typedef和hk_Present都应该是stdcall调用约定,但仍然不起作用,我已经尝试了几天来解决这个问题:(看起来需要大量您没有考虑到的参数。可能就是这样。我的问题是,除其他外,我从未使用虚拟设备找到有效地址。导航所有指向V表的指针只是一个头痛的问题。因此我将代码更改为hook EndScene…。我还发现函数,并为函数创建了签名,现在我可以在代码中使用签名扫描函数,在加载d3d9.dll模块后定位地址。