9

我需要用我自己的实现替换标准系统调用(例如 SYS_mkdir)。

正如我在一些资料中读到的,包括Stackoverflow 上的这个问题sys_call_table, is not export symbol since kernel version 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]’

如何替换系统调用?

编辑:有没有没有内核补丁的解决方案?

4

5 回答 5

8

这对我有用。

请参阅 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();
}
于 2012-12-16T21:29:02.073 回答
7

是的,有一个无需修补/重建内核的解决方案。使用Kprobes基础设施(或 SystemTap)。

这将允许您使用内核模块在内核中的任何点放置“探针”(函数)。

现在可以防止通过修改 sys_call_table 来做类似的事情(它是只读的)并且被认为是肮脏的黑客!Kprobes/Jprobes/etc 是一种“干净”的方法。此外,内核源代码树中提供的文档和示例非常好(查看内核 src 树 - Documentation/kprobes.txt)。

于 2012-12-15T07:48:00.710 回答
1

该问题是由于 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);    
于 2013-01-17T16:05:46.270 回答
0

Use LSM infrustructure.

Look at LSM hooks path_mkdir or inode_mkdir for details. One question that needs to be solved is how to register your own LSM module while the system don't allow it explicitly. See the answer for details here:

How can I implement my own hook function with LSM?

于 2012-12-17T18:57:54.213 回答
0

首先,您需要确定 sys_call_table 的位置。见这里

在写入刚刚定位的系统表之前,您必须使其内存页可写。对于这里的检查,如果这不起作用,试试这个

于 2012-12-14T13:14:01.193 回答