기본 콘텐츠로 건너뛰기

Heap-Syscall

Heap-Syscall

힙 메모리 할당과 시스템 호출

malloc은 OS에서 메모리를 얻기 위해 brk 또는 mmap syscall을 사용하여 메모리를 확보한다.

brk

brk: brk는 프로그램 중단 위치를 증가시켜 커널에서 메모리를 얻는다. 처음 시작(start_brk) 및 힙 세그먼트 끝(brk)은 동일한 위치를 가리킨다.

  • ASLR이 꺼지면 start_brkbrk는 data/bss 세그먼트 (end_data)`끝을 가리킨다.
  • ASLR이 켜지면 start_brkbrk는 data/bss 세그먼트 (end_data)끝에 임의의 brk 오프셋을 더한 것과 같다.
    enter image description here

위의 프로세스 가상 메모리 레이아웃 그림은 start_brk가 힙 세그먼트의 시작이고 brk(프로그램 중단)이 힙 세그먼트의 끝임을 보여준다.

예시

/* sbrk and brk example */
#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());

   /* sbrk(0) gives current program break location */

  tmp_brk = curr_brk = sbrk(0);
  printf("Program Break Location1:%p\n", curr_brk);
  getchar();
   	 
   /* brk(addr) increments/decrements program break location */

   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;
}

이제 컴파일 후 프로그램을 실행하여 살펴보자.

# gcc -o brk ./brk.c 
# ./brk
Welcome to sbrk example:19109
Program Break Location1:0x804a000

터미널 창을 하나 더 실행하여 프로세스 메모리 공간을 살펴보자.

# cat /proc/19109/maps
08048000-08049000 r-xp 00000000 08:01 1032560    /home/iamroot/workspace/heap/brk
08049000-0804a000 rw-p 00000000 08:01 1032560    /home/iamroot/workspace/heap/brk
b7e98000-b7e99000 rw-p b7e98000 00:00 0 
b7e99000-b7fd4000 r-xp 00000000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0 
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0 
b7fe7000-b8000000 r-xp 00000000 08:01 851989     /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989     /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0          [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
  • Program break 증가 전: start_brk = brk = end_data = 0x804a000
[Enter 입력]
Program Break Location2:0x804b000
 # cat /proc/19109/maps
 08048000-08049000 r-xp 00000000 08:01 1032560    /home/iamroot/workspace/heap/brk
 08049000-0804a000 rw-p 00000000 08:01 1032560    /home/iamroot/workspace/heap/brk
 0804a000-0804b000 rw-p 00000000 00:00 0          [heap]
 b7e98000-b7e99000 rw-p b7e98000 00:00 0
 b7e99000-b7fd4000 r-xp 00000000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
 b7fd4000-b7fd5000 r--p 0013b000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
 b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
 b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
 b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
 b7fe7000-b8000000 r-xp 00000000 08:01 851989     /lib/ld-2.5.so
 b8000000-b8002000 rw-p 00019000 08:01 851989     /lib/ld-2.5.so
 bffeb000-c0000000 rw-p bffeb000 00:00 0          [stack]
 ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
  • Program break 증가 후: start_brk = end_data = 0x804a000, brk = 0x804b000
    • 0804a000-0804b000은 세그먼트의 가상 주소 범위이다.
    • rw-p는 Flags (읽기, 쓰기, 비실행, 비공개)이다.
    • 00000000 은 파일 오프셋이다.
    • 00:00 은 Major / Minor device number 이다.
    • 0 은 아이 노드 번호이다.

mmap

mmap: mallocmmap을 사용하여 private anonymous mapping 세그먼트를 생성한다. 주된 목적은 새 메모리(0으로 채워짐)를 할당하는 것으로, 이 새 메모리는 프로세스를 호출하여 독점적으로 사용된다.

/* Private anonymous mapping example using mmap syscall */
#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();

   /* Unmap mapped region. */
   ret = munmap(addr, (size_t)132*1024);
   if(ret == -1)
            errExit("munmap");
   printf("After munmap\n");
   getchar();
   return 0;
}
# ./mmap 
Welcome to private anonymous mapping example::PID:20139
Before mmap
  • mmap 이전: 공유 라이브러리 libc.sold-linux.so에 속한 메모리 매핑 세그먼트만 볼 수 있다.
# cat /proc/20139/maps
08048000-08049000 r-xp 00000000 08:01 1032542    /home/iamroot/workspace/heap/mmap
08049000-0804a000 rw-p 00000000 08:01 1032542    /home/iamroot/workspace/heap/mmap
b7e98000-b7e99000 rw-p b7e98000 00:00 0
b7e99000-b7fd4000 r-xp 00000000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
b7fe7000-b8000000 r-xp 00000000 08:01 851989     /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989     /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0          [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
[Enter 입력]
After mmap
  • mmap 이후: 매핑 세그먼트가 (b7e77000 ~ b7e98000)이 이미 존재하던 매핑 세그먼트(b7e98000 ~ b7e99000)와 결합된 것을 볼 수 있다.
# cat /proc/20139/maps
08048000-08049000 r-xp 00000000 08:01 1032542    /home/iamroot/workspace/heap/mmap
08049000-0804a000 rw-p 00000000 08:01 1032542    /home/iamroot/workspace/heap/mmap
b7e77000-b7e99000 rw-p 00000000 00:00 0
b7e99000-b7fd4000 r-xp 00000000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
b7fe7000-b8000000 r-xp 00000000 08:01 851989     /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989     /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0          [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
  • b7e77000-b7e99000은 세그먼트의 가상 주소 범위이다.
  • rw-p는 Flags (읽기, 쓰기, 비실행, 비공개)이다.
  • 00000000 은 파일 오프셋이다.
  • 00:00 은 Major / Minor device number 이다.
  • 0 은 아이 노드 번호이다.
[Enter 입력]
After munmap
  • munmap 이후: 매핑되었던 메모리가 해제되었음을 볼 수 있다.
# cat /proc/20139/maps
08048000-08049000 r-xp 00000000 08:01 1032542    /home/iamroot/workspace/heap/mmap
08049000-0804a000 rw-p 00000000 08:01 1032542    /home/iamroot/workspace/heap/mmap
b7e98000-b7e99000 rw-p b7e98000 00:00 0
b7e99000-b7fd4000 r-xp 00000000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd4000-b7fd5000 r--p 0013b000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd5000-b7fd7000 rw-p 0013c000 08:01 886016     /lib/tls/i686/cmov/libc-2.5.so
b7fd7000-b7fda000 rw-p b7fd7000 00:00 0
b7fe3000-b7fe7000 rw-p b7fe3000 00:00 0
b7fe7000-b8000000 r-xp 00000000 08:01 851989     /lib/ld-2.5.so
b8000000-b8002000 rw-p 00019000 08:01 851989     /lib/ld-2.5.so
bffeb000-c0000000 rw-p bffeb000 00:00 0          [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]

이 블로그의 인기 게시물

데일 카네기 인간관계론 정리

Remove-Server-Header

응답 메시지 내 서버 버전 정보 제거 1. Apache 1) 조치 방법 “/etc/htpd/conf/httpd.conf” 파일 안에서 1. ServerTokens OS → ServerTokens Prod 2. ServerSignature On → ServerSignature Off 로 변경한 후 아파치를 재시작하면 헤더 값의 아파치 버전 정보 및 OS 정보를 제거할 수 있다. 2) 참고 URL http://zetawiki.com/wiki/CentOS_ 아파치_보안권장설정_ServerTokens_Prod,_ServerSignature_Off 2. IIS 1) 조치 방법 IIS 6.0 urlscan_setup 실행. 설치. \windows\system32\inetsrv\urlscan\urlscan.ini 파일을 열어 다음 수정(RemoveServerHeader=0 을 RemoveServerHeader=1 로 변경) 서비스에서 IIS Admin Service 재시작. IIS 7.0 IIS 관리자를 열고 관리하려는 수준으로 이동합니다. 기능 보기에서 HTTP 응답 헤더를 두 번 클릭합니다. HTTP 응답 헤더 페이지에서 제거할 헤더를 선택합니다. 작업 창에서 제거를 클릭하고 예를 클릭합니다. 2) 참고 URL IIS 6.0 : http://gonnie.tistory.com/entry/iis6- 응답헤더-감추기 IIS 7.0 : https://technet.microsoft.com/ko-kr/library/cc733102(v=ws.10).aspx 3. jetty 1) 조치 방법 “jetty.xml” 파일에서 jetty.send.server.version=false 설정 2) 참고 URL http://attenuated-perspicacity.blogspot.kr/2009/09/jetty-61x-hardening.html 4. Nginx ...

American Fuzzy Lop And Address Sanitizer

American Fuzzy Lop And Address Sanitizer Address Sanitizer(ASAN) 단지 gcc/clang에 -fsanitize=address 옵션을 추가하는 것으로 간단히 사용할 수 있지만 그 효과는 충분하다. Example Out Of Bounds Read #include <stdio.h> int main() { int a[ 2 ] = { 3 , 1 }; int i = 2 ; printf ( "%i\n" , a[i]); } 예제 파일을 OutOfBoundsRead.c 로 생성하고 ASAN 옵션을 지정하여 clang 으로 컴파일하자. clang -g -fsanitize = address -fno -omit -frame -pointer OutOfBoundsRead . c -o OutOfBoundsRead 생성된 OutBoundsRead 파일을 실행하면 다음과 같은 결과를 볼 수 있다. ================================================================= ==3678==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc0ba87428 at pc 0x47b7db bp 0x7ffc0ba87390 sp 0x7ffc0ba87388 READ of size 4 at 0x7ffc0ba87428 thread T0 ==3678==WARNING: Trying to symbolize code, but external symbolizer is not initialized! #0 0x47b7da (/root/ASAN/OutOfBoundsRead+0x47b7da) #1 0x7faba0260f44 (/lib/x86_64-linux-gnu/libc.so.6+0x21f44) #2 0x...