Ptmalloc堆概述-Brk系统调用

brk

1.1 program break

未初始化数据段末尾后的第一个位置;

等于或超过此地址的地方均不可访问;

增加program break可以为进程分配内存;

减少program break则释放内存;

初始时,堆的起始地址 start_brk 以及堆的当前末尾 brk 指向同一地址。根据是否开启ASLR,两者的具体位置会有所不同

不开启 ASLR 保护时,start_brk 以及 brk 会指向 data/bss 段的结尾。

开启 ASLR 保护时,start_brk 以及 brk 也会指向同一位置,只是这个位置是在 data/bss 段结尾后的随机偏移处。

 

1.2 Brk系统调用

32

#define __NR_brk 45

64

#define __NR_brk 12

参数:请求的中断点

功能:

映射内存,返回新的中断点;

参数为0时,返回program break

失败时,返回0

注意:分配的堆是以页为单位的。如果请求的中断点不是页边界,则实际分配的会到页边界,而系统调用返回的中断点仍然是期望的中断点。

1.3 brk函数

#include <unistd.h>

       int brk(void *addr);

       void *sbrk(intptr_t increment);

brk函数

设置中断点;

成功返回0,失败返回-1

Sbrk函数

设置中断点的增量;

成功返回0;失败返回-1

参数为0时,返回program break的当前位置

2 C示例 

注意:Ubuntu 16.04上好像有问题。使用sbrk函数获取program break时,第一次调用时heap还没有分配,后面的调用才是真正的program break

#include <stdio.h>
#include <unistd.h>

int main()
{
     void *ptr;

    ptr= sbrk( 0);
printf( "ptr=%p \n ", ptr);

     getchar();
    ptr= sbrk( 0);
     printf( "ptr=%p \n ", ptr);

     getchar();
    ptr= sbrk( 0);
     printf( "ptr=%p \n ", ptr);
     return 0;
}


millionsky@ubuntu-16:~/tmp/sbrk$ gcc -m32 x.c

millionsky@ubuntu-16:~/tmp/sbrk$ ./a.out

ptr=0x804b000

ptr=0x806c000

ptr=0x806c000

millionsky@ubuntu-16:~/tmp/sbrk$ gcc x.c

millionsky@ubuntu-16:~/tmp/sbrk$ ./a.out

ptr=0x602000

ptr=0x623000

ptr=0x623000

millionsky@ubuntu-16:~$ cat /proc/`pgrep a.out`/maps | grep heap

0804b000-0806c000 rw-p 00000000 00:00 0                                  [heap]

strace执行发现确实有分配0x1000的系统调用,但不知道为什么被调用

millionsky@ubuntu-16:~/tmp$ strace ./a.out

brk(NULL)                               = 0x9c3e000

......

munmap(0xf76fb000, 109576)              = 0

brk(NULL)                               = 0x9c3e000

fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 18), ...}) = 0

brk(0x9c5f000)                          = 0x9c5f000

write(1, "ptr=0x9c3e000\n", 14ptr=0x9c3e000

)         = 14

3 ASM示例

brk.asm

SYS_BRK equ 45
SYS_READ equ 3
SYS_WRITE equ 4
SYS_EXIT equ 1
STD_IN equ 0
STD_OUT equ 1
SYS_CALL equ 0x80     ;0x80
section .data
hello: db 'Press any key!', 0
helloLen: equ $-hello

section .bss
buf resb 1 ; 1000-byte buffer (in data section)

section .text

global _start
_start:
mov ebx, 0
mov eax, SYS_BRK
int SYS_CALL

mov eax,SYS_WRITE ; 'write' system call = 4
mov ebx,STD_OUT ; file descriptor 1 = STDOUT
mov ecx,hello ; string to write
mov edx,helloLen ; length of string to write
int SYS_CALL ; call the kernel

mov edx, 1 ; max length
mov ecx, buf ; buffer
mov ebx, STD_IN ; stdin
mov eax, SYS_READ ; sys_read
int SYS_CALL

mov eax, SYS_EXIT
mov ebx, 0
int SYS_CALL


makefile

build:
    nasm -felf32 brk.asm
    ld -melf_i386 brk.o -o brk


GDB调试,查看系统调用的返回值;
或者查看/proc/pid/maps

参考文章

1. 深入理解程序设计使用Linux汇编语言

2. https://ctf-wiki.github.io/ctf-wiki/pwn/heap/heap_overview/

猜你喜欢

转载自blog.csdn.net/luozhaotian/article/details/80266833