[Dreamhack-system] Linux Memory Layout

박정원·2023년 3월 27일

보안공부

목록 보기
16/43

리눅스 프로세스의 메모리 구조

세그먼트

리눅스에서는 프로세스의 메모리를 크게 5가지의 세그먼트로 구분함

코드 세그먼트

  • 실행 가능한 기계 코드가 위치하는 영역, 텍스트 세그먼트라고도 불림
  • 프로그램이 동작하려면 코드를 실행할 수 있어야 하므로 이 세그먼트에는 읽기 권한과 실행 권한이 부여됨, 쓰기 권한이 있으면 공격자가 악의적인 코드를 삽입하기 쉬워지므로 대부분의 현대 운영체제는 이를 제거함
    int main() { return 31337;}
    여기서 정수 31337을 반환하는 main함수가 컴파일되면 기계 코드로 변환되는데, 이 기계코드가 코드 세그먼트에 위치하게 됨

데이터 세그먼트

  • 컴파일 시점에 값이 정해진 전역 변수 및 전역 상수들이 위치함
  • 이 세그먼트는 쓰기가 가능한 것과 불가능한 것으로 다시 분류되는데, 쓰기가 가능한 세그먼트는 전역 변수와 같이 값이 변할 수 있는 데이터들이 위치함 -> data 세그먼트라고 불림
  • 쓰기가 불가능한 세그먼트에는 실행되면서 값이 변하면 안되는 데이터들이 위치함 (전역으로 선언된 상수) -> rodata 세그먼트라고 불림
    int data_num = 31337;                       // data
    char data_rwstr[] = "writable_data";        // data
    const char data_rostr[] = "readonly_data";  // rodata
    char *str_ptr = "readonly";  // str_ptr은 data, 문자열은 rodata
    int main() { ... }
    str_ptr => "readonly"라는 문자열을 가리킴
    이때 "readonly"는 rodata에 위치하고, str_ptr은 전역 변수로서 data에 위치함

BSS 세그먼트

  • BSS 세그먼트는 컴파일 시점에 값이 정해지지 않은 전역 변수가 위치하는 메모리 영역임, 개발자가 선언만 하고 초기화하지 않은 전역변수 등이 포함됨
  • 이 세그먼트 메모리 영역은 프로그램이 시작될 때 모두 0으로 값이 초기화됨
    int bss_data;
    int main() {
    printf("%d\n", bss_data); //0
    return 0;
    }
    위의 코드에서 초기화되지 않은 전역 변수인 bss_data가 BSS 세그먼트에 위치하게 됨

스택 세그먼트

  • 스택 세그먼트는 프로세스의 스택이 위치하는 영역임, 함수의 인자나 지역 변수와 같은 임시 변수들이 실행중에 여기에 저장됨
  • 스택 세그먼트는 스택 프레임이라는 단위로 사용됨, 이는 함수가 호출될 때 생성되고, 반환될 때 해제됨
    void func() {
     int choice = 0;
     scanf("%d", &choice);
     if (choice)
       call_true();
     else
       call_false();
     return 0;
    }
    유저가 입력한 choice에 따라 call_true()가 호출될 수도, call_false()가 호출될 수도 있음
  • 즉, 어떤 프로세스가 실행될 때, 이 프로세스가 얼마 만큼의 스택 프레임을 사용하게 될 지를 미리 계산하는 것은 일반적으로 불가능-> 작은 크기의 스택 세그먼트를 먼저 할당해주고, 부족해질 때마다 이를 확장해줌
  • 위의 코드에서는 지역 변수 choice가 스택에 저장됨

힙 세그먼트

  • 힙 데이터가 위치하는 세그먼트로, 스택과 마찬가지로 실행중에 동적으로 할당될 수 있으며, 리눅스에서는 스택 세그먼트와 반대 방향으로 자람
    int main() {
     int *heap_data_ptr =
         malloc(sizeof(*heap_data_ptr));  // 동적 할당한 힙 영역의 주소를 가리킴
     *heap_data_ptr = 31337;              // 힙 영역에 값을 씀
     printf("%d\n", *heap_data_ptr);  // 힙 영역의 값을 사용함
     return 0;
    }
  • 위의 예제 코드에서는 heap_data_ptr에 malloc()으로 동적 할당한 영역의 주소를 대입하고 이 영역에 값을 씀 -> heap_data_ptr은 지역변수이므로 스택에 위치하고, malloc으로 할당받은 힙 세그먼트의 주소를 가리킴
profile
보안, 프런트엔드 공부 중!

0개의 댓글