Debuggers 1012:Introductory GDB

sec875發表於2024-10-04

OpenSecurityTraining2 Learning Paths: Vulnerability Hunting & Exploitation
python:https://www.learnpython.org/
路徑圖:https://ost2.fyi/OST2_LP_Vulns_Exploits.pdf

Debuggers 1012:Introductory GDB(與 python ) --> Architecture 1001:x86-64 Assembly --> Reverse Engineering 3201:Symbolic Analysis

Download & Install

設定 Ubuntu 系統

VMWare Workstation Player 16: x86-64 Ubuntu 20.04 VM
https://www.youtube.com/watch?v=wGL-IFr-8Is
https://ubuntu.com/download/desktop

VirtualBox 6.1: x86-64 Ubuntu 20.04 VM
https://apps.p.ost2.fyi/learning/course/course-v1:OpenSecurityTraining2+Lab_Setup_x86-64_Ubuntu+2021_v1/home

安裝 gcc 和 gdb

sudo apt-get install -y gcc gdb
gcc –v
gdb –version

Create Test Executable

Compiling Test Programs fibber.c and echo.c

將以下程式碼複製並貼上到名為 fibber.c 檔案中

// fibber.c: A simple recursive Fibbonacci sequence calculation program
#include <stdio.h>

unsigned int fibbonacci(unsigned int n){
    if(n <= 1){
        return n;
    }
    else{
        return (fibbonacci(n-1) + fibbonacci(n-2));
    }
}

int main(){
    unsigned int n = 10;

    printf("First %d elements of the Fibbonacci sequence: ", n);

    for(unsigned int i = 0; i < n; i++){
        printf("%d ", fibbonacci(i));
    }
    printf("\n");
    return 0;
}

編譯它

gcc -ggdb fibber.c -o fibber_bin # -ggdb 將GDB debugging symbols新增到二進位制檔案中

透過執行“./fibber_bin”(不帶引號)確認其已執行。

複製並貼上以下程式碼到名為 echo.c 的檔案中

// echo.c: A simple program to take input on the command line and echo it back out
#include <stdio.h>
void main(int argc, char ** argv){
    if(argv[1] != NULL && argv[1] != ""){
        printf("You entered %s for argv[1]\n", argv[1]);
    } else {
        printf("You didn't enter an argv[1]\n");
    }
}

Compile it with:

gcc -ggdb echo.c -o echo_bin

透過執行“./echo_bin yo”(不帶引號)確認其執行。

Loading Binaries

Loading a Binary from Disk

從檔案系統載入二進位制檔案:選項 1

user@ubuntu:~$ gdb --quiet ./fibber_bin 
Reading symbols from ./fibber_bin...
(No debugging symbols found in ./fibber_bin)
(gdb) 

--quiet is equivalent to -q

從檔案系統載入二進位制檔案:選項 2

user@ubuntu:~$ gdb -q
(gdb) file ./fibber_bin 
Reading symbols from ./fibber_bin...
(No debugging symbols found in ./fibber_bin)
(gdb)

退出 GDB

user@ubuntu:~$ gdb -q
(gdb) quit
user@ubuntu:~$

Starting, Stopping, Restarting Binaries

Commands: run, start, continue

執行(或重新執行)程式
run(簡稱:r)命令將執行程式
https://www.sourceware.org/gdb/current/onlinedocs/gdb
https://web.archive.org/web/20221209001604/http://www.sourceware.org/gdb/current/onlinedocs/gdb/Starting.html#Starting

執行需要 CLI 引數的程式
如果您的程式需要 CLI 引數,則可以在執行命令後傳遞它們,就像您直接呼叫程式一樣。
比如:./echo_bin yo

user@ubuntu:~$ gdb ./echo_bin -q
Reading symbols from ./echo_bin...
(gdb) r
Starting program: /home/user/echo_bin 
You didn't enter an argv[1]
[Inferior 1 (process 60868) exited with code 034]
(gdb) r hi
Starting program: /home/user/echo_bin hi
You entered hi for argv[1]
[Inferior 1 (process 60872) exited with code 033]
(gdb) r yo
Starting program: /home/user/echo_bin yo
You entered yo for argv[1]
[Inferior 1 (process 60873) exited with code 033]

啟動程式並在其入口點中斷
start 命令類似於 run,只不過它在程式的入口點設定斷點。(後面的二進位制課程將教你如何自己找到入口點。)

user@ubuntu:~$ gdb ./fibber_bin -q
Reading symbols from ./fibber_bin...
(gdb) start 
Temporary breakpoint 1 at 0x1189
Starting program: /home/user/fibber_bin 

Temporary breakpoint 1, 0x0000555555555189 in main ()
(gdb)

與執行類似,您可以在啟動命令後指定其他 CLI 引數:

user@ubuntu:~$ gdb ./echo_bin -q
Reading symbols from ./echo_bin...
(No debugging symbols found in ./echo_bin)
(gdb) start hi
Temporary breakpoint 1 at 0x1169
Starting program: /home/user/echo_bin hi

Temporary breakpoint 1, 0x0000555555555169 in main ()
(gdb)

繼續執行在斷點處停止的程式
如果你使用 start 啟動了程式,那麼可以使用 continue(縮寫:c)從程式設定的臨時斷點繼續執行。

user@ubuntu:~$ gdb ./echo_bin -q
Reading symbols from ./echo_bin...
(gdb) start hi
Temporary breakpoint 1 at 0x1169
Starting program: /home/user/echo_bin hi

Temporary breakpoint 1, 0x0000555555555169 in main ()
(gdb) c
Continuing.
You entered hi for argv[1]
[Inferior 1 (process 60985) exited with code 033]
(gdb)

https://web.archive.org/web/20221211033727/https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#Continuing-and-Stepping

Working with Breakpoints in Source & Assembly Debugging

Code Breakpoints: Setting, Listing, and Deleting

設定程式碼斷點:
可以使用 break 命令(縮寫:b)設定斷點。

(gdb) break main
Breakpoint 1 at 0x11a9
(gdb) b fibbonacci
Breakpoint 2 at 0x1169

列出程式碼斷點:
可以使用 info breakpoints 或更短的形式 info break 和 info b 列出斷點

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000011a9 <main>
2       breakpoint     keep y   0x0000000000001169 <fibbonacci>
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000011a9 <main>
2       breakpoint     keep y   0x0000000000001169 <fibbonacci>

取消設定程式碼斷點:
clear <address> 命令可以刪除地址處的斷點,該地址由符號名稱或 * 後跟絕對記憶體地址指定。

(gdb) clear *0x00000000000011a9
(gdb) info b
Deleted breakpoint 1 Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x0000000000001169 <fibbonacci>
(gdb) clear fibbonacci
(gdb) info b
Deleted breakpoint 2 No breakpoints or watchpoints.

delete <breakpoint number from info breakpoints>(縮寫:d)將刪除“info b”輸出中指定的編號所給出的特定斷點。

(gdb) b main
Breakpoint 3 at 0x11a9
(gdb) info b
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x00000000000011a9 <main>
(gdb) delete 3
(gdb) info b
No breakpoints or watchpoints.

https://web.archive.org/web/20221205090253/http://www.sourceware.org/gdb/current/onlinedocs/gdb/Delete-Breaks.html#Delete-Breaks

Breakpoints as offets vs. addresses in memory 斷點作為偏移量 VS 記憶體中的地址
請注意,當斷點最初列印出來時,它們是較小的數字。但是當程式啟動並再次列印出來時,它們是較大的數字。這是因為在程式執行之前,“地址”實際上只是可執行檔案程式碼執行開始處的偏移量。偵錯程式還不知道程式將在記憶體中的哪個位置載入,直到它實際執行。這也是因為作業系統可能會隨機化可執行檔案在記憶體中的載入位置(一種稱為地址空間佈局隨機化 (ASLR) 的機制,旨在幫助緩解一些安全漏洞。)因此,在可執行檔案啟動後,偵錯程式現在可以顯示可執行檔案在記憶體中載入並啟動後的真實地址。(注意:如果您執行相同的步驟,您的地址通常會與下面顯示的不同。)

sec875@ubuntu:~$ gdb ./fibber_bin -q
Reading symbols from ./fibber_bin...
(gdb) b main
Breakpoint 1 at 0x11a9: file fibber.c, line 13.
(gdb) break fibbonacci
Breakpoint 2 at 0x1169: file fibber.c, line 4.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000011a9 in main at fibber.c:13
2       breakpoint     keep y   0x0000000000001169 in fibbonacci at fibber.c:4
(gdb) r
Starting program: /home/sec875/fibber_bin 

Breakpoint 1, main () at fibber.c:13
13	int main(){
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00005555555551a9 in main at fibber.c:13
	breakpoint already hit 1 time
2       breakpoint     keep y   0x0000555555555169 in fibbonacci at fibber.c:4
(gdb) delete 2
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00005555555551a9 in main at fibber.c:13
	breakpoint already hit 1 time
(gdb) clear *0x00005555555551a9

(gdb) info b
Deleted breakpoint 1 No breakpoints or watchpoints.
(gdb) b main
Breakpoint 3 at 0x5555555551a9: file fibber.c, line 13.
(gdb) delete 3
(gdb) info b
No breakpoints or watchpoints.
(gdb) quit
A debugging session is active.

	Inferior 1 [process 6761] will be killed.

Quit anyway? (y or n) y
sec875@ubuntu:~$ 

檢查符號表:https://sourceware.org/gdb/current/onlinedocs/gdb.html/Symbols.html#Symbols

查詢程式中定義的符號(變數、函式和型別的名稱)。此資訊是程式文字中固有的,不會隨著程式的執行而改變。GDB 會在程式的符號表、啟動 GDB 時指定的檔案中(請參閱選擇檔案)或檔案管理命令之一(請參閱指定檔案的命令)中找到它。

sec875@ubuntu:~$ gdb ./fibber_bin1 -q
Reading symbols from ./fibber_bin1...
(No debugging symbols found in ./fibber_bin1)
(gdb) p 'main'
$1 = {<text variable, no debug info>} 0x11a9 <main>
(gdb) p 'fibbonacci'
$2 = {<text variable, no debug info>} 0x1169 <fibbonacci>
(gdb) info address main
Symbol "main" is at 0x11a9 in a file compiled without debugging.
(gdb) info address fibbonacci
Symbol "fibbonacci" is at 0x1169 in a file compiled without debugging.
(gdb) b main
Breakpoint 1 at 0x11a9
(gdb) b fibbonacci
Breakpoint 2 at 0x1169
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000011a9 <main>
2       breakpoint     keep y   0x0000000000001169 <fibbonacci>
(gdb) info symbol 0x11a9
main in section .text
(gdb) info symbol 0x1169
fibbonacci in section .text
(gdb) 

無符號(fibber_bin1)與有符號(fibber_bin)

gcc -ggdb fibber.c -o fibber_bin # -ggdb 將GDB debugging symbols新增到二進位制檔案中
sec875@ubuntu:~$ gdb ./fibber_bin1 -q
Reading symbols from ./fibber_bin1...
(No debugging symbols found in ./fibber_bin1)
(gdb) p './fibber.c'::main
No symbol table is loaded.  Use the "file" command.
(gdb) p 'fibber.c'::main
No symbol table is loaded.  Use the "file" command.
(gdb) file fibber.bin1
fibber.bin1: No such file or directory.
(gdb) file fibber.c
"/home/sec875/fibber.c": not in executable format: file format not recognized
(gdb) file fibber_bin1 
Reading symbols from fibber_bin1...
(No debugging symbols found in fibber_bin1)
(gdb) q
sec875@ubuntu:~$ gdb ./fibber_bin -q
Reading symbols from ./fibber_bin...
(gdb) p 'fibber.c'::main
$1 = {int ()} 0x11a9 <main>
(gdb) p 'fibber.c'::return
No symbol "return" in specified context.
(gdb) p 'fibber.c'::fibbonacci
$2 = {unsigned int (unsigned int)} 0x1169 <fibbonacci>
(gdb) b main
Breakpoint 1 at 0x11a9: file fibber.c, line 13.
(gdb) c
The program is not being run.
(gdb) r
Starting program: /home/sec875/fibber_bin 

Breakpoint 1, main () at fibber.c:13
13	int main(){
(gdb) p 'fibber.c'::main
$3 = {int ()} 0x5555555551a9 <main>
(gdb) 

Working with Breakpoints in Source & Assembly Debugging

All Breakpoints: Disabling and Enabling