미역줄기의 이모저모

기초 CS- Introduction 본문

Hacking/Smashing the stack

기초 CS- Introduction

미역줄기줄기 2024. 2. 23. 20:01
728x90

드림핵 강의랑 많이 겹치지만.. 이건 정말 공부하고 쓰는 글이라 다듬어지지 않은 날 것의(?) 글이다.


 

1.1 x86 Memory layout

출처: 최재영(cjy) e-mail: ebp@nate.com

 

위의 그림은 x86 환경에서 하나의 프로세스가 가상 메모리에 로드되어 실행될 때의 메모리 구조이다. 최상위에 있는 커널 영역은 접근 못한다 (아님말고)  그 밑으로는 유저 영역의 코드 영역, 데이터 영역, bss 영역, 힙 영역, 스택 영역이다.

 

코드 영역

  • 읽기 권한
  • 실제 프로그램을 실행하는 기계어 명령들이 위치한다.

데이터 영역

  • 전역 변수와 정적 변수가 위치

BSS 영역

  • 초기화 되지 않은 전역변수와 정적 변수들이 위치한다

힙 영역

  • 동적으로 할당되는 변수의 데이터가 위치

스택 영역

  • 프로그램에서 사용되는 각종 정보(환경변수, 파라미터, 리턴 값 등)
  • 함수 내부에서 선언한 지역변수 데이터
  • 높은 주소에서 낮은 주소로

공유 라이브러이 영역

  • 스택과 힙 영역 사이에 존재
  • 공유 라이브러리들이 존재(.so)

출처: 최재영(cjy) e-mail: ebp@nate.com

 

 


1.2 Stack structure during function call

스택은 LIFO(Last In First Out) 구조이다. push와 pop 명령을 통해 스택에 값을 저장하고 다시 가져온다.

 

출처: 최재영(cjy) e-mail: ebp@nate.com

 

#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; 
}

 

이 코드를 통해서 스택의 흐름을 살펴본다.

 

 

1. main 함수 호출 직전의 스택의 상황

  • 프로그램 실행 시 처음부터 main이 호출되는 건 아님
  • main 함수 호출 직전의 스택의 상황
  • main 역시 __libc_start_main() 이라는 함수에 의해서 호출 되므로 main 함수의 인자 argc와 **argv를 파라미터로 설정 후 main 함수를 call 하게 된다.

 

2. 함수 프롤로그

 

  • call은 실행 후 복귀할 주소를 스택에 저장한 후! 명령을 수행
  • call 을 통해 호출 시에 ESP가 가리키던 스택의 주소에 복귀주소가 저장되고 자신을 호출한 Caller의 Frame Pointer를 스택에 저장
  • 현재 ESP위치를 EBP 레지스터에 저장하고 이 주소를 현재 함수의 Frame Pointer로 사용
  • return address: call 명령으로 호출된 함수 리턴 후 실행 될 주소
  • frame Pointer: 지역변수 혹은 함수의 파라미터 값에 접근하기 위한 기준으로 사용

caller의 frame pointer를 스택에 저장하고 현재 함수의 frame pointer를 ebp 레지스터로 설정하는 작업을 함수 프롤로그라고 함

 

 

3. main 함수의 지역변수 할당

 

char buf1[20] = "Newheart_main";

 

  • buf1[20]이라는 지역변수에는 "Newheart_main" 이라는 정적인 문자열이 저장

 

4. Func 함수 프롤로그

Func(1, 2, 3);

  • func 함수가 호출되고 새로운 stack frame이 생성된다
  • stack frame: 함수가 호출되어 복귀주소를 저장하는 것 부터 함수가 종료되어 리턴하는 과정까지의 스택 영역
  • caller 함수인 main의 frame pointer의 주소를 스택에 저장 후 새로운 frame pointer를 생성

 

5. Func 함수의 지역변수 할당

 

 

 

 

 

6. Func 함수의 에필로그 과정을 통해 main 함수로 복귀

 

에필로그 수행 전에 add $0x10, $esp 와 같이 ESP 레지스터를 이동시켜 사용했던 지역변수 메모리 공간을 정리한 후에 에필로그를 수행

 

함수 에필로그 leave-ret은 instruction을 수행한다

현재 FP의 위치로 ESP를 이동하고 POP EBP를 통해 Caller함수의 FP로 복귀하고, POP EIP, JMP EIP를 통해 이전 함수의 흐름으로 복귀 할 수 있다 (EIP레지스터는 다음 실행할 Instruction의 주소를 저장한다)

 

 

7. Func 함수 종료 후에 다시 Main 함수의 흐름으로 복귀하여 0을 리턴하고 마찬가지로 main 함수의 에필로그 과정을 통해 main 함수를 종료한다.