1. Introduction
Pwnable(System Hacking)에서 가장 기본이자 중요한 부분인 Memory Layout에 대해서 소개하려고 한다.
2. Memory Layout
memexaple.c
#include<stdio.h>
int data = 10;
const char data_rostr;
int bss;
int main() {
int *h = malloc(4);
*h = 1234;
int s = 20;
return 0;
}
위에 코드는, 전역변수 data와 data_rostr, bss, main()함수 안에 있는 지역변수 h와 s가 선언이 되어있다.
변수 data, data_rostr, bss, h, s 그리고 main() 함수들은 메모리에 어떻게 mapping이 될까?
메모리는 여러 세그먼트들로 구분합니다. 대표적으로 크게 5가지의 code, data, BSS, heap, stack 세그먼트들이 있다.
segmenat |
---|
code |
data |
BSS |
↓ heap ↓ |
↓.↓ |
. |
↑.↑ |
↑ stack ↑ |
표와 같이 메모리가 저장되는 위치를 간략하게 표현해 보았다.
이제 위에서 작성한 memexample.c에서 main()함수와 변수들이 어디에 mapping이 되는지 설명하려고 한다.
2-1. Code Segment
segmenat |
---|
code |
data |
BSS |
↓ heap ↓ |
↓.↓ |
. |
↑.↑ |
↑ stack ↑ |
설명
Code Segment에는 실행 가능한 기계코드가 위치하는 영역이다.
main()함수 등 함수들이 위치하게 된다.
또한, 프로그램이 동작하려면 함수들은 실행이 가능해야 하므로, 읽기 권한, 실행 권한 이 주어진다.
쓰기 권한은 이 영역에서 없다. 왜냐하면 이 영역에는 실행 권한이 있기 때문에 공격자(해커)가 이 영역에서 마음대로 자신이 원하는 영역으로 위치시키는 코드를 작성할 수 있게 되기 때문이다.
#include<stdio.h>
int data = 10;
const char data_rostr;
int bss;
int main() {
int *h = malloc(4);
*h = 1234;
int s = 20;
return 0;
}
2-2. Data Segment
segmenat |
---|
code |
data |
BSS |
↓ heap ↓ |
↓.↓ |
. |
↑.↑ |
↑ stack ↑ |
설명
Data Segemnt에는 전역 변수 및 전역 상수들이 위치한다. (data, data_rostr)
이 영역은 다시 쓰기가 가능한 영역과 쓰기가 불가능한 영역으로 다시 나뉜다.
쓰기가 가능한 영역은 프로그램이 실행되면서 값이 변할 수 있는 데이터들이 위치합니다. 이 영역을 Data Segment라고 한다. (data)
쓰기가 불가능한 영역은 프로그램이 실행되면서 값이 변하면 안되는 데이터들이 위치합니다. 이 영역을 rodata(read-only data) Segment라고 한다.
#include<stdio.h>
int data = 10;
const char data_rostr;
int bss;
int main() {
int *h = malloc(4);
*h = 1234;
int s = 20;
return 0;
}
2-3. BSS Segment
segmenat |
---|
code |
data |
BSS |
↓ heap ↓ |
↓.↓ |
. |
↑.↑ |
↑ stack ↑ |
설명
BSS Segment(Block Started By Symbol Segment)에는 값이 정해지지 않은 전역 변수들이 위치하는 영역이다.(bss)
다시 말해 선언만 하고 값을 할당하지 않은(초기화하지 않은) 전역변수들이 위치한다.
이 영역의 메모리 영역은 프로그램이 시작될 때, 모두 0으로 값을 초기화시킨다.
이 영역에는 쓰기 권한과 읽기 권한이 주어진다.
#include<stdio.h>
int data = 10;
const char data_rostr;
int bss;
int main() {
int *h = malloc(4);
*h = 1234;
int s = 20;
return 0;
}
2-4. Stack Segment
segmenat |
---|
code |
data |
BSS |
↓ heap ↓ |
↓.↓ |
. |
↑.↑ |
↑ stack ↑ |
설명
Stack Segment는 스택이 위치하는 세그먼트입니다.
함수의 인자나 지역변수들이 저장된다.(s)
Stack Segment는 주소가 높은 곳에서 주소가 낮은 곳으로 자란다.
다시 말해, 지역 변수가 선언 될 때 주소가 높은 곳에서 부터 값을 넣을 수 있는 공간을 만든다.
이 영역에는 쓰기 권한과 읽기 권한이 주어진다.
2-5. Heap Segment
segmenat |
---|
code |
data |
BSS |
↓ heap ↓ |
↓.↓ |
. |
↑.↑ |
↑ stack ↑ |
설명
Heap Segemnt에는 힙 데이터가 위치하는 세그먼트입니다.
실행중에 동적으로 할당될 수 있다.
이 영역은 Stack Segment와 반대로 주소가 낮은 곳에서 높은 곳으로 자란다.
C언어에서 malloc(), calloc() 등을 호출해서 할당받는 데이터들이 이 영역에 위치하게 된다.(h)
이 영역에는 쓰기 권한과 읽기 권한이 주어진다.
memexaple.c 에서 h에 malloc()으로 동적 할당한 영역의 주소를 대입하고, 이 영역에 값을 넣는다.
h는 지역변수이므로 stack에 위치하며, malloc으로 할당 받은 Heap Segment의 주소를 가리킨다.
즉, h는 지역 변수이므로 Stack에 위치하고, 이 h안에는 Heap 영역의 주소를 가리키고, 그 후 heap에서 malloc()으로 값을 할당을 받는다.
#include<stdio.h>
int data = 10;
const char data_rostr;
int bss;
int main() {
int *h = malloc(4);
*h = 1234;
int s = 20;
return 0;
}
3. Conclusion
세그먼트 | 역할 | 권한 | 사용 예 |
---|
코드 세그먼트 | 실행 가능한 코드가 저장된 영역 | 읽기, 실행 | main() 등의 함수 코드 |
데이터 세그먼트 | 초기화된 전역 변수 또는 상수가 위치하는 영역 | 읽기와 쓰기 또는 읽기만 | 초기화된 전역 변수, 전역 상수 |
BSS 세그먼트 | 초기화되지 않은 데이터가 위치하는 영역 | 읽기, 쓰기 | 초기화되지 않은 전역 변수 |
스택 세그먼트 | 임시 변수가 저장되는 영역 | 읽기, 쓰기 | 지역 변수, 함수의 인자 등 |
힙 세그먼트 | 실행중에 동적으로 사용되는 영역 | 읽기, 쓰기 | malloc(), calloc() 등으로 할당 받은 메모리 |
마치며
여기까지 Memory Layout에 대해서 알아보았다.
다음 시간에는 Background: Computer Architecture를 알아보자.
Reference