컴퓨터는 CPU와 메모리로 구성되어 있다.
CPU는 실행할 명령어와 명령어 처리에 필요한 데이터를 메모리에서 읽고, ISA에 따라 처리하고, 연산의 결과를 다시 메모리에 적재한다.
이와 같이 CPU의 동작과 메모리 사이에 밀접한 연관이 있다.
메모리 오염(Memory Corruption) 취약점 : 공격자가 메모리를 악의적으로 조작 -> 그 값에 의해 CPU도 잘못된 동작을 할 수 있다.
시스템 해킹의 많은 공격기법이 메모리 오염을 기반으로 하고 있다.
리눅스 메모리 구조에 대해 알아보며, 프로세스 메모리의 전체 구조에 대해 통찰할 수 있도록 하자.
0. 세그먼트(Segment)란
리눅스에서는 프로세스의 메모리를 크게 5가지의 세그먼트(Segment)로 구분한다.
세그먼트란 적재되는 데이터의 용도별로 메모리의 구획을 나눈 것이다.
운영체제가 메모리를 용도별로 나누면, 각 용도에 맞게 적절한 권한을 부여할 수 있다.
권한 : 읽기, 쓰기, 실행
CPU는 메모리에 대해 권한이 부여된 행위만 할 수 있다.
실행 중인 프로세스의 메모리가 5개의 영역(세그먼트)으로 구분된다.
1. 코드 세그먼트
= 텍스트 세그먼트
실행 가능한 코드가 저장된 영역
권한 : 읽기, 실행
예) main() 등의 함수 코드
2. 데이터 세그먼트
컴파일 시점에 값이 정해진 전역 변수 및 전역 상수들이 위치하는 영역
권한 : 읽기와 쓰기(data 세그먼트) 또는 읽기 전용(rodata(read-only data) 세그먼트)
예) 초기화된 전역 변수, 전역 상수
int data_num = 111; // 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 변수 주의 깊게 살펴볼 것.
3. BSS 세그먼트(Block Started By Symbol Segment)
컴파일 시점에 값이 정해지지 않은 전역 변수가 위치하는 메모리 영역
권한 : 읽기, 쓰기
예) 초기화되지 않은 전역 변수
-> 프로그램이 시작될 때, 모두 0으로 값이 초기화 된다.
int bss_data;
int main() {
printf("%d\n", bss_data); // 0
return 0;
}
4. 스택 세그먼트
임시 변수가 저장되는 영역
권한 : 읽기, 쓰기
예) 지역 변수, 함수의 인자 등
5. 힙 세그먼트
실행 중에 동적으로 사용되는 영역
권한 : 읽기, 쓰기
예) malloc(), calloc() 등으로 할당 받은 메모리
🔒총정리 Quiz
각 변수 혹은 함수가 위치하는 세그먼트는 무엇인가?
#include <stdlib.h>
int a = 0xa; // 데이터 세그먼트
const char b[] = "d_str"; // b와 "d_str"는 rodata 세그먼트
int c; // bss 세그먼트
int foo(int arg) { // 코드 세그먼트
int d = 0xd; // 스택 세그먼트
return 0;
}
int main() {
int *e = malloc(sizeof(*e)); // 힙 세그먼트
return 0;
}
※출처※
해커들의 놀이터, Dreamhack
해킹과 보안에 대한 공부를 하고 싶은 학생, 안전한 코드를 작성하고 싶은 개발자, 보안 지식과 실력을 업그레이드 시키고 싶은 보안 전문가까지 함께 공부하고 연습하며 지식을 나누고 실력 향
dreamhack.io