这是一个学术问题。我做了一个宏来调用并通过vtable获得指向虚拟函数的指针。但是更改vfunc地址变量会导致内存损坏。
因此,事实证明该存储区受到了保护吗?

它的经典实现。我对64位程序使用GCC(MinGW),编译器在该对象的第一个隐藏字段处添加了指向其类的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;
}

最佳答案

Vtables和常量一样,都是以只读方式加载和映射的。一个vtable永远都不会被修改。

为此,您可能需要更改加载和映射的方式,可能是通过更改程序集或目标代码以将该节标记为可读写,或者在启动后在运行时进行另一次映射(我不知道是否甚至可行)。

关于c++ - 是否可以在vtable中更改任何func指针?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60913089/

10-12 04:02