By in09 | March 10, 2016
우리집에 GDB 있는데… 메모리 보고갈래? #02
Day#2 애프터 신청 (너 gdb 사용법, 갖고싶다.. 너란 stack )
tomato.c
//tomato.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void func2() {
puts("func2()");
}
void sum(int a, int b) {
printf("sum : %d\n", a+b);
func2();
}
int main(int argc, char *argv[]) {
int num=0;
char arr[10];
sum(1,2);
strcpy(arr,argv[1]);
printf("arr: %s\n", arr);
if(num==1){
system("/bin/sh");
}
return 0;
}
compile
$ gcc -fno-stack-protector -o tomato tomato.c
-fno-stack-protector
옵션을 포함하는 이유
gcc가 스택을 보호하기 위해
canary
라는 것을 삽입해요.
함수 내에서 사용하는 스택 프레임과 return address 사이에 canary를 넣어염.
Buffer Overflow가 발생해canary
를 덮었을 때, 이를 감지하고 프로그램을 강제 종료 해 버린답니당!
이를SSP(Stack Smashing Protection)
이라고 해요.
여기에선 오버플로우가 발생해도 프로그램이 강제 종료되지 않도록–fno-stack-protector
옵션을 사용해 보호기법을 해제한겁니답 반대로 모든 프로시져에 이 보호기법을 적용하기 위해서는-fstack-protector-all
옵션을 사용하세염
1. 너GDB 사용법
” 하라니까 하겠는데, 근데 gdb를 왜 써야되는데?”
지..진정하세요;;
gdb는 오픈소스로 공개되어있는 무료 디버거랍니다.
아 디버거가 뭐냐거여?
님들 해답지보고 공부할 때
왜 이러저러하게 이 답이 도출이 되는지 보잖아요
디버거도 그런검미다
코드에서 이 라인을 실행할 때 어떤 값이 어떤 메모리 주소에 올라가고
그 과정을 보여주는거져
컴퓨터 계의 X-RAY랄까?
gdb를 쓰면 물론 콘솔 기반이라.. 처음 쓸 때는 좀 어렵고 빡치고 하긴 해여..
ida 봐봐여… 아름답잖아요..
하지만 ELF 파일과 같은 Linux 기반의 실행파일을
동적으로 따라가며 분석할 때 gdb 참 쓸만하져
그래서 이거 씀미다!
긍까 쫄지말고 긔긔!!
gdb로 tomato를 실행시켜봅시당!
$ gdb ./tomato
이건 그냥 gdb로 tomato에 붙은 것에 불과해여.
아직 우리의 토마토는 실행되지 않았담미다.
일단 gdb 켜봤으면 뭐.. 어셈도 한번 봐주고
tomato를 실행하기 전에 이것 저것 설정도 해줘야쥬?
일단 보기 편하게 어셈 코드를 intel 형식으로 설정해
main을 출력해 보겠습니답ㅎㅎ
◎ GDB 사용법 1
- set disassembly-flavor [명령어 형식]
- 어셈블리 코드 문법을 설정하는 명령어
- x86에서 Intel과 at&t 둘 중 하나를 골라 쓰면 됨
- [명령어 형식의 예] :
intel
,att
◎ GDB 사용법 2
- disas [함수이름]
- 함수의 어셈블리 코드를 보는 명령어
(gdb) disas main
Dump of assembler code for function main:
0x080484cf <+0>: push ebp
0x080484d0 <+1>: mov ebp,esp
0x080484d2 <+3>: sub esp,0x10
0x080484d5 <+6>: mov DWORD PTR [ebp-0x4],0x0
0x080484dc <+13>: push 0x2
0x080484de <+15>: push 0x1
0x080484e0 <+17>: call 0x80484ae <sum>
0x080484e5 <+22>: add esp,0x8
0x080484e8 <+25>: mov eax,DWORD PTR [ebp+0xc]
0x080484eb <+28>: add eax,0x4
0x080484ee <+31>: mov eax,DWORD PTR [eax]
0x080484f0 <+33>: push eax
0x080484f1 <+34>: lea eax,[ebp-0xe]
0x080484f4 <+37>: push eax
0x080484f5 <+38>: call 0x8048350 <strcpy@plt>
0x080484fa <+43>: add esp,0x8
0x080484fd <+46>: lea eax,[ebp-0xe]
0x08048500 <+49>: push eax
0x08048501 <+50>: push 0x80485c2
0x08048506 <+55>: call 0x8048340 <printf@plt>
0x0804850b <+60>: add esp,0x8
0x0804850e <+63>: cmp DWORD PTR [ebp-0x4],0x1
0x08048512 <+67>: jne 0x8048521 <main+82>
0x08048514 <+69>: push 0x80485cb
0x08048519 <+74>: call 0x8048370 <system@plt>
0x0804851e <+79>: add esp,0x4
0x08048521 <+82>: mov eax,0x0
0x08048526 <+87>: leave
0x08048527 <+88>: ret
End of assembler dump.
메인이 이렇게 구성되어 있네요.
main
에 breakpoint
를 걸고 한번 실행해 볼까요?
0x080484cf <+0>: push ebp
요 부분이 main
의 시작이잖아요?
◎ GDB 사용법 3
- b *[메모리주소]
- breakpoint를 거는 명령
[메모리 주소]
나[함수의 이름]
혹은 이를 기준으로 한[offset <+0>]
으로 breakpoint를 걸어도 됩니당- breakpoint를 걸 땐, 주소 앞에
*
를 붙이세요!
(gdb) b * main
Breakpoint 1 at 0x80484cf
(gdb) b *0x80484cf
Note: breakpoint 1 also set at pc 0x80484cf.
Breakpoint 2 at 0x80484cf
(gdb) b *main+0
Note: breakpoints 1 and 2 also set at pc 0x80484cf.
Breakpoint 3 at 0x80484cf
모두 똑같은 곳에 breakpoint가 걸렸죠?
breakpoint 정보를 확인해볼게용
◎ GDB 사용법 4
- info b
- breakpoint 정보를 열람할 수 있는 명령어
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484cf <main>
2 breakpoint keep y 0x080484cf <main>
3 breakpoint keep y 0x080484cf <main>
Breakpoint가 중복되니 삭제해보도록 하겠습니당!
◎ GDB 사용법 5
- d [breakpoint 번호]
- breakpoint를 삭제 할 수 있는 명령어
(gdb) d 3
(gdb) d 2
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x080484cf <main>
이제 프로그램을 실행해볼게요!
이제야 비로소.. 아 토마토 다 뿔었겠네ㅡㅡ
◎ GDB 사용법 6
- run [매개변수]
- gdb 내부에서 프로그램 실행
(gdb) run aaaaaaaaaa
Starting program: tomato aaaaaaaaaa
Breakpoint 1, 0x080484cf in main ()
(gdb)
헌데 명령행 인자로 main의 매개변수에 값이 넘어가죠?
그래서 aaaaaaaaa
스트링을 넘겨준 거예요.
$ ./tomato aaaaaaaaaa
sum : 3
func2()
arr: aaaaaaaaaa
터미널에서 위와 같이 실행하는 것과 동일한거죠!
현재 우리 실행 흐름이 어디에 있는지 EIP
를 확인해볼게요!
Main에 멈춰있어야겠죠?
(gdb) r aaaaaaaaaa
Starting program: tomato aaaaaaaaaa
Breakpoint 1, 0x080484cf in main ()
(gdb) disas main
Dump of assembler code for function main:
=> 0x080484cf <+0>: push ebp
0x080484d0 <+1>: mov ebp,esp
0x080484d2 <+3>: sub esp,0x10
=>
화살표가 보이졍?
아주 잘 멈춰져있네요.
인스트럭션을 한줄 한줄 실행해볼게염
◎ GDB 사용법 7
- ni
- 다음 인스트럭션 실행
(gdb) ni
0x080484d0 in main ()
(gdb) ni
0x080484d2 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x080484cf <+0>: push ebp
0x080484d0 <+1>: mov ebp,esp
=> 0x080484d2 <+3>: sub esp,0x10
0x080484d5 <+6>: mov DWORD PTR [ebp-0x4],0x0
0x080484dc <+13>: push 0x2
0x080484de <+15>: push 0x1
현재 EIP가 멈춰져있는 곳 이 전의 밑줄 친 인스트럭션을 보면
esp 값을 ebp 값에 저장하고 있죠?
esp, ebp는 스택과 관련한 레지스터잖아요!
그 메모리에 어떤 값이 담겨있는지 gdb로 확인해보도록 하게씀미당!
그 전에 메모리 출력 방식에 대해 정리하고 가도록 할게요.
몇 바이트만큼 그리고 몇 진법으로 출력할 것인지 정해 옵션을 주어 출력해 주면 됨미다.
◎ GDB 사용법 8
- x/b
- 1바이트 출력
- x/h
- 2바이트 출력
- x/w
- 4바이트 출력
(gdb) x/b 0x080484cf
0x80484cf <main>: 0x55
(gdb) x/h 0x080484cf
0x80484cf <main>: 0x8955
(gdb) x/w 0x080484cf
0x80484cf <main>: 0x83e58955
해당 메모리 주소의 값을 각각 1바이트, 2바이트, 4바이트만큼 출력해주었습니다.
◎ GDB 사용법 9
- x/x
- 메모리 주소값을 16진수로 출력
- x/u
- 메모리 주소값을 10진수로 출력
(gdb) x/x 0x080484cf
0x80484cf <main>: 0x83e58955
(gdb) x/u 0x080484cf
0x80484cf <main>: 2212858197
해당 메모리 주소 값을 16진수, 10진수로 출력해주었습니다.
보통 아래와 같이들 씁니당!
(진법 옵션이든 바이트 옵션이든 생략되면 이전 옵션으로 실행해줍니다.)
(gdb) x/wx 0x080484e6
0x80484e6 <main>: 0x83e58955
(gdb) x/4b 0x080484e6
0x80484e6 <main>: 0x55 0x89 0xe5 0x83
값을 ebp
값에 저장하고 있죠?
esp
, ebp
는 스택과 관련한 레지스터잖아요!
그 메모리에 어떤 값이 담겨있는지 gdb로 확인해보도록 할게씀미당!
그 전에 메모리 출력 방식에 대해 정리하고 가도록 할게요.
몇 바이트만큼 그리고 몇 진법으로 출력할 것인지 정해 옵션을 주어 출력해주면 된다는거!
(gdb) x/wx 0x080484cf
0x80484cf <main>: 0x83e58955
(gdb) x/4b 0x080484cf
0x80484cf <main>: 0x55 0x89 0xe5 0x83
헙.. 근데 출력되는 순서가 조금 이상하죠?
4바이트 출력한 것과 1바이트씩 4개를 출력한 것과 순서가 반대예요!
바이트 오더링 개념에 대해 이해를 해야 합니다!
- Byte Ordering - Little Endian & Big Endian
- Intel CPU는 바이트를 배열할 때 거꾸로 쓰게 됩니다.
예를 들어 0x12345678을 저장한다고 하면, 0x78563412와 같이 거꾸로 저장하게 됩니다.
이런 방식을Little Endian
이라 지칭합니다.- 반면, gdb는 디버깅 시에 보기 편하게 하기 위해서
Big Endian
형식으로0x12345678
와 같이 출력해주기 때문에,
1바이트씩 출력할 때와 4바이트로 출력할 때 달리 보이는 거예요.- 참고로 네트워크 상에서는
Big Endian
형식의 바이트 오더링을 사용합니다.
특정 레지스터를 기준으로 메모리 값을 보고 싶거나, 레지스터의 정보를 보고 싶을 때는 아래와 같이 합니다.
(gdb) x/4wx $esp
0xffffd230: 0x00000001 0x00000002 0x08048539 0x00000000
◎ GDB 사용법 10
- $[레지스터 이름]
- 레지스터를 기준으로 메모리 값을 출력
◎ GDB 사용법 11
- info r
- 레지스터의 정보를 출력
다음은 ebp와 esp를 출력 해 본 것이고,
레지스터의 정보를 출력 해 본 것입니당.
(gdb) x/wx $ebp
0xffffd248: 0x00000000
(gdb) x/wx $esp
0xffffd248: 0x00000000
(gdb) info reg $ebp
ebp 0xffffd248 0xffffd248
(gdb) i r $ebp $esp
ebp 0xffffd248 0xffffd248
esp 0xffffd248 0xffffd248
(gdb) i r
eax 0xf7fc2dbc -134468164
ecx 0xc85e173 210100595
edx 0xffffd274 -11660
ebx 0x0 0
esp 0xffffd248 0xffffd248
ebp 0xffffd248 0xffffd248
esi 0xf7fc1000 -134475776
edi 0xf7fc1000 -134475776
eip 0x80484d2 0x80484d2 <main+3>
eflags 0x296 [ PF AF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
자.. 이제 gdb의 기본적인 사용법은 거진 다 익힌 것 같아요.
이제 우리 좀 더 알아가볼까요..?ㅎㅎ
2. 갖고싶다.. 너란 STACK..
현재 EIP
의 상황은 다음과 같아여. main 함수에서 인스트럭션 두 개를 실행했지여.
0x080484cf <+0>: push ebp
0x080484d0 <+1>: mov ebp,esp
=> 0x080484d2 <+3>: sub esp,0x10
0x080484d5 <+6>: mov DWORD PTR [ebp-0x4],0x0
0x080484dc <+13>: push 0x2
0x080484de <+15>: push 0x1
2-1. Stack의 시작
$ push ebp
$ mov ebp, esp
단 두 줄의 인스트럭션만 실행이 되었기 때문에 별 거 없을 것 같지여?
하지만 저 단 두 줄의 어셈이 의미하는 바는 상당합니다.
바로 스택(프레임)이 생성
되기 때문이예여.
저 두 줄의 의미는
1. 함수가 실행이 될 때, 그 이전의 ebp(sfp)를 스택에 push하고
2. 현재 esp를 ebp에 저장하라.
입니다.
아직 어떤 데이터도 스택에 push 되지 않았기 때문에 esp
는 ebp
와 같겠지여!
이렇게 스택 프레임이 생성됩니다.
2-2. 스택을 보자!!
0x080484e0 <+17>: call 0x80484ae <sum>
여기에 브레이크포인트를 걸고 실행시킨 후의 스택의 상황을 보겠습니답.
breakpoint까지 한 번에 뛰려면 c 명령을 사용하면 됩니당.
(gdb) c
Continuing.
Breakpoint 1, 0x080484e0 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x080484cf <+0>: push ebp
0x080484d0 <+1>: mov ebp,esp
0x080484d2 <+3>: sub esp,0x10
0x080484d5 <+6>: mov DWORD PTR [ebp-0x4],0x0
0x080484dc <+13>: push 0x2
0x080484de <+15>: push 0x1
=> 0x080484e0 <+17>: call 0x80484ae <sum>
0x080484e5 <+22>: add esp,0x8
원하는 곳에 멈춰잇쪄?
그럼 sum 함수
가 call 되기 전의 상황과 후의 상황을 좀 볼까여?
◎ sum
이 call되기 전 상황
(gdb) i r $esp $ebp
esp 0xffffd230 0xffffd230
ebp 0xffffd248 0xffffd248
(gdb) x/8wx $esp
0xffffd230: 0x00000001 0x00000002 0x08048539 0x00000000
0xffffd240: 0xf7fc1000 0x00000000 0x00000000 0xf7e29637
그리고 sum 함수 안으로 들어가보도록 하겠습니다.
call을 할 때는 다음 인스트럭션의 주소를 스택에 쌓고 가죠?
0x080484e0 <+17>: call 0x80484ae <sum>
0x080484e5 <+22>: add esp,0x8
0x080484e8 <+25>: mov eax,DWORD PTR [ebp+0xc]
call sum에 breakpoint를 걸고 sum 안으로 들어가면
스택에 ESP(0x00000001)
위에 0x080484e5
가 쌓였을 거예여!
확인해볼까욤?
◎ sum
이 call된 후의 상황
(gdb) x/16wx $esp
0xffffd22c: 0x080484e5 0x00000001 0x00000002 0x08048539
0xffffd23c: 0x00000000 0xf7fc1000 0x00000000 0x00000000
0xffffd24c: 0xf7e29637 0x00000002 0xffffd2e4 0xffffd2f0
0xffffd25c: 0x00000000 0x00000000 0x00000000 0xf7fc1000
sum 함수 안으로 들어가 보겠습니다.
◎ GDB 사용법 12
- si
- 함수 안으로 진입
(gdb) si
0x080484ae in sum ()
(gdb) disas sum
Dump of assembler code for function sum:
=> 0x080484ae <+0>: push ebp
0x080484af <+1>: mov ebp,esp
0x080484b1 <+3>: mov edx,DWORD PTR [ebp+0x8]
0x080484b4 <+6>: mov eax,DWORD PTR [ebp+0xc]
0x080484b7 <+9>: add eax,edx
0x080484b9 <+11>: push eax
0x080484ba <+12>: push 0x80485b8
0x080484bf <+17>: call 0x8048340 <printf@plt>
0x080484c4 <+22>: add esp,0x8
0x080484c7 <+25>: call 0x804849b <func2>
0x080484cc <+30>: nop
0x080484cd <+31>: leave
0x080484ce <+32>: ret
End of assembler dump.
sum 함수 안으로 들어왔쪄?
오 역시나
Push ebp
Mov ebp, esp
하고 있어욤!
Push ebp를 실행하면 그 이전 스택 프레임(main)의 ebp가 sum의 스택 프레임에 push 될거예여!
즉, main의 ebp 0xffffd248
가 esp에 들어가겠쬬?
(gdb) ni
0x080484af in sum ()
(gdb) disas sum
Dump of assembler code for function sum:
0x080484ae <+0>: push ebp
=> 0x080484af <+1>: mov ebp,esp
0x080484b1 <+3>: mov edx,DWORD PTR [ebp+0x8]
0x080484b4 <+6>: mov eax,DWORD PTR [ebp+0xc]
0x080484b7 <+9>: add eax,edx
0x080484b9 <+11>: push eax
0x080484ba <+12>: push 0x80485b8
0x080484bf <+17>: call 0x8048340 <printf@plt>
0x080484c4 <+22>: add esp,0x8
0x080484c7 <+25>: call 0x804849b <func2>
0x080484cc <+30>: nop
0x080484cd <+31>: leave
0x080484ce <+32>: ret
End of assembler dump.
(gdb) x/x $esp
0xffffd228: 0xffffd248
오오… 마쟈마쟈ㅠㅠ
Mov ebp, esp
를 하면
그리고 현재 esp를 sum stack frame의 바닥
즉, sum의 ebp로 만들어주겠져?
그러므로 sum의 ebp에는 main의 ebp가 있게되겠져!
이제 새로운 sum의 스택 프레임을 확인해볼까요?
(gdb) x/16wx $ebp
0xffffd158: 0xffffd178 0x080484e5 0x00000001 0x00000002
0xffffd168: 0x08048539 0x00000000 0xf7fc1000 0x00000000
0xffffd178: 0x00000000 0xf7e29637 0x00000002 0xffffd214
0xffffd188: 0xffffd220 0x00000000 0x00000000 0x00000000
이제 새로운 sum의 스택 프레임이 생성되었습니다!!
(현재 tomato.c에서 sum(1,2)라인이 실행 중이겠져?)
상단의 스택을 첫줄만 간추려보도록 하겠습니당!
0xffffd158: 0xffffd178 0x080484e5 0x00000001 0x00000002
보이심까?
새로운 스택 프레임의
ebp
를 기준으로
return address
는ebp-4
,
매개인자는ebp-8
,ebp -12
와 같이 들어가게 됩니다!
꼭 기억하세욤!
자.. 또 sum
안에서 func2
를 호출했어요!
(gdb) disas sum
Dump of assembler code for function sum:
0x080484ae <+0>: push ebp
0x080484af <+1>: mov ebp,esp
=> 0x080484b1 <+3>: mov edx,DWORD PTR [ebp+0x8]
0x080484b4 <+6>: mov eax,DWORD PTR [ebp+0xc]
0x080484b7 <+9>: add eax,edx
0x080484b9 <+11>: push eax
0x080484ba <+12>: push 0x80485b8
0x080484bf <+17>: call 0x8048340 <printf@plt>
0x080484c4 <+22>: add esp,0x8
0x080484c7 <+25>: call 0x804849b <func2>
0x080484cc <+30>: nop
0x080484cd <+31>: leave
0x080484ce <+32>: ret
End of assembler dump.
(gdb) b *sum+25
Breakpoint 3 at 0x80484c7
(gdb) c
Continuing.
sum : 3
Breakpoint 3, 0x080484c7 in sum ()
(gdb) disas sum
Dump of assembler code for function sum:
0x080484ae <+0>: push ebp
0x080484af <+1>: mov ebp,esp
0x080484b1 <+3>: mov edx,DWORD PTR [ebp+0x8]
0x080484b4 <+6>: mov eax,DWORD PTR [ebp+0xc]
0x080484b7 <+9>: add eax,edx
0x080484b9 <+11>: push eax
0x080484ba <+12>: push 0x80485b8
0x080484bf <+17>: call 0x8048340 <printf@plt>
0x080484c4 <+22>: add esp,0x8
=> 0x080484c7 <+25>: call 0x804849b <func2>
0x080484cc <+30>: nop
0x080484cd <+31>: leave
0x080484ce <+32>: ret
End of assembler dump.
그럼 아마 스택의 모습은 | func2 stack frame | sum stack frame | main stack frame|
와 같이 되겠져?
확인해볼게염!!
(gdb) si
0x0804849b in func2 ()
(gdb) disas func2
Dump of assembler code for function func2:
=> 0x0804849b <+0>: push ebp
0x0804849c <+1>: mov ebp,esp
0x0804849e <+3>: push 0x80485b0
0x080484a3 <+8>: call 0x8048360 <puts@plt>
0x080484a8 <+13>: add esp,0x4
0x080484ab <+16>: nop
0x080484ac <+17>: leave
0x080484ad <+18>: ret
End of assembler dump.
(gdb) ni
0x0804849c in func2 ()
(gdb) ni
0x0804849e in func2 ()
(gdb) x/24wx $esp
0xffffd150: 0xffffd158 0x080484cc 0xffffd178 0x080484e5
0xffffd160: 0x00000001 0x00000002 0x08048539 0x00000000
0xffffd170: 0xf7fc1000 0x00000000 0x00000000 0xf7e29637
0xffffd180: 0x00000002 0xffffd214 0xffffd220 0x00000000
0xffffd190: 0x00000000 0x00000000 0xf7fc1000 0xf7ffdc04
0xffffd1a0: 0xf7ffd000 0x00000000 0xf7fc1000 0xf7fc1000
시작이 있으면 끝이 있겠져?
스택의프레임이시작되는 Push ebp
,Mov ebp, esp
를 자세히 살펴 보았으니
스택 프레임의 끝
Leave
,Ret
을 살펴보도록 하겠습니다.
2-3. 스택의 끝
$ leave
$ ret
◎ 현재 EIP의 위치
(gdb) disas func2
Dump of assembler code for function func2:
0x0804849b <+0>: push ebp
0x0804849c <+1>: mov ebp,esp
0x0804849e <+3>: push 0x80485b0
0x080484a3 <+8>: call 0x8048360 <puts@plt>
0x080484a8 <+13>: add esp,0x4
0x080484ab <+16>: nop
=> 0x080484ac <+17>: leave
0x080484ad <+18>: ret
End of assembler dump.
현재 eip는 leave 실행을 기다리고 있습니다!!
◎ 현재 leave 실행 전 스택 프레임 상황
(gdb) x/32wx $esp
0xffffd150: 0xffffd158 0x080484cc 0xffffd178 0x080484e5
0xffffd160: 0x00000001 0x00000002 0x08048539 0x00000000
0xffffd170: 0xf7fc1000 0x00000000 0x00000000 0xf7e29637
0xffffd180: 0x00000002 0xffffd214 0xffffd220 0x00000000
0xffffd190: 0x00000000 0x00000000 0xf7fc1000 0xf7ffdc04
0xffffd1a0: 0xf7ffd000 0x00000000 0xf7fc1000 0xf7fc1000
0xffffd1b0: 0x00000000 0x5d7d9f4f 0x67f5715f 0x00000000
0xffffd1c0: 0x00000000 0x00000000 0x00000002 0x080483a0
◎ leave 실행 후 스택 프레임 상황
(gdb) ni
0x080484ad in func2 ()
(gdb) disas func2
Dump of assembler code for function func2:
0x0804849b <+0>: push ebp
0x0804849c <+1>: mov ebp,esp
0x0804849e <+3>: push 0x80485b0
0x080484a3 <+8>: call 0x8048360 <puts@plt>
0x080484a8 <+13>: add esp,0x4
0x080484ab <+16>: nop
0x080484ac <+17>: leave
=> 0x080484ad <+18>: ret
End of assembler dump.
(gdb) x/32wx $esp
0xffffd154: 0x080484cc 0xffffd178 0x080484e5 0x00000001
0xffffd164: 0x00000002 0x08048539 0x00000000 0xf7fc1000
0xffffd174: 0x00000000 0x00000000 0xf7e29637 0x00000002
0xffffd184: 0xffffd214 0xffffd220 0x00000000 0x00000000
0xffffd194: 0x00000000 0xf7fc1000 0xf7ffdc04 0xf7ffd000
0xffffd1a4: 0x00000000 0xf7fc1000 0xf7fc1000 0x00000000
0xffffd1b4: 0x5d7d9f4f 0x67f5715f 0x00000000 0x00000000
0xffffd1c4: 0x00000000 0x00000002 0x080483a0 0x00000000
Leave
실행 후에 func2의 stack frame이 모두 정리된 것 보이시나여?!
그리고 ebp
가 sum
의 ebp
로 바뀌고 esp
도 sum
의 esp
로 바뀌었습니다.
(gdb) x/i 0x080484cc
0x80484cc <sum+30>: nop
그리고 Ret
을 만나면 0x080484cc
로 리턴해 나머지 sum의 인스트럭션을 실행하고,
끝으로 sum
의 stack frame도 정리되고,
나머지 main의 인스트럭션을 실행한 후 프로그램을 종료되겠씀미다아아!!
쟈아아아 오늘은 gdb
도 써보고 스택 프레임
에 대해서도 자세히 알아보았눈데
어떠셔쎄여!!
다음 번엔 좀 더 다이나믹한 데이트를 합씨당!!
아 물론 데이트 코스는 제가 짭니당^ㅠ^
차회 예고
그럼 이만 뿅!!