前面兩天我們開始進入 Reverse Engineering:
前面使用 strings、objdump、IDA 時,我們都是在程式沒有執行的情況下分析 Binary。
但有些程式只看 Assembly 很難理解實際執行流程,因此今天要介紹:
GDB
也就是透過實際執行程式,觀察:
GDB 全名是:
GNU Debugger
它原本是一個 Debugger,但在 Reverse Engineering 和 Pwn 中也非常常見。
簡單來說:
Static Analysis
→ 看程式可能怎麼執行
Dynamic Analysis
→ 看程式實際怎麼執行
先準備一個簡單的程式:
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int c = a + b;
printf("%d\n", c);
return 0;
}
Compile:
gcc -g -O0 test.c -o test
其中:
-g → 保留 Debug Symbol
-O0 → 關閉 Optimization
接著開啟 GDB:
gdb ./test
如果習慣 Intel Syntax,可以先設定:
set disassembly-flavor intel
接著:
disassemble main
就可以看到 main() 的 Assembly。
例如:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-0x4], 0xa
這些其實就是前面 Assembly 文章中介紹過的內容。
Breakpoint 可以讓程式執行到指定位置時暫停。
例如:
break main
簡寫:
b main
接著執行:
run
或:
r
程式就會在 main() 暫停。
Reverse 時很常用這種方式:
找到感興趣的位置
↓
下 Breakpoint
↓
觀察程式狀態
可以使用:
info registers
查看目前 Register。
例如:
rax
rbx
rsp
rbp
rip
其中:
RIP
代表目前程式執行的位置。
可以搭配:
x/i $rip
查看目前正在執行的 Instruction。
例如:
=> mov DWORD PTR [rbp-0x4], 0xa
如果想一條一條執行 Assembly,可以使用:
si
代表:
Step Into
另外:
ni
代表:
Step Over
兩者主要差在遇到:
call function
時:
si → 進入 Function
ni → 不進 Function
GDB 可以直接查看 Memory。
例如:
x/8gx $rsp
代表從 $rsp 開始,查看 8 組 8-byte 的資料。
之後進入 Pwn 時,這類指令會非常常用。
如果不想繼續單步執行,可以使用:
continue
簡寫:
c
程式就會繼續執行,直到遇到下一個 Breakpoint 或程式結束。
| 指令 | 功能 |
|---|---|
b main |
設定 Breakpoint |
r |
執行程式 |
c |
繼續執行 |
disas main |
查看 Assembly |
info registers |
查看 Register |
x/i $rip |
查看目前 Instruction |
x/8gx $rsp |
查看 Stack Memory |
si |
Step Into |
ni |
Step Over |
實際操作流程通常就是:
Breakpoint
↓
Run
↓
Observe
↓
Step
↓
Observe
今天介紹了最基本的 GDB 操作:
Breakpoint
Register
Memory
Single Step
Static Analysis 和 Dynamic Analysis 通常會一起使用:
IDA / Ghidra
+
GDB
↓
Reverse Engineering
例如先用 IDA 找到可疑的 Function,再使用 GDB 下 Breakpoint,觀察 Register 和 Memory 的變化。
下一篇就可以實際拿一個簡單的 Crackme,把前面學到的 Static Analysis 和 Dynamic Analysis 串起來。