Сбой модуля ядра при чтении адреса функции таблицы системных вызовов - PullRequest
3 голосов
/ 23 октября 2019

Я изучаю руткиты и пытаюсь перехватить таблицу системных вызовов. Поскольку я уже могу динамически получать адрес таблицы из /boot/System.map-$(uname -r), я проследил и изолировал проблемную часть кода в независимом, более простом модуле, показанном ниже. Он пытается получить и отобразить адрес системного вызова kill, но insmod возвращает «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» всегда печатает правильное значение?

1 Ответ

2 голосов
/ 23 октября 2019

(0. Почему происходит сбой и что я могу с этим сделать?)

Если конфигурация ядра включает CONFIG_RANDOMIZE_BASE=y, таблица системных вызовов будет со случайным смещениемиз адреса, указанного в файле System.map из-за рандомизации расположения адресного пространства ядра (KASLR). Вы ничего не можете сделать с рандомизацией, кроме как использовать ядро ​​без этой опции конфигурации или загрузиться с опцией nokaslr.

Вы можете использовать тот факт, что глобальные символы сдвигаются на одну и ту же случайную величину,Если sys_call_table имеет адрес 0x0xffffffff81c002a0 в System.map, а system_wq имеет адрес 0xffffffff821204b8 в System.map, то вы знаете, что sys_call_table будет начинаться с 0x520218 байт до system_wq в действующей системе.

  1. Почему «% p» печатает значение, отличное от «% lx»?

Обработка по умолчанию в ядре для %p бездобавленные модификаторы для печати указателей на разные вещи должны печатать хешированную версию значения указателя, чтобы избежать утечки адресов в пространство пользователя. Однако %lx этого не делает.

Почему «% p» печатает разные значения после перезагрузки, а «% lx» всегда печатает правильное значение?

Значения хешированного указателя, напечатанные %p, хешируются с помощьюслучайный ключ, установленный во время инициализации ядра.

...