Подпишитесь на наш Telegram-канал, чтобы всегда быть в курсе важных обновлений! Перейти

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

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

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

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

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

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

И так, код и пример как обычно:
C++:
Expand Collapse Copy
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++:
Expand Collapse Copy
// Создаем экземпляр
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++:
Expand Collapse Copy
// Так же создаем экземпляр
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
 
Назад
Сверху Снизу