我的内核模块不挂钩系统调用,如何解决这个问题?

问题描述 投票:0回答:1

内核模块代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kprobes.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/fs.h>

MODULE_LICENSE("GPL");

static void my_write_cr0(long value) {
    __asm__ volatile("mov %0, %%cr0" :: "r"(value) : "memory");
}

#define disable_write_protection() my_write_cr0(read_cr0() & (~0x10000))
#define enable_write_protection() my_write_cr0(read_cr0() | 0x10000)

unsigned long* sys_call_table_address;
asmlinkage int (*original_chmod)(const char __user*, umode_t);

static struct kprobe kp = {
    .symbol_name = "kallsyms_lookup_name"
};

typedef unsigned long (*kallsyms_lookup_name_t)(const char* name);

unsigned long* get_sys_call_table_address(void) {
    kallsyms_lookup_name_t kallsyms_lookup_name;
    int ret = register_kprobe(&kp);
    if (ret < 0) {
        printk(KERN_ERR "InterceptChmod: register_kprobe failed, returned %d\n", ret);
        return NULL;
    }
    kallsyms_lookup_name = (kallsyms_lookup_name_t)kp.addr;
    unregister_kprobe(&kp);
    if (!kallsyms_lookup_name) {
        printk(KERN_ERR "InterceptChmod: kallsyms_lookup_name not found\n");
        return NULL;
    }
    unsigned long* address = (unsigned long*)kallsyms_lookup_name("sys_call_table");
    if (!address) {
        printk(KERN_ERR "InterceptChmod: sys_call_table not found\n");
    }
    else {
        printk(KERN_INFO "InterceptChmod: sys_call_table address: %p\n", address);
    }
    return address;
}

asmlinkage int custom_chmod(const char __user* filename, umode_t mode) {
    char fname[256];

    // Copy the filename from user space to kernel space
    if (strncpy_from_user(fname, filename, sizeof(fname)) > 0) {
        fname[sizeof(fname) - 1] = '\0'; // Ensure null termination
        printk(KERN_INFO "InterceptChmod: chmod intercepted for file: %s, mode: %o\n", fname, mode);
    }
    else {
        printk(KERN_INFO "InterceptChmod: chmod intercepted, failed to get filename, mode: %o\n", mode);
    }

    // Call the original chmod system call
    return original_chmod(filename, mode);
}

static int __init intercept_chmod_init(void) {
    printk(KERN_INFO "InterceptChmod: Loading module\n");

    sys_call_table_address = get_sys_call_table_address();
    if (!sys_call_table_address) {
        printk(KERN_ERR "InterceptChmod: Failed to get sys_call_table_address\n");
        return -EFAULT;
    }

    printk(KERN_INFO "InterceptChmod: sys_call_table address: %p\n", sys_call_table_address);

    original_chmod = (void*)sys_call_table_address[__NR_chmod];
    printk(KERN_INFO "InterceptChmod: Original chmod address: %p\n", original_chmod);

    disable_write_protection();
    sys_call_table_address[__NR_chmod] = (unsigned long)custom_chmod;
    enable_write_protection();

    printk(KERN_INFO "InterceptChmod: Hooked chmod system call, new address: %p\n", (void*)sys_call_table_address[__NR_chmod]);
    return 0;
}

static void __exit intercept_chmod_exit(void) {
    if (sys_call_table_address) {
        disable_write_protection();
        sys_call_table_address[__NR_chmod] = (unsigned long)original_chmod;
        enable_write_protection();
        printk(KERN_INFO "InterceptChmod: Restored original chmod system call, address: %p\n", (void*)sys_call_table_address[__NR_chmod]);
    }

    printk(KERN_INFO "InterceptChmod: Module unloaded\n");
}

module_init(intercept_chmod_init);
module_exit(intercept_chmod_exit);

我使用 Linux 6.8.11-amd64、OracleVM VirtualBox 和 X86_64 处理器。

我使用以下方式加载模块:

sudo insmod lkm_chmod.ko
然后我测试他的使用命令
sudo chmod 755 testfile
他没有记录这个。 我的日志看起来像这样。

[ 9245.540511] InterceptChmod: Loading module
[ 9245.561100] InterceptChmod: sys_call_table address: 00000000d760dd16
[ 9245.561105] InterceptChmod: sys_call_table address: 00000000d760dd16
[ 9245.561106] InterceptChmod: Original chmod address: 0000000014a7fad1
[ 9245.561110] InterceptChmod: Hooked chmod system call, new address: 00000000ce1988d5
[ 9330.452750] InterceptChmod: Restored original chmod system call, address: 0000000014a7fad1
[ 9330.452766] InterceptChmod: Module unloaded

我不明白为什么他不工作,我的日志中没有错误。我尝试将 __NR_chmod 更改为 __NR_open 或 __NR_close,但他不起作用。 我尝试使用 ChatGPT,他只说废话,只是重复我的代码。

c security linux-kernel x86-64 system-calls
1个回答
0
投票

好吧,我在这个答案中找到了解决方案answer。感谢 Ian Abbott 指出在 6.9 及更早版本中

sys_call_table
不再有效。 现在我修复了代码,他开始使用kprobes工作。

#include <linux/kprobes.h>
#include <linux/ptrace.h>

static int sys_read_kprobe_pre_handler(struct kprobe* p, struct pt_regs* regs)
{
    printk(KERN_NOTICE "ROOTKIT: read(%ld, 0x%lx, 0x%lx)\n", regs->di, regs->si, regs->dx);
    return 0;
}

struct kprobe syscall_kprobe = {
    .symbol_name = "__x64_sys_read",
    .pre_handler = sys_read_kprobe_pre_handler,
};

static int __init startup(void)
{
    int err;

    err = register_kprobe(&syscall_kprobe);
    if (err) {
        pr_err("register_kprobe() failed: %d\n", err);
        return err;
    }
    printk(KERN_NOTICE "ROOTKIT: Starting of due");
    return 0;
}

static void __exit shutdown(void)
{
    unregister_kprobe(&syscall_kprobe);
    printk(KERN_NOTICE "ROOTKIT: Ending");
}

module_init(startup);
module_exit(shutdown);
MODULE_LICENSE("GPL");
© www.soinside.com 2019 - 2024. All rights reserved.