2011-09-27 126 views
3

我使用下面的模塊代碼來掛鉤系統調用(代碼記入其他人,例如Linux Kernel: System call hooking example)。系統調用掛鉤的問題

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/moduleparam.h> 
#include <linux/unistd.h> 
#include <asm/semaphore.h> 
#include <asm/cacheflush.h> 

void **sys_call_table; 

asmlinkage int (*original_call) (const char*, int, int); 

asmlinkage int our_sys_open(const char* file, int flags, int mode) 
{ 
    printk(KERN_ALERT "A file was opened\n"); 
    return original_call(file, flags, mode); 
} 

int set_page_rw(long unsigned int _addr) 
{ 
    struct page *pg; 
    pgprot_t prot; 
    pg = virt_to_page(_addr); 
    prot.pgprot = VM_READ | VM_WRITE; 
    return change_page_attr(pg, 1, prot); 
} 

int init_module() 
{ 
    // sys_call_table address in System.map 
    sys_call_table = (void*)0xffffffff804a1ba0; 
    original_call = sys_call_table[1024]; 
    set_page_rw(sys_call_table); 
    sys_call_table[1024] = our_sys_open; 
    return 0; 
} 

void cleanup_module() 
{ 
    // Restore the original call 
    sys_call_table[1024] = original_call; 
} 

當insmod的編譯.ko文件,終端拋出 「殺死」。當查看'cat/proc/modules'文件時,我會看到加載狀態。

my_module 10512 1 - Loading 0xffffffff882e7000 (P) 

正如預期的那樣,我不能勉強這個模塊,因爲它抱怨它正在使用。系統重新啓動以獲得清除狀態。

之後,在註釋上述源sys_call_table[1024] = our_sys_open;sys_call_table[1024] = original_call;中的兩條代碼行後,它可以成功執行insmod。更有意思的是,當取消註釋這兩行(更改回原始代碼)時,已編譯的模塊可以成功執行insmod。我不太明白爲什麼會發生這種情況?有什麼辦法可以成功編譯代碼並直接進行insmod嗎?

我在Linux內核2.6.24.6的Redhat上做過這些。

回答

1

我認爲你應該看看kprobes API,它在Documentation/krpobes.txt中有詳細記錄。它使您能夠在每個地址(例如系統調用條目)上安裝處理程序,以便您可以執行所需的任務。額外的好處是你的代碼會更加便攜。

如果您只想跟蹤那些系統調用,您可以使用審計子系統,編寫自己的userland守護進程,以便能夠從審計kthread接收NETLINK套接字上的事件。 libaudit提供了一個簡單的API來註冊/讀取事件。

如果你確實有一個很好的理由不使用kprobes/audit,我建議你檢查你試圖寫入的值是否在你設置可寫的頁面之上。快速計算表明:

offset_in_sys_call_table * sizeof(*sys_call_table) = 1024 * 8 = 8192 

這是後兩頁設置可寫的,如果你正在使用的4K頁面的一個。