【发布时间】:2020-04-03 05:10:32
【问题描述】:
这是一个学术问题。我制作了一个宏来调用并通过 vtable 获取指向虚函数的指针。但是更改 vfunc 地址变量会导致内存损坏。 那么事实证明,这个内存区域是受到保护的?
它的经典实现。我将 GCC (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;
}
【问题讨论】:
-
虚拟表是一个实现细节。没有更多的上下文,这个问题无法回答。请包括minimal reproducible example
-
这是XY problem吗?
-
@theWiseBro 第一句话:“这是一个学术问题”
-
@idclev463035818 是的 vptr/vtable 是人工制品,但实际上所有编译器都使用几乎相同的 impl 策略,至少在简单的情况下(即没有复杂的 MI 层次结构、没有虚拟基础和没有协方差)。
标签: c++ protection vtable