리눅스 메모리 구조
리눅스에서는 프로세스의 메모리를 5가지의 세그먼트(Segment)로 구분한다.
세그먼트란 적재되는 데이터의 용도별로 메모리의 구획을 나눈 것.
그림과 같이 코드 세그먼트, 데이터 세그먼트, BSS 세그먼트, 힙 세그먼트, 스택 세그먼트로 구분.
운영체제가 메모리를 용도별로 나누면 생기는 장점?
용도에 맞게 세그먼트마다 적절한 권한을 부여할 수 있다.
코드 세그먼트( Code Segment, Text Segment라고도 불림)
실행할 명령어(기계 코드)가 위치하는 영역이다.
읽기 권한과 실행 권한이 부여된다. -> 왜냐면 프로그로그램이 동작하려면 코드를 실행할 수 있어야 하니까
쓰기 권한은 없음 -> 왜냐면 공격자가 악의 적인 코드를 삽입하기 쉬워짐.
int main() { return 31337; }
정수 31337을 반환하는 main함수가 컴파일 되면 554889e5b8697a00005dc3라는 기계 코드로 변환되는데, 이 기계 코드가 코드 세그먼트에 위치하게 됨.
데이터 세그먼트( Data Segment)
프로그램 실행 중 사용할 전역변수와 전역상수를 저장하는 영역이다.
쓰기가 가능한 세그먼트(.data)와 불가능한 세그먼트(.rodata)로 나뉨.
.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" -> 상수 문자열 취급
str_ptr -> data
이런식으로 저장된다고 생각하면 될듯.
BSS 세그먼트( Block Started By Symbol Segment)
컴파일 시점에 값이 정해지지 않은 전역 변수가 위치하는 영역이다.
읽기 권한과 쓰기 권한이 부여된다.
초기화되지 않은 전역 변수가 저장된다.
데이터 세그먼트는 초기화 여부에 따라도 나뉘어진다.
초기화 된게 뭔데
.data | 초기화된 전역 변수 저장 |
.bss | 초기화되지 않은 전역 변수 저장 |
초기화 된게 뭔데
초기화된 변수 = 선언할 때 값을 지정한 변수
초기화 안 된 변수 = 선언할 때 값을 지정하지 않은 변수
예를들어, int x = 10;은 값이 지정돼서 초기화된 변수이고 int x; 은 초기화 안된 변수임.
BSS 세그먼트 영역은 프로그램이 시작될 때, 모두 0으로 값이 초기화된다.
int bss_data;
int main() {
printf("%d\n", bss_data); // 0
return 0;
}
여기서 bss_data 변수는 선언할 때 값을 지정하지 않았기 때문에 BSS세그먼트에 저장되게 됨.
스택 세그먼트 ( Stack Segment)
프로세스의 스택이 위치하는 영역이다.
읽기권한과 쓰기 권한이 부여된다. -> CPU가 자유롭게 값을 읽고 써야하니까
함수의 인자나 지역변수와 같은 임시 변수들이 실행중에 이 영역에 저장된다.
스택 프레임 단위로 사용된다.
void func() {
int choice = 0;
scanf("%d", &choice);
if (choice)
call_true();
else
call_false();
return 0;
}
이 코드를 보면 유저가 입력한 choice에 따라 call_true가 호출될 수도 call_false가 호출될수도 있다.
따라서 스택프레임의 필요한 크기를 예측할 수 없어서 운영체제는 스택 세그먼트를 부족할 때마다 확장시킨다.
힙 세그먼트
힙 데이터가 위치하는 세그먼트이다.
읽기권한과 쓰기 권한이 부여된다.
리눅스에서는 스택 세그먼트와 반대 방향으로 자란다.
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으로 할당받은 힙 세그먼트의 주소를 가리킨다.
'System Hacking > Basics' 카테고리의 다른 글
[시스템 해킹] gdb/pwndbg 사용법 (0) | 2025.03.07 |
---|---|
[시스템 해킹] pwndbg 설치방법 / Linux (0) | 2025.03.07 |
[시스템 해킹] 어셈블리어(assembly language) - 2/ 스택, 프로시저, 시스템콜 (0) | 2025.03.07 |
[시스템 해킹] 어셈블리어(assembly language) - 1/ 데이터이동, 산술연산, 논리연산, 비교, 분기 (0) | 2025.03.07 |
[시스템 해킹] 컴퓨터 구조와 ISA (0) | 2025.03.05 |