Подведи собственные итоги года совместно с YOUGAME и забери ценные призы! Перейти

Что такое VMT

Пользователь
Пользователь
Статус
Оффлайн
Регистрация
24 Июл 2018
Сообщения
721
Реакции
78
кто может популярно объяснить новичку что такое virtual method tables (vmt) и в чём его суть
Как оно используется в создании читов?
 
метод хука.
Пожалуйста, авторизуйтесь для просмотра ссылки.
насколько я знаю vmt это не метод хука
метод хука это vmt hooking
я же спрашиваю что такое vmt просто напросто и всё
я не могу просто начать хукать через него мне просто нужно понять что это такое
 
популярно объяснить новичку

Это результат использования virtual в C++, такой префикс ставится перед функциями, когда ты хочешь указать что они виртуальные.

Применение очень простое, обычно чтобы вызвать какой-то метод класса, тебе точно нужно знать какого типа этот объект на этапе компиляции, но виртуальные функции позволяют тебе реализовать абстрактный интерфейс, т.е. есть базовый класс который описывает что есть некие функции, но как они будут реализованы зависит от конечного класса, который может их переопределять.

При этом ты можешь работать с объектом как с абстрактным классом, не зная деталей его реализации, а вызываться будут именно методы конечных классов.


Теперь о том что такое VMT, это то, как этот механизм реализован в бинарном виде.

Попросту для каждого класса с виртуальными методами содержится таблица их адресов в секции константных данных.

Затем при создании объекта в самое начало данных записывается указатель на эту таблицу.

При вызове виртуального метода, компилятор именно подставит чтение адреса из вирт. таблицы, а не конкретный адрес в бинаре.

Это часто используется в играх, в CS GO в том числе.

Некоторое время хук вирт. таблиц был неплохим сложно обнаруживаемым методом хука, т.е. ты просто меняешь адрес вирт таблицы на свою модифицированную копию, и т.к. данные объекта находятся в динамической памяти обнаружить такое невозможно, без знания семантики объекта.

Пример:

Код:
Expand Collapse Copy
class Base
{
public:
    virtual void func1() { printf("base1\n"); }
    virtual void func2() { printf("base2\n"); }
};

class First : public Base // наследует
{
public:
    void func1() override { printf("first1\n"); } // переопределяет
    float val = 0;
};

class Second : public Base // наследует
{
public:
    void func2() override { printf("second2\n"); } // переопределяет
    bool val = false;
};

void Test(Base* obj)
{
    obj->func1();
    obj->func2();
}

Base base;
First first
Second second;
Test(&base);
Послав в Test base напечатается base1 и base2, если first то first1 и base2, а с second уже base1 и second2.
Без virtual методов, всегда бы печаталось base1 и base2, независимо от типа, потому что в параметре выставлен Base* и вызывались бы его методы.
Примерно так это выглядит в бинарном виде:

Код:
Expand Collapse Copy
// вирт таблица Base::vftable
void* Base::func1 // 0000
void* Base::func2 // 0004

// вирт таблица First::vftable
void* First::func1 // 0000
void* Base::func2 // 0004

// вирт таблица Second::vftable
void* Base::func1 // 0000
void* Second::func2 // 0004

// содержимое base
void* vftable; // 0000 указывает на Base::vftable

// содержимое first
void* vftable; // 0000 указывает на First::vftable
float val; // 0004

// содержимое second
void* vftable; // 0000 указывает на Second::vftable
bool val; // 0004
Т.е. при вызове в Test компилятор просто читает vftable + нужное смещение, а без виртуальных методов просто бы подставлял конкретные адреса.
 
Последнее редактирование:
Назад
Сверху Снизу