iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0

假設今天有一段基本的程式

#include <stdio.h>

int main() {
    printf("Hello World!\n");
    return 0;
}

它會經過以下幾個階段,最後產生可以執行的 Binary
大致可以表示成:

hello.c
   ↓ Preprocessor
hello.i
   ↓ Compiler
hello.s
   ↓ Assembler
hello.o
   ↓ Linker
hello

0x01 Preprocessor

在這個階段中,像是 #include <stdio.h> , #define 等等
都會在這個階段中被處理
#include 會將對應 Header 的內容展開,而 Macro 也會在這個階段進行替換。
這邊可以使用:

gcc -E hello.c -o hello.i

只執行 preprocessing 的部分。

0x02 Compiler

這個階段是把 C code 轉成 Assembly
而 Assembly 的部分會根據你的

  • Compiler
  • Compiler version
  • Architecture
  • Optimization
  • OS
  • 等因素

有不同的結果
可以使用:

gcc -S hello.c -o hello.s

然後 Compiler 在編譯的過程中可能對程式做很多轉換以及最佳化
這也帶出 Reverse Engineering 很重要的一個觀念:

我們看到的 Assembly,不一定能一對一對應回原本的 Source Code

0x03 Assembler

雖然說 Assembly 已經是低階語言了
但由於 CPU 執行的是 Machine Code
所以還需要 Assembler 將 Assembly 轉成 Machine Code
可以使用:

gcc -c hello.c -o hello.o

執行完之後會得到 hello.o
這是一個 Object File
其中已經包含了編譯後的 Machine Code
但它還不是一個完整的 Executable

Object File

上述的 hello.o 如果使用 file 指令去檢視的話,可能會出現

hello.o: ELF 64-bit LSB relocatable, x86-64, ...

會發現他有一個關鍵字 relocatable,並不是 executable
這是因為程式裡還有一些「這個 Function 到底在哪裡」之類的資訊尚未被解析。
比如說像是 printf() 根本就不在我們實際寫的程式中,那他的程式碼在哪裡?
像這些未解決的 Symbol 會在下個階段被解決

0x04 Linker

在這個階段中 Linker 會把 Object File 之間的 Symbol Reference 解析起來
並處理程式所依賴的 Library,最後產生可以執行的 Binary
程式會使用到 C Standard Library 裡面的函數,但這些函數並不是寫在我們自己的 hello.c 裡
可以透過:

gcc hello.o -o hello

進行 Linking
透過 file 指令查看會顯示:

ELF 64-bit LSB pie executable, x86-64, ...

這樣才是我們平常可以直接 ./hello 執行的程式

0x05 結論

正常開發時,我們從高階的 Source Code 產生低階的 Machine Code
而 Reverse Engineering 則是從 Binary、Assembly 等低階資訊出發,重新理解程式原本的邏輯
如果剛剛有注意到 file 的輸出的話,應該會一直看到一個東西:ELF

像是:

ELF 64-bit LSB relocatable

以及:

ELF 64-bit LSB pie executable

所以明天就來看看:ELF 到底是什麼?


上一篇
Day01|前言
下一篇
Day03|淺談 ELF
系列文
從零開始の Binary CTF:30 天系統化學習 Rev & Pwn3
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言