윈도우의 PE 파일은 PE 헤더와 1개 이상의 섹션으로 구성.
섹션: 유사한 용도로 사용되는 데이터가 모여있는 영역
섹션에 대한 정보는 PE 헤더에 적혀있다. PE 헤더에 저장되는 섹션과 관련된 데이터 중 중요한 것들은
PE에 “.text”, “.data”, “.rdata” 섹션이 일반적으로 사용된다.
실행 가능한 기계 코드가 위치하는 영역
프로그램이 동작하려면 코드를 실행할 수 있어야 하므로 이 세그먼트에는 읽기 권한과 실행 권한이 부여된다. 쓰기 권한이 있으면 공격자가 악의적인 코드를 삽입하기가 쉬워지므로, 대부분의 현대 운영체제는 이 세그먼트에 쓰기 권한을 제거한다.
ex)
int main() {
return 31337;
}
정수 31337을 반환하는 main 함수가 컴파일되면 554889e5b8697a00005dc3이라는 기계 코드로 변환. 이 기계 코드가 코드 세그먼트에 위치.
컴파일 시점에 값이 정해진 전역 변수들이 위치하는 영역
CPU가 이 섹션의 데이터를 읽고 쓸 수 있어야 하므로, 읽기/쓰기 권한이 부여된다.
ex)
int data_num = 31337;
char data_rwstr[] = "writable_data"; // data
int main() { ... }입력하세요
.data 섹션에 포함되는 여러 데이터의 유형
컴파일 시점에 값이 정해진 전역 상수와 참조할 DLL 및 외부 함수들의 정보가 저장
CPU가 이 섹션의 데이터를 읽을수 있어야 하므로 읽기 권한이 부여되지만, 쓰기는 불가능.
ex)
const char data_rostr[] = "readonly_data";
char *str_ptr = "readonly"; // str_ptr은 .data, 문자열은 .rdata
int main() { ... }
.rdata 섹션에 포함되는 여러 데이터의 유형
str_ptr은 “readonly”라는 문자열을 가리키고 있는데, str_ptr은 전역 변수로서 .data에 위치하지만, “readonly”는 상수 문자열로 취급되어 .rdata에 위치.
프로그램 실행에 있어 필요한 스택과 힙 역시 가상 메모리 공간에 적재
윈도우즈 프로세스의 각 쓰레드는 자신만의 스택 공간을 가진다. 보통 지역 변수나 함수의 리턴 주소가 저장. 자유롭게 읽고 쓸수 있어야 하기 때문에 읽기/쓰기 권한이 부여.
스택은 확장될 때, 기존 주소보다 낮은 주소로 확장
ex)
void func() {
int choice = 0;
scanf("%d", &choice);
if (choice)
call_true();
else
call_false();
return 0;
}
지역변수 choice가 스택에 저장
모든 종류의 데이터 저장 가능. 비교적 스택보다 큰 데이터도 저장할 수 있고 전역적으로 접근이 가능. 실행중 동적으로 할당받는다.
보통은 데이터를 읽고 쓰기만 하기 때문에 읽기/쓰기 권한만을 가지나, 상황에 따라 실행 권한을 가지는 경우도 존재.
ex)
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으로 할당받은 힙 세그먼트의 주소를 가리킨다.
섹션 | 역할 | 일반적인 권한 | 사용 예 |
---|---|---|---|
.text | 실행 가능한 코드가 저장된 영역 | 읽기, 실행 | main() 등의 함수 코드 |
.data | 초기화된 전역 변수가 위치하는 영역 | 읽기와 쓰기 | 초기화된 전역 변수, 전역 상수 |
.rdata | 초기화된 전역 상수나 임포트 데이터가 위치 | 읽기 전용 | 전역 상수, 임포트 데이터 |
스택 | 일시적으로 저장하고 사용하는 임시 영역 | 읽기, 쓰기 | 지역 변수, 함수의 인자 등 |
힙 | 자유롭게 사용할 수 있는 영역 | 읽기, 쓰기 | malloc(), calloc() 등으로 할당 받은 메모리 |