본문 바로가기

System Security/Technology

스택 프레임(Stack Frame)이란?

스택 프레임(Stack Frame)이란 스택 영역에 함수를 구분하기 위해 생성되는 공간으로서 Parameters, Return Address, Local variables를 포함하고 있으며, 함수 호출 시 생성되고 함수가 종료되면서 소멸됩니다. 

Call Stack(https://en.wikipedia.org/wiki/Call_stack)

프로그램은 함수 호출 시 스택 프레임을 생성하기 위해 함수의 프롤로그(Prolog) 과정을 거치고, 스택 프레임을 소멸시키기 위해 함수의 에필로그(Epilog) 과정을 거치게 됩니다. 그럼, 함수의 프롤로그와 에필로그는 어떠한 과정을 수행하는지 알아봅시다. 

 

예를 들어, 아래와 같은 코드가 있다고 가정해봅시다.

 

#include <stdio.h>
 
void sum(int a, int b) {
    printf("sum : %d\n", a+b);
}
 
int main() {
    int num1, num2 ; 

    scanf("%d %d", &num1, &num2);   
    sum(num1, num2);
    
    return 0;
}

이 프로그램은 단순히 두 개의 정수 값을 입력 받아 Sum 함수를 호출하여 입력받은 두 정수의 합을 구하는 코드입니다. 

gdb를 통해 main 함수부터 살펴봅시다. 

 

main 함수를 보면 위와 같이 sum 함수를 호출하는 부분을 찾을 수 있습니다. 함수를 호출 할 때는 call instruction을 수행하게 되는데 이것은 아래 instruction과 동일합니다. 

 

Call instruction

push eip
jmp 함수의 주소

그럼, 실제로 위에서 설명한 방식대로 동작하는지 확인해봅시다. 아래와 같이 sum 함수가 호출되기 전에 break를 걸고 실행해줍니다.

 

이후, si 명령을 통해 sum() 함수로 들어가봅시다. 이후, esp를 확인해보면 0x080484af (call 0x804846b의 다음 instruction) 주소가 스택에 push 된 것을 볼 수 있습니다. 또한, return address (0x80484af) 오른쪽에 보시면 3과 5가 들어가 쓰여져있는 것을 볼 수 있는데  이는 parameter 값임을 알 수 있습니다.  

 

이후, sum 함수에 대해 살펴봅시다. 이제 본격적으로 함수의 프롤로그와 에필로그에 대해 설명을 해보도록 하겠습니다. 

함수의 프롤로그(Prolog)

위 어셈블리 코드에서 함수의 프롤로그 부분은 아래와 같습니다. 함수 프롤로그 부분에서는 스택 프레임을 형성하는 역할을 합니다. 들어가기 앞서, 간단히 ebp와 esp에 대해 소개를 드리면 ebp는 스택 상에 한 데이터를 가리키는 포인터를 의미하고, esp는 Stack Segment의 맨 꼭대기를 가리키는 포인터를 의미합니다. 또한 ebp는 base pointer, esp는 stack pointer 라고도 부릅니다.

 

ebp를 push 함으로써 caller 함수(현재 함수를 호출한 함수, main 함수)의 ebp 값을 스택에 저장합니다. 이 과정을 거치는 이유는 이전에 수행하던 함수의 데이터를 보존하기 위해서입니다. 

 

그럼, 한 번 함수의 프롤로그 실행되는 과정을 자세히 살펴보도록 합시다. 

push ebp가 수행된 후, 스택의 상태를 살펴보면  0xbfffefe8이 push 된 것을 볼 수 있습니다. 여기에서 0xbfffefe8는 main 함수의 ebp 입니다. 

  • push ebp

  • mov ebp, esp 

이후, esp가 가리키는 주소 값을 ebp에 복사함으로써 함수가 시작될 때에 stack pointer와 base pointer를 새로 지정하는데 이러한 과정을 함수의 프롤로그 과정이라고 합니다. 

 

함수의 에필로그(Epilog)

다음으로, 아래 어셈블리 코드는 함수의 에필로그 부분을 나타냅니다. 함수 에필로그 부분에서는 스택 프레임을 소멸시키는 역할을 합니다. 

 

leave instruction

mov esp, ebp
pop ebp

leave instruction 은 위와 같이 [mov esp, ebp], [pop ebp] 와 같습니다. stack pointer를 이전의 base pointer로 지정해줌으로써 sum() 함수를 호출하면서 확장했던 스택 공간을 없애버리고, Push 해서 저장해두었던 이전 함수 main() 함수의 base pointer를 복원시키는 작업을 합니다.

 

위 과정 (leave instruction)을 거치면, esp는 return address를 가리키고 있게 됩니다. 

 

ret instruction

pop eip

ret instruction은 위와 같이 [pop eip]와 같으며, call instruction의 다음 instruction으로 return 하라는 의미로서 EIP 레지스터에 return address를 pop 하여 집어넣는 역할을 합니다. 

 

이렇게 함수의 에필로그 과정을 거치며, call instruction의 다음 instruction으로 돌아가게 됩니다. 

 

참고 문헌 

[1] https://en.wikipedia.org/wiki/Call_stack

 

'System Security > Technology' 카테고리의 다른 글

메모리 보호 기법  (0) 2022.02.13
CTF Tools  (0) 2022.02.13
Use after free  (0) 2022.01.23
GOT Overwrite  (0) 2022.01.22
NOP Sled  (0) 2022.01.19