可加载内核模块编程和系统调用拦截

时间:2012-09-27 02:38:51

标签: c linux kernel

假设我们想拦截退出系统调用并在任何进程调用它时在控制台上打印消息。为了做到这一点,我们必须编写自己的假退出系统调用,然后让内核调用我们的假退出函数而不是原始的退出调用。在我们的假出口呼叫结束时,我们可以调用原始的出口呼叫。为此,我们必须操纵系统调用表数组(sys_call_table)。 使用sys_call_table数组,我们可以操作它以使sys_exit入口指向我们新的假出口调用。我们必须存储一个指向原始sys_exit调用的指针,并在完成将消息打印到控制台后调用它。源代码:

 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <sys/syscall.h>

 extern void *sys_call_table[];

 asmlinkage int (*original_sys_exit)(int);

 asmlinkage int our_fake_exit_function(int error_code)
 {
    /*print message on console every time we
     *are called*/
    printk("HEY! sys_exit called with error_code=%d\n",error_code);

    /*call the original sys_exit*/
    return original_sys_exit(error_code);
 }

 /*this function is called when the module is
 *loaded (initialization)*/
 int init_module()
 {
     /*store reference to the original sys_exit*/
     original_sys_exit=sys_call_table[__NR_exit];

     /*manipulate sys_call_table to call our
      *fake exit function instead
      *of sys_exit*/
     sys_call_table[__NR_exit]=our_fake_exit_function;
 }


 /*this function is called when the module is
   *unloaded*/
 void cleanup_module()
 {
     /*make __NR_exit point to the original
      *sys_exit when our module
      *is unloaded*/
     sys_call_table[__NR_exit]=original_sys_exit;
 }

当我编译这个程序时,我收到警告:

  

警告:&#34; sys_call_table&#34; [/home/roiht/driver/one.ko] undefined!

正如我搜索的那样,我发现2.5之后的内核版本改变了sys_call表的概念。 那么,我的问题是在新内核版本中执行此操作的替代方法是什么?

2 个答案:

答案 0 :(得分:1)

如果已使用EXPORT_SYMBOL()在内核中显式导出任何内核变量,则可以在模块中使用它。从内核版本2.6开始,sys_call_table的导出已被删除。因此,如果要使用此方法,请显式导出变量。作为惯例,isis导出是在变量声明之后立即完成的,但我想从任何定义了此变量的文件中导出也会这样做。要检查方法是否有效,只需查看“cat / proc / kallsyms”的输出。

捕获exit syscall的另一种方法是在syscall执行的sysenter部分放置一个钩子。点击此处了解更多详情:http://articles.manugarg.com/systemcallinlinux2_6.html

答案 1 :(得分:0)

您可以从与您的内核对应的sys_call_table文件中读取System.map-xxx的地址。该文件通常位于/ boot目录中,名称为System.map-<kernel-version>,其中kernel-version是命令uname -r的结果。您可以使用模块参数将地址传递给模块。