gpt4 book ai didi

C++ 转换为 base 和 "overwriting"vptr 问题

转载 作者:可可西里 更新时间:2023-11-01 10:24:29 25 4
gpt4 key购买 nike

我刚刚阅读了一个新的 C++ 挑战: http://blogs.msdn.com/b/vcblog/archive/2014/02/04/challenge-vulnerable-code.aspx

提供的代码如果充满问题,有些对任何有良好编程习惯的人来说都是显而易见的,有些只有 C++ 本地人才能看到 :-)

评论中描述了特定行 (37) 特别危险:

ImageFactory::DebugPrintDimensions((ImageFactory::CustomImage*)image);

然后该函数调用 CustomImage 的虚方法(在 CustomImage 中首次定义)。

这据称导致 CustomImage 的第一个成员被视为实例的 vptr(实际上它是一个 unique_ptr)并使它指向的二进制文件被视为可执行文件(可能是恶意的)代码..

虽然我能理解这一点,但我想知道为什么这真的有效。

CustomImage 是一个虚拟类,所以(可能)它的前 4 个字节(假设 X86)是 THE vptr,unique_ptr 成员是下一个。类型转换似乎没有改变任何东西......

...如何执行 unique_ptr 持有的数据?

最佳答案

我的看法(我很高兴得到纠正):

这里,CustomImage 是一个多态类(在 Windows ABI 下有一个 vptr 作为第一个“成员”),但 Image 不是。定义的顺序意味着 ImageFactory 函数知道 CustomImage 是一个 Image,但是 main () 没有。

所以当工厂做的时候:

Image* ImageFactory::LoadFromDisk(const char* imageName)
{
return new (std::nothrow) CustomImage(imageName);
}

CustomImage* 指针被转换为 Image*,一切正常。因为 Image 不是多态的,指针被调整为指向 CustomImage 中的 (POD) Image 实例——但重要的是,这是 vptr 之后,因为它总是在 MS ABI 的多态类中排在第一位(我假设)。

然而,当我们到达

ImageFactory::DebugPrintDimensions((ImageFactory::CustomImage*)image);

编译器看到从一个它一无所知的类到另一个类的 C 风格转换。它所做的只是获取它拥有的地址并假装它是一个 CustomImage*。该地址实际上指向自定义图像中的 Image;但是因为 Image 是空的,并且大概是空基类优化生效了,所以它最终指向 CustomImage 中的第一个成员,即 unique_ptr.

现在,ImageFactory::DebugPrintDimensions() 假定已将一个指向完全完整的 CustomImage 的指针传递给它,因此地址等于 vptr。但它并没有——它被交给了 unique_ptr 的地址,因为在它被调用的时候,编译器并不知道更多。所以现在它取消引用它认为是 vptr 的东西(我们真正控制的数据),寻找虚函数的偏移量并盲目地执行它——现在我们有麻烦了。

有几件事可以帮助缓解这种情况。首先,由于我们通过基类指针操作派生类,Image 应该有一个虚拟析构函数。这将使 Image 成为多态的,而且很可能我们不会遇到问题(我们也不会泄漏内存)。

其次,因为我们是从基到派生进行转换,所以应该使用 dynamic_cast 而不是 C 风格的转换,后者会涉及运行时检查和正确的指针调整。

最后,如果编译器在编译 main() 时掌握了所有信息,它可能能够警告我们(或正确执行转换,针对 的多态性质进行调整>自定义图片)。因此,也建议将类定义移动到 main() 之上。

关于C++ 转换为 base 和 "overwriting"vptr 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21595943/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com