为什么这会在堆栈而不是堆上分配?

时间:2017-02-04 20:02:07

标签: c memory memory-management

编辑:我原来的问题不再准确,所以我重写了它。

所以我正在编写一个程序来演示C中的堆喷雾(我知道这是不寻常的)。我正在使用malloc分配一个巨大的缓冲区(100MB),但是它分配到标记为映射而不是[heap]的段中,我无法弄清楚原因。

我的代码:

int NOPSize = 960;
int ShellcodeSize = 64;
int PayloadSize = NOPSize + ShellcodeSize;
char Payload[PayloadSize];
char* HeapBuf = (char*)malloc(0x6400000);   //104,857,600 (100MB)

for (int x = 0; x < PayloadSize; x++)
    Payload[x] = (x <= NOPSize) ? '\x90' : '\x41';

for (int x = 0; x < 0x6400000; x++)
    HeapBuf[x] = Payload[x % PayloadSize];

printf("%x\n", HeapBuf);
free(HeapBuf);

使用从调用free时设置的断点获取的GDB-PEDA输出vmmap:

0x80000000 0x80001000 r-xp  /root/Documents/a.out
0x80001000 0x80002000 r--p  /root/Documents/a.out
0x80002000 0x80003000 rw-p  /root/Documents/a.out
0x80003000 0x80024000 rw-p  [heap]
0xb19fd000 0xb7dfe000 rw-p  mapped
0xb7dfe000 0xb7faf000 r-xp  /lib/i386-linux-gnu/libc-2.24.so
0xb7faf000 0xb7fb1000 r--p  /lib/i386-linux-gnu/libc-2.24.so
0xb7fb1000 0xb7fb2000 rw-p  /lib/i386-linux-gnu/libc-2.24.so
0xb7fb2000 0xb7fb5000 rw-p  mapped
0xb7fd4000 0xb7fd7000 rw-p  mapped
0xb7fd7000 0xb7fd9000 r--p  [vvar]
0xb7fd9000 0xb7fdb000 r-xp  [vdso]
0xb7fdb000 0xb7ffd000 r-xp  /lib/i386-linux-gnu/ld-2.24.so
0xb7ffe000 0xb7fff000 r--p  /lib/i386-linux-gnu/ld-2.24.so
0xb7fff000 0xb8000000 rw-p  /lib/i386-linux-gnu/ld-2.24.so
0xbffdf000 0xc0000000 rw-p  [stack]

printf输出位于顶部映射段中的0xb19fd008

有趣的是,如果我删除对[heap]的调用,printf段就会消失。所以我的问题是,为什么[heap]段的存在取决于对printf的调用,为什么打印的地址位于映射的段中,而不是[heap]段?感谢。

3 个答案:

答案 0 :(得分:2)

HeapBuf就像您在代码中拥有的任何其他intlongchar一样驻留在堆栈上,因为指针本身仅仅是一个数字。但它指向的内存确实是在堆上分配的。

答案 1 :(得分:1)

我无法复制OP的结果。但是,与OP不同,我在x86-64内核和64位二进制文​​件上运行。

这是一个小型测试程序 test.c

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

void self_maps(void)
{
    FILE *in;
    int   c;

    in = fopen("/proc/self/maps", "r");
    if (!in)
        return;

    /* Let the C library handle the buffering. */
    while ((c = getc(in)) != EOF)
        putchar(c);

    fclose(in);
}

int main(void)
{
    size_t NOPSize = 960;
    size_t ShellcodeSize = 64;
    size_t PayloadSize = NOPSize + ShellcodeSize;
    size_t BufferSize = 0x6400000;
    size_t i;

    char Payload[PayloadSize];
    char *HeapBuf;

    HeapBuf = malloc(BufferSize);
    if (!HeapBuf) {
        fprintf(stderr, "Out of memory.\n");
        return EXIT_FAILURE;
    }

    printf("Payload = %p\n", (void *)Payload);
    printf("HeapBuf = %p\n", (void *)HeapBuf);

    for (i = 0; i < NOPSize; i++)
        Payload[i] = '\x90';

    for (i = NOPSize; i < PayloadSize; i++)
        Payload[i] = '\x41';

    for (i = 0; i < BufferSize; i++)
        HeapBuf[i] = Payload[i % PayloadSize];

    printf("\n");
    self_maps();

    free(HeapBuf);

    return EXIT_SUCCESS;
}

如果我使用

编译并运行它
gcc -Wall -O2 test.c -o test

./test

我得到输出

Payload = 0x7fff3122b6b0
HeapBuf = 0x7f378806a010

00400000-00401000 r-xp 00000000 08:07 4587700                /.../test
00600000-00601000 r--p 00000000 08:07 4587700                /.../test
00601000-00602000 rw-p 00001000 08:07 4587700                /.../test
022c3000-022e5000 rw-p 00000000 00:00 0                      [heap]
7f378806a000-7f378e46b000 rw-p 00000000 00:00 0 
7f378e46b000-7f378e62a000 r-xp 00000000 08:05 1966262        /lib/x86_64-linux-gnu/libc-2.23.so
7f378e62a000-7f378e82a000 ---p 001bf000 08:05 1966262        /lib/x86_64-linux-gnu/libc-2.23.so
7f378e82a000-7f378e82e000 r--p 001bf000 08:05 1966262        /lib/x86_64-linux-gnu/libc-2.23.so
7f378e82e000-7f378e830000 rw-p 001c3000 08:05 1966262        /lib/x86_64-linux-gnu/libc-2.23.so
7f378e830000-7f378e834000 rw-p 00000000 00:00 0 
7f378e834000-7f378e85a000 r-xp 00000000 08:05 1966245        /lib/x86_64-linux-gnu/ld-2.23.so
7f378ea2c000-7f378ea2f000 rw-p 00000000 00:00 0 
7f378ea57000-7f378ea59000 rw-p 00000000 00:00 0 
7f378ea59000-7f378ea5a000 r--p 00025000 08:05 1966245        /lib/x86_64-linux-gnu/ld-2.23.so
7f378ea5a000-7f378ea5b000 rw-p 00026000 08:05 1966245        /lib/x86_64-linux-gnu/ld-2.23.so
7f378ea5b000-7f378ea5c000 rw-p 00000000 00:00 0 
7fff3120c000-7fff3122d000 rw-p 00000000 00:00 0              [stack]
7fff3126c000-7fff3126e000 r--p 00000000 00:00 0              [vvar]
7fff3126e000-7fff31270000 r-xp 00000000 00:00 0              [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0      [vsyscall]

因为我使用的GNU C库的版本使用大于130 kB左右的分配的内存映射,HeapBuf是自己的映射:

7f378806a000-7f378e46b000 rw-p 00000000 00:00 0 

答案 2 :(得分:1)

这里有两件事,在我进入它们之前,我必须警告你,根据地图输出中字符串/lib/i386-linux-gnu/libc-2.24.so的存在,我推断出操作您运行程序的系统使用Linux内核和GNU C库(&#39; glibc&#39;)。我要告诉你的一些内容对这些组件非常特别。

首先:由于历史原因,有两种不同的方法可以在操作系统上分配内存,这些方法符合&#34; Unix&#34; (对于第一个订单:任何人仍然使用的所有内容,Windows除外):系统调用sbrkmmapsbrk更加有限;它只能在预定位置管理单个内存区域的 size ,而mmap(及其对应munmap)可以在任何地方分配和释放独立的内存块地址空间。 Linux的/proc/PID/maps文件对[heap]管理的内存区域使用sbrk标签。分配有mmap的独立内存块标记为&#34;映射&#34;。

第二:glibc的malloc实施使用sbrk进行小额分配,mmap进行大额分配(参见M_MMAP_THRESHOLD0xb19fd000 0xb7dfe000 rw-p mapped 的讨论}})。 &#34; small&#34;之间的默认阈值和&#34;大&#34;是128 千字节;你分配了0x6400000字节= 100 兆字节,这显然要大得多。您的映射转储行

malloc

只比您要求的页面大一页 - 差异是由于[heap]为其自己的簿记信息占用了一些额外空间。

当您致电printf时会显示stdout段,因为 - 再次,这是glibc的怪癖 - 第一次使用malloc执行任何操作时,会在内部分配一些内存,使用sbrk。该分配小于而不是128kB,因此它会被放入mmap区域,并且就在那里。

(根据您正在尝试模拟的#34;堆喷和#34;攻击,要么您不在乎自己的<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width:device-width, initial-scale = 1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <style> .affix { top: 0; width: 100%; } .affix + .container-fluid { padding-top: 70px; } </style> </head> <body> <div class="container-fluid"> <div class="alert alert-warning alert-dismissable fade in"> <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a> <strong>Warning!</strong> This site uses cookies </div> <nav class="navbar navbar-inverse" data-spy="affix" data-offset-top="197"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Something</a> </div> <div class="collapse navbar-collapse" id="myNavbar"> <ul class="nav navbar-nav"> <li><a href="#">Home</a> </li> <li><a href="#">Pag 1</a> </li> <li><a href="#">Pag 2</a> </li> </ul> <ul class="nav navbar-nav navbar-right"> <li> <a href="#"> <span class="glyphicon glyphicon-log-in"> </span> </a> </li> </ul> </div> </div> </div> <div class="container-fluid" style="height:1000px"> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> <h1>Some text to enable scrolling</h1> </div> </body> </html>分配中的100MB因为您&# 39;只是试图覆盖足够的整个地址空间,野指针有很大的机会指向那里,或者你需要分配大量的对象,每个对象的大小与易受攻击的应用程序中的一些关键数据,这样您就有可能将分配与应用程序混淆。)

相关问题