如何使用MSVC使malloc每次返回相同的地址?
出于调试目的,我希望malloc在每次执行程序时返回相同的地址,但是在MSVC中情况并非如此。 例如:如何使用MSVC使malloc每次返回相同的地址?,c,visual-c++,malloc,C,Visual C++,Malloc,出于调试目的,我希望malloc在每次执行程序时返回相同的地址,但是在MSVC中情况并非如此。 例如: #include <stdlib.h> #include <stdio.h> int main() { int test = 5; printf("Stack: %p\n", &test); printf("Heap: %p\n", malloc(4)); return 0; } …我每次都会得到相同的堆栈地址,但堆地址会更改
#include <stdlib.h>
#include <stdio.h>
int main() {
int test = 5;
printf("Stack: %p\n", &test);
printf("Heap: %p\n", malloc(4));
return 0;
}
…我每次都会得到相同的堆栈地址,但堆地址会更改
我已经尝试添加注册表值HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\MoveImages,但它不起作用。malloc返回的堆栈地址和指针每次都可能不同。事实上,当程序在Mac/OS上多次编译和运行时,两者都不同 编译器和/或操作系统可能会导致这种行为,使利用软件缺陷变得更加困难。在某些情况下,可能有一种方法可以防止这种情况发生,但如果您的目标是重播同一系列malloc地址,则其他因素可能会更改地址,例如时间敏感行为、文件系统副作用,更不用说非确定性线程行为。您应该尽量避免在测试中依赖此选项
还请注意,&test应转换为void*,因为%p需要一个void指针,但不能保证它具有与int*相同的表示形式。事实证明,您可能无法从MSVC运行时库获得确定性行为。C/C++运行库的调试版本和生产版本最终都会调用名为_malloc_base的函数,该函数反过来调用Win32 API函数。不幸的是,无论是HeapAlloc还是提供其堆的函数,都没有记录标志或以其他方式获得确定性行为 正如@Enosh_Cohen所建议的那样,你可以在VirtualAlloc的基础上增加你自己的分配方案,但是你会失去MSVC分配函数提供的功能。建议在VirtualAlloc的基础上创建一个新的malloc,所以我这样做了。事实证明这有点挑战性,因为VirtualAlloc本身不是确定性的,所以我正在记录我使用的过程 首先,抓住。到源的ftp链接已断开;使用 然后,将win32mmap函数替换为此处放入公共域的函数,就像Doug Lea的malloc本身一样:
static void* win32mmap(size_t size) {
/* Where to ask for the next address from VirtualAlloc. */
static char *next_address = (char*)(0x1000000);
/* Return value from VirtualAlloc. */
void *ptr = 0;
/* Number of calls to VirtualAlloc we have made. */
int tries = 0;
while (!ptr && tries < 100) {
ptr = VirtualAlloc(next_address, size,
MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (!ptr) {
/* Perhaps the requested address is already in use. Try again
* after moving the pointer. */
next_address += 0x1000000;
tries++;
}
else {
/* Advance the request boundary. */
next_address += size;
}
}
/* Either we got a non-NULL result, or we exceeded the retry limit
* and are going to return MFAIL. */
return (ptr != 0)? ptr: MFAIL;
}
现在编译生成的malloc.c并将其与程序链接,从而覆盖MSVCRT分配器
有了这个,我现在得到了一致的malloc地址
但要注意:
我使用的确切地址0x1000000是通过枚举我的地址空间来选择的,用于查找一个大的、一致可用的漏洞。即使禁用ASLR,地址空间布局似乎也存在一些不可避免的不确定性。您可能需要调整该值
我确认,在我的特殊情况下,这种方法可以在100次连续运行中获得相同的地址。这对于我想要进行的调试来说已经足够好了,但是在足够多的迭代之后,或者在重新启动之后,这些值可能会改变,等等
此修改不应用于生产代码,仅用于调试。重试限制是一种攻击,我没有做任何事情来跟踪堆何时收缩
这不是malloc的保证行为,也从来没有在任何地方指定过。如果你有其他的要求,你应该考虑使用自己的包装器来满足你的要求。但请记住,只在需要的测试中使用该包装器。您可以在windows中使用VirtualAlloc来分配特定的地址。请参阅以下问题:@Someprogrammerdude虽然确定性返回值不是malloc的保证行为,并且在缺少虚拟内存硬件的系统中可能无法实现,但它是一个对调试有用的属性。同样,这也是伪随机生成器提供种子函数的原因之一。我建议在这个问题中添加windows标记,因为它适用于在windows下运行的所有程序,而不仅仅是那些使用MSVC编译的程序。
static void* win32mmap(size_t size) {
/* Where to ask for the next address from VirtualAlloc. */
static char *next_address = (char*)(0x1000000);
/* Return value from VirtualAlloc. */
void *ptr = 0;
/* Number of calls to VirtualAlloc we have made. */
int tries = 0;
while (!ptr && tries < 100) {
ptr = VirtualAlloc(next_address, size,
MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (!ptr) {
/* Perhaps the requested address is already in use. Try again
* after moving the pointer. */
next_address += 0x1000000;
tries++;
}
else {
/* Advance the request boundary. */
next_address += size;
}
}
/* Either we got a non-NULL result, or we exceeded the retry limit
* and are going to return MFAIL. */
return (ptr != 0)? ptr: MFAIL;
}