[逆向工程] 001 Win32 漏洞利用開發完整入門指南:從系統架構到組合語言基礎

前言:什麼是漏洞利用開發?

在開始學習技術細節之前,讓我們先了解一些基本概念:

漏洞利用開發(Exploit Development) 是資訊安全領域中一個專門的技術方向,主要目標是:

  1. 發現軟體中的安全漏洞
  2. 理解這些漏洞如何被利用
  3. 開發程式碼來「觸發」並「利用」這些漏洞
  4. 協助開發者修補這些安全問題

為什麼要學習漏洞利用開發?

  • 防守方觀點:了解攻擊手法才能設計更好的防禦機制
  • 紅隊演練:滲透測試需要實際的漏洞利用能力
  • 研究目的:發現新的漏洞並負責任地揭露
  • 職涯發展:資安研究員、滲透測試工程師的核心技能

學習本文需要的前置知識

  • 基本的程式設計概念(變數、函式、迴圈等)
  • 對作業系統有初步了解
  • 願意學習低階程式設計概念的心態

Windows 系統架構基礎

系統啟動流程:從開機到作業系統

了解 Windows 如何啟動,對於理解記憶體佈局非常重要:

[開機 ROM] → [Boot Loader] → [OS Kernel] → [User Land]

詳細流程:

  1. Boot ROM(開機 ROM)
    • 電腦開機時,首先執行儲存在 ROM 中的程式碼
    • 負責載入 Boot Loader(開機載入器)
  2. Boot Loader(開機載入器)
    • 將作業系統載入到 RAM(隨機存取記憶體)中
    • 準備系統執行環境
  3. Kernel(核心) 啟動後執行以下工作:
    • 管理記憶體配置
    • 初始化各種核心元件
    • 建立 User Land(使用者空間)
  4. User Land(使用者空間)
    • 允許執行應用程式
    • 「桌面」就是最早啟動的 User Land 應用程式之一

重要觀念:「所有程式都在記憶體中執行」— 這是漏洞利用的核心概念!

Ring 權限等級:核心模式 vs 使用者模式

Windows 採用 Ring(環) 的概念來區分程式的執行權限:

┌─────────────────────────────────────────────────────┐
│                    User Land                         │
│  ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐                   │
│  │程式1│ │程式2│ │程式3│ │程式4│    ← Ring 3       │
│  └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘                   │
│     │      │      │      │                          │
│     ▼      ▼      ▼      ▼                          │
│  ┌────────────────────────────────┐                 │
│  │    System Calls (ntdll.dll)    │                 │
│  └────────────────────────────────┘                 │
├─────────────────────────────────────────────────────┤
│                     Kernel                           │
│  ┌─────────────────┐  ┌──────────────────────────┐  │
│  │ Windows Executive│  │  Low Level OS Functions │  │
│  │ - 記憶體管理     │  │  - 排程                  │  │
│  │ - 行程管理       │  │  - 中斷處理             │  │
│  │ - 執行緒管理     │  │  - 例外處理             │  │
│  │ - I/O           │  │  - 多處理器同步         │  │
│  │ - 網路          │  └──────────────────────────┘  │
│  │ - IPC           │                                │
│  └─────────────────┘                    ← Ring 0    │
│  ┌─────────────────────────────────────────────┐    │
│  │                    HAL                       │    │
│  │        (Hardware Abstraction Layer)         │    │
│  └─────────────────────────────────────────────┘    │
├─────────────────────────────────────────────────────┤
│  ┌─────┐  ┌────────────┐  ┌──────────┐  ┌─────┐    │
│  │ CPU │  │ 實體記憶體  │  │ 硬碟儲存 │  │ NIC │    │
│  └─────┘  └────────────┘  └──────────┘  └─────┘    │
│                      Hardware                        │
└─────────────────────────────────────────────────────┘

Ring 3(使用者模式)
– 一般應用程式執行的空間
– 權限受限,無法直接存取硬體
– 需要透過 System Call(系統呼叫)來請求核心服務

Ring 0(核心模式)
– 作業系統核心執行的空間
– 擁有最高權限,可直接存取硬體
– 包含驅動程式、核心元件

資安觀點:漏洞利用的終極目標之一就是「權限提升」— 從 Ring 3 提升到 Ring 0

Windows 初始系統進程

當 Windows 啟動時,會依序建立以下系統進程:

進程名稱 說明 重要性
System Idle Process 系統閒置進程
System Process (PID 4) 系統進程(核心執行緒) 非真正的使用者模式程式
smss.exe Session Manager(工作階段管理員) 第一個使用者模式進程
lsm.exe Local Session Manager
csrss.exe Windows Subsystem 關鍵系統進程
wininit.exe Session 0 初始化 關鍵系統進程
winlogon.exe 登入進程 關鍵系統進程
services.exe Service Control Manager 管理 svchost.exe 子進程
lsass.exe Local Security Authentication Server 認證服務

標示為「關鍵」的進程:如果被終止,系統會當機或重新啟動


記憶體管理深入解析

虛擬記憶體:為什麼重要?

Windows 使用 虛擬記憶體(Virtual Memory) 系統,這是理解漏洞利用的關鍵:

核心概念:

  1. 實體記憶體(Physical Memory)
    • 實際安裝的 RAM
    • 被分割成「頁框(Page Frames)」
  2. 虛擬記憶體(Virtual Memory)
    • 每個進程「看到」的記憶體空間
    • 被分割成「頁面(Pages)」
    • 比實體記憶體大很多!
  3. 頁面表(Page Table)
    • 負責將虛擬位址轉換成實體位址
    • 每個進程都有自己的頁面表
┌─────────────────────┐          ┌─────────────────────┐
│  虛擬記憶體(頁面)   │          │ 實體記憶體(頁框)  │
│                     │          │                     │
│  0x00010000 ────────┼──────────┼→ 頁框 A             │
│  0x00020000         │          │                     │
│  0x00030000 ────────┼──────┐   │  頁框 B             │
│  ...                │      │   │                     │
│  0x7fffffff ────────┼──┐   │   │  頁框 C ←──────────┼─┐
│                     │  │   │   │                     │ │
└─────────────────────┘  │   │   │  頁框 D ←──────────┼─┘
                         │   │   │                     │
                         │   └───┼→ 頁框 E             │
                         │       │                     │
                         └───────┼→ 頁框 F             │
                                 │                     │
                                 │  ┌─────────┐        │
                                 │  │ Disk    │←───────│
                                 │  │ (Swap)  │  交換  │
                                 │  └─────────┘        │
                                 └─────────────────────┘

頁面(Page)的重要特性

特性 說明
固定大小 x86 預設為 4KB(可透過 PAE 設為 2MB)
ACL 控制 每個頁面都有存取控制(讀/寫/執行)
交換機制 不常用的頁面可被「交換」到硬碟
獨立性 不同進程的頁面互相隔離

資安觀點:頁面的執行權限(是否可執行程式碼)是現代防禦機制的基礎!

頁面查詢機制

當 CPU 需要存取某個虛擬位址時:

  1. TLB(Translation Lookaside Buffer):快取查詢
    • 如果找到 → 直接使用
  2. Page Walk(頁面遍歷):完整查詢
    • 如果 TLB 沒有 → 查詢頁面表
    • 找到後加入 TLB 快取

過多交換 = 「Thrashing(顛簸)」

當系統記憶體不足時:
– 大量頁面被交換到硬碟
– 系統變得極慢
– 這就是為什麼增加 RAM 可以改善效能


Win32 進程與執行緒

進程(Process)是什麼?

進程 是程式執行時的「容器」:

┌─────────────────────────────────────────────────────────┐
│                     進程 (Process)                       │
│                                                         │
│  ┌──────────────────────────────────────────────────┐   │
│  │           私有虛擬位址空間                        │   │
│  │         (0x00010000 - 0x7FFFFFFF)               │   │
│  │                                                  │   │
│  │   ┌─────────┐  ┌─────────┐  ┌─────────┐        │   │
│  │   │  .text  │  │  .data  │  │  Stack  │        │   │
│  │   │ (程式碼)│  │ (資料)  │  │  (堆疊) │        │   │
│  │   └─────────┘  └─────────┘  └─────────┘        │   │
│  │                                                  │   │
│  │   ┌─────────┐  ┌─────────────────────┐         │   │
│  │   │  Heap   │  │   DLL (kernel32,    │         │   │
│  │   │ (堆積)  │  │    ntdll, ...)      │         │   │
│  │   └─────────┘  └─────────────────────┘         │   │
│  │                                                  │   │
│  └──────────────────────────────────────────────────┘   │
│                                                         │
│  ┌────────────┐  ┌────────────┐                        │
│  │  Thread 1  │  │  Thread 2  │   執行緒               │
│  │  ┌──────┐  │  │  ┌──────┐  │                        │
│  │  │Stack │  │  │  │Stack │  │                        │
│  │  │TEB   │  │  │  │TEB   │  │                        │
│  │  └──────┘  │  │  └──────┘  │                        │
│  └────────────┘  └────────────┘                        │
│                                                         │
│  ┌─────────────────────────────┐                       │
│  │           PEB               │  進程環境區塊          │
│  │  - 主程式位置               │                       │
│  │  - DLL 載入資訊             │                       │
│  │  - 堆積資訊                 │                       │
│  └─────────────────────────────┘                       │
│                                                         │
│  其他資源:Process ID、Access Token、開啟的 Handle...  │
│                                                         │
└─────────────────────────────────────────────────────────┘

進程的關鍵元件

1. PEB(Process Environment Block,進程環境區塊)

每個進程只有一個 PEB,包含:
– 主執行檔的位置
– Loader Data(載入器資料):已載入的 DLL 清單
– 堆積(Heap)資訊

2. TEB(Thread Environment Block,執行緒環境區塊)

每個執行緒都有一個 TEB,包含:
– PEB 的位置
– 執行緒所屬的堆疊位置
SEH 鏈的第一個項目 ← 這在漏洞利用中非常重要!

四大記憶體區段

區段 說明 權限
Code (.text) 程式碼區段,存放 CPU 指令 唯讀 + 可執行
Data (.data) 資料區段,存放變數和緩衝區 可讀寫,不可執行
Stack(堆疊) 存放函式參數、區域變數、返回位址 可讀寫(+ 可執行?)
Heap(堆積) 動態配置的記憶體 可讀寫

進程的虛擬記憶體配置

在 32 位元 Windows 上:

0x00000000 ┌─────────────────────────┐
           │       Reserved          │  保留區域
0x00010000 ├─────────────────────────┤
           │                         │
           │    User Land Space      │  使用者空間
           │    (約 2GB)             │  進程可使用的範圍
           │                         │
           │  - EXE 映像             │
           │  - DLL 映像             │
           │  - Stack                │
           │  - Heap                 │
           │                         │
0x7FFFFFFF ├─────────────────────────┤
           │                         │
           │    Kernel Space         │  核心空間
           │    (約 2GB)             │  使用者進程無法存取
           │                         │
0xFFFFFFFF └─────────────────────────┘

重要:使用者模式的進程只能存取 0x00010000 到 0x7FFFFFFF 的範圍!

進程隔離

每個進程的記憶體是邏輯上隔離的:
– 進程 A 無法直接讀取進程 B 的記憶體
– 需要使用特殊 API:ReadProcessMemory() / WriteProcessMemory()
– 例外:共享記憶體區段(需要特別設定)

執行緒(Thread)是什麼?

執行緒是程式碼執行的最小單位:

  • 一個進程至少有一個執行緒
  • 多執行緒可以「同時」執行(實際上是快速切換)
  • 每個執行緒有自己的:
    • CPU 狀態/暫存器
    • 兩個堆疊(核心模式 + 使用者模式)
    • TLS(Thread Local Storage)
    • Thread ID
    • TEB

Context Switch(上下文切換)

這是多工作業的關鍵機制:

  1. 核心排程器決定切換執行緒
  2. 儲存目前執行緒的 CPU 狀態
  3. 載入下一個執行緒的 CPU 狀態
  4. 繼續執行

這就是「多工作業的錯覺」— 快速切換讓使用者感覺程式同時在執行!


PE 檔案格式詳解

什麼是 PE 檔案?

PE(Portable Executable) 是 Windows 可執行檔的格式:
.exe 檔案
.dll 檔案(動態連結程式庫)
.sys 檔案(驅動程式)

PE 檔案結構總覽

┌─────────────────────────────────────────┐
│              DOS Header                  │  MZ 標頭(向後相容)
├─────────────────────────────────────────┤
│              PE Header                   │  "PE" 簽章
│  - Machine Type (I386, AMD64...)        │
│  - Number of Sections                   │
│  - Timestamp                            │
├─────────────────────────────────────────┤
│           Optional Header                │
│  - AddressOfEntryPoint  ← 程式進入點    │
│  - ImageBase           ← 預設載入位址   │
│  - SectionAlignment                     │
│  - SizeOfImage                          │
│  - SizeOfHeaders                        │
├─────────────────────────────────────────┤
│           Data Directories               │
│  - Import Table        ← IAT           │
│  - Export Table        ← EAT           │
│  - Resource Table                       │
│  - ...                                  │
├─────────────────────────────────────────┤
│           Section Table                  │
│  - .text (RX)    程式碼                 │
│  - .rdata (R)    唯讀資料               │
│  - .data (RW)    可讀寫資料             │
│  - .reloc (R)    重定位資訊             │
├─────────────────────────────────────────┤
│                                         │
│           Section Data                   │
│  ┌─────────────────────────────────┐    │
│  │           .text                  │    │
│  │      (可執行程式碼)              │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │           .data                  │    │
│  │      (初始化資料)                │    │
│  └─────────────────────────────────┘    │
│  ┌─────────────────────────────────┐    │
│  │           .rdata                 │    │
│  │      (唯讀資料/字串)             │    │
│  └─────────────────────────────────┘    │
│                                         │
└─────────────────────────────────────────┘

從檔案到記憶體:載入過程

當你執行一個 .exe 時:

┌────────────────────┐          ┌────────────────────────┐
│  PE 檔案(硬碟)    │          │   記憶體中的進程       │
│                    │          │                        │
│  00000000: MZ...   │          │  0x00010000 ┌────────┐ │
│  00000100: PE...   │   載入   │             │ Header │ │
│  00000200: .text   │  ────→  │  0x00011000 ├────────┤ │
│  00001000: .data   │          │             │ .text  │ │
│  00002000: .rdata  │          │             │ (RX)   │ │
│                    │          │  0x00015000 ├────────┤ │
└────────────────────┘          │             │ .data  │ │
                                │             │ (RW)   │ │
                                │  0x00017000 ├────────┤ │
                                │             │ .rdata │ │
                                │             │ (R)    │ │
                                │             └────────┘ │
                                │                        │
                                │  0x7FFFFFFF            │
                                └────────────────────────┘

載入步驟:

  1. 解析標頭:讀取 PE Header 資訊
  2. 映射區段:將檔案區段映射到記憶體頁面
  3. 處理 IAT/EAT:解析匯入/匯出表
  4. 載入依賴 DLL:載入所需的外部程式庫
  5. 處理重定位:如果需要的話(ASLR)
  6. 執行進入點:呼叫 AddressOfEntryPoint

ImageBase 與 ASLR

ImageBase 是 PE 檔案「希望」被載入的位址:
– 預設 EXE:0x00400000
– 預設 DLL:0x10000000

ASLR(Address Space Layout Randomization)
– 現代 Windows 會隨機化載入位址
– 讓攻擊者難以預測記憶體配置
– 這是重要的安全機制!

IAT 與 EAT:模組間的橋樑

IAT(Import Address Table,匯入位址表)

當你的程式要呼叫 MessageBoxA() 時:
1. MessageBoxAuser32.dll
2. 你的程式 IAT 記錄:「我需要 user32.dll 的 MessageBoxA」
3. 載入器填入實際位址到 IAT
4. 你的程式透過 IAT 間接呼叫

myapp.exe                          user32.dll
┌───────────────┐                  ┌───────────────┐
│ 程式碼:        │                  │ EAT:          │
│ CALL [IAT+0]  │───────────┐      │ MessageBoxA   │
│               │           │      │ → 0x77D10000  │
├───────────────┤           │      └───────────────┘
│ IAT:          │           │              │
│ [0] = ???     │ ←─────────┘              │
│     ↓         │                          │
│  載入時填入   │ ←─────────────────────────┘
│ [0] = 0x77D10000                         
└───────────────┘

EAT(Export Address Table,匯出位址表)

DLL 用來「公開」函式給其他模組使用:
– 列出所有可被外部呼叫的函式
– 提供函式名稱與實際位址的對應


CPU 暫存器完整介紹

什麼是暫存器?

暫存器(Register) 是 CPU 內部的高速儲存單元:
– 存取速度比記憶體快很多
– 數量有限
– 用於暫時儲存資料和控制執行流程

x86 暫存器分類

1. 通用暫存器(General Purpose Registers)- 32 位元

暫存器 全名 主要用途 分割方式
EAX Accumulator 運算結果、函式回傳值 AX → AH + AL
EBX Base 通用(無特定用途) BX → BH + BL
ECX Counter 迴圈計數器 CX → CH + CL
EDX Data EAX 的擴充(乘除法) DX → DH + DL
ESP Stack Pointer 指向堆疊頂端 SP
EBP Base Pointer 指向堆疊框架底部 BP
ESI Source Index 字串操作的來源位址 SI
EDI Destination Index 字串操作的目標位址 DI

暫存器的分割結構

┌─────────────────────────────────────────────────┐
│                    EAX (32 bits)                │
│  ┌──────────────────────┬──────────────────────┐│
│  │      High 16 bits    │     AX (16 bits)     ││
│  │                      ├──────────┬───────────┤│
│  │                      │ AH (8b)  │  AL (8b)  ││
│  └──────────────────────┴──────────┴───────────┘│
│                                                 │
│  例如:EAX = 0x12345678                         │
│        AX  = 0x5678                             │
│        AH  = 0x56                               │
│        AL  = 0x78                               │
└─────────────────────────────────────────────────┘

2. EIP(Instruction Pointer,指令指標)

┌──────────────────────────────────────────────────┐
│  EIP - 最重要的暫存器!                          │
│                                                  │
│  • 指向「下一條要執行的指令」的位址              │
│  • CPU 會依據 EIP 來決定執行什麼                 │
│  • 這是**唯讀**的!你無法直接修改它              │
│                                                  │
│  ⚠️ 但是...                                     │
│  如果攻擊者能夠「間接」控制 EIP,               │
│  就能控制程式的執行流程!                        │
│                                                  │
│  這就是漏洞利用的核心目標!                      │
└──────────────────────────────────────────────────┘

3. 區段暫存器(Segment Registers)- 16 位元

暫存器 說明
CS Code Segment – 程式碼區段基底
DS Data Segment – 資料區段基底
SS Stack Segment – 堆疊區段基底
ES Extra Segment – 額外區段(字串操作)
FS Extra – 指向 TEB!
GS Extra

重要FS:[0] 在 x86 Windows 指向 TEB,這在 SEH 利用中很關鍵!

4. EFLAGS(旗標暫存器)

這個 32 位元暫存器被分割成許多「旗標位元」:

旗標 名稱 說明
CF Carry Flag 進位旗標(無號數溢位)
ZF Zero Flag 運算結果為零時設定
SF Sign Flag 結果為負數時設定
OF Overflow Flag 有號數溢位
DF Direction Flag 字串操作方向
PF Parity Flag 同位旗標

這些旗標用於條件判斷,決定是否執行分支跳躍!


x86 組合語言基礎

為什麼要學組合語言?

  1. 理解程式真正在做什麼
  2. 分析惡意程式
  3. 撰寫 Shellcode
  4. 了解漏洞利用原理

基本概念

Opcode vs Assembly

高階語言(C)    →    組合語言(ASM)    →    機器碼(Opcode)
                         ↓
                    人類可讀                  CPU 可執行

例如:
int a = 5;       →    MOV EAX, 5          →    B8 05 00 00 00
  • Assemble(組譯):ASM → Opcode
  • Disassemble(反組譯):Opcode → ASM
  • Decompile(反編譯):Opcode → 高階語言

組合語言語法

Intel 語法(我們主要使用這種):

指令  目標, 來源
MOV   EAX,  5        ; 將 5 放入 EAX

AT&T 語法(Linux 常見):

指令  來源, 目標
movl  $5,  %eax      ; 同樣的事情,但方向相反

常用指令詳解

資料移動

MOV  EAX, 5          ; EAX = 5
MOV  EAX, EBX        ; EAX = EBX
MOV  EAX, [EBX]      ; EAX = *EBX (從 EBX 指向的位址讀取)
MOV  [EAX], EBX      ; *EAX = EBX (寫入 EAX 指向的位址)

方括號 [ ] 表示「記憶體位址」,類似 C 的指標解參考

算術運算

ADD  EAX, 5          ; EAX = EAX + 5
SUB  EAX, 5          ; EAX = EAX - 5
INC  EAX             ; EAX = EAX + 1
DEC  EAX             ; EAX = EAX - 1
MUL  EBX             ; EDX:EAX = EAX * EBX
DIV  EBX             ; EAX = EDX:EAX / EBX, EDX = 餘數

邏輯運算

AND  EAX, EBX        ; EAX = EAX & EBX
OR   EAX, EBX        ; EAX = EAX | EBX
XOR  EAX, EAX        ; EAX = 0 (自己 XOR 自己 = 0,常用來清零)
NOT  EAX             ; EAX = ~EAX
NEG  EAX             ; EAX = -EAX

堆疊操作

PUSH EAX             ; ESP = ESP - 4; *ESP = EAX
POP  EBX             ; EBX = *ESP; ESP = ESP + 4

圖解 PUSH 與 POP:

初始狀態:              PUSH EAX 後:            POP EBX 後:
EAX = 0x50505050       EAX = 0x50505050        EAX = 0x50505050
EBX = 0x12345678       EBX = 0x12345678        EBX = 0x50505050 ←變了
ESP = 0x00120008       ESP = 0x00120004 ←變了  ESP = 0x00120008

    STACK                  STACK                   STACK
0x00120000 │41414141│   0x00120000│41414141│   0x00120000│41414141│
0x00120004 │42424242│   0x00120004│50505050│←  0x00120004│50505050│
0x00120008 │43434343│←  0x00120008│43434343│   0x00120008│43434343│←

注意:堆疊是往低位址成長的!PUSH 會減少 ESP

流程控制

; 無條件跳躍
JMP  label           ; 跳到 label

; 條件跳躍(依據 EFLAGS)
JE   label           ; Jump if Equal (ZF=1)
JNE  label           ; Jump if Not Equal (ZF=0)
JZ   label           ; Jump if Zero (ZF=1)
JNZ  label           ; Jump if Not Zero (ZF=0)
JG   label           ; Jump if Greater (有號數)
JL   label           ; Jump if Less (有號數)
JA   label           ; Jump if Above (無號數)
JB   label           ; Jump if Below (無號數)

; 比較指令(設定 EFLAGS)
CMP  EAX, EBX        ; 計算 EAX - EBX,只設定旗標,不改變暫存器
TEST EAX, EAX        ; 計算 EAX & EAX,只設定旗標

函式呼叫

CALL function        ; PUSH 返回位址; JMP function
RET                  ; POP EIP (返回)

CALL 的詳細流程:

執行前:                執行 CALL 0x401000 後:
EIP = 0x401050          EIP = 0x401000 (跳到函式)
ESP = 0x00120008        ESP = 0x00120004

    STACK                   STACK
0x00120004│        │    0x00120004│0x401055│← 返回位址
0x00120008│........│←   0x00120008│........│

NOP 指令

NOP                  ; No Operation,什麼都不做
                     ; Opcode: 0x90

常見用途:
– 對齊程式碼
– 除錯佔位
NOP Sled(已過時的漏洞利用技巧)

警告:濫用 NOP 是不好的習慣!會使 payload 變大且更容易被偵測

Endianness(位元組順序)

x86 使用 Little Endian(小端序)

數值:0x12345678

在記憶體中的排列:
位址     內容
0x0000   78  ← 最低位元組(LSB)先存
0x0001   56
0x0002   34
0x0003   12  ← 最高位元組(MSB)後存

所以 0x12345678 在記憶體中看起來是:\x78\x56\x34\x12

漏洞利用注意:寫入位址時需要反轉位元組順序!


漏洞利用術語解釋

基本術語

術語 英文 定義
漏洞 Vulnerability 可能被利用的軟體弱點(溢位、邏輯錯誤、資訊洩露等)
漏洞利用 Exploit 利用漏洞來執行攻擊者控制操作的程式碼
0day Zero-day 在開發者得知之前就被利用的漏洞
Payload Payload 漏洞利用成功後執行的程式碼
Shellcode Shellcode 通常用於取得 shell 的 payload

記憶體相關漏洞類型

1. Buffer Overflow(緩衝區溢位)

當資料超出緩衝區的預定大小:

char buffer[8];
strcpy(buffer, "AAAAAAAAAAAAAAAAAAAA");  // 寫入超過 8 bytes!
正常情況:                 溢位後:
┌──────────────┐          ┌──────────────┐
│   buffer[8]  │          │   AAAAAAAA   │
├──────────────┤          ├──────────────┤
│ 其他變數     │          │   AAAA...   │ ← 被覆蓋!
├──────────────┤          ├──────────────┤
│ 返回位址     │          │   0x41414141 │ ← 危險!
└──────────────┘          └──────────────┘

2. Stack Overflow(堆疊溢位)

Buffer Overflow 發生在堆疊上,可能覆蓋:
– 區域變數
– 儲存的 EBP
返回位址 ← 最危險的目標!

3. Heap Overflow(堆積溢位)

Buffer Overflow 發生在堆積上,可能覆蓋:
– 堆積管理結構
– 其他動態配置的資料

4. Format String(格式化字串漏洞)

當使用者輸入被當作格式字串:

printf(user_input);  // 危險!
// 如果 user_input = "%x %x %x",會洩露堆疊內容
// 如果 user_input = "%n",可以寫入記憶體!

5. Off-by-One(差一錯誤)

緩衝區大小計算錯誤,多寫入 1 個位元組:

char buffer[10];
for (int i = 0; i <= 10; i++) {  // 應該是 i < 10
    buffer[i] = 'A';  // buffer[10] 溢位!
}

重要區別

┌────────────────────────────────────────────────────────┐
│  Stack Buffer Overflow ≠ Stack Overflow                │
│                                                        │
│  Stack Buffer Overflow:                               │
│    堆疊上的緩衝區被溢位覆蓋                            │
│                                                        │
│  Stack Overflow:                                      │
│    通常指堆疊空間耗盡(如無窮遞迴)                    │
└────────────────────────────────────────────────────────┘

總結與學習資源

本文重點回顧

  1. Windows 架構
    • Ring 0(核心)與 Ring 3(使用者)的區別
    • 進程、執行緒的概念
  2. 記憶體管理
    • 虛擬記憶體與實體記憶體
    • 頁面與頁框
    • 進程位址空間配置
  3. PE 檔案格式
    • 從檔案到記憶體的載入過程
    • IAT/EAT 的作用
  4. CPU 暫存器
    • 通用暫存器的用途
    • EIP 的重要性
    • EFLAGS 與條件跳躍
  5. 組合語言
    • 基本指令(MOV, PUSH, POP, CALL, RET…)
    • Little Endian 位元組順序
  6. 漏洞類型
    • Buffer Overflow
    • Stack Overflow
    • Format String
    • Off-by-One

延伸學習資源

線上教程:
– LiveOverflow YouTube 頻道
– Exploit Education 練習平台

書籍推薦:
Hacking: The Art of Exploitation by Jon Erickson
The Shellcoder’s Handbook
A Bug Hunter’s Diary by Tobias Klein

參考資料:
– Intel 64 and IA-32 Architectures Software Developer Manuals
– MSDN Windows 開發文件
– PE 格式規格(Microsoft 官方)

飛飛
飛飛

講師學歷:臺科資工所、逢甲資工系畢業。
技術專長:OSINT、滲透測試、網站開發、專業易懂教育訓練。
證照書籍:OSCP、OSCE³、著《資安這條路:領航新手的 Web Security 指南》。
教學經驗:60+ 企業教學經驗、指導過上百位學員。
教學特色:新手友善、耐心指導、擅長圖解(流程圖、心智圖)引導學習。
社群經驗:目前經營全臺資安社群 CURA,曾任臺科資安社社長、逢甲黑客社社長。
社群交流:LINE 社群《飛飛的資安大圈圈》,即時分享經驗、鼓勵交流。
社群分享:FB 粉專《資安這條路,飛飛來領路》,分享文章與圖卡整理。
個人網站:feifei.tw 分享資安技術文章;pbtw.tw 分享 AI 相關應用;ssdlc.feifei.tw 分享軟體安全開發流程文章。