GDB

  • 보통은 GDB라고 부르는 GNU Debugger는 GNU 소프트웨어 시스템을 위한 기본 디버거입니다.

  • GDB는 다양한 유닉스 기반의 시스템에서 동작하는 이식성있는 디버거로, 에이다, C, C++, 포트란 등의 여러 프로그래밍 언어를 지원합니다.

  • 기본 GDB에 pwngdb와 gef를 설치하면 더 보기 좋고 편리하게 사용할 수 있습니다.


사용법

-> GDB에서 소스 코드를 볼 수 있는 추가 디버그 정보를 포함하도록 컴파일(-g 옵션)

1
2
gcc -g -o test test.c
g++ -g -o test test.c

-> GDB 실행

1
2
3
4
5
6
7
8
9
qdb -q [프로그램명]
gdb -q [프로그램명] [프로세스PID]


ex)
gdb -q ./test
gdb -q test

gdb -q test 1234

-> Intel 문법 설정

1
2
3
4
set disassembly-flavor intel
ex)
shell : echo "set disassembly-flavor intel" > ~/.gdbinit
gdb : set disassembly-flavor intel

-> GDB 종료

1
2
3
4
5
q(quit)

or

ctrl+d

명령어

-> l (list)

  • 소스 코드 출력
  • 기본 출력 라인 수는 10이지만, set listsize [라인 수] 명령어로 변경
1
2
3
4
5
6
7
8
9
10
11
12
l
l [라인 수]
l [함수명]
l [파일명]:[함수명]
l [파일명]:[라인수]


ex)
l 10
l main
l test:main
l test:15

-> disas (disassemble)

  • 어셈블리 코드 출력
1
2
3
4
5
6
7
8
9
10
11
disas [함수명] : 특정 함수의 어셈블리 코드 출력
disas [함수 내의 시작 주소] [함수 내의 종료 주소] : 주소 사이의 어셈블리 코드 출력
x/[명령 수]i [선두 주소]


ex)
disas main

disas 0x1122334 0x1122445

x/10i 0x1122334

-> 진행 명령어

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
r(run) : 프로그램 수행
r [arg1] [arg2] : 프로그램 실행 시 인자를 지정하여 수행

k(kill) : 프로그램 수행 종료

s(step) : 현재 행 수행 후 정지, 함수 호출 시 함수 안으로 들어감
s [n] : s 명령어를 n번 수행 후 정지

n(next) : 현재 행 수행 후 정지, 함수 호출 시 함수 수행 후 다음 행으로 감
n [n] : n 명령어를 n번 수행 후 정지

c(countinue) : 다음 브레이크 포인트까지 진행

u(until) : 현재 루프를 빠져 나감

finish : 현재 함수가 길어서 끝나는 지점으로 이동

return : 현재 함수가 길어서 남은 부분을 수행하지 않고 빠져 나옴
return [n] : return 명령어 사용 시 return 값을 임의로 지정


ex)
r
r 2 5
s 2
n 3
return 4123

-> info 명령어와 스택 상태 검사

  • info 명령어는 현재 디버깅에 대한 여러 정보를 주는 명령어로 축약어는 i이 이다.
  • i만 입력하면 어떤 옵션으로 어떤 정보를 확인할 수 있는지 목록이 보인다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
i <tab키> : info로 확인 가능한 명령어 출력

i set : 설정 가능한 내용 출력

i r : 레지스터 전체 출력
i r $[레지스터] : 레지스터의 값 출력

i signals : signal 종류 출력

i f : 스택 프레임 내용 출력

i args : 현재 함수로 넘어온 인자의 정보를 확인

i local : 현재 함수의 지역 변수를 확인

i locals : 현재 위치한 행에서 접근 가능한 지역 변수들 목록 확인

i variables : 현재 위치한 행에서 접근 가능한 전역 변수들 목록 확인

i catch : 함수의 예외 핸들러를 출력

i b : 등록된 breakpoints와 watchpoints를 확인

i line : 현재 디버깅하고 있는 위치 정보 확인

i program : 현재 프로그램의 process 정보 확인

bt : 전체 스택 프레임 출력(콜스택).
백트레이스로 프로그램 스택을 역으로 탐색하므로, segmentation fault가 발생했다면 오류 지점에 도달하기 전 과정을 확인하여 오류 지점 확인

frame [스택 번호] : 스택 번호의 스택 프레임으로 이동

up : 상위 스택 프레임으로 이동
up [n] : n번 만큼 상위 스택 프레임으로 이동

down : 하위 스택 프레임으로 이동
down [n] : 숫자만큼 하위 스택 프레임으로 이동


-> b (breakpoint)

  • 브레이크 포인트
  • i(info) b(breakpoint) 명령어로 현재 설정된 브레이크 포인트의 목록을 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
b func : func 함수의 시작 부분에 브레이크 포인트 설정

b n : n번째 행에 브레이크 포인트 설정

b +n : 현재 행에서 n번째 행 이후 브레이크 포인트 설정

b -n : 현재 행에서 n번째 행 이전 브레이크 포인트 설정

b *0x1122334 : 특정 주소에 브레이크 포인트 설정

tb : 기능과 문법은 명령어 b와 동일하나, 1회용 브레이크 포인트

info b : 현재 브레이크 포인트 지우기

cl(clear) : 특정 symbol에 걸려있는 breakpoint나 watchpoint를 제거할 때 사용
cl [변수명 or 함수명] : 변수명이나 함수명에 걸린 breakpoint나 watchpoint 제거

d(delete) : 모든 breakpoint 지우기
d [n] : n번째 breakpoint 제거

disable br : 모든 브레이크 포인트 비활성화
disable br [n ...] : n번째 브레이크 포인트 비활성화

enable br : 모든 브레이크 포인트 활성화
enable br [n ...] : n번째 브레이크 포인트 활성화

b n if var == N : var 변수의 값이 N일 때 n번 행에 브레이크 포인트 설정

condition [n] var == 0 : var 변수가 0일 때 n번 브레이크 포인트 동작


ex)
b main
b 10
b +3
b -3
cl main
cl 10
cl test:main
cl test:10
d
d 5
disable br
disable br 1 3
enable br
enable br 1 3
b 10 if var == 0
condition 3 if var == 0

-> watch

  • 특정 변수를 watchpoints로 걸어두어 소스의 지점에 거는 것이 아닌 변수 자체에 break를 설정
  • watchpoints가 걸린 변수의 값이 변할 때 break 걸리므로, 변수값의 변화와 코드의 변화를 확인할 때 유용
  • b와 동일하게 i(info) 명령어를 사용 가능
1
2
3
4
5
6
7
8
9
watch [변수명] : 변수에 값이 써질 때 브레이크
rwatch [변수명] : 변수의 값이 읽혀질 때 브레이크
awatch [변수명] : 변수에 읽기, 쓰기 경우에 브레이크


ex)
watch a
rwatch b
awatch c

-> x (examine, 메모리 주소를 직접 조사하거나 실행될 때 조사하는 용도)

  • 조사할 메모리의 위치와 메모리를 어떻게 보여줄지에 대한 두 개의 인자가 필요.
  • 표현 형식도 한 글자의 축약형을 사용.
  • 표현 형식 문자 앞에 숫자로 얼마나 많이 출력할 것인지 표기.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
x/[범위][출력 형식][범위의 단위] [메무리 주소나 함수명]

표현 형식 문자
o : 8진법으로 보여준다.
x : 16진법으로 보여준다.
u, d : 부호가 없는(unsigned) 표준 10진법으로 보여준다.
t : 2진법으로 보여준다.
c : 최초 1byte 값을 문자형으로 출력
f : 부동소수점
a : 가장 가까운 심볼의 오프셋 출력
s : 문자열로 출력
i : 어셈블리 형식으로 출력
z : hex, zero padded on the left

표시 유닛 크기(범위의 단위) 문자
b(byte) : 1byte
h(Halfword) : 2byte
w(word) : 4byte
g(Giant) : 8byte


ex)
x/10 main
x/20 $rip

x/o 0x11223344
x/x $rip
x/u $rip
x/t $rip

x/6x $rip
x/12x $rip

x/8xb main
x/4xh main

x/10i 0x1122334

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

(gdb) x/8x 0x7fffffffd910
0x7fffffffd910: 0x05ffda98 0x00000000 0x00000002 0x00000001
0x7fffffffd920: 0xffffd940 0x00007fff 0x004005cc 0x00000000

(gdb) x/8o 0x7fffffffd910
0x7fffffffd910: 0577755230 0 02 01
0x7fffffffd920: 037777754500 077777 020002714 0

(gdb) x/8c 0x7fffffffd910
0x7fffffffd910: -104 '\230' -38 '\332' -1 '\377' 5 '\005' 0 '\000' 0 '\000' 0 '\000' 0 '\000'

(gdb) x/8s 0x7fffffffd910
0x7fffffffd910: "\230\332\377\005"
0x7fffffffd915: ""
0x7fffffffd916: ""
0x7fffffffd917: ""
0x7fffffffd918: "\002"
0x7fffffffd91a: ""
0x7fffffffd91b: ""
0x7fffffffd91c: "\001"

(gdb) x/8d 0x7fffffffd910
0x7fffffffd910: -104 -38 -1 5 0 0 0 0

(gdb) x/8t 0x7fffffffd910
0x7fffffffd910: 10011000 11011010 11111111 00000101 00000000 00000000 00000000 00000000

(gdb) x/8f 0x7fffffffd910
0x7fffffffd910: 4.9729545178123994e-316 2.1219957919534036e-314
0x7fffffffd920: 6.9533558073448912e-310 2.0729947080329522e-317
0x7fffffffd930: 6.9533558073488437e-310 2.1219957919534036e-314
0x7fffffffd940: 6.9533558073464722e-310 2.0730100240679732e-317

(gdb) x/8a 0x7fffffffd910
0x7fffffffd910: 0x5ffda98 0x100000002
0x7fffffffd920: 0x7fffffffd940 0x4005cc <func2+29>
0x7fffffffd930: 0x7fffffffd990 0x100000002
0x7fffffffd940: 0x7fffffffd960 0x4005eb <func1+29>

(gdb) x/8i 0x7fffffffd910
0x7fffffffd910: cwtl
0x7fffffffd911: (bad)
0x7fffffffd913: add $0x0,%eax
0x7fffffffd918: add (%rax),%al
0x7fffffffd91a: add %al,(%rax)
0x7fffffffd91c: add %eax,(%rax)
0x7fffffffd91e: add %al,(%rax)
0x7fffffffd920: rex fcos

(gdb) x/8z 0x7fffffffd910
0x7fffffffd910: 0x0000000005ffda98 0x0000000100000002
0x7fffffffd920: 0x00007fffffffd940 0x00000000004005cc
0x7fffffffd930: 0x00007fffffffd990 0x0000000100000002
0x7fffffffd940: 0x00007fffffffd960 0x00000000004005eb

-> p (print)

  • 내부에 존재하는 어떠한 값을 출력해보고 싶을 때 사용
  • 일반 수식도 지원하므로 변수에 어떤 값을 연산한 결과 등 출력
  • 메모리 주소를 출력을 위해 & 사용
  • 메모리 주소에 있는 내용을 출력을 위해 * 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
p [함수명]          : 함수의 주소 출력
p [변수명] : 해당 변수의 값 출력
p [포인터 변수] : 포인터 변수의 주소값 출력
p &[변수명] : 변수의 주소 출력
p *[메모리 주소] : 메모리 주소의 값 출력
p *[포인터 변수] : 포인터 변수의 실제 값 출력
p *[포인터] : struct/class의 배열일 때 배열의 크기를 알림
p $[레지스터명] : 레지스터의 값 출력
p/[출력형식] [변수명]: 출력 형식에 맞추어 변수값 출력
p [변수명] [연산] : 변수에 연산한 값 출력
p (캐스팅)[변수명] : 변수를 캐스팅하여 출력
p [포인터 변수 or 배열]+[n] : 특정 주소 + n번째 위치 출력
p [변수명] = [값] : 특정 변수의 값을 설정
p '[파일명]'::[변수명] : p 명령어는 지역 변수를 우선시하므로, 동일한 이름의 전역 변수를 사용할 때 :: 를 사용
p [함수명]::[변수명]: 특정 함수에 있는 변수를 확인
p (*this) : 디버깅 하다가 객체의 내용을 보고 싶을 때, class 내부에서 간단히 사용

표현 형식 문자
o : 8진법으로 보여준다.
x : 16진법으로 보여준다.
u, d : 부호가 없는(unsigned) 표준 10진법으로 보여준다.
t : 2진법으로 보여준다.
c : 최초 1byte 값을 문자형으로 출력
f : 부동소수점
a : 가장 가까운 심볼의 오프셋 출력
s : 문자열로 출력
i : 어셈블리 형식으로 출력


ex)
p main
p a
p ptrb
p &a
p *0x1122334
p *ptrb
p $rip
p/t bina
p/o ob
p/x hex
p/c chara
p i * 4 - 2
p (char*)a
p (array[0]+5)
p a=1
p 'test.c'::a
p func1::a

-> 화면에 값을 자동으로 디스플레이

  • display 명령어를 이용하면 매 단계가 진행될 때마다 자동으로 변수의 값을 출력
  • p를 매번 타이핑 하기 귀찮을 때 유용하며, 동일한 방식으로 출력 형식을 지정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
display [변수명] : 특정 변수의 값을 매번 출력할
dispaly/[출력 형식] [변수명] : 출력 형식에 맞추어 변수값 출력
undisplay [번호] : 출력하던 display 변수 제거
disable display [번호] : 일시적으로 디스플레이 중단
enable display [번호] : 중단했던 번호 다시 출력

표현 형식 문자
o : 8진법으로 보여준다.
x : 16진법으로 보여준다.
u, d : 부호가 없는(unsigned) 표준 10진법으로 보여준다.
t : 2진법으로 보여준다.
c : 최초 1byte 값을 문자형으로 출력
f : 부동소수점
a : 가장 가까운 심볼의 오프셋 출력
s : 문자열로 출력
i : 어셈블리 형식으로 출력


ex)
display a
display/x a
disable display 1
enable display 1
undisplay 1

-> set

  • 디버깅 도중에 존재하는 변수의 값을 변경하거나 디버깅에 사용되는 변수를 정의할 때 사용
  • set 명령어는 축약어가 존재하지 않음
  • p 명령어와 동일하게 &와 *를 지원하므로 특정 메모리의 값도 변경 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
set [변수명] = [값] : 변수의 값 변경
set $[변수명] = [값] : 변수를 정의, 프로그램 내에 존재하는 일반 변수와 구별하기 위해 $를 필수로 붙여줘야 함
set {타입}[주소] = [값] : 특정 메모리에 값을 지정


ex)
set a = 10;

set $a = 4;
p env[$a++]

set {int}0x1122334455 = 100

set *((int*)0x1122334) = 123321

-> ETC

1
2
3
4
5
6
7
8
9
call [함수명(인자)] : 특정 함수를 인자값으로 호출

jump *[주소] : 주소로 강제 분기

jump [행번호] : 특정 행으로 강제 분기

jump [함수명] : 특정 함수로 강제 분기

show convience : 지금까지 설정한 변수를 확인

TIPs

어셈블리어를 시작적으로 보여준다.

1
2
# gdb 실행한 상태에서 입력
(gdb) layout asm

레지스터를 시각적으로 보여준다.

1
2
# gdb 실행한 상태에서 입력
(gdb) layout reg

코어 파일을 분석

1
gdb -c core

참고