前面幾天介紹了 ELF、Assembly、Register、Stack 等基本概念。
從今天開始,就正式進入 Reverse Engineering 的分析流程。
當我們拿到一個未知 Binary 時,其實不用急著直接開 IDA 或 Ghidra。
我們可以先透過一些簡單的工具快速了解它。
這種不執行程式、只分析 Binary 本身的方法,就是:
Static Analysis
先建立:
#include <stdio.h>
#include <string.h>
int main() {
char password[32];
printf("Password: ");
scanf("%31s", password);
if (strcmp(password, "shark_is_cute") == 0) {
puts("Correct!");
} else {
puts("Wrong!");
}
return 0;
}
然後編譯:
gcc chall.c -o chall
接下來假裝我們只有 chall,不知道 Source Code 長什麼樣子。
拿到未知 Binary,我通常會先:
file chall
可能看到:
ELF 64-bit LSB pie executable, x86-64,
dynamically linked, not stripped
從這一行就可以知道:
其中:
not stripped
代表 Binary 還保留一些 Symbol 資訊。
這對 Reverse Engineering 來說非常有幫助。
下一個很好用的工具:
strings chall
可能直接看到:
Password:
Correct!
Wrong!
這時我們甚至還沒開始看 Assembly,就已經得到很多資訊。
實際上也常搭配:
strings chall | grep -i flag
或:
strings chall | grep -i pass
快速找可疑字串。
不過要注意:
看到 String 不代表它就是真的答案。
作者也可以故意放假資訊
所以 strings 比較適合拿來找線索。
前面介紹過 ELF,現在可以直接看看 Binary 的結構。
readelf -h chall
查看 ELF Header。
例如:
Class: ELF64
Machine: Advanced Micro Devices X86-64
Entry point address: 0x1070
如果想看 Section:
readelf -S chall
可能看到:
.text
.rodata
.data
.bss
.plt
.got
其中:
.text → Machine Code
.rodata → Read Only Data / String
.data → Initialized Data
.bss → Uninitialized Data
這就是前面學過的 ELF 結構真正出現在 Binary 裡的樣子。
接著可以看看 Binary 裡有哪些 Symbol:
nm chall
可能看到:
main
printf
scanf
strcmp
puts
如果程式自己寫了一個:
check_password()
那也可能直接看到:
check_password
這對 Reverse Engineer 來說是一個很明顯的線索。
例如看到:
check_password
print_flag
win
admin
通常都值得優先分析。
可以試著:
strip chall
再執行:
nm chall
可能會看到:
no symbols
原本的 Function Name 不見了。
但要注意:
Symbol 消失,不代表 Function 消失。
程式的 Machine Code 還在,只是 Function Name 被移除了。
所以 Reverse Engineering 很重要的一件事情,就是:
從程式行為重新理解每個 Function 在做什麼。
最後我們可以直接看 Assembly:
objdump -d -M intel chall
可能看到:
push rbp
mov rbp, rsp
sub rsp, 0x20
這些就是前幾天學過的 Function Prologue。
往下還可能看到:
call printf@plt
call scanf@plt
call strcmp@plt
光看到這些 Function Call,其實就可以開始推測:
顯示訊息
↓
讀取 Input
↓
比較字串
↓
Correct / Wrong
這就是 Static Analysis 的核心:
不一定要完全看懂每一行 Assembly,也可以先透過線索建立程式的行為模型。
所以之後拿到未知 Binary,可以先按照:
Binary
↓
file
↓
strings
↓
readelf
↓
nm
↓
objdump
簡單來說:
file chall
strings chall
readelf -h chall
nm chall
objdump -d -M intel chall
透過這些工具,我們可以快速了解:
再決定下一步要分析哪裡。
今天介紹的是:
Static Analysis
也就是:
不執行程式,直接分析 Binary。
而另一種方式是:
Dynamic Analysis
也就是在程式執行時觀察:
Register
Memory
Stack
Control Flow
例如使用:
gdb ./chall
實際 Reverse Engineering 通常會:
Static Analysis
↓
找到可疑位置
↓
Dynamic Analysis
↓
驗證推測
兩種方式互相搭配。
今天開始正式從:
學習 Assembly
走向:
分析 Binary
學到幾個最基本的工具:
file
strings
readelf
nm
objdump
最重要的不是把 Command 背起來,而是建立一個習慣:拿到 Binary 先蒐集資訊,再決定要分析哪裡。
下一篇就來進入 GUI Disassembler:IDA/Ghidra