模块在写入系统调用表时被杀死

时间:2018-10-20 20:19:43

标签: linux-kernel system-calls

我尝试编写一个挂钩系统读取功能的内核模块。但是,一旦我尝试将函数的指针写入sys调用表,该模块就会被杀死。这是我的初始化函数:

int init_module(void)
{
  // set rw/ro functions
  patch_set_memory_rw = (void *) kallsyms_lookup_name("set_memory_rw");
  patch_set_memory_ro = (void *) kallsyms_lookup_name("set_memory_ro");

  if( patch_set_memory_rw == NULL ||
      patch_set_memory_ro == NULL){
    // something went wrong
    printk(KERN_ALERT "ERROR WITH RW/RO!");
    return 1;
  }
  // Inform that module is staring
  //printk(KERN_INFO "Start Hook Read.");
  syscall_table_pu64 = (void **)kallsyms_lookup_name("sys_call_table");

  //for debugging
  //printk(KERN_ALERT "syscall addr is %llx", syscall_table_pu64);


  // swap read call with own read function
  orig_read_p = syscall_table_pu64[__NR_read];
  // set memory rw to change it
  patch_set_memory_rw((uint64_t)syscall_table_pu64, 1);
  syscall_table_pu64[__NR_read] = own_read_func;
  return 0;
}

该错误发生在行中

syscall_table_pu64[__NR_read] = own_read_func;

有人知道我的问题是什么吗?我不知道。 错误消息是

RIP: init_module+0x76/0xa0 [hook_read] RSP: ffffa4ad46233c70

RIP: 0033:0x7f01920bb839
[ 3476.855557] RSP: 002b:00007fffcc925288 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[ 3476.857431] RAX: ffffffffffffffda RBX: 0000559daa9f6790 RCX: 00007f01920bb839
[ 3476.858902] RDX: 0000000000000000 RSI: 0000559daa012c2e RDI: 0000000000000003
[ 3476.860550] RBP: 0000559daa012c2e R08: 0000000000000000 R09: 00007f019238e000
[ 3476.861959] R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000
[ 3476.863399] R13: 0000559daa9f6760 R14: 0000000000000000 R15: 0000000000000000
[ 3476.864747] Code: 89 05 d7 22 00 00 48 8b 10 48 89 c7 be 01 00 00 00 48 8b 05 d5 22 00 00 48 89 15 b6 22 00 00 e8 71 3f 26 e2 48 8b 05 b2 22 00 00 <48> c7 00 00 f0 59 c0 31 c0 5d c3 48 c7 c7 40 00 5a c0 e8 f3 f1 

2 个答案:

答案 0 :(得分:0)

系统调用表是只读的。请勿尝试对其进行修改。

如果要挂接读/写操作,则需要选择另一种方式。您可能要研究的一种机制是kprobes系统。

答案 1 :(得分:-1)

我最终确定了我的问题。为了删除syscall的写保护,您可以(当然)不使用它的linux syscall:D让我花了3个小时才意识到这一点。而是使用

write_cr0 (read_cr0 () & (~ 0x10000));

启用写入和

write_cr0 (read_cr0 () | 0x10000);

使您的记忆再次只读。