读取系统调用 table 函数地址时内核模块崩溃
Kernel module crash when reading system call table function address
我正在研究 rootkit 并尝试挂钩系统调用 table。因为我已经可以从 /boot/System.map-$(uname -r) 动态检索 table 的地址,所以我跟踪并将有问题的代码部分隔离到一个独立的、更简单的模块中,如下所示.它试图检索并显示 kill 系统调用的地址,但在模块加载时 insmod returns "Killed",这是在强调的行上专门引发的错误。
内核版本: 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”总是打印正确的值?
(0. Why does it crash and what can i do about it?)
如果内核配置包括 CONFIG_RANDOMIZE_BASE=y
,由于内核地址 space,系统调用 table 将与 System.map 文件中指定的地址随机偏移] 布局随机化(KASLR)。除了使用没有此配置选项的内核或使用 nokaslr
选项启动之外,您对随机化无能为力。
您可以利用全局符号移动相同随机量这一事实。如果 sys_call_table
在 System.map 中的地址为 0x0xffffffff81c002a0,而 system_wq
在 System.map 中的地址为 0xffffffff821204b8,那么你知道 sys_call_table
将在 0x520218 字节之前开始system_wq
在实时系统中。
- Why does "%p" print a different value than that of "%lx"?
内核对 %p
的默认处理方式是打印指向不同事物的指针的散列版本,以避免将地址泄露给用户 space。但是,%lx
不会那样做。
- Why does "%p" print different values after reboots while "%lx" always prints the correct value?
%p
打印的散列指针值在内核初始化期间使用随机密钥集散列。
我正在研究 rootkit 并尝试挂钩系统调用 table。因为我已经可以从 /boot/System.map-$(uname -r) 动态检索 table 的地址,所以我跟踪并将有问题的代码部分隔离到一个独立的、更简单的模块中,如下所示.它试图检索并显示 kill 系统调用的地址,但在模块加载时 insmod returns "Killed",这是在强调的行上专门引发的错误。
内核版本: 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”总是打印正确的值?
(0. Why does it crash and what can i do about it?)
如果内核配置包括 CONFIG_RANDOMIZE_BASE=y
,由于内核地址 space,系统调用 table 将与 System.map 文件中指定的地址随机偏移] 布局随机化(KASLR)。除了使用没有此配置选项的内核或使用 nokaslr
选项启动之外,您对随机化无能为力。
您可以利用全局符号移动相同随机量这一事实。如果 sys_call_table
在 System.map 中的地址为 0x0xffffffff81c002a0,而 system_wq
在 System.map 中的地址为 0xffffffff821204b8,那么你知道 sys_call_table
将在 0x520218 字节之前开始system_wq
在实时系统中。
- Why does "%p" print a different value than that of "%lx"?
内核对 %p
的默认处理方式是打印指向不同事物的指针的散列版本,以避免将地址泄露给用户 space。但是,%lx
不会那样做。
- Why does "%p" print different values after reboots while "%lx" always prints the correct value?
%p
打印的散列指针值在内核初始化期间使用随机密钥集散列。