【问题标题】:Is it possible to change any func pointer in vtable?是否可以更改 vtable 中的任何 func 指针?
【发布时间】: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


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 2021-07-18
    • 2021-01-07
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多