Можно ли изменить любой забавный указатель c в vtable? - PullRequest
1 голос
/ 29 марта 2020

Это академический c вопрос. Я сделал макрос для вызова и получения указателя на виртуальную функцию через виртуальную таблицу. Но изменение адресной переменной vfun c приводит к повреждению памяти. Так получается, что эта область памяти защищена от эксплойтов?

Ее класс c реализация. Я использую G CC (MinGW) для 64-битных программ, компилятор добавляет указатель на vtable (массив) своего класса в первом скрытом поле объекта.

#define VTABLE_CALL(FUNC_TYPE, OBJECT, OFFSET, ...) \
    ((FUNC_TYPE)(*((size_t**)&(OBJECT))[(OFFSET)]))(__VA_ARGS__)

#define VTABLE_GET(OBJECT, OFFSET) \
    ((void*)((*(size_t**)&(OBJECT))[(OFFSET)]))

#define VTABLE_SET(OBJECT, OFFSET, NEW_FUNC_P) \
((*((size_t***)&(OBJECT))[(OFFSET)]) = (size_t*)(NEW_FUNC_P))

Итак, этот код дает SegFault

class A {
virtual void foo(void) { printf("Test\n"); }
};

int main()
{
    typedef void (*VMethod) (void*); // void* for "this"

    A a; // our object with first hidden vTablePtr;
    VMethod vm;

    VTABLE_CALL(VMethod, a, 0, &a); // call A::foo

    vm = (VMethod) VTABLE_GET(a, 0);
    vm(&a); // call again A::foo

    /* replace the pointer to ourselves */
    VTABLE_SET(a, 0, vm); // segmentation fault

    /* foot shot completed */
    return 0;
}

1 Ответ

3 голосов
/ 03 апреля 2020

Vtables, как и константы, загружаются и отображаются только для чтения. Vtable никогда не должен изменяться.

Чтобы сделать это, вам нужно изменить способ загрузки и отображения, возможно, изменив сборку или объектный код, чтобы отметить раздел для чтения-записи, или сделать другое сопоставление во время выполнения после запуска (я не знаю, возможно ли это вообще).

...