简体   繁体   中英

Kernel module crash when reading system call table function address

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.

Kernel version : 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 (after a reboot):

[   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

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. Why does it crash and what can i do about it?)

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.

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. Why does "%p" print a different value than that of "%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. Why does "%p" print different values after reboots while "%lx" always prints the correct value?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM