已阅读this interesting article在概述调试堆损坏的技术时,我开始想知道如何根据自己的需要调整它。基本思想是提供一个自定义的 malloc() 来分配整页内存,然后为这些页面启用一些内存保护位,以便程序在写入时崩溃,并且可以在行为中捕获有问题的写指令.示例代码是Linux下的C(mprotect()用于开启保护),我很好奇如何将其应用于原生C++和Windows。 VirtualAlloc() 和/或 VirtualProtect() 看起来很有前途,但我不确定使用场景会是什么样子。
Fred *p = new Fred[100];
ProtectBuffer(p);
p[10] = Fred(); // like this to crash please
我知道在 Windows 中存在用于调试内存损坏的专门工具,但我仍然很好奇是否可以使用这种方法“手动”执行此操作。
编辑:此外,这在 Windows 下是个好主意,还是只是一种有趣的智力练习?
最佳答案
是的,您可以使用 VirtualAlloc 和 VirtualProtect 设置内存部分以防止读/写操作。
您将不得不重新实现 operator new
和 operator delete
(以及它们的 [] 亲戚),以便您的内存分配由您的代码控制。
请记住,它只会以每页为基础,每次分配您将使用(至少)三页值(value)的虚拟内存 - 在 64 位系统上不是一个大问题,但可能如果您在 32 位系统中有很多分配,则会导致问题。
大致需要做的事情(您实际上应该找到构建 Windows 的页面大小 - 我太懒了,所以我将使用 4096 和 4095 来表示页面大小和页面大小-1 - 你还需要比这段代码做更多的错误检查!!!):
void *operator new(size_t size)
{
Round size up to size in pages + 2 pages extra.
size_t bigsize = (size + 2*4096 + 4095) & ~4095;
// Make a reservation of "size" bytes.
void *addr = VirtualAlloc(NULL, bigsize, PAGE_NOACCESS, MEM_RESERVE);
addr = reinterpret_cast<void *>(reinterpret_cast<char *>(addr) + 4096);
void *new_addr = VirtualAlloc(addr, size, PAGE_READWRITE, MEM_COMMIT);
return new_addr;
}
void operator delete(void *ptr)
{
char *tmp = reinterpret_cast<char *>(ptr) - 4096;
VirtualFree(reinterpret_cast<void*>(tmp));
}
正如我所说的那样——我没有尝试编译这段代码,因为我只有一个 Windows 虚拟机,而且我懒得下载编译器并查看它是否真的编译。 [我知道这个原理是有效的,因为我们在几年前的工作中做过类似的事情]。
关于c++ - 是否可以保护内存区域免受 WinAPI 的影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14595989/