读取系统调用表函数地址时内核模块崩溃

2023-12-07

我正在研究 rootkit 并尝试挂钩系统调用表。由于我已经可以从 /boot/System.map-$(uname -r) 动态检索表的地址,因此我跟踪了代码的有问题的部分并将其隔离到一个独立的、更简单的模块中,如下所示。它尝试检索并显示 Kill 系统调用的地址,但 insmod 在模块加载时返回“Killed”,这是专门在强调的行上引发的错误。

内核版本:5.2.0-3-amd64

Module:

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

typedef asmlinkage int (*sys_kill_ptr_t)(pid_t, int);

static sys_kill_ptr_t sys_kill_ptr;
static unsigned long *syscall_table;

static int __init lkm_init(void)
{
    printk("[+] LKM: init\n");

    // System call table address in /boot/System.map-$(uname -r)
    syscall_table = (unsigned long *)0xffffffff81c002a0;

    printk(KERN_INFO "[+] LKM: syscall_table @ 0x%p\n",  syscall_table);
    printk(KERN_INFO "[+] LKM: syscall_table @ 0x%lx\n", (unsigned long)syscall_table);

    /* Error */
    sys_kill_ptr = (sys_kill_ptr_t)syscall_table[__NR_kill];
    /* Error */

    printk(KERN_INFO "[+] LKM: sys_kill_ptr @ 0x%p\n", (void *)sys_kill_ptr);

    return 0;
}

static void __exit lkm_exit(void)
{
    printk("[-] LKM: exit\n");
}

module_init(lkm_init);
module_exit(lkm_exit);

dmesg:

[ 3708.343306] [+] LKM: init
[ 3708.343309] [+] LKM: syscall_table @ 0x000000004853bd64
[ 3708.343360] [+] LKM: syscall_table @ 0xffffffff81c002a0
[ 3708.343407] BUG: unable to handle page fault for address: ffffffff81c00490
[ 3708.343460] #PF: supervisor read access in kernel mode
[ 3708.343501] #PF: error_code(0x0000) - not-present page

dmesg(重启后):

[   86.822522] [+] LKM: init
[   86.822525] [+] LKM: syscall_table @ 0x0000000000248a4b
[   86.822644] [+] LKM: syscall_table @ 0xffffffff81c002a0
[   86.822757] BUG: unable to handle page fault for address: ffffffff81c00490
[   86.822903] #PF: supervisor read access in kernel mode
[   86.823005] #PF: error_code(0x0000) - not-present page

我有以下问题:
(0. 为什么会崩溃?我该怎么办?)
1. 为什么“%p”打印的值与“%lx”不同?
2. 为什么“%p”在重启后打印不同的值,而“%lx”总是打印正确的值?


(0. 为什么会崩溃?我该怎么办?)

如果内核配置包括CONFIG_RANDOMIZE_BASE=y,由于内核地址空间布局随机化 (KASLR),系统调用表将位于 System.map 文件中指定的地址的随机偏移处。除了使用没有此配置选项的内核,或者使用nokaslr option.

您可以利用全局符号移动相同随机量的事实。如果sys_call_tableSystem.map 中的地址为 0x0xffffffff81c002a0,并且system_wqSystem.map 中有一个地址 0xffffffff821204b8,那么你就知道sys_call_table将从 0x520218 字节之前开始system_wq在直播系统中。

  1. 为什么“%p”打印的值与“%lx”不同?

内核的默认处理%p没有附加修饰符来打印指向不同事物的指针的方法是打印指针值的散列版本,以避免将地址泄漏到用户空间。然而,%lx不这样做。

  1. 为什么“%p”在重新启动后打印不同的值,而“%lx”总是打印正确的值?

打印的散列指针值%p在内核初始化期间使用随机密钥集进行哈希处理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

读取系统调用表函数地址时内核模块崩溃 的相关文章

随机推荐