GDB調試工具指南+Peda插件的使用方式

0x01 什麼是GDB

GDB是在Linux裡面用來調試C/C++程序的強大工具。而它主要的用途如下。
• Start your program, specifying anything that might affect its behavior.
• Make your program stop on specifed conditions.
• Examine what has happened, when your program has stopped.
• Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.

0x02 啟動GDB的方法

在Terminal输入gdb進入GDB的環境後就可以用file <program名字>來開始調試你程序(program)。

有3種啟動的方式。

方法 1

gdb <program>

program是你的當前要執行的文件,一般在你現在所處於的目錄下

方法 2

gdb <program> core

用gdb同時調試一個運行中的程序以及core文件。

方法 3

gdb <program> <PID>

此外,你也可以指定GDB去調試運行中程序的Process ID。

0x02 GDB 常用參數選項

  • -s <program> :讀取program的符號表(Symbol Table)。
  • -e <program> :用program作为可執行的文件来執行,或者在和core dump連接的時候用来檢查出數據
  • -c <program> :用program作為core dump。
  • -p <program> :配合attach指令,來連接PID的號碼。
  • -x <program> :從program裡面執行GDB的指令
  • -ex command :執行單一的GDB指令 例子:gdb -ex ’target sim’

0x03 檢測源代碼(Source File)

list
list <linenum>
list function
list -
set listsize count
set listsize unlimited

0x04 設置斷點

1
2
3
4
5
6
7
8
9
10
基本使用 break <location>,以下是可以用的location。
(gdb) b/break # 没有参数,表示下一跳指令處停住
(gdb) b/break linenum/func # 停在第linenum行或某個function處
(gdb) b/break -/+offset # 在當前行號前/後的offset行停住 例子: break -
(gdb) b/break filename:linenum # 停在源文件filename的linenum行
(gdb) b/break filename:func # 停在在源文件的function入口
(gdb) b/break *address # 在内存地址address處設定斷點
(gdb) b/break label # 停在有label這個名字的那行
(gdb) b/break function:label # 停在源文件的funtion裡面有label這個名字的那行
(gdb) b/break if <condition> # 條件成立是停住,如在循环中:break if i=50

0x05 查看資訊

1
2
3
基本使用 info <想看的資訊>
(gdb) info <breakpoint> #
(gdb) info <register> # 查看所有 register 狀態

0x06 內存的顯示方式

GDB中使用“x”命令来打印内存的值,格式为x/nfu addr。其意思為以f格式打印從addr開始的n个長度單元為u的內存值。參數具體含義如下:

  • n:輸出單元的個數。
  • f:是輸出格式,可用參數(‘x’=16進制, ‘d’=10進制, ‘u’=無符號10進制, ‘o’=8進制, ‘t’=2進制,‘a’=地址, ‘c’=符號, ‘f’=浮點數, ‘s’=字符串)。Default設定是x =16進制。
  • u:標明一個單元的長度。b是一個byte,h是兩個byte(halfword),w是四個byte(word),g是八個byte(giant word)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Example 1:打印16個在地址a以16進位表示且大小為byte數值
(gdb) x/16xb a
0x7fffffffe4a0: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
0x7fffffffe4a8: 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f

Example 2:打印16個在地址a以無符號10進位表示且大小為byte數值
(gdb) x/16ub a
0x7fffffffe4a0: 0 1 2 3 4 5 6 7
0x7fffffffe4a8: 8 9 10 11 12 13 14 15

Example 3:打印16個在地址a以2進位表示且大小為byte的數值
(gdb) x/16tb a
0x7fffffffe4a0: 00000000 00000001 00000010 00000011 00000100 00000101 00000110 00000111
0x7fffffffe4a8: 00001000 00001001 00001010 00001011 00001100 00001101 00001110 00001111

Example 4:打印16個在地址a以16進位表示的
(gdb) x/16xw a
0x7fffffffe4a0: 0x03020100 0x07060504 0x0b0a0908 0x0f0e0d0c
0x7fffffffe4b0: 0x13121110 0x17161514 0x1b1a1918 0x1f1e1d1c
0x7fffffffe4c0: 0x23222120 0x27262524 0x2b2a2928 0x2f2e2d2c
0x7fffffffe4d0: 0x33323130 0x37363534 0x3b3a3938 0x3f3e3d3c

其他實用Command

disass # 反組譯某個function
ni - next instruction
• si - step into
• backtrace - 顯⽰上層所有 stack frame 的資訊
• continue

set address=value
• 將 address 中的值設成 value ⼀次設 4 byte
• 可將
換成 {char/short/long} 分別設定 1/2/8 byte
• e.g.
• set *0x602040=0xdeadbeef
• set {int}0x602040=1337

在有debug symbol下
• list : 列出 source code
• b 可直接接⾏號斷點
• info local : 列出區域變數
• print val : 印出變數 val 的值

attach pid : attach ⼀個正在運⾏的 process
• 可以配合 ncat 進⾏ exploit 的 debug
• ncat -ve ./a.out -kl 8888
• echo 0 > /proc/sys/kernel/yama/ptrace_scope

表演時間來啦(Is my Show Time)

預備文件:hello.c

1
2
3
4
5
6
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
return 0;
}

編譯gcc -g hello.c -o hello後就開始用GDB來調試。

查看其匯編語言

/m
When this option is specified, the disassemble command will show the source lines that correspond to the disassembled instructions.
/r
When this option is specified, the disassemble command will show the raw byte values of all disassembled instructions.

disass 0x4004ef,0x4004f9

參考鏈接

http://wiki.ubuntu.org.cn/%E7%94%A8GDB%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F
https://deepzz.com/post/gdb-debug.html

未完待續

0%