Гайд [ASI] Хукаем d3d9

CleanLegend

Известный
Автор темы
Всефорумный модератор
476
928
Привет. Сегодня разберем как хукать d3d9 для рисования квадратов или своего меню.​

Что нам нужно хукануть для полноценного рисования?
- Present/EndScene (Вывод на экран информации)
- Reset (Перезагрузка интерфейса)

Подключаем заголовки:
C++:
#include <Windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

Создаем прототип и экземпляр:
C++:
typedef HRESULT(WINAPI* _EndScene)(IDirect3DDevice9*); //прототип
_EndScene oEndScene; //экземпляр прототипа, для возврата оригинала

typedef HRESULT(WINAPI* _Reset)(IDirect3DDevice9*, D3DPRESENT_PARAMETERS*);
_Reset oReset;

Функции подмены:
C++:
HRESULT WINAPI myEndScene(IDirect3DDevice9* m_pDevice)
{
    return oEndScene(m_pDevice); // возврат оригинала
}
HRESULT WINAPI myReset(IDirect3DDevice9* m_pDevice, D3DPRESENT_PARAMETERS *pPresentationParameters)
{
    auto  result = oReset(m_pDevice, pPresentationParameters);
    return result;
}
Функция хука:
C++:
void InitHook()
{
    void** vTableDevice = *(void***)(*(DWORD*)0xC97C28); // адрес Device
    VMTHookManager* vmtHooks = new VMTHookManager(vTableDevice); 
    oEndScene = (_EndScene)vmtHooks->Hook(42, (void*)myEndScene);  // 42 - номер EndScene
    oReset = (_Reset)vmtHooks->Hook(16, (void*)myReset);// 16 - номер Reset
}
В точке входа создаем поток и в нем вызываем хук:
C++:
int WINAPI Thread()
{
    while (*(DWORD*)0xC8D4C0 != 9) // проверка на статус загрузки игры
        Sleep(100);
    InitHook();
    return 0;
}

BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
        CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Thread, NULL, NULL, NULL);
    return TRUE;
}
Пример для тестирования:
C++:
void DrawRect(LPDIRECT3DDEVICE9 m_pDevice, int X, int Y, int L, int H, D3DCOLOR color)
{
    D3DRECT rect = { X, Y, X + L, Y + H };
    m_pDevice->Clear(1, &rect, D3DCLEAR_TARGET, color, 0, 0);
}
HRESULT WINAPI myEndScene(IDirect3DDevice9* m_pDevice)
{
    DrawRect(m_pDevice, 250, 250, 10, 10, 0xFFFF0000);
    return oEndScene(m_pDevice);
}
Получаем:
qAEN8Gn.png


Класс VMTHookManager
C++:
VMTHookManager::VMTHookManager(void** vTable) : m_vTable(vTable)
{
    m_numberFuncs = GetNumberOfFunctions(); //getting the number of virtual functions
    m_originalFuncs = new void*[m_numberFuncs]; // allocating memory so we can save here the addresses of the original functions
    for (unsigned short i = 0; i < m_numberFuncs; i++) //loop to fill our array with the original addresses
    {
        m_originalFuncs[i] = GetFunctionAddyByIndex(i); // saving the address of the original functions
    }
}

VMTHookManager::~VMTHookManager()
{
    UnhookAll(); //unhooking all the functions
    delete[] m_originalFuncs; //we need to free the allocated memory
}

void* VMTHookManager::GetFunctionAddyByIndex(unsigned short index)
{
    if (index < m_numberFuncs) //check if the index is in the range of the vtable
    {
        return m_vTable[index]; //return the address
    }
    return nullptr; //if not, return nullptr
}

void* VMTHookManager::Hook(unsigned short index, void* ourFunction)
{
    uintptr_t bufferOriginalFunc = NULL; //buffer to store the address
    if (!toHook(index, true, ourFunction, &bufferOriginalFunc)) //checking if it failed
    {
        return nullptr; //didn't work, return nullptr
    }
    return reinterpret_cast<void*>(bufferOriginalFunc); //worked, return the original address
}

bool VMTHookManager::Unhook(unsigned short index)
{
    if (!toHook(index))// checking if it failed
    {
        return false; // return false, didn't work
    }
    return true; // return true, worked
}

void VMTHookManager::UnhookAll()
{
    for (int index = 0; index < m_numberFuncs; index++) //loop to unhook all the functions
    {
        if (m_vTable[index] == m_originalFuncs[index]) //checking if the function isn't hooked
        {
            continue; //if not hooked skip this index
        }
        Unhook(index); //unhook
    }
}

unsigned short VMTHookManager::GetNumberOfFunctions() //private function
{
    unsigned short index = 0; //index
    MEMORY_BASIC_INFORMATION mbiBuffer = { 0 }; //buffer to store the information of some memory region
    while (true)
    {
        if (!m_vTable[index]) //if vtable[index] is null
        {
            break; //exit loop
        }
        if (!VirtualQuery(m_vTable[index], &mbiBuffer, sizeof(mbiBuffer))) //if VirtualQuery failed
        {
            break; //exit loop
        }
#define CAN_EXECUTE (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)
        if ((mbiBuffer.State != MEM_COMMIT) || (mbiBuffer.Protect & (PAGE_GUARD | PAGE_NOACCESS)) || !(mbiBuffer.Protect & CAN_EXECUTE)) //if the region isn't commited and/or executable
        {
            break; //exit loop
        }
        ++index;
    }
    return index;
}

bool VMTHookManager::toHook(unsigned short index, bool hook, void* ourFunction, uintptr_t* bufferOriginalFunc)
{
    DWORD OldProtection = NULL; //it will save the protection here
    if (index < m_numberFuncs)
    {
        VirtualProtect(m_vTable + index, 0x4, PAGE_EXECUTE_READWRITE, &OldProtection);//changing the protection
        if (hook)
        {
            if (!ourFunction || !bufferOriginalFunc)
            {
                VirtualProtect(m_vTable + index, 0x4, OldProtection, &OldProtection); //restore original protection and return
                return false;
            }
            *bufferOriginalFunc = (uintptr_t)m_vTable[index]; // saving the original address in our buffer so we can call the function
            m_vTable[index] = ourFunction; //change the address to our function
            VirtualProtect(m_vTable + index, 0x4, OldProtection, &OldProtection); //restore protection
            return true;
        }
        else
        {
            m_vTable[index] = m_originalFuncs[index]; //copy the original address to the vtable[index]
            VirtualProtect(m_vTable + index, 0x4, OldProtection, &OldProtection); // restore protection
            return true;
        }
    }
    return false;
}
C++:
class VMTHookManager
{
public:
    VMTHookManager(void** vTable); //constructor
    ~VMTHookManager(); //destructor
    void* GetFunctionAddyByIndex(unsigned short index);// getting the address of a function in the vtable by index
    void* Hook(unsigned short index, void* ourFunction); // hooking the virtual function by index
    bool Unhook(unsigned short index); // unhooking the virtual function by index
    void UnhookAll(); //unhook all the functions

private:
    //member variables
    void** m_vTable; // the vtable of some object
    unsigned short m_numberFuncs; // number of virtual functions
    void** m_originalFuncs = nullptr; // we'll save the original addresses here

    unsigned short GetNumberOfFunctions(); //get the number of virtual functions
    bool toHook(unsigned short index, bool hook = false, void* ourFunction = nullptr, uintptr_t* bufferOriginalFunc = nullptr); //function used to hook/unhook
};
 

rraggerr

проверенный какой-то
1,626
846
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Present:

C++:
typedef HRESULT(WINAPI* _Present)(IDirect3DDevice9* , const RECT *, const RECT *, HWND , const RGNDATA *); //прототип
_Present oPresent; //экземпляр прототипа, для возврата оригинала

HRESULT WINAPI hooked_Present(IDirect3DDevice9* pDevice, const RECT *pSourceRect, const RECT *pDestRect, HWND hdest, const RGNDATA *pDirtyRegion)
{

     return oPresent(pDevice, pSourceRect, pDestRect, hdest, RGNDATA, pDirtyRegion); // возврат оригинала
}


oPresent = (_Present)vmtHooks->Hook(17, (void*)hooked_Present);
 
Последнее редактирование модератором:

deropleat

Известный
105
56
Немного другой хук, который не требует очистки девайса под итог.

VMTHook.h
C++:
#pragma once

#include <cstdint>
#include <cstddef>
#include <cstring>
#include <memory>

class VMTHook
{
private:
    std::uintptr_t** BaseClass = nullptr;
    std::unique_ptr<std::uintptr_t[]> CurrentVTF = nullptr;
    std::uintptr_t* OriginalVTF = nullptr;
    std::size_t TotalFuncs = 0;
public:
    VMTHook(void) = default;
    VMTHook(void* BaseClass)
    {
        this->BaseClass = static_cast<std::uintptr_t**>(BaseClass);
        while (static_cast<std::uintptr_t*>(*this->BaseClass)[this->TotalFuncs])++this->TotalFuncs;
        const std::size_t TableSize = this->TotalFuncs * sizeof(std::uintptr_t);
        this->OriginalVTF = *this->BaseClass;
        this->CurrentVTF = std::make_unique<std::uintptr_t[]>(this->TotalFuncs);
        std::memcpy(this->CurrentVTF.get(), this->OriginalVTF, TableSize);
        *this->BaseClass = this->CurrentVTF.get();
    };
    ~VMTHook()
    {
        *this->BaseClass = this->OriginalVTF;
    };
    template <typename Fn = void*> inline const Fn GetOrigIndex(std::size_t FunctionIndex)
    {
        return reinterpret_cast<Fn>(this->OriginalVTF[FunctionIndex]);
    }
    inline bool TableIndexHook(void* new_function, const std::size_t FunctionIndex)
    {
        if (FunctionIndex > this->TotalFuncs) return false;
        this->CurrentVTF[FunctionIndex] = reinterpret_cast<std::uintptr_t>(new_function);
        return true;
    }
    inline bool TableIndexUnHook(const std::size_t FunctionIndex)
    {
        if (FunctionIndex > this->TotalFuncs) return false;
        this->CurrentVTF[FunctionIndex] = this->OriginalVTF[FunctionIndex];
        return true;
    }
    inline std::size_t GetMaxIndex()
    {
        return this->TotalFuncs;
    }
};

Hooks.cpp
C++:
using PresentFn = long(__stdcall*)(IDirect3DDevice9*, const RECT*, const RECT*, HWND, const RGNDATA*);

long __stdcall g_pHooks::Present(IDirect3DDevice9* pDevice, const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion)
{
    static auto OriginalFunc = MyDevice->GetOrigIndex<PresentFn>(17);

    if (!init) g_pRender->Init(pDevice, init);
    g_pRender->PaintBegin();
    g_pRender->SizeReset();
    pDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, false);
    g_pMenu->MyDevice = pDevice;
    g_pMenu->Update();

    return OriginalFunc(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}

Render.cpp
C++:
void CRender::Line(int sX, int sY, int eX, int eY, D3DCOLOR D3DCOLOR)
{
    vertex pVertex[2] = { { sX, sY, 0.0f, 1.0f, D3DCOLOR }, { eX, eY, 0.0f, 1.0f, D3DCOLOR } };
    MyDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
    MyDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
    MyDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
    MyDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    MyDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    MyDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    MyDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    MyDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
    MyDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
    MyDevice->SetTexture(0, NULL);
    MyDevice->SetPixelShader(NULL);
    MyDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
    MyDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, &pVertex, sizeof(vertex));
}

48BRHEEGO_4.jpg
 
У

Удалённый пользователь 123482

Гость
Без MoonLoader'a не работает :/
 

loganhackerdff

Известный
868
517
Если я сделаю через хук, на фрапсе будет видно? дарк говорит что если хукать то не будет
 

deropleat

Известный
105
56
Немного другой хук, который не требует очистки девайса под итог.

VMTHook.h
C++:
#pragma once

#include <cstdint>
#include <cstddef>
#include <cstring>
#include <memory>

class VMTHook
{
private:
    std::uintptr_t** BaseClass = nullptr;
    std::unique_ptr<std::uintptr_t[]> CurrentVTF = nullptr;
    std::uintptr_t* OriginalVTF = nullptr;
    std::size_t TotalFuncs = 0;
public:
    VMTHook(void) = default;
    VMTHook(void* BaseClass)
    {
        this->BaseClass = static_cast<std::uintptr_t**>(BaseClass);
        while (static_cast<std::uintptr_t*>(*this->BaseClass)[this->TotalFuncs])++this->TotalFuncs;
        const std::size_t TableSize = this->TotalFuncs * sizeof(std::uintptr_t);
        this->OriginalVTF = *this->BaseClass;
        this->CurrentVTF = std::make_unique<std::uintptr_t[]>(this->TotalFuncs);
        std::memcpy(this->CurrentVTF.get(), this->OriginalVTF, TableSize);
        *this->BaseClass = this->CurrentVTF.get();
    };
    ~VMTHook()
    {
        *this->BaseClass = this->OriginalVTF;
    };
    template <typename Fn = void*> inline const Fn GetOrigIndex(std::size_t FunctionIndex)
    {
        return reinterpret_cast<Fn>(this->OriginalVTF[FunctionIndex]);
    }
    inline bool TableIndexHook(void* new_function, const std::size_t FunctionIndex)
    {
        if (FunctionIndex > this->TotalFuncs) return false;
        this->CurrentVTF[FunctionIndex] = reinterpret_cast<std::uintptr_t>(new_function);
        return true;
    }
    inline bool TableIndexUnHook(const std::size_t FunctionIndex)
    {
        if (FunctionIndex > this->TotalFuncs) return false;
        this->CurrentVTF[FunctionIndex] = this->OriginalVTF[FunctionIndex];
        return true;
    }
    inline std::size_t GetMaxIndex()
    {
        return this->TotalFuncs;
    }
};

Hooks.cpp
C++:
using PresentFn = long(__stdcall*)(IDirect3DDevice9*, const RECT*, const RECT*, HWND, const RGNDATA*);

long __stdcall g_pHooks::Present(IDirect3DDevice9* pDevice, const RECT* pSourceRect, const RECT* pDestRect, HWND hDestWindowOverride, const RGNDATA* pDirtyRegion)
{
    static auto OriginalFunc = MyDevice->GetOrigIndex<PresentFn>(17);

    if (!init) g_pRender->Init(pDevice, init);
    g_pRender->PaintBegin();
    g_pRender->SizeReset();
    pDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, false);
    g_pMenu->MyDevice = pDevice;
    g_pMenu->Update();

    return OriginalFunc(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}

Render.cpp
C++:
void CRender::Line(int sX, int sY, int eX, int eY, D3DCOLOR D3DCOLOR)
{
    vertex pVertex[2] = { { sX, sY, 0.0f, 1.0f, D3DCOLOR }, { eX, eY, 0.0f, 1.0f, D3DCOLOR } };
    MyDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
    MyDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
    MyDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
    MyDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    MyDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    MyDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    MyDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    MyDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
    MyDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
    MyDevice->SetTexture(0, NULL);
    MyDevice->SetPixelShader(NULL);
    MyDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
    MyDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, &pVertex, sizeof(vertex));
}

48BRHEEGO_4.jpg
Решил недавно возобновить свой проект этого рода и стокнулся как раз с проблемой которая изображена на скриншоте - меню рисуется под чатом. Возможно то, что большинство в курсе решения данной проблемы, но все-таки считаю нужным поделиться, мало ли.

Эта проблема возникает исключительно в том случае, если меню было внедрено в игру после прохождения загрузочного окна GTA. Если внедрить в момент самой загрузки, то подобного бага не будет.
Если я сделаю через хук, на фрапсе будет видно? дарк говорит что если хукать то не будет
Насколько я знаю, то это зависит от того, что ты будешь хукать.
  • EndScene - не обходит OBS.
  • Present - обходит OBS.
Однако оба хука будут видны на скриншотах. Не проверял на самом деле подлинность информации, но в некоторых играх это действительно так, и думаю, что гташка - не исключение.
Без MoonLoader'a не работает :/
Если в чите присутствуют функции связанные с данной библиотекой - тогда все ясно. Если же ты говоришь конкретно про меню (чистое, без любого СДК) - то такого быть не может. Рисуя подобным образом ты используешь лишь стандартный набор функций директа, которые автоматически доступны за счет использования d3d9 игрой.

И если ты используешь данную библиотеку, то лучше откажись от неё. Для подобного рода читов более уместно будет использовать СДК от собейта. Однако, все зависит от того, какую цель ты ставишь на свой проект. Выпустить чит независящий от чего-либо (СДК собейта) или же аналог каким-то асишкам, сфшкам итп (с СФ, МЛ).
 
Последнее редактирование:

Dheyker

Новичок
14
0
What's wrong? the square is not drawn on the screen
C++:
#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS 1

#include <Windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <string>
#include <assert.h>
#include <process.h>
#include <dinput.h>
#include <tchar.h>

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

#include "VMTHookManager.h"

WNDPROC oWndProc;

DWORD g_dwSAMP_Addr;

typedef HRESULT(WINAPI* _EndScene)(IDirect3DDevice9*); //прототип
_EndScene oEndScene; //экземпляр прототипа, для возврата оригинала

typedef HRESULT(WINAPI* _Present)(IDirect3DDevice9*, const RECT*, const RECT*, HWND, const RGNDATA*); //прототип
_Present oPresent; //экземпляр прототипа, для возврата оригинала

typedef HRESULT(WINAPI* _Reset)(IDirect3DDevice9*, D3DPRESENT_PARAMETERS*);
_Reset oReset;

void DrawRect(LPDIRECT3DDEVICE9 m_pDevice, int X, int Y, int L, int H, D3DCOLOR color)
{
    D3DRECT rect = { X, Y, X + L, Y + H };
    m_pDevice->Clear(1, &rect, D3DCLEAR_TARGET, color, 0, 0);
}

HRESULT WINAPI hooked_Present(IDirect3DDevice9* pDevice, const RECT* pSourceRect, const RECT* pDestRect, HWND hdest, const RGNDATA* pDirtyRegion)
{
    DrawRect(pDevice, 250, 250, 10, 10, 0xFFFF0000);
    return oPresent(pDevice, pSourceRect, pDestRect, hdest, pDirtyRegion); // возврат оригинала
}

HRESULT WINAPI myEndScene(IDirect3DDevice9* m_pDevice)
{
    return oEndScene(m_pDevice);
}

HRESULT WINAPI myReset(IDirect3DDevice9* m_pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters)
{
    auto  result = oReset(m_pDevice, pPresentationParameters);
    return result;
}

void InitHook()
{
    void** vTableDevice = *(void***)(*(DWORD*)0xC97C28); // адрес Device
    VMTHookManager* vmtHooks = new VMTHookManager(vTableDevice);
    oPresent = (_Present)vmtHooks->Hook(17, (void*)hooked_Present);
    oEndScene = (_EndScene)vmtHooks->Hook(42, (void*)myEndScene);  // 42 - номер EndScene
    oReset = (_Reset)vmtHooks->Hook(16, (void*)myReset);// 16 - номер Reset
}

int WINAPI Thread()
{
    while (*(DWORD*)0xC8D4C0 != 9) // проверка на статус загрузки игры
        Sleep(100);
    InitHook();
    return 0;
}

BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
        CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Thread, NULL, NULL, NULL);
    return TRUE;
}