먼저 gdb를 통해 stack0 을 메인함수까지 디스어셈블을 해보았다.

다음과 같은 프로그램의 C 소스코드는 다음과 같다.

#include <stdlib.h>#include <unistd.h>#include <stdio.h>int main(int argc, char **argv)
{
  volatile int modified;
  char buffer[64];

  modified = 0;
  gets(buffer);

  if(modified != 0) {
      printf("you have changed the 'modified' variable\\n");
  } else {
      printf("Try again?\\n");
  }
}

위에 코드를 해석해보자면

64바이트의 크기로 변수 buffer을 선언하고 4바이트 크기의 modified 변수 또한 선언한다.

if문을 통해 modified 변수가 0인지 아닌지 확인해 Success 혹은 Failed를 타나내게 출력한다.

어셈블리어 부분 또한 해석을 해보자.

   0x080483f4 <+0>:     push   ebp
   0x080483f5 <+1>:     mov    ebp,esp
   0x080483f7 <+3>:     and    esp,0xfffffff0
   0x080483fa <+6>:     sub    esp,0x60
   0x080483fd <+9>:     mov    DWORD PTR [esp+0x5c],0x0
   0x08048405 <+17>:    lea    eax,[esp+0x1c]
   0x08048409 <+21>:    mov    DWORD PTR [esp],eax
   0x0804840c <+24>:    call   0x804830c <gets@plt>
   0x08048411 <+29>:    mov    eax,DWORD PTR [esp+0x5c]
   0x08048415 <+33>:    test   eax,eax
   0x08048417 <+35>:    je     0x8048427 <main+51>
   0x08048419 <+37>:    mov    DWORD PTR [esp],0x8048500
   0x08048420 <+44>:    call   0x804832c <puts@plt>
   0x08048425 <+49>:    jmp    0x8048433 <main+63>
   0x08048427 <+51>:    mov    DWORD PTR [esp],0x8048529
   0x0804842e <+58>:    call   0x804832c <puts@plt>
   0x08048433 <+63>:    leave
   0x08048434 <+64>:    ret

1행 ~ 3행 까지는 함수 프롤로그로 스택구조의 최하위를 가리키기 위해 존재하는 어셈블리어다.

Push ebp는 ebp를 스택에 저장하는 걸 뜻하며 mov ebp, esp 는 현재 esp 위치에 ebp를 끌어올리는 명령어다.

0x080483fa <+6>:     sub    esp,0x60

부분에서 esp 레지스터에 main 함수가 사용할 0x60 크기 만큼 공간을 할당한다.

0x080483fd <+9>:     mov    DWORD PTR [esp+0x5c],0x0

esp+0x5c에 주소를 0으로 지정한다.

변수에 0을 지정하는 것은 modified 변수 밖에 없으므로 esp+0x5c는 modified 변수의 주소인 것을 확인할 수 있다.

그 밖에 DWORD는 데이터의 크기를 나타내므로 4바이트를 의미한다. (( 그 외에는 WORD =2byte BYTE = 1byte 가 있다.

0x08048405 <+17>: lea eax,[esp+0x1c]
0x08048409 <+21>: mov DWORD PTR [esp],eax
0x0804840c <+24>: call 0x804830c <gets@plt>