阅读本文前你可能已经知道,malloc通过系统调用的方式从操作系统申请内存。事实上,malloc内部是通过系统调用brk或mmap来申请内存的。如下面的进程虚拟内存布局图所示,mmap对应Memory Mapping Segment
,brk对应Heap
。
brk
brk通过增加program break的位置(brk)从内核申请(非零值初始化的)内存。一开始,堆段(heap segment)的起始位置(start_brk)和结束位置(brk)指向同一个位置:
- 当ASLR(Address Space Layout Randomization)关闭时,
start_brk
和brk同时指向data/bss
段的结束位置(end_data)。 - 当ASLR打开时,
start_brk
和brk同时指向data/bss
段的结束位置(end_data
)再加上一个随机的brk偏移。
上面的进程虚拟内存布局图展示了,start_brk是堆段的开始位置,brk(program break)则是堆段的结束位置。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <stdio.h> #include <unistd.h> #include <sys/types.h>
int main() { void *curr_brk, *tmp_brk = NULL;
printf("Welcome to sbrk example:%d\n", getpid());
tmp_brk = curr_brk = sbrk(0); printf("Program Break Location1:%p\n", curr_brk); getchar();
brk(curr_brk+4096);
curr_brk = sbrk(0); printf("Program break Location2:%p\n", curr_brk); getchar();
brk(tmp_brk);
curr_brk = sbrk(0); printf("Program Break Location3:%p\n", curr_brk); getchar();
return 0; }
|
在增加program break之前,输出如下:
1 2 3 4 5 6 7 8 9
| sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/syscalls$ ./sbrk Welcome to sbrk example:6141 Program Break Location1:0x804b000 ... sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/syscalls$ cat /proc/6141/maps ... 0804a000-0804b000 rw-p 00001000 08:01 539624 /home/sploitfun/ptmalloc.ppt/syscalls/sbrk b7e21000-b7e22000 rw-p 00000000 00:00 0 ...
|
start_brk=brk=end_data=0x804b000
此时没有堆段。
译者yoko注,这里通过cat /proc/<pid>/maps
的方式查看进程映射的内存区域,输出的含义下文会具体讲
在增加program break之后,输出如下:
1 2 3 4 5 6 7 8 9 10 11
| sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/syscalls$ ./sbrk Welcome to sbrk example:6141 Program Break Location1:0x804b000 Program Break Location2:0x804c000 ... sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/syscalls$ cat /proc/6141/maps ... 0804a000-0804b000 rw-p 00001000 08:01 539624 /home/sploitfun/ptmalloc.ppt/syscalls/sbrk 0804b000-0804c000 rw-p 00000000 00:00 0 [heap] b7e21000-b7e22000 rw-p 00000000 00:00 0 ...
|
start_brk=end_data=0x804b000
brk=0x804c000
可以观察到堆段。
其中0804b000-0804c000 rw-p 00000000 00:00 0 [heap]
的含义:
0804b000-0804c000
是这个堆段的虚拟地址范围。rw-p
标准的含义是Read, Write, NoeXecute, Private
00000000
是文件偏移量,由于并没有映射任何文件,所以为零00:00
是major/minor device number,由于并没有映射任何文件,所以为零0
是inode,由于并没有映射任何文件,所以为零[heap]
是堆段
mmap
malloc使用mmap创建一个私有匿名的映射段。这个映射段的主要目的是申请一块(零值初始化的)新内存,并且这块内存只能被调用的这个进程独占使用。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <stdio.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h>
void static inline errExit(const char* msg) { printf("%s failed. Exiting the process\n", msg); exit(-1); }
int main() { int ret = -1; printf("Welcome to private anonymous mapping example::PID:%d\n", getpid()); printf("Before mmap\n"); getchar(); char* addr = NULL; addr = mmap(NULL, (size_t)132*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) errExit("mmap"); printf("After mmap\n"); getchar();
ret = munmap(addr, (size_t)132*1024); if(ret == -1) errExit("munmap"); printf("After munmap\n"); getchar(); return 0; }
|
调用mmap之前:如下输出我们可以看到,只有属于libc.so
和ld-linux.so
共享库的内存映射段。
1 2 3 4 5 6
| sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/syscalls$ cat /proc/6067/maps 08048000-08049000 r-xp 00000000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap 08049000-0804a000 r--p 00000000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap 0804a000-0804b000 rw-p 00001000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap b7e21000-b7e22000 rw-p 00000000 00:00 0 ...
|
调用mmap之后:如下输出我们可以观察到,我们mmap映射的内存段(b7e00000–b7e21000
,大小是132KB)和已经存在的内存映射段(b7e21000–b7e22000
)合并了(变成b7e00000-b7e22000
)。
1 2 3 4 5 6
| sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/syscalls$ cat /proc/6067/maps 08048000-08049000 r-xp 00000000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap 08049000-0804a000 r--p 00000000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap 0804a000-0804b000 rw-p 00001000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap b7e00000-b7e22000 rw-p 00000000 00:00 0 ...
|
其中b7e00000-b7e22000 rw-p 00000000 00:00 0
的含义:
b7e00000-b7e22000
是这个段的虚拟地址范围rw-p is Flags (Read, Write, NoeXecute, Private)
00000000
是文件偏移量,由于并没有映射任何文件,所以为零00:00
是major/minor device number,由于并没有映射任何文件,所以为零0
是inode,由于并没有映射任何文件,所以为零
调用munmap之后:如下输出我们可以看到,mmap映射的内存段已经被解除映射了,换言之,相应的已归还给操作系统。
1 2 3 4 5 6
| sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/syscalls$ cat /proc/6067/maps 08048000-08049000 r-xp 00000000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap 08049000-0804a000 r--p 00000000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap 0804a000-0804b000 rw-p 00001000 08:01 539691 /home/sploitfun/ptmalloc.ppt/syscalls/mmap b7e21000-b7e22000 rw-p 00000000 00:00 0 ...
|
注意:我们以上所做实验,ASLR是关闭的。
英文原文地址:https://sploitfun.wordpress.com/2015/02/11/syscalls-used-by-malloc/
本文完,作者yoko,尊重劳动人民成果,转载请注明原文出处: https://pengrl.com/p/20032/