簡體   English   中英

linux-kernel模塊中的系統調用攔截(內核3.5)

[英]System call interception in linux-kernel module (kernel 3.5)

我需要用自己的實現替換標准系統調用(例如SYS_mkdir)。

正如我在一些來源中讀到的,包括Stackoverflow上的這個問題sys_call_table自內核版本2.6以來不是導出符號。

我嘗試了以下代碼:

    #include <linux/module.h> 
    #include <linux/kernel.h> 
    #include <linux/unistd.h> 
    #include <asm/syscall.h> 

    int (*orig_mkdir)(const char *path); 

    ....

    int init_module(void) 
    { 
            orig_mkdir=sys_call_table[__NR_mkdir]; 
            sys_call_table[__NR_mkdir]=own_mkdir;  
            printk("sys_mkdir replaced\n"); 
            return(0); 
    } 

    ....

不幸的是我收到編譯錯誤:

 error: assignment of read-only location ‘sys_call_table[83]’

如何更換系統調用?

編輯:有沒有內核修補的解決方案?

這對我有用。

請參閱Linux內核:系統調用掛鈎示例https://bbs.archlinux.org/viewtopic.php?id=139406

asmlinkage long (*ref_sys_open)(const char __user *filename, int flags, umode_t mode);
asmlinkage long new_sys_open(const char __user *filename, int flags, umode_t mode)
{
  return ref_sys_open(filename, flags, mode);
}

static unsigned long **aquire_sys_call_table(void)
{
  unsigned long int offset = PAGE_OFFSET;
  unsigned long **sct;

  while (offset < ULLONG_MAX) {
    sct = (unsigned long **)offset;

    if (sct[__NR_close] == (unsigned long *) sys_close) 
      return sct;

    offset += sizeof(void *);
  }
  print("Getting syscall table failed. :(");
  return NULL;
}


// Crazy copypasted asm stuff. Could use linux function as well...
// but this works and will work in the future they say.
static void disable_page_protection(void) 
{
  unsigned long value;
  asm volatile("mov %%cr0, %0" : "=r" (value));

  if(!(value & 0x00010000))
    return;

  asm volatile("mov %0, %%cr0" : : "r" (value & ~0x00010000));
}

static void enable_page_protection(void) 
{
  unsigned long value;
  asm volatile("mov %%cr0, %0" : "=r" (value));

  if((value & 0x00010000))
    return;

  asm volatile("mov %0, %%cr0" : : "r" (value | 0x00010000));
}


static int __init rootkit_start(void) 
{

  //Hide me

  print("loaded");

  if(!(sys_call_table = aquire_sys_call_table()))
    return -1;

  disable_page_protection(); 
  {
    ref_sys_open = (void *)sys_call_table[__NR_open];
    sys_call_table[__NR_open] = (unsigned long *)new_sys_open;
  }
  enable_page_protection();
  return 0;
}

static void __exit rootkit_end(void) 
{
  print("exiting");

  if(!sys_call_table) {
    return;
  }

  disable_page_protection();
  {
    sys_call_table[__NR_open] = (unsigned long *)ref_sys_open;
  }
  enable_page_protection();
}

是的,沒有修補/重建內核的解決方案。 使用Kprobes基礎結構(或SystemTap)。

這將允許您使用內核模塊在內核中的任何位置放置“探測器”(函數)。

現在可以通過修改sys_call_table來執行類似的操作(它是只讀的)並被視為臟黑客! Kprobes / Jprobes / etc是一種“干凈”的方式。此外,內核源代碼樹提供的文檔和示例非常好(在內核src樹下看 - Documentation / kprobes.txt )。

首先,您需要確定sys_call_table的位置。 看到這里

在寫入剛剛找到的系統表之前,必須使其內存頁面可寫。 對於檢查這里 ,如果還是不行,請嘗試

使用LSM infrustructure。

有關詳細信息,請查看LSM鈎子path_mkdirinode_mkdir 需要解決的一個問題是如何在系統不明確允許的情況下注冊您自己的LSM模塊。 有關詳細信息,請參閱答案:

如何用LSM實現自己的鈎子函數?

該問題是由於sys_call_table是只讀的。 為了避免錯誤,在操作sys_call_table之前,你必須使它也可寫。 內核提供了實現它的功能。 該函數以set_mem_rw()的形式給出。

在操作sys_call_table之前,只需添加以下代碼片段即可

set_mem_rw((long unsigned int)sys_call_table,1);

在內核模塊的退出函數中,請不要忘記將sys_call_table恢復為只讀。它可以實現如下。

set_mem_ro((long unsigned int)sys_call_table,1);    

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM