Linux内核:系统调用挂钩的例子 [英] Linux Kernel: System call hooking example

查看:460
本文介绍了Linux内核:系统调用挂钩的例子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试写一些简单的测试code作为挂钩系统调用表的示范。

sys_call_table的不再出口2.6,所以我只是抓住从System.map文件的地址,我可以看到它是正确的(通过在我发现地址记忆来看,我可以看到指针到系统调用)。

然而,当我试图修改此表,内核给出了一个糟糕和无法处理的虚拟地址c061e4f4内核寻呼请求和机器重启。

这是CentOS的5.4运行2.6.18-164.10.1.el5。是否有某种保护或者我只是有一个错误吗?我知道它带有SELinux的,我已经试过把它在permissive模式,但它不会有所作为

下面是我的code:

 的#include<的Linux / kernel.h>
#包括LT&; Linux的/ - module.h中GT;
#包括LT&; Linux的/ moduleparam.h>
#包括LT&; Linux的/ unistd.h中>无效** sys_call_table的;asmlinkage INT(* original_call)(为const char *,INT,INT);asmlinkage INT our_sys_open(为const char *文件,诠释旗帜,INT模式)
{
   printk的(一个文件打开\\ n);
   返回original_call(文件,标志,模式);
}INT的init_module()
{
    //在sys_call_table的的System.map地址
    sys_call_table中=(无效*)0xc061e4e0;
    original_call = sys_call_table的[__ NR_open]    //挂钩:在这里崩溃
    sys_call_table的[__ NR_open] = our_sys_open;
}虚空在cleanup_module()
{
   //恢复原来的呼叫
   sys_call_table的[__ NR_open] = original_call;
}


解决方案

我终于找到了自己的答案。

<一个href=\"http://www.linuxforums.org/forum/linux-kernel/133982-cannot-modify-sys_call_table.html\">http://www.linuxforums.org/forum/linux-kernel/133982-cannot-modify-sys_call_table.html

内核在某一点改变,使得只有在读系统调用表

cypherpunk:


  

哪怕是晚,但解决方案
  可能别人的兴趣也:在
  entry.S中文件,你会发现:code:

  .section伪.RODATA,一
#包括syscall_table_32.S


  
  

sys_call_table的 - >只读你必须
  编译内核新的,如果你想
  黑客与周围sys_call_table的...


的链接,也具有改变存储器可写的一个例子。

nasekomoe:


  

大家嗨。感谢您的答复。一世
  解决了这个问题很久以前
  修改访问内存页面。一世
  已经实现了两个函数,做
  它为我的上级code:

 的#include&LT; ASM / cacheflush.h&GT;
#IFDEF KERN_2_6_24
#包括LT&; ASM / semaphore.h&GT;
INT set_page_rw(长无符号整数_addr)
{
    结构页*皮克;
    pgprot_t PROT;
    PG = virt_to_page(_addr);
    prot.pgprot = VM_READ | VM_WRITE;
    返回change_page_attr(PG,1,PROT);
}INT set_page_ro(长无符号整数_addr)
{
    结构页*皮克;
    pgprot_t PROT;
    PG = virt_to_page(_addr);
    prot.pgprot = VM_READ;
    返回change_page_attr(PG,1,PROT);
}#其他
#包括LT&; Linux的/ semaphore.h&GT;
INT set_page_rw(长无符号整数_addr)
{
    返回set_memory_rw(_addr,1);
}INT set_page_ro(长无符号整数_addr)
{
    返回set_memory_ro(_addr,1);
}#ENDIF // KERN_2_6_24


下面是原来的code,对我的作品的修改版本。

 的#include&LT;的Linux / kernel.h&GT;
#包括LT&; Linux的/ - module.h中GT;
#包括LT&; Linux的/ moduleparam.h&GT;
#包括LT&; Linux的/ unistd.h中&GT;
#包括LT&; ASM / semaphore.h&GT;
#包括LT&; ASM / cacheflush.h&GT;无效** sys_call_table的;asmlinkage INT(* original_call)(为const char *,INT,INT);asmlinkage INT our_sys_open(为const char *文件,诠释旗帜,INT模式)
{
   printk的(一个文件打开\\ n);
   返回original_call(文件,标志,模式);
}INT set_page_rw(长无符号整数_addr)
{
   结构页*皮克;
   pgprot_t PROT;
   PG = virt_to_page(_addr);
   prot.pgprot = VM_READ | VM_WRITE;
   返回change_page_attr(PG,1,PROT);
}INT的init_module()
{
    //在sys_call_table的的System.map地址
    sys_call_table中=(无效*)0xc061e4e0;
    original_call = sys_call_table的[__ NR_open]    set_page_rw(sys_call_table中);
    sys_call_table的[__ NR_open] = our_sys_open;
}虚空在cleanup_module()
{
   //恢复原来的呼叫
   sys_call_table的[__ NR_open] = original_call;
}

I'm trying to write some simple test code as a demonstration of hooking the system call table.

"sys_call_table" is no longer exported in 2.6, so I'm just grabbing the address from the System.map file, and I can see it is correct (Looking through the memory at the address I found, I can see the pointers to the system calls).

However, when I try to modify this table, the kernel gives an "Oops" with "unable to handle kernel paging request at virtual address c061e4f4" and the machine reboots.

This is CentOS 5.4 running 2.6.18-164.10.1.el5. Is there some sort of protection or do I just have a bug? I know it comes with SELinux, and I've tried putting it in to permissive mode, but it doesn't make a difference

Here's my code:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.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("A file was opened\n");
   return original_call(file, flags, mode);
}

int init_module()
{
    // sys_call_table address in System.map
    sys_call_table = (void*)0xc061e4e0;
    original_call = sys_call_table[__NR_open];

    // Hook: Crashes here
    sys_call_table[__NR_open] = our_sys_open;
}

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

解决方案

I finally found the answer myself.

http://www.linuxforums.org/forum/linux-kernel/133982-cannot-modify-sys_call_table.html

The kernel was changed at some point so that the system call table is read only.

cypherpunk:

Even if it is late but the Solution may interest others too: In the entry.S file you will find: Code:

.section .rodata,"a"
#include "syscall_table_32.S"

sys_call_table -> ReadOnly You have to compile the Kernel new if you want to "hack" around with sys_call_table...

The link also has an example of changing the memory to be writable.

nasekomoe:

Hi everybody. Thanks for replies. I solved the problem long ago by modifying access to memory pages. I have implemented two functions that do it for my upper level code:

#include <asm/cacheflush.h>
#ifdef KERN_2_6_24
#include <asm/semaphore.h>
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 set_page_ro(long unsigned int _addr)
{
    struct page *pg;
    pgprot_t prot;
    pg = virt_to_page(_addr);
    prot.pgprot = VM_READ;
    return change_page_attr(pg, 1, prot);
}

#else
#include <linux/semaphore.h>
int set_page_rw(long unsigned int _addr)
{
    return set_memory_rw(_addr, 1);
}

int set_page_ro(long unsigned int _addr)
{
    return set_memory_ro(_addr, 1);
}

#endif // KERN_2_6_24

Here's a modified version of the original code that works for me.

#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("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*)0xc061e4e0;
    original_call = sys_call_table[__NR_open];

    set_page_rw(sys_call_table);
    sys_call_table[__NR_open] = our_sys_open;
}

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

这篇关于Linux内核:系统调用挂钩的例子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆