Self-Improvement

함수 호출, 복귀(push ebp, mov epb esp, ret) 본문

리버싱 기초

함수 호출, 복귀(push ebp, mov epb esp, ret)

JoGeun 2020. 5. 12. 13:41
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <string.h>
 
int num2 = 3;
 
void func2() {
    printf("func2()\n");
}
 
void sum(int a, int b)
{
    printf("sum : %d\n", a + b);
    func2();
    printf("%d\n", num2);
 
}
 
int main(int argc, char*argv[]) {
    int num = 0;
    char arr[10];
    sum(12);
    printf("END\n");
    printf("%d\n", num);
    printf("%d\n", num2);
}
cs

 

main() -> sum() -> func2() -> sum() -> main()

위처럼 진행이 이루어진다.

 

Main()

1. push ebp -----> 기존 EBP 값을 스택에 쌓는다.

2. mov ebp, esp -----> ESP 값을 EBP에 할당해준다.

3. sub esp, E0 -----> ESP 즉 스택의 공간은 E0(10진수 224)만큼 공간을 늘려준다.

위의 3가지 행동은 Main()함수 시작을 위한 스택 공간을 만들어주는 것이다.

스택은 높은 주소에서 낮은 주소로 움직이며 "sub esp, E0"을 통해 E0만큼의 스택 공간을 확보하는 것이다.

 

Sum() 함수를 호출하는 과정을 확인해 본다.

Main()함수가 시작할때와 동일한 루틴을 가지고 있다.

1. push ebp ------> Main()함수에서 사용된 EBP를 스택에 넣는다

2. mov ebp, esp -----> ESP 값을 EBP에 할당해준다.

3. sub esp, E0 -----> ESP 즉 스택의 공간은 C0(10진수 208)만큼 공간을 늘려준다.

함수를 호출하게 되면 기존의 함수에서 사용된 EBP를 스택에 저장해준다.

스택 = | Main() |  sum() |

 

func()함수를 호출하면 위와 똑같은 과정을 한번 더 거친다

스택 = | Main() |  sum() | func() |

 

func() 함수에서 sum()함수로 돌아갈때를 봐본다.

1. mov esp, ebp -----> 돌아가기 위해(스택 정리) ebp를 esp에 할당해준다.

2. pop ebp -----> ebp를 스택에서 빼면 기존의 sum() 함수의 다음행 주소가 스택에 있다.

3. ret -----> sum()함수로 돌아간다.

ret를 수행하는 순간 sum()+41 = 0x162881 주소로 돌아간다.

 

※ 설명은 이상하게 하였지만 결론은 b 함수를 Call 하기전 기존 함수 a의 스택들은 저장해놓고 새로운 b 함수의 스택 공간이 생겨난다.  b 함수가 종료될 때는 b함수 스택을 정리해주고 저장해놓은 a의 함수 주소로 돌아가게 된다.

 

※ printf() 함수(call 161046)와 같은 단순한 함수들은 call 하기전 스택에 push 된 2개의 인자 공간(8바이트)만큼 call하고 난뒤에 스택을 정리해준다. 그리하여 printf()함수가 끝나고 "add esp,8"로 이제는 쓸모 없어진 2개의 인자 스택 공간을 정리해준다.