有没有办法可靠地 malloc 与先前释放的块相同的内存块,然后访问先前在其中的内容?
Is there a way to reliably malloc the same block of memory as a previously freed block, then access the content that was previously in it?
我有以下 C 程序,它请求一些内存 (str1
),将文件内容读入 space 然后释放它。接下来,请求一个相同大小(str2
)的块,并将内容打印到标准输出。
我想要的是 str2
包含 str1
的内容,以便输出始终是文件的内容。
我知道我正在做的是未定义的行为,因为我不能保证已分配的内存内容将包含什么。但是,我正在尝试做一些卑鄙的事情来进行演示,其中文件中的数据可以在代码审查中不明显的情况下被泄露。
几乎所有时间,我在 str1
和 str2
的相同地址收到一块内存,而 大多数时候 当我运行 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);
}
Is there a way to reliably malloc the same block of memory as a previously freed block
是的,使用 realloc
而不是 free
+ malloc
。否则,没有可靠或安全的方法可以在同一地址获得准确的金额。
I receive a block of memory at the same address for both str1 and str2
好吧,这个简单的程序中没有太多其他内容,所以这也许不足为奇。虽然没有保证。此外,除非您实际对堆进行写访问,否则实际上可能不会调用内存分配。所以 str2
可能只是一些随机地址,以防整个 malloc 调用被优化掉。或者,调用 malloc 但 OS 从不分配任何实际内存。
is there any explanation for why it doesn't work at all on Linux?
我不知道,但我怀疑 ASLR 可能与此有关。某些 Linux 专家将不得不回答该部分。
本质上,当你分配和释放时发生的事情对你来说是一个黑盒子。绝对没有可靠的方法来获得相同的地址。调用 free
意味着您告诉 OS 您已完成内存处理,并且无法撤消此操作。
What I want is for str2 to contain the content of str1 so that the output is always the content of the file.
这里基本上有三个选项。
- 等待
free
的呼叫
- 在调用之前复制缓冲区
free
- 编写您自己的
malloc
和 free
实现
来自评论:
imagine that I'm going to allocate some memory then read something sensitive (e.g. a private key) into that block and do something with it. Later, I allocate some memory of the same size and stick some data into it that will be saved to a file. If I don't overwrite all the data in the block then it may contain some sensitive info that would get saved to the file. In that case, it may not be obvious from a code review that some sensitive data exfiltration is possible. I want to demonstrate that sensitive data can be exfiltrated in a non-obvious manner.
不错,但这类攻击几乎总是依赖于未定义的行为。正如您自己所说,这是一个安全问题。因此,提供可靠的方法来做到这一点真的没有意义。
这是我在 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] = '[=13=]';
printf("%s", str); // Will print nothing, but only first character is wiped
我有以下 C 程序,它请求一些内存 (str1
),将文件内容读入 space 然后释放它。接下来,请求一个相同大小(str2
)的块,并将内容打印到标准输出。
我想要的是 str2
包含 str1
的内容,以便输出始终是文件的内容。
我知道我正在做的是未定义的行为,因为我不能保证已分配的内存内容将包含什么。但是,我正在尝试做一些卑鄙的事情来进行演示,其中文件中的数据可以在代码审查中不明显的情况下被泄露。
几乎所有时间,我在 str1
和 str2
的相同地址收到一块内存,而 大多数时候 当我运行 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);
}
Is there a way to reliably malloc the same block of memory as a previously freed block
是的,使用 realloc
而不是 free
+ malloc
。否则,没有可靠或安全的方法可以在同一地址获得准确的金额。
I receive a block of memory at the same address for both str1 and str2
好吧,这个简单的程序中没有太多其他内容,所以这也许不足为奇。虽然没有保证。此外,除非您实际对堆进行写访问,否则实际上可能不会调用内存分配。所以 str2
可能只是一些随机地址,以防整个 malloc 调用被优化掉。或者,调用 malloc 但 OS 从不分配任何实际内存。
is there any explanation for why it doesn't work at all on Linux?
我不知道,但我怀疑 ASLR 可能与此有关。某些 Linux 专家将不得不回答该部分。
本质上,当你分配和释放时发生的事情对你来说是一个黑盒子。绝对没有可靠的方法来获得相同的地址。调用 free
意味着您告诉 OS 您已完成内存处理,并且无法撤消此操作。
What I want is for str2 to contain the content of str1 so that the output is always the content of the file.
这里基本上有三个选项。
- 等待
free
的呼叫
- 在调用之前复制缓冲区
free
- 编写您自己的
malloc
和free
实现
来自评论:
imagine that I'm going to allocate some memory then read something sensitive (e.g. a private key) into that block and do something with it. Later, I allocate some memory of the same size and stick some data into it that will be saved to a file. If I don't overwrite all the data in the block then it may contain some sensitive info that would get saved to the file. In that case, it may not be obvious from a code review that some sensitive data exfiltration is possible. I want to demonstrate that sensitive data can be exfiltrated in a non-obvious manner.
不错,但这类攻击几乎总是依赖于未定义的行为。正如您自己所说,这是一个安全问题。因此,提供可靠的方法来做到这一点真的没有意义。
这是我在 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] = '[=13=]';
printf("%s", str); // Will print nothing, but only first character is wiped