리버싱
가상주소공간의 스택메모리 - 호출된 함수의 복귀주소와 분석
이둥둥
2025. 3. 3. 15:27
복귀주소 개념을 이해하기 위한 선행 개념
- 스택: LIFO 구조의 자료구조로 함수 호출 시 로컬 변수와 복귀 주소를 저장함
- 스택 프레임: 함수 호출마다 생성되는 메모리 블록, 반환되면 프레임이 제거됨
- 프로그램 카운터: 다음에 실행될 명령어의 주소를 저장하는 레지스터
- 스택 포인터: 스택의 가장 마지막, 위쪽 데이터 위치를 나타내는 포인터
- 프레임 포인터: 스택 프레임의 시작 위치를 가리키는 포인터
호출하는 호출자 Caller 함수는 호출대상 Callee 함수를 호출할 때 되돌아올 주소값을 스택에 백업함
1. 복귀주소 Return Address란?
함수가 끝난 후 다시 돌아갈 주소를 복귀주소라고 한다. 함수명() 명령이 호출되고 실행될 때 복귀주소가 스택에 저장되고 함수 실행이 끝나면 원래 프로그램으로 돌아가야 함. 인텔 계열 아키텍처에서는 주로 스택에 복귀주소를 저장하고, MIPS 및 ARM 아키텍처는 레지스터에 저장한다.
스택에 저장된 복귀주소는 마지막에 실행되는 RET명령어에 의해 참조됨. RET 명령어는 스택에 저장된 복귀주소를 꺼내와 원래 실행위치로 돌아가는 역할을 하고, 이는 POP EIP 명령어와 동일한 역할이다.
2. CALL/RET의 동작
CALL 명령어는 함수를 호출할 때 현재 실행 중인 코드의 위치(복귀주소)를 스택에 저장한 후, 새로운 함수로 이동한다.
RET 명령어는 함수가 종료될 때 스택에 저장된 복귀주소로 돌아가는 명령어로, 스택에서 복귀주소를 꺼내 CPU의 명령어 포인터(EIP)에 넣는다.
EIP | 현재 실행 중인 명령어 주소 가리키는 레지스터 |
EBP | 함수의 스택 프레임의 기준을 나타내는 레지스터, 함수 호출에 생성되는 스택 프레임의 시작 |
ESP | 스택의 현재 탑을 가리키는 레지스터, 데이터가 추가되면 업데이트되어 현재 위치 추적 |
3. 함수 호출
Main 함수 다음에 A 함수로 넘어가는 프로그램을 실행한다고 가정해 보자
- Main 함수 호출
- Main 함수가 호출되면, 해당 함수의 Saved Frame Pointer가 스택에 저장되고, 지역 변수(Local Variable)도 스택에 할당된다. - A 함수 호출
- Main 함수에서 A 함수를 호출할 때, A 함수의 Saved Frame Pointer와 지역 변수가 추가로 스택에 저장된다.
- 이때, Main 함수가 끝난 후 돌아올 복귀주소(Return Address)도 스택에 함께 저장된다. - A 함수 종료 및 복귀
- A 함수가 종료되면, LEAVE 명령어가 실행되어 Saved Frame Pointer와 복귀주소가 스택에서 제거된다.
- 이후 RET 명령어가 실행되어, 스택에 저장된 복귀주소를 참조하여 Main 함수로 돌아간다. - 여러 함수 호출 시 스택 처리
- Main 함수가 여러 다른 함수를 호출할 때마다, 각각의 함수는 자신의 Saved Frame Pointer, 지역 변수, 그리고 복귀주소를 스택에 쌓는다.
- 각 함수가 종료되면, 스택에 쌓인 정보를 정리하고 복귀주소를 참조하여 이전 함수로 돌아간다.