Гайд Подмена (хук) функций в игре силами GameOverlayRenderer

f3mb0y
Участник
Статус
Оффлайн
Регистрация
14 Фев 2017
Сообщения
625
Реакции[?]
291
Поинты[?]
1K
Всего лишь пример, написанный за 15 минут (очень долго для такого).
Эта тема не новая, но здесь я не видел подобного...
Если вкратце то Valve подменяет некоторые функции для рисовки своего оверлея (и не только :roflanEbalo:). И мы можем использовать инструменты Valve подмены своих функций.

Из плюсов данной имплементации:
- Можно подменять виртуалки (методы классов) и обычные функции...

Из минусов:
-Не удобный конструктор класса
-Нет поддержки RTTI (но это уже к вальве)

Где это можно использовать?
- В небольших проектах, где нет смысла использовать большие библиотеки.
- В качестве замены "известных" библиотек.

И сразу отвечу на вопрос: "А меня может забанить? Это лучше того что в паблик исходниках?"
- Да, может. Особенно при подмене методов в интерфейсах.
- Не знаю на сколько лучше, но необычно это точно.

И так, код и пример как обычно:
C++:
template<typename T>
class CValveHook
{
public:
    CValveHook(DWORD Address) :
        m_Address((DWORD_PTR)Address)
    {
        // Конструктор
    }

    CValveHook(PVOID Address) :
        m_Address((DWORD_PTR)Address)
    {
        // Конструктор
    }

    ~CValveHook() // Деструктор
    {
        this->Unhook();
        this->m_Trampoline = nullptr;
        this->m_Address = 0x0;
    }

    void Hook(PVOID Detour)
    {
        this->m_Trampoline = this->HookFunc((PVOID)this->m_Address, Detour);
       
        if (this->m_Trampoline)
        {
                // Успешно подменили (хукнули) функцию
        }
    }

    void HookMethod(PVOID Detour, int index) // Подменяем виртуальный метод
    {
        PVOID* Instance = *(PVOID**)this->m_Address;
       
        this->m_Trampoline = this->HookFunc(Instance[index], Detour);
    }

    T GetTrampoline() //получаем "оригинал" функции
    {
    if (!this->m_Trampoline)
        return T{ }; // Что то пошло не так, например забыли вызвать Hook...
       
        return (T)this->m_Trampoline;
    }

    void Unhook() // Снимаем хук...
    {
        this->UnhookFunc((PVOID)this->m_Address);
    }
       
private:
    PVOID HookFunc(PVOID Target, PVOID Detour)
    {
        using Fn = void*(__cdecl*)(void*, void*, int);

        static Fn SteamHookMethodFn = nullptr;
        if (!SteamHookMethodFn)
        {
            SteamHookMethodFn = MemoryAPI::FindPattern(Images::GameOverlay, VMPDecryptStringA("55 8B ? 83 ? ? 53 56 FF ? ? 8D ? ? C7")).cast<Fn>();
            LOG("SteamHookMethodFn: 0x%X", (DWORD)SteamHookMethodFn);
        }
        return SteamHookMethodFn(Target, Detour, NULL);
    }

    void UnhookFunc(PVOID Target)
    {
        using Fn = void(__cdecl*)(void*, bool); //void*, char

        static Fn SteamUnhookMethodFn = nullptr;

        if (!SteamUnhookMethodFn)
        {
            SteamUnhookMethodFn = MemoryAPI::FindPattern(Images::GameOverlay, VMPDecryptStringA("55 8B ? 64 ? ? ? ? ? 6A ? 68 ? ? ? ? 50 64 ? ? ? ? ? ? 81 ? ? ? ? ? 56 8B ? ? 85")).cast<Fn>();
            LOG("SteamUnhookMethodFn: 0x%X", (DWORD)SteamUnhookMethodFn);
        }

        SteamUnhookMethodFn(Target, NULL);
    }

    DWORD_PTR m_Address = 0x0;
    PVOID m_Trampoline = nullptr;
};
Как использовать? Просто:

Для хука функции по ее адресу:

C++:
// Создаем экземпляр
using EquipItemInLoadoutFn = bool(__thiscall*)(PVOID, int, int, uint64_t);
CValveHook<EquipItemInLoadoutFn>* pValveHook = nullptr;

// В инициализации хака

// Это адрес нашей функции
pValveHook = new CValveHook<EquipItemInLoadoutFn>(pOffset->CSInventoryManager.EquipItemInLoadout.cast<PVOID>());

// Подменяем (хукаем)
pValveHook->Hook((PVOID)hookEquipItemInLoadout);
Для хука функции в виртуальной таблице (метода):

C++:
// Так же создаем экземпляр
using EquipItemInLoadoutFn = bool(__thiscall*)(PVOID, int, int, uint64_t);
CValveHook<EquipItemInLoadoutFn>* pValveHook = nullptr;

// В инициализации

// Но тут уже указатель на таблицу (поинтер)
pValveHook = new CValveHook<EquipItemInLoadoutFn>(Extended::pCSInventoryManager);

// Хукаем
pValveHook->HookMethod((PVOID)hookEquipItemInLoadout, 20);

// Как видим тут уже добавился индекс (позиция нашей функции в таблице)

для анхука (возвращение метода) просто используем Unhook().

Всем спасибо, stay tuned
 
Сверху Снизу