contributed by < OscarShiang
>
hideproc
的原理在於使用 ftrace hook 進行 live patching 進而更改 find_ge_pid()
函式的行為。
當我們利用 ps
或是列出 /proc/
目錄底下的程序時,實際上會使用到 find_ge_pid()
函式來進行查找 (在 /fs/proc/base.c
中的 proc_pid_readdir()
使用 next_tgid()
遍尋所有程序,而其實作則使用 find_ge_pid()
),所以若我們改變 find_ge_pid()
的行為,就可以達到隱藏程序的效果。
但是我們的目的並不是要完全取代原本的實作,而是偏移部份程序查照的結果。我們使用的方式是利用 ftrace 註冊 hook_ftrace_thunk()
函式,當有程序想要呼叫 find_ge_pid()
時, ftrace 會將其跳轉到我們先前指定的 hook_ftrace_thunk()
函式,透過更改 Instruction Pointer 位址從而跳轉到 hook_find_ge_pid()
,利用原先的 find_ge_pid()
函式進行操作後,如果預期的 pid 是我們想要隱藏者時,我們將代入到 find_ge_pid()
的 pid
+ 1 讓其無法取得預期的結果,將列表中的 pid 隱藏。
而我們操作 hidden_proc
的 hidden list 的方式是使用 VFS 來進行。
在範例程式中,我們使用以下命令將指定 pid 隱藏
實際上進行處理的函式是在 device_write()
,經由命令分析後,使我們能夠動態修改 hidden list。
我參考 next_tgid()
的方式來進行實作
因為 parent 的資訊保存在 task_struct
結構裡面,所以我們需要依序經由以下步驟取得 ppid
find_get_pid()
: 利用 pid 取得 struct pid
的位址get_task_pid()
: 透過 struct pid
的位址取得 struct task_struct
的位址task->parent->pid
: 得到 ppid為了方便使用我將其包裝成 get_ppid()
:
接著在模組中新增一個新的命令 addwp
(add with parent) 用以將指定 pid 以及其 parent pid 加入隱藏的 list 中
相關的 commit 可以參考
50f8eb9
這邊為了驗證模組行為,我準備了一個簡單的程式:
上述這段程式碼的作用就是產生一組 process 與 child process,並印出兩者的 pid
編譯後,執行結果大致如下
我們可以透過 ps aux
檢查二者是否可以被看見
接著我們使用 addwp
命令將 child process pid 加入到 hidden list 中
透過讀取 /dev/hideproc
檢查二者是否被加入到 list 之中
此時若使用 ps aux
則無法查到兩個 test_proc
的狀態
TODO
在原本的實作中,因為沒有 exit function 中實作資源釋放。所以如果我們將模組載入後移除,使用 insmod
重新載入模組時會得到 Killed
的輸出,並無法再次載入模組。
解決的方式就是在 _hideproc_exit()
加入與 _hideproc_init()
成對的資源釋放即可。
kstrtol
回傳值檢查根據 Kernel API Doc 對於 return value 的描述
Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. Used as a replacement for the obsolete simple_strtoull. Return code must be checked.
但在 device_write()
處並沒有針對 kstrtol()
的回傳值做檢查,
因此需要在這邊加上檢查
因為 kstrtol
錯誤原因有兩種,所以不直接回傳 -EINVAL
,而是將 kstrtol
產生的回傳值回傳回去。
在原本的實作中,hideproc
在收到 del <pid>
的命令時並不只會將我們指定的 pid 從隱藏列表中刪除,而是會將所有列表中的 node 全部刪除
因此我在 unhide_process()
中加上核對 pid 的機制,避免其將所有節點刪除
我們可以透過對 /dev/hideproc
寫入命令來增刪我們想要隱藏的 pid,但是在 hide_process()
函式中我們並不會對 pid 進行任何的檢查,因此就會有 list 中有重複好幾個 pid 的情況產生
我們可以利用下列的命令重複將 pid 589 加入 list 中
接著查看隱藏的清單即可見三個 pid node
我們在 hide_process()
中加入檢查機制以避免將相同的 pid 加入 list 中
若我們這時嘗試重複加入一個 pid 589 時,就會產生以下的錯誤提示
device_read()
發生 buffer overflowTODO
linux2021