함수 프롤로그
--함수 내에서 사용할 스택프레임(함수가 사용하는 영역)을 설정한다--
push ebp
mov ebp, esp
함수 에필로그
--함수 내에서의 수행을 마치고 처음 호출한 지점으로 돌아가기 위해 스택을 복원한다--
leave,ret
-
leave:
-move esp,ebp
-pop ebp
-
ret:
-pop eip
-jmp eip
분석할 소스 코드이다
#incluse <stdio.h>
void function(int a, int b, int c){
printf("%d", a);
printf("%d", b);
printf("%d", c);
}
int main()
{
function(1,2,3);
}
코드를 어셈블리어로 분석한 것이다
0x08048369 <main+0>: push ebp
0x0804836a <main+1>: mov ebp,esp
0x0804836c <main+3>: sub esp,0x8
0x0804836f <main+6>: and esp,0xfffffff0
0x08048372 <main+9>: mov eax,0x0
0x08048377 <main+14>: sub esp,eax
0x08048379 <main+16>: sub esp,0x4
0x0804837c <main+19>: push 0x3
0x0804837e <main+21>: push 0x2
0x08048380 <main+23>: push 0x1
0x08048382 <main+25>: call 0x8048328 <function>
0x08048387 <main+30>: add esp,0x10
0x0804838a <main+33>: leave
0x0804838b <main+34>: ret
0x08048328 <function+0>: push ebp
0x08048329 <function+1>: mov ebp,esp
0x0804832b <function+3>: sub esp,0x8
0x0804832e <function+6>: sub esp,0x8
0x08048331 <function+9>: push DWORD PTR [ebp+8]
0x08048334 <function+12>: push 0x8048438
0x08048339 <function+17>: call 0x8048268 <printf>
0x0804833e <function+22>: add esp,0x10
0x08048341 <function+25>: sub esp,0x8
0x08048344 <function+28>: push DWORD PTR [ebp+12]
0x08048347 <function+31>: push 0x8048438
0x0804834c <function+36>: call 0x8048268 <printf>
0x08048351 <function+41>: add esp,0x10
0x08048354 <function+44>: sub esp,0x8
0x08048357 <function+47>: push DWORD PTR [ebp+16]
0x0804835a <function+50>: push 0x8048438
0x0804835f <function+55>: call 0x8048268 <printf>
0x08048364 <function+60>: add esp,0x10
0x08048367 <function+63>: leave
0x08048368 <function+64>: ret
<m+1> |
---|
esp,ebp ㅁ SFP |
ㅁ RET |
esp를 ebp에 넣어줌으로서 같게해준다
<m+3> |
---|
esp(ebp-8) ㅁ |
ㅁ |
ebp ㅁ SFP |
ㅁ RET |
esp에 8바이트를 넣어준다
<m+6>,<m+16> |
---|
esp(ebp-12) ㅁ |
ㅁ |
ebp ㅁ SFP |
ㅁ RET |
0xfffffff0(4바이트) 와 0x4 를 넣어줌으로써 esp는 ebp-12가된다
<m+19>,<m+21>,<m+23> |
---|
esp(ebp-24) ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ebp ㅁ SFP |
ㅁ RET |
각 3,2,1 순서대로 넣었다
<m+19>,<m+21>,<m+23> |
---|
esp(ebp-28) ㅁ RET(0x8048387) |
ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ebp ㅁ SFP |
ㅁ RET |
call을 이용하여 다시 되돌아올 함수의 위치를 설정한다
<f+0> |
---|
esp(ebp-32) ㅁ SFP(main의 ebp) |
ㅁ RET(0x8048387) |
ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ebp ㅁ SFP |
ㅁ RET |
function함수로 들어가 main의 ebp를 넣어준다
<f+1> |
---|
esp, ebp ㅁ SFP(main의 ebp) |
ㅁ RET(0x8048387) |
ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ㅁ SFP |
ㅁ RET |
esp를ebp에 넣어줌으로써 서로 같아짐
<f+3>,<f+6> |
---|
esp(ebp-16) ㅁ |
ㅁ |
ebp ㅁ SFP(main의 ebp) |
ㅁ RET(0x8048387) |
ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ㅁ SFP |
ㅁ RET |
0x8을 esp에 두번 넣어준다
<f+9> |
---|
esp(ebp-20) ㅁ 1 ([ebp+8]) |
ㅁ |
ㅁ |
ebp ㅁ SFP(main의 ebp) |
ㅁ RET(0x8048387) |
ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ㅁ SFP |
ㅁ RET |
ebp 에서 8바이트 위인 1을 esp에 넣어준다
<f+12> |
---|
esp(ebp-24) ㅁ 0x8048438 |
ㅁ 1 ([ebp+8]) |
ㅁ |
ㅁ |
ebp ㅁ SFP(main의 ebp) |
ㅁ RET(0x8048387) |
ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ㅁ SFP |
ㅁ RET |
4바이트 0x8048438를 넣어준다
<f+22> |
---|
esp(ebp-8) ㅁ |
ebp ㅁ SFP(main의 ebp) |
ㅁ RET(0x8048387) |
ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ㅁ SFP |
ㅁ RET |
add 0x10(10진수로 16)만큼을 더해서 없애준다
이후 나머지 2,3도 이와같은 방법으로 출력한다
<f+61> |
---|
esp(ebp-28) ㅁ RET(0x8048387) |
ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ebp ㅁ SFP |
ㅁ RET |
leave는 mov esp,ebp를 한뒤에 pop ebp를 해줌으로 ebp가 sfp(main의 ebp)까지 날려버려서 ebp가 다시 내려가고 sfp를 ebp에 넣어줘서 main의 ebp로 돌아갔다
<f+64> |
---|
esp(ebp-24) ㅁ 1 |
ㅁ 2 |
ㅁ 3 |
ㅁ |
ㅁ |
ebp ㅁ SFP |
ㅁ RET |
ret은 pop eip뒤에 jump eip를 해주는데 pop eip로 먼저 call로 갈곳을 정해뒀던 주소를 eip라는 레지스터(저장소)에 저장시키면서 pop의영향으로 4바이트를 꺼내고 jum eip을 해줘서 저장한 주소로 이동하면서 ret이 라사진다
<m+30> |
---|
esp(ebp-8) ㅁ |
ebp ㅁ SFP |
ㅁ RET |
add 로 0x10(16바이트를) 더해줘서 스택을 줄인뒤
<m+33> |
---|
esp,ebp ㅁ SFP |
ㅁ RET |
다시 leave안에있는 mov esp,ebp 로 ebp를 esp에 넣어주어서 같게한다음
<m+33> |
---|
ㅁ RET |
pop ebp로 SFP를 꺼내주고
<m+34> |
---|
ret의 구성인 pop eip와 jum eip로 함수로인해 ret이 꺼내지고 스택이 끝나는 모습이다.
깔끔한 정리