본문 바로가기

Learning/└◆Reversing

[참고]변수의 메모리 배치 확인 및 GDB 사용법

변수의 메모리 배치 확인 및 GDB 사용법에 대해서

 

 

 

사용시스템

- HackMe(level9/apple)

 

 

1. 변수의 메모리 배치

 

변수의 메모리 배치를 확인하기 위해서 프로그램을 만들어 보자.

 

변수와 변수의 사이에 dummy 라는 공간확인(정확한 배열을 위함)

여러개의 지역변수를 많이 할당한 것을 배열이라고 한다.(순차적)

 

[level9@ftz level9]$ ls -l

 

합계 12

-rw-r--r-- 1 root root   391   1113  2002 hint

drwxr-xr-x 2 root level9 4096  224   2002 public_html

drwxrwxr-x 2 root level9 4096  116   2009 tmp

 

 

[level9@ftz level9]$ cd tmp

[level9@ftz level9]$ vi distance.c  중간에 공백의 여부(dummy)를 판별하는 방법

#include <stdio.h>

 

int main()

{

     char AA;              <-- 1char = 1byte

     char strAA[1];

     char strBB[2];        sizeof = 크기(길이)

     char strCC[3];        sizeof(strAA) 와 AA - strAA의 값이 동일한지 비교

     char strDD[5];        더미 공간이 있는지 확인할 수 있다.

     char strEE[9];

     char strFF[17];

 

     printf("AA's address: 0x%x, sizeof: 0x%x\n", &AA, sizeof(AA));

     printf("strAA[1]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strAA, sizeof(strAA), &AA - strAA);            /* 동일하면 공간이 없다는 뜻 

     printf("strBB[2]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strBB, sizeof(strBB), strAA - strBB);          /*전체 크기에서 AA-BB주소공간을 빼기

     printf("strCC[3]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strCC, sizeof(strCC), strBB - strCC);          /* 나머지도 다 같은 뜻

     printf("strDD[5]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strDD, sizeof(strDD), strCC - strDD);

     printf(" strEE[9]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strEE, sizeof(strEE), strDD - strEE);

     printf("strFF[17]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strFF, sizeof(strFF), strEE - strFF);

 

     return 0;

}

 

=> 메모리가 꼭 순서대로 할당받지 않는 것을 알 수 있다. 중간에 더미 공간이 있을 수도 없을 수도 있다.

컴파일러가 CPU가 읽어들이기 좋은 배치에다가 배열을 해준다. 공간들은 2의 배수로만 늘어난다.

 


[예상] 스택의 구조가 아래와 같이 할당되는가?

 

<-- 낮은주소(0x00000000)                    높은주소(0xFFFFFFFF) --> 

+------+---------+--------+--------+--------+--------+--------+--+-------+

|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|strBB[2]|strAA[1]|AA|.......|

+------+---------+--------+--------+--------+--------+--------+--+-------+

     주소1      주소2    주소3    주소4    주소5   주소6    주소7

=> 더미공간이 있는지를 판단하는것이 가장 중요하다

높은주소 - 낮은주소 = AA - strAA 가 strAA의 크기와 동일 하다면 더미공간은 존재하지 않는다.

 

printf("strAA[1]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strAA, sizeof(strAA), &AA - strAA);

[level9@ftz tmp]$ gcc -o distance distance.c

[level9@ftz tmp]$ ./distance  

AA's address: 0xbfffe2ef, sizeof: 0x1

strAA[1]'s address: 0xbfffe2ee, sizeof: 0x1, distance: 0x1 /* &AA - strAA */

strBB[2]'s address: 0xbfffe2ec, sizeof: 0x2, distance: 0x2 /* strAA - strBB */

strCC[3]'s address: 0xbfffe2d0, sizeof: 0x3, distance: 0x1c /* strBB - strCC */ 25차이

strDD[5]'s address: 0xbfffe2c0, sizeof: 0x5, distance: 0x10 /* strCC - strDD */

strEE[9]'s address: 0xbfffe2b0, sizeof: 0x9, distance: 0x10 /* strDD - strEE */

strFF[17]'s address: 0xbfffe290, sizeof: 0x11, distance: 0x20 /* strEE - strFF */

 

 

====================================================================

메모리주소         변수명         변수의크기         메모리공간

====================================================================

0xbfffe6ee       strAA[1]       0x1 (1 bytes)        0x1 (1 bytes)  /* &AA - strAA   */

0xbfffe6ec       strBB[2]       0x2 (2 bytes)        0x2 (2 bytes)  /* strAA - strBB */

0xbfffe6d0       strCC[3]       0x3 (3 bytes)        0x1c(28 bytes) /* strBB - strCC */

0xbfffe6c0       strDD[5]       0x5 (5 bytes)        0x10(16 bytes) /* strCC - strDD */

0xbfffe6b0       strEE[9]       0x9 (9 bytes)        0x10(16 bytes) /* strDD - strEE */

0xbfffe690      strFF[17]       0x11(17bytes)        0x20(32 bytes) /* strEE - strFF */

====================================================================

-> 실제 메모리 공간은 2의 배수 형태로 운영체제와 컴파일러마다 최고의 성능을 낼수 있도록 기본 원칙을 어기지 않는 범위 안에서 약간의 변형을 가한다.


(예상)

<-- 낮은주소(0x00000000) 높은주소(0xFFFFFFFF) --> 

+------+---------+--------+--------+--------+--------+--------+--+-------+

|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|strBB[2]|strAA[1]|AA|.......|

+------+---------+--------+--------+--------+--------+--------+--+-------+

     주소1      주소2    주소3    주소4    주소5   주소6    주소7


(실제)

+------+---------+--------+--------+--------+---+--------+--------+--+-------+

|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|25 |strBB[2]|strAA[1]|AA|.......|

+------+---------+--------+--------+--------+---+--------+--------+--+-------+

     주소1      주소2    주소3    주소4    주소5   주소6    주소7

 

 

==============================================================================

  

2. gdb 사용법 


gdb 사용법

-------------------------------------------------------------------------------

명령어                   설명

-------------------------------------------------------------------------------

gdb                      <파일이름> 지정된 파일을 gdb로 열기

list                     gcc 컴파일시 -ggdb 옵션을 지정한 경우 소스 확인 가능

disassemble              주소/함수명 지정된 함수를 디스어셈블해 실행

run                      지정된 파일을 실행

continue                 브레이크 걸린 상태에서 계속 진행

break                    주소/함수명 주소나 함수에 브레이크 포인터를 걸기

x/32x                    주소 주소에서 32개를 16진수로 출력(x/32s는 문자열)

info registers           레지스터의 값을 출력

nexti                    함수 내부로 들어가지 않고 한 라인 실행

stepi                    함수 내부로 들어가면서 한 라인 실행

help                     도움말 출력

backtrace                프로그램 실행의 스택 추적 결과 출력

quit                     gdb 종료

-------------------------------------------------------------------------------


[level9@ftz tmp]$ vi bof.c (# cat ../hint > bof.c ; vi bof.c)

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>


main()

{

        char buf2[10];

        char buf[10];


        printf("It can be overflow : ");

        fgets(buf, 40, stdin);


        if(strncmp(buf2, "go", 2) == 0)

        {

                printf("Good Skill!\n");

                setreuid(3010, 3010);

                system("/bin/bash");

        }

}

 

필요하면 적당하게 편집작업을 한다.

 

[level9@ftz tmp]$ gcc -ggdb -o bof bof.c     원본 소스가 같이 내장된다. 디버깅 용도

[level9@ftz tmp]$ gdb bof ($ gdb /home/level9/tmp/bof)

GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...

(gdb) quit

 

 

 

 

[level9@ftz tmp]$ gdb

 

GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu".

(gdb) file /home/level9/tmp/bof

Reading symbols from /home/level9/tmp/bof...done.

(gdb) help                    /* 카테고리 커맨드 검색

List of classes of commands:

 

aliases -- Aliases of other commands

breakpoints -- Making program stop at certain points

data -- Examining data

files -- Specifying and examining files

internals -- Maintenance commands

obscure -- Obscure features

running -- Running the program

stack -- Examining the stack

status -- Status inquiries

support -- Support facilities

tracepoints -- Tracing of program execution without stopping the program

user-defined -- User-defined commands

 

Type "help" followed by a class name for a list of commands in that class.

Type "help" followed by command name for full documentation.

Command name abbreviations are allowed if unambiguous.

(gdb) help data                 /* disassemble 커맨드를 볼 수 있다.

Examining data.

 

List of commands:

 

append -- Append target code/data to a local file

call -- Call a function in the program

delete display -- Cancel some expressions to be displayed when program stops

delete mem -- Delete memory region

disable display -- Disable some expressions to be displayed when program stops

disable mem -- Disable memory region

disassemble -- Disassemble a specified section of memory

display -- Print value of expression EXP each time the program stops

dump -- Dump target code/data to a local file

enable display -- Enable some expressions to be displayed when program stops

enable mem -- Enable memory region

inspect -- Same as "print" command

mem -- Define attributes for memory region

output -- Like "print" but don't put in value history and don't print newline

print -- Print value of expression EXP

printf -- Printf "printf format string"

ptype -- Print definition of type TYPE

restore -- Restore the contents of FILE to target memory

set -- Evaluate expression EXP and assign result to variable VAR

---Type <return> to continue, or q <return> to quit---

set variable -- Evaluate expression EXP and assign result to variable VAR

undisplay -- Cancel some expressions to be displayed when program stops

whatis -- Print data type of expression EXP

x -- Examine memory: x/FMT ADDRESS

 

Type "help" followed by command name for full documentation.

Command name abbreviations are allowed if unambiguous.

(gdb) list                     /* -ggdb옵션을 줘야 볼 수 있다.

1       #include <stdio.h>

2       #include <stdlib.h>

3       #include <unistd.h>

4

5       main()

6       {

7               char buf[10];

8               char buf2[10];

9

10              printf("It ca be overflow : ");

(gdb) list 1,20

1       #include <stdio.h>

2       #include <stdlib.h>

3       #include <unistd.h>

4

5       main()

6       {

7               char buf[10];

8               char buf2[10];

9

10              printf("It ca be overflow : ");

11              fgets(buf, 40, stdin);

12

13              if(strncmp(buf2, "go", 2) == 0)

14              {

15                      printf("Good Skill!\n");

16                      setreuid(3010, 3010);

17                      system("/bin/bash");

18              }

19      }

(gdb) disassemble main

Dump of assembler code for function main:

0x08048420 <main+0>:  push %ebp

0x08048421 <main+1>:  mov %esp,%ebp

0x08048423 <main+3>:  sub $0x28,%esp

0x08048426 <main+6>:  and $0xfffffff0,%esp

0x08048429 <main+9>:  mov $0x0,%eax

0x0804842e <main+14>: sub %eax,%esp

0x08048430 <main+16>: sub $0xc,%esp

0x08048433 <main+19>: push $0x8048554

0x08048438 <main+24>: call 0x8048350 <printf>

0x0804843d <main+29>: add $0x10,%esp

0x08048440 <main+32>: sub $0x4,%esp

0x08048443 <main+35>: pushl 0x8049698

0x08048449 <main+41>: push $0x28

0x0804844b <main+43>: lea 0xffffffe8(%ebp),%eax

0x0804844e <main+46>: push %eax

0x0804844f <main+47>: call 0x8048320 <fgets>

0x08048454 <main+52>: add $0x10,%esp

0x08048457 <main+55>: sub $0x4,%esp

0x0804845a <main+58>: push $0x2

0x0804845c <main+60>: push $0x8048569

0x08048461 <main+65>: lea 0xffffffd8(%ebp),%eax

0x08048464 <main+68>: push %eax

---Type <return> to continue, or q <return> to quit---

0x08048465 <main+69>: call 0x8048330 <strncmp>

0x0804846a <main+74>: add $0x10,%esp

0x0804846d <main+77>: test %eax,%eax

0x0804846f <main+79>: jne 0x80484a6 <main+134>

0x08048471 <main+81>: sub $0xc,%esp

0x08048474 <main+84>: push $0x804856c

0x08048479 <main+89>: call 0x8048350 <printf>

0x0804847e <main+94>: add $0x10,%esp

0x08048481 <main+97>: sub $0x8,%esp

0x08048484 <main+100>: push $0xbc2

0x08048489 <main+105>: push $0xbc2

0x0804848e <main+110>: call 0x8048360 <setreuid>

0x08048493 <main+115>: add $0x10,%esp

0x08048496 <main+118>: sub $0xc,%esp

0x08048499 <main+121>: push $0x8048579

0x0804849e <main+126>: call 0x8048310 <system>

0x080484a3 <main+131>: add $0x10,%esp

0x080484a6 <main+134>: leave

0x080484a7 <main+135>: ret

End of assembler dump.

(gdb) run

Starting program: /home/level9/tmp/bof

It ca be overflow : AAAA

 

Program exited with code 0221.        비정상 적으로 종료 되었다. 하고 끝난다(221)

                                      그 중간에 코드를 분석하기 위해 브레이크 포인트를 건다.

(gdb) break *0x08048438  break pointer를 정한다.(b *main+000) 

Breakpoint 1 at 0x8048438: file bof.c, line 10.  동적분석시 b.p 위치 매우 중요

(gdb) break *0x0804844f                         입출력이 있는곳에 b.p 위치 권장

Breakpoint 2 at 0x804844f: file bof.c, line 11.  printf 는 권장하지 않는다.

(gdb) break *0x080484a6                         입력받기 전 상태, 해당 코드 실행전

Breakpoint 3 at 0x80484a6: file bof.c, line 19.

(gdb) run

Starting program: /home/level9/tmp/bof


Breakpoint 1, 0x08048438 in main () at bof.c:10

10 printf("It ca be overflow : ");

(gdb) continue

Continuing.

 

Breakpoint 2, 0x0804844f in main () at bof.c:11

11 fgets(buf, 40, stdin);

(gdb) continue

Continuing.

It ca be overflow : AAAA

 

Breakpoint 3, main () at bof.c:19

19 }

(gdb) x/s buf                s는 string이란 뜻, buf안에 string을 해석

0xbfffedf0: "AAAA\n"

(gdb) x/x buf         x/x 버퍼에 있는 내용을 16진수로 출력 x/b 10진수로 출력

0xbfffedf0: 0x41414141

(gdb) info registers

eax            0xffffffad       -83

ecx            0xffffffad       -83

edx            0x67000005       1728053253

ebx            0x42130a14       1108544020

esp            0xbffff1d0       0xbffff1d0

ebp            0xbffff1f8       0xbffff1f8

esi            0x40015360       1073828704

edi            0x80484d8        134513880       <-- 앞 16진수 / 뒤 10진수 형태

eip            0x80484a6        0x80484a6      변형이 안되는 레지스터는 둘다 16진수

eflags         0x282    642

cs             0x23     35

ss             0x2b     43

ds             0x2b     43

es             0x2b     43

fs             0x0      0

gs             0x33     51

(gdb) run

The program being debugged has been started already.

Start it from the beginning? (y or n) y      아직 끝나지 않았는데 재시작

Starting program: /home/level9/tmp/bof

 

Breakpoint 1, 0x08048438 in main () at bof.c:10

10 printf("It ca be overflow : ");

(gdb) nexti                     현재 함수에서 다음번 째 코드로 이동

0x0804843d 10 printf("It ca be overflow : ");

(gdb) nexti                    

11 fgets(buf, 40, stdin);

(gdb) stepi                     서브함수 : 함수안에서 명령어 라인 하나씩 이동

0x08048443 11 fgets(buf, 40, stdin);

(gdb) stepi                     한 개의 라인씩 실행된다.(멈춰있는 것이 아니다.)

0x08048449 11 fgets(buf, 40, stdin);

(gdb) help

List of classes of commands:

 

aliases -- Aliases of other commands

breakpoints -- Making program stop at certain points

data -- Examining data

files -- Specifying and examining files

internals -- Maintenance commands

obscure -- Obscure features

running -- Running the program

stack -- Examining the stack

status -- Status inquiries

support -- Support facilities

tracepoints -- Tracing of program execution without stopping the program

user-defined -- User-defined commands

 

Type "help" followed by a class name for a list of commands in that class.

Type "help" followed by command name for full documentation.

Command name abbreviations are allowed if unambiguous.

(gdb) help backtrace

Print backtrace of all stack frames, or innermost COUNT frames.

With a negative argument, print outermost -COUNT frames.

Use of the 'full' qualifier also prints the values of the local variables.

 

(gdb) backtrace

#0 0x08048449 in main () at bof.c:11

#1 0x42015574 in __libc_start_main () from /lib/tls/libc.so.6

(gdb) quit

The program is running. Exit anyway? (y or n) y

        

 

break pointer는 어디에다 걸어야 하나?   

1. 모든 함수에다 break pointer를 건다. (printf 제외)

2. 입력 받는 전후 부분에다가 break pointer를 건다.

3. 감각 부분 (점프 부분)