1. GDB란?


1) 개념


- GNU Debugger 
- 오픈 소스로 공개되어 있는 무료 디버거
- GNU 소프트웨어 시스템을 위한 기본 디버거
- 다양한 유닉스 기반의 시스템에서 동작하는 디버거
- C, C++, 포트란 등의 여러 프로그래밍 언어를 지원

2) 기능


- 컴퓨터 프로그램의 실행을 추적하고 수정할 수 있는 많은 기능들을 제공
- 사용자는 프로그램의 내부 변수들의 값을 주시하거나 변경 가능
- 프로그램의 일반적인 실행 과정과 독립적으로 함수를 호출 가능
 
3) 명령어


① 시작과 종료
- gdb [프로그램명] : 시작
- q(quit) or ctrl+d : 종료


② 소스보기(list or l)
- list : 메인함수 기점으로 소스 출력
- list 10 : 10행을 기준으로 출력
- list func : func 함수의 소스 출력
- list- : 출력된 행의 이전행 출력
- list file.c : file의 func 함수 부분 출력
- file.c:10 : file의 10행을 기준으로 출력 


③ 브레이크 포인트(break or b)
- b func : func 함수의 시작부분에 브레이크 포인트 설정
- b 10 : 10행에 브레이크 포인트 설정
- b *0x8049000 : 특정 주소에 브레이크 포인트 설정
- tb : b와 같으나 1회용 브레이크 포인트. 문법은 b와 동일
-info b : 현재 브레이크 포인트 보기
- cl : 브레이크 포인트 지우기
- d : 모든 브레이크 포인트 지우기


④ 진행 명령어
- run(r) : 프로그램 수행
- kill(k) : 프로그램 수행 종료
- step(s) : 현재 행 수행 후 정지, 함수 호출 시 함수 안으로 들어감
- next(n) : 현재 행 수행 후 정지, 함수 호출시 함수 수행 다음 행으로 감
- n 5 : n 다섯번 수행
- continue(c) : 다음 브레이크 포인트까지 진행
- u : 현재 루프를 빠져나감
- finish : 현재 함수를 수행하고 빠져나감
- return : 현재 함수를 수행하지 않고 빠져나감
- return 123 : 위와 같으나 리턴값 지정
- si : 어셈블리 명령어 단위의 수행 (step)
- ni : 어셈블리 명렁어 단위의 수행 (next)


⑤ 와치 포인트
- watch 변수명 : 특정변수에 와치 포인트를 설정하고, 특정변수가 바뀔 때마다 브레이크가 걸리면서 이전/현재 값을 출력


⑥ 변수출력
- info locals : 현재 스택의 로컬변수 모두를 출력
- info variables : 전역변수 모두 출력 (스압)
- p [변수명] : 해당변수 value 출력
- 포인터변수 입력시 주소값 출력, *포인터변수명 -> 실제 value 출력
- p $[레지스터명] : 레지스터값 출력
- p *[포인터] : struct/class의 배열일 때 배열의 크기를 알림
- p /[출력형식][변수명] : 출력형식에 맞추어 변수값 출력


⑦ 스택 상태 검사
- info f : 스택 프레임 내용 출력
- info args : 함수 호출시 인자를 출력
- info locals : 함수의 지역변수를 출력
- info catch : 함수의 예외 핸들러를 출력
- bt : 전체 스택 프레임 출력(콜스택)
- frame [스택번호] : 스택번호의 스택 프레임으로 이동


⑧ 기타
- disas [함수명] : 특정함수의 어셈블리 코드 출력
- disas [주소] [주소] : 주소 사이의 어셈블리 코드 출력
- call [함수명(인자)] : 특정 함수를 인자값으로 호출
- jump *[주소] : 주소로 강제적으로 분기
- jump [행번호] : 특정 행으로 강제 분기
- jump [함수명] : 특정 함수로 강제 분기
- info signals : signal 종류 출력

 

2. GDB 코드 분석

 

 

먼저 분석할 코드를 보면 위와 같다. 

3개의 매개변수를 갖는 function() 함수가 있고 char은 크기가 1byte이기 때문에

buffer1은 15byte, buffer2는 10byte를 갖는다.

 

 

위와 같이 작성한 코드를 32bit로 컴파일한다.

 

 

위와 같이 gdb [파일이름] 이라는 명령어를 입력하여 gdb에 들어갈 수 있다.

 

 

pdisas 명령어는 disas(함수의 어셈블리 코드 출력)를 색깔을 입혀 출력해주는 gdb-peda의 명령어이다.

main() 함수의 어셈블리 코드를 확인해보면 위와 같다.

위와 같은 코드는 메모리 구조의 code segment 부분에 해당한다.

 

 

또한, main() 함수 안의 function() 함수의 어셈블리 코드도 확인할 수 있고, 

이도 마찬가지로 메모리 구조의 code segment 부분에 해당한다.

이때 여기서 전역변수 선언을 하지 않았기 때문에 데이터 영역에는 아무것도 없고,

스택 영역에는 환경변수, argc. argv pointer 등이 들어간다. (이 코드에서는 환경변수)

 

 

메인 함수를 실행했을 때 eip는 맨 첫줄일 것이므로 

위와 같이 b *[주소] 명령어를 입력하여 맨 처음에 브레이크 포인트를 걸어준다.

 

 

run을 해보면 bp를 건 주소에서 잘 걸리는 것을 확인할 수 있다.

 

 

eip 명령어는 앞으로 수행할 명령어의 주소 위치를 담고 있다.

info reg eip를 해보면 메인 함수의 맨 처음 주소를 가리키고 있는 것을 확인할 수 있다.

 

 

메인 함수의 프롤로그를 살펴보자.

push ebp : ecx-0x4를 해준 값을 ebp에 넣음

mov ebp, esp : esp값을 ebp에 복사 → 두 값이 가르키는 주소가 같아짐

sub esp,0x4 : esp-0x4 → 공간 확장의 의미

push 0x3 : 스택에 인자값을 넣음 → 스택 구조는 반대이기 때문에 1, 2, 3의 순서대로 실행

call 0x804843b <function> : function 함수로 인자값 전달하며 이동

 

 

 

call 명령어를 실행한 후 돌아와야 할 주소는 eip 레지스터에 저장된다.

이때 돌아와야 할 주소의 바로 위 주소(0x8048478)에 bp를 걸어준다.

 

 

위는 run을 했을 때 결과 화면이다.

 

 

위와 같이 continue 명령어를 통해 다음 bp로 넘어갈 수 있다.

 

 

si 명령어를 통해 다음 줄을 실행할 수 있다. 

 

 

 

info reg eip를 통해 주소를 확인해 보면 function 함수의 주소가 들어가 있는 것을 확인할 수 있다.

 

 

function 함수의 프롤로그를 살펴보자.

push ebp : 메인함수에서 사용하는 ebp를 다시 저장

mov ebp, esp : ebp에 esp 값을 이동 → base pointer 값

sub esp,0x28 : 28byte 만큼의 공간 확장

 

 

아까 buffer1은 15, buffer2는 10이었는데 이 버전에서는 word(4byte) 단위로 할당되기 때문에

buffer1은 16byte, buffer2는 12byte가 할당되므로 위와 같이 28byte만큼의 공간을 확장시킨다.

 

 

함수의 에필로그를 확인해보자.

leave 명령어는 mov %ebp/%esp, pop %ebp를 의미하고 

ret 명령어로 return해준다.

 

 

add esp,0x10 : 어셈블리는 16진수이므로 16만큼의 크기를 더한다는 의미

                       → 스택에서 더한다 : 반환한다는 의미

'2021-1 STUDY > Pwnable Study' 카테고리의 다른 글

Week05_basic_exploitation_001  (0) 2021.05.19
Week05_BOF  (0) 2021.05.19
Week03_collision  (0) 2021.05.05
Week03_setuid  (0) 2021.05.05
Week02_Pwntools  (0) 2021.04.28

+ Recent posts