首页 > 解决方案 > 有没有办法可靠地分配与先前释放的块相同的内存块,然后访问以前在其中的内容?

问题描述

我有以下 C 程序,它请求一些内存 ( str1),将文件的内容读入该空间,然后释放它。接下来,请求相同大小 ( str2) 的块,并将内容打印到标准输出。

我想要的是str2包含的内容,str1以便输出始终是文件的内容。

我知道我正在做的是未定义的行为,因为我无法保证已分配的内存内容将包含什么。但是,我正在尝试做一些不为人知的事情来进行演示,在该演示中,文件中的数据可以被泄露,而在代码审查中并不明显。

几乎所有时间,我都会在同一地址收到一块内存,用于str1str2,并且大多数时候,当我在 macOS 和 Windows 上运行程序时,会打印文件的内容。它似乎永远不会在 Linux 上发生(在 Linux 上,调用free()似乎将内存块归零)。

有没有办法让它在 Windows 和 macOS 上更可靠,是否有任何解释为什么它在 Linux 上根本不起作用?

我的代码是:

#include <stdlib.h>
#include <stdio.h>

int main() {
  FILE *file = fopen("data.txt", "r");
  char *str1 = malloc(4096*sizeof(char));
  fread(str1, 1, 4096, f);
  free(str1);
  
  char *str2 = malloc(4096);
  printf("Content: %s\n", str2);
  free(str2);
}

标签: cmallocdynamic-memory-allocationfreeundefined-behavior

解决方案


本质上,当你分配和释放时发生的事情对你来说是一个黑匣子。绝对没有可靠的方法来获得相同的地址。调用free意味着您告诉操作系统您已完成内存处理,并且无法撤消此操作。

我想要的是 str2 包含 str1 的内容,以便输出始终是文件的内容。

你在这里基本上有三个选择。

  1. 等待呼叫free
  2. 在调用之前复制缓冲区free
  3. 编写你自己的实现mallocfree

来自评论:

想象一下,我要分配一些内存,然后将一些敏感的东西(例如私钥)读入那个块并用它做一些事情。后来,我分配了一些相同大小的内存并将一些数据粘贴到其中,这些数据将保存到一个文件中。如果我不覆盖块中的所有数据,那么它可能包含一些将保存到文件中的敏感信息。在这种情况下,从代码审查中可能不会明显看出某些敏感数据泄露是可能的。我想证明敏感数据可以以不明显的方式被泄露。

好东西,但这些漏洞几乎总是依赖于未定义的行为。正如您自己所说,这是一个安全问题。因此,提供一种可靠的方法来做到这一点真的没有意义。

这是一个在 Fedora Linux 上为我工作的片段。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void) {
    char *s = malloc(100);
    const char str[] = "Hello, World. Prepare to meet your doom.";
    strcpy(s, str);
    free(s);
    for(int i=0; i<strlen(str); i++) 
        putchar(s[i]);
    puts("");
}

我的输出:

$ ./a.out 
��epare to meet your doom.

如您所见,我得到了部分数据,但不是全部。为了演示这种未定义的行为,这里有不同优化的输出:

$ gcc k.c -O1
$ ./a.out 
0Separe to meet your doom.
$ gcc k.c -O2
$ ./a.out 
@�
$ gcc k.c -O3
$ ./a.out 
�

您的方法对此非常不可靠,因为您将打印到字符串中的第一个 0。这是不会输出任何内容的代码,它可以欺骗您数据已被擦除。这就是我putchar在上面的循环中使用的原因。

char str[] = "Hello, World";
str[0] = '\0';
printf("%s", str); // Will print nothing, but only first character is wiped

推荐阅读