System & Reversing

함수 프롤로그, 에필로그에 대한 간단한 고찰.

_방탄유리_ 2023. 3. 13. 00:53

오늘 알아볼 것

- 함수 프롤로그, 에필로그란 뭘까?


열어가는 글

저번까지는 메모리 구조에 대해 알아봤다. 이번에는 함수 프롤로그, 에필로그에 알아볼 시간이다.

 

근데 여기서 함수 프롤로그/에필로그를 알기전에 스택 프레임이란 걸 꼭 알고 넘어가야 한다고 한다.

더보기

stack frame

= 함수 자기 자신만이 가지는 공간. 스택에서 함수가 호출되면 생기는 공간? 이랄까..?

이 이미지가 stack 프레임을 잘 설명하는 것 같다.

 

여기서 EBP란?

-> stack 상의 한 데이터의 주소가 저장되어 있는 레지스터.

  • 그 데이터 위부터 한 함수가 실행된 이후의 값들이 쌓인다.

         = 그 해당 함수의 시작 지점.

         = 함수가 종료되지 않는 EBP값은 변하지 않는다.

 

여기서 ESP란?

-> stack에 맨 꼭대기의 주소가 저장되어있는 레지스터.

-> 여기서 push또는 pop이 일어난다고 한다.

 

 

EIP는 또 뭔가?

->  CPU가 다음에 실행해야 할 명령어의 주소저장되어 있는 레지스터라고 한다.

조금이라도 이해했다 치고 프롤로그와 에필로그에 대해 알아봐야겠다.


함수 프롤로그(prolog)

 

- 함수 실행 준비과정이다.

 

기본적인 구조는 다음과 같다.

 

  1. push ebp     // 함수가 종료된 후 ebp를 이전 함수의 ebp로 재설정하기 위해 stack에 이전 함수의 ebppush한다.
  2. mov ebp, esp // 호출된 함수의 시작을 알리기 위해 현재 esp값 ebp에 복사한다.

함수 프롤로그를 이루고 나서 생기는 일.

여기서 변수가 들어오면 esp가 적어지게되어 stack이 커지게 될 것이다.

 

즉, 이 프롤로그는 함수의 스택 프레임을 형성하는 그 시작점에 생기는 일이라고 한다.

 

 


함수 에필로그(Eplilog)

- 함수 내에서의 수행을 마치고 처음 호출한 지점으로 돌아가기 위해 스택을 복원하는 과정.

 

다음과 같은 명령어들에 의해 수행된다.

 

1. leave

 현재 esp값이 가리키고 있는 SFP를 pop해서 ebp에 넣음으로 이전 함수로 돌아가게 된다.

더보기

mov esp, ebp // esp에 ebp값을 복사해줌으로써 결국 둘은 같아짐.

pop ebp // 그리고 ebp 값을 pop하게 된다.

 

    = 현재 esp가 있는 곳에서 4byte를 복사하여 ebp에 담는다.

저 esp는 이전함수의 ebp에 위치한다. 

 

 

2. ret // 

더보기

pop eip // stack에 미리 저장해놓았던 return address(함수 종료 후 돌아갈 주소)를 eip에 넣어주고

jmp eip // 그 주소로 이동.

-> 함수를 호출한 후의 명령을 계속 수행할 수 있도록 해주는 과정.

 

 

이렇게 적었는데도 에필로그가 이해가 안되어 저 블로그에 적혀있는데로 다시 이해하기 위해 다시 적기로 했다.

더보기

에필로그 방식

 

1. 처음에 ebp를 esp로 복사하여 결국 둘이 같아진다. 저 화살표에 적혀있듯이 ebp,esp다.

ebp를 esp로 복사해서 결국 같이 있는걸 나타낸 그림.

2. 그리고 ebp의 값을 pop하게 된다고 한다. 

정확히는 현재 esp가 있는 곳에서 4byte를 복사해서 ebp에 담는거다. 게다가 저 화살표는 SFP(이전함수의 ebp)의 위치다. 나를 호출한 함수의 ebp 말이다. -> 이게 이해가 안된다. ebp값은 안바뀐다매..

 

여하튼,  이게 esp + 4가 되서 esp의 위치는 RET로 가게 된다고 한다.

esp에 4byte가 추가되어 바뀐 esp의 위치를 나타내는 그림.

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

= eip에는 RET에 담긴 stack의 주소가 들어가게 된다고 한다.

+ esp + 4를 하게 된다.

 

마지으로 jmp eip명령을 수행해서 eip에 저장된 주소, 즉 리턴어드레스(RET)로 이동하며 함수 에필로그가 진행된다고 한다.

결국 RET를 가지고 다음 함수로 넘어간다는 뜻인것 같다.

 

 

 


 결론

여기서 내가 주목해야할 점은 함수가 종료된 이후에 스택에 저장되어있는 return address다.

 

그 return adress에 256bit 이상의 명령어를 넣어서 악의적인 shell code를 넣을 수 있다고 한다.

 

아래 사진을 보면

이 사진이 스택 프레임의 구조와 같은건데 그중 저 위에 다시한번 본건 function()에 해당되는 것과 같은 곳이라고 한다.

 

더보기

저기서 지역변수, 매개변수에 해당되는건 뭘까..)

여기서

우리가 입력한 영역이 그대로 ebp 레지스터에 들어가게 된다는데..

위 사진에서 main이  함수 에필로그를 할때 문제가 발생하게 된다고 한다.

 

저 상태에서 leave가 호출되면 오버플로우가 되서

 

1. mov esp, 변조된 esp

2. pop 변조된 esp

가 된다고 한다.

 

아마 예상컨데 이거 버퍼 오버플로우의 기초인것 같다. 내일 다시한번 또 다시한번 계속계속 복습하고 반복학습을 해야할 것 같다.

 

더보기