读取系统调用表功能地址时内核模块崩溃 [英] Kernel module crash when reading system call table function address

查看:830
本文介绍了读取系统调用表功能地址时内核模块崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am studying rootkits and trying to hook the system call table. As i can already dynamically retrieve the table's address from /boot/System.map-$(uname -r), i traced and isolated the problematic part of the code into an independent, simpler module, shown below. It tries to retrieve and display the address of the kill system call, but insmod returns "Killed" on module load, which is an error provoked specifically on the emphasized line.

内核版本:5.2.0-3-amd64

Kernel version: 5.2.0-3-amd64

模块:

#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"总是打印正确的值?

I have the following questions:
(0. Why does it crash and what can i do about it?)
1. Why does "%p" print a different value than that of "%lx"?
2. Why does "%p" print different values after reboots while "%lx" always prints the correct value?

推荐答案

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

(0. Why does it crash and what can i do about it?)

如果内核配置包括CONFIG_RANDOMIZE_BASE=y,由于内核地址空间布局随机化(KASLR),系统调用表将与System.map文件中指定的地址有一个随机偏移.除了使用没有此配置选项的内核或使用nokaslr选项引导之外,您对随机化没有什么其他用途.

If the kernel configuration includes CONFIG_RANDOMIZE_BASE=y, the system call table will be at a random offset from the address specified in the System.map file due to kernel address space layout randomization (KASLR). There is not much you can do about the randomization other than use a kernel without this configuration option, or boot with the nokaslr option.

您可以利用这样一个事实,即全局符号偏移相同的随机量.如果sys_call_table在System.map中具有0x0xffffffff81c002a0的地址,并且system_wq在System.map中具有0xffffffff821204b8的地址,则您知道sys_call_table将在实时系统中以开头的0x520218字节开头.

You can exploit the fact that global symbols are shifted by the same random amount. If sys_call_table has an address of 0x0xffffffff81c002a0 in System.map, and system_wq has an address of 0xffffffff821204b8 in System.map, then you know that sys_call_table will start 0x520218 bytes before system_wq in the live system.

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

%p的内核的默认处理方法是不打印输出指向不同内容的指针的附加修饰符,即打印指针值的哈希版本,以避免将地址泄漏给用户空间.但是,%lx不会这样做.

The kernel's default handling for %p with no appended modifiers for printing pointers to different things is to print a hashed version of the pointer value to avoid leaking addresses to userspace. However, %lx doesn't do that.

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

%p打印的散列指针值在内核初始化期间使用随机键集进行散列.

The hashed pointer values printed by %p are hashed with a random key set during kernel initialization.

这篇关于读取系统调用表功能地址时内核模块崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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