f3mb0y
-
Автор темы
- #1
Всего лишь пример, написанный за 15 минут (очень долго для такого).
Эта тема не новая, но здесь я не видел подобного...
Если вкратце то Valve подменяет некоторые функции для рисовки своего оверлея (и не только ). И мы можем использовать инструменты Valve подмены своих функций.
Из плюсов данной имплементации:
- Можно подменять виртуалки (методы классов) и обычные функции...
Из минусов:
-Не удобный конструктор класса
-Нет поддержки RTTI (но это уже к вальве)
Где это можно использовать?
- В небольших проектах, где нет смысла использовать большие библиотеки.
- В качестве замены "известных" библиотек.
И сразу отвечу на вопрос: "А меня может забанить? Это лучше того что в паблик исходниках?"
- Да, может. Особенно при подмене методов в интерфейсах.
- Не знаю на сколько лучше, но необычно это точно.
И так, код и пример как обычно:
Как использовать? Просто:
Для хука функции по ее адресу:
Для хука функции в виртуальной таблице (метода):
для анхука (возвращение метода) просто используем Unhook().
Всем спасибо, stay tuned
Эта тема не новая, но здесь я не видел подобного...
Если вкратце то Valve подменяет некоторые функции для рисовки своего оверлея (и не только ). И мы можем использовать инструменты 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