从内核劫持系统调用

时间:2018-11-30 21:51:35

标签: c ubuntu linux-kernel kernel

我想拦截open()系统调用,以便在用户每次打开文件时进行测试,应该在dmesg中显示消息“ OPEN IS!”。

已显示dmesg中的系统调用表和公开呼叫地址,但看不到消息“ OPEN IS!”。内核v.4.18

我想知道问题是什么。代码:

unsigned long cr0;
static unsigned long *__sys_call_table;

typedef asmlinkage int (*orig_open_t)(const char *, int, int);

orig_open_t orig_open;

unsigned long *
get_syscall_table_bf(void)
{
    unsigned long *syscall_table;
    unsigned long int i;

    for (i = (unsigned long int)ksys_close; i < ULONG_MAX;
            i += sizeof(void *)) {
        syscall_table = (unsigned long *)i;

        if (syscall_table[__NR_close] == (unsigned long)ksys_close) {
            printk(KERN_INFO "syscall: %08lx\n", syscall_table);
            return syscall_table;
        }
    }
    return NULL;
}

asmlinkage int
hacked_open(const char *filename, int flags, int mode)
{
    printk(KERN_INFO "OPEN IS!\n");
    return 0;
}

static inline void
protect_memory(void)
{
    write_cr0(cr0);
}

static inline void
unprotect_memory(void)
{
    write_cr0(cr0 & ~0x00010000);
}

static int __init
diamorphine_init(void)
{
    __sys_call_table = get_syscall_table_bf();
    if (!__sys_call_table)
        return -1;

    cr0 = read_cr0();

    orig_open = (orig_open_t)__sys_call_table[__NR_open];

    unprotect_memory();
    __sys_call_table[__NR_open] = (unsigned long)hacked_open;
    printk(KERN_INFO "WE DO IT!\n");
    printk(KERN_INFO "hacked is: %08lx\n", hacked_open);
    protect_memory();

    return 0;
}

static void __exit
diamorphine_cleanup(void)
{
    unprotect_memory();
    __sys_call_table[__NR_open] = (unsigned long)orig_open;
    protect_memory();
}

module_init(diamorphine_init);
module_exit(diamorphine_cleanup);

MODULE_LICENSE("GPL");

1 个答案:

答案 0 :(得分:1)

我猜想您的上钩方式有误。您要么挂错了syscall表的偏移量,要么就完全退出了。我不明白为什么您明确地开始使用ksys_close()进行搜索,尤其是当它是内联函数时。您应该尝试像这样查找syscall表符号:

typedef void (*_syscall_ptr_t)(void); 
_syscall_ptr_t *_syscall_table = NULL; 
_syscall_table=(_syscall_ptr_t *)kallsyms_lookup_name("sys_call_table");

我看到的一个不同的(巨大)问题是重置CR0,它允许系统中的任何内容在写入时写入只读存储器,而不是遍历页面并在特定位置设置W位您要编辑的页面。

另外一个小建议:您应该完成钩子才能重定向到原始的打开syscall。否则,您将导致整个系统从STDIN中读取每个新打开的文件描述符(最终将杀死您的系统)