Hacking/Pwnable

스택 프레임 (Stack Frame)

GunP4ng 2024. 3. 24. 22:19

스택 프레임


1. 스택 프레임

1. 스택프레임이란?

스택은 함수가 사용하는 지역변수, 파라미터 등이 저장되는 공간이다.

하지만 이런 스택 영역을 아무런 구분 없이 사용하게 된다면, 서로 다른 함수가 같은 메모리 영역을 사용할 수 있게 된다.

 

따라서 함수별로 사용하는 스택의 영역을 명확히 구분하기 위해 스택 프레임(Stack Frame)이 사용된다.

대부분의 프로세스에서는 함수가 자신이 호출될 때 스택 프레임을 만들고, 반환할 때 이를 정리한다.

 

2. 함수 호출 단계

함수 호출

  • 함수가 사용할 매개변수를 스택에 넣고 함수 시작 지점으로 점프한다.

함수 프롤로그

  • 함수 내에서 사용할 스택 프레임을 설정한다.

함수의 본체

  • 함수의 내용을 수행한다.

함수 에필로그

  • 함수가 끝나면 처음 호출한 지점으로 돌아가기 위해 스택을 복원한다.

 

 

2. RET & SFP

1. ebp esp 는 어떻게 쓰이는가?

#include <stdio.h>

int Func(int num1, int num2, char num3) {
	int i = 1, j = 2;
    return 0;
}

int main(int argc, char *argv[]) {
	char buf1[20] = "Newheart_main";
    Func(1, 2, 3);
    return 0;
}

위와 같은 예제코드가 있다.

 

스택에는 프로그램에서 사용되는 환경변수, 함수파라미터 등이 쌓인다고 했다.

위의 코드에 나오는 것들 대부분이 스택에 쌓일 것이다.

 

그럼 esp, ebp 는 언제 쓰이냐?

함수가 메모리에 호출되면 스택 프레임(Stack Frame)을 잡아준다고 했다.

이 스택 프레임이 ebp 와 esp 사이의 공간이라고 생각하면 된다.

스택에 파라미터 저장

위의 그림은 main 함수의 파라미터가 스택에 쌓이고

esp 값이 파라미터 크기만큼 마이너스( - ) 되어 스택이 커지게 된다.

 

2. RET (Return Address)

함수가 호출되면 함수의 파라미터들이 스택에 먼저 쌓이고 그 후에 CALL 명령이 떨어진다.

함수가 다 끝나고 그 다음 실행되어야 할 부분이 RET (Return Address)으로 파라미터 다음에 쌓인다.

 

RET 에는 현재 함수가 호출된 CALL 명령 다음에 실행할 부분의 주소가 담긴다.

호출 이전 함수로 돌아가는 것이다.

ret는 32bit 운영체제에서는 4byte, 64bit 운영체제에서는 8byte이다.

스택에 RET 저장

파라미터 다음에 RET (Return Address)가 오게 된다.

 

3. SFP (Stack Frame Pointer)

RET 다음에는 이전 함수의 프레임 포인터 (FP, Frame Pointer) 가 저장되어야 한다.

FP 가 있어야 현재 함수가 끝나고 이전 함수로 돌아갔을 때의 스택 프레임을 복원할 수 있다.

현재 함수 사용 중에 이전 함수의 지역 변수 등을 참조할 경우에도 쓰인다.

 

이것을 SFP (Stack Frame Pointer)라고 한다.

쉽게 ebp 에 저장된 위치(이전 함수에서 ebp가 가리키던 곳) 가 SFP 라고 보면 된다.

ebp 는 함수가 사용하는 스택 영역의 기준점이되고, 스택에 쌓이는 것들은 ebp 를 기준으로 위치를 파악한다.

sfp 는 32bit 운영체제에서는 4byte, 64bit 운영체제에서는 8byte이다.

스택에 SFP 저장

RET 다음에 SFP 가 저장된 스택 모습이다.

이제 함수의 프롤로그와 에필로그를 알아보자.

 

 

3. 함수 프롤로그(Prologue)

1. 함수 프롤로그

스택에 SFP 까지 저장된 이후에는 스택에 쌓일 지역변수가 없기 때문에 esp 는 SFP 가 저장된 메모리 주소를 갖고있다.

이 때 ebp 에 esp 의 값을 복사한다.

(새로운 함수의 스택 프레임을 생성하는 것이다)

 

이 과정을 함수의 프롤로그(Prologue)라고 한다.

함수의 프롤로그

RET 는 Return Address 로 call 명령으로 호출된 함수에서 리턴 후 실행될 주소이다.

SFP 는 호출된 함수를 불러낸 함수(caller) 의 프레임 포인터를 저장한 것이다.

이 과정이 main 함수의 프롤로그인 것이다.

 

어셈블리로 보면 다음과 같다

PUSH EBP	; 함수 시작(EBP를 사용하기 전에 기존의 값을 스택에 저장)
MOV EBP, ESP	; 현재의 ESP (스택 포인터)를 EBP 에 저장

함수 수행을 마치면 제자리로 돌아가기 위해 ebp 의 값을 스택에 push 하여 저장한다.

ebp 에 esp 를 저장해줌으로써 스택 프레임을 생성해준다.

 

2. 함수 본체

함수 호출 시 파라미터가 먼저 스택에 쌓이게 된다.

그리고 함수 프롤로그 후에 함수의 지역 변수가 스택 메모리에 할당된다.

위의 코드 내용을 스택에 넣으면 아래 그림과 같다.

Func() 함수까지 저장됨

main 함수의 프롤로그가 끝난 후 함수의 지역변수가 스택에 저장된다.

그 다음 Func() 함수의 파라미터가 저장되고, Func() 함수의 프롤로그가 저장된다.

프롤로그가 끝나면 Func() 함수의 지역변수까지 저장된다. 

 

Func() 함수의 파라미터가 저장될 때 C언어의 입력 순서와 반대로 스택에 저장되게 된다.

Func(1, 2, 3);

이지만 스택에는 3, 2, 1 순으로 저장되게 된다. 

 

CALL Func()까지 마치면 스택은 위와 같은 상황이된다.

 

 

4. 함수 에필로그(Epilogue)

1. 함수 에필로그

함수의 에필로그는 함수가 종료되어 나를 호출한 함수로 돌아갈 때 스택을 정리하는 과정이다.

Func() 함수가 종료되어 호출한 함수 main() 으로 돌아가는 과정인 것이다.

 

함수 에필로그는 두 개의 명령으로 이루어져 있다.

LEAVE
RET

 

2. leave 명령어

leave 는 아래와 같은 명령어를 수행한다.

MOVE ESP, EBP
POP EBP

 

먼저 MOVE ESP, EBP 명령이다.

func() 함수를 종료하기 위해 ebp 의 값을 esp 에 대입해준다.

MOVE esp, ebp

ebp 의 값을 esp 에 복사하여 둘이 같아지게 된다.

esp 가 SFP 에 위치하게 되는 것이다. 여기서 SFP는 Main() 함수의 FP이다.

다시 말해 이전 함수의(main) ebp 인 것이다.

 

다음은 POP EBP 명령이다.

POP EBP

pop 명령은 현재 esp 가 있는 곳에서 4byte 를 복사하여 피연산자에 담고 esp + 4 를 한다.

현재 esp가 있는 곳은 SFP, 즉 main 함수의 ebp 이다.

ebp 에 main 함수의 ebp 를 복사해주고, esp + 4 를 하여 esp 는 RET를 가리키게 된다.

 

3. RET 명령어

ret 는 아래와 같은 명령어를 수행한다

POP EIP
JMP EIP

 

먼저 POP EIP 명령이다.

leave 명령이 끝난 후 esp 는 RET 를 가리키게 된다.

POP EIP

여기서 pop eip 명령을 수행하게 되면 esp 가 있는 곳에서 4byte를 복사해 eip 에 담게 된다.

즉, eip 에는 RET 에 담긴 스택 주소 (Return Address) 가 들어간다.

그 다음 esp + 4 를 한다.

 

다음은 JMP EIP 명령이다.

eip 에 저장된 주소, 즉 RET (Return Address)로 이동하여 함수 에필로그가 진행된다.

JMP EIP

스택 상태를 확인해보면 Func() 함수를 호출하기 전의 상태로 돌아왔다.

main 함수도 위와 같은 과정으로 에필로그를 거쳐 함수가 종료되게 된다.

 

 


Reference

https://plummmm.tistory.com/353

https://yks-study.tistory.com/38#%F0%9F%93%A2%ED%95%A8%EC%88%98%EC%9D%98%20%ED%98%B8%EC%B6%9C%20%EB%8B%A8%EA%B3%84-1

https://jiravvit.tistory.com/entry/%ED%95%A8%EC%88%98-%ED%94%84%EB%A1%A4%EB%A1%9C%EA%B7%B8prolog-%ED%95%A8%EC%88%98-%EC%97%90%ED%95%84%EB%A1%9C%EA%B7%B8eplilog

https://dokhakdubini.tistory.com/394