LINUX.ORG.RU

Перехват системных вызовов начиная с ядра 4.15

 ,


0

1

Привет всем.

Кто-нибудь знает, что сделали с ядром начиная с 4.15 в части перехвата системных вызовов?

Раньше работала стратегия, находишь таблицу вызовов в памяти ядра, патчишь ее, подставляя адреса своих функций вместо оригинальных адресов обработчиков. И потом вызываешь оригинальные обработчики из своих функций. Это отлично работало раньше.

Но начиная с ядра 4.15 больше не работает. Даже если ты найдешь табличку, пропатчишь ее своими адресами, фиг там! И непонятно почему. Кто-нить в курсе что там понаделали? И как теперь перехватывать вызовы?

Заранее спасибо! :-)

★★★★★

По моему, начиная с 4.15 включили по умолчанию ASLR и KASLR для защиты от подмены адресов

sigurd ★★★★★ ()

И как теперь перехватывать вызовы?

Не читал, но man ptrace

anonymous ()
Ответ на: комментарий от sigurd

ASLR и KASLR к защите от подмены адресов не имеют никакого отношения.

anonymous ()

const struct pt_regs *regs

https://stackoverflow.com/questions/55027649/memory-isolation-in-new-linux-kernels-or-what

The change in the behavior happened between kernels 4.16 and 4.16.2 (i.e. between April 1, 2018 and April 12, 2018). Considering this, we have pretty narrow list of commits to check, and the changes are likely to be in the syscalls mechanism. Well, looks like this commit is what we are looking for (and few more around).

The crucial part of this commit is that it changes signatures of the functions defined by SYSCALL_DEFINEx so that they accept a pointer to struct pt_regs instead of syscall arguments, i.e. sys_read(unsigned int fd, char __user * buf, size_t count) becomes sys_read(const struct pt_regs *regs). This means, that hacked_read_test(unsigned int fd, char *buf, size_t count) is no longer a valid replacement for sys_read()!

в крацце - заменили кишки.

Было:

SOME_syscall_blabla( unsigned int fd, char *buf, size_t count )

Стало:

SOME_syscall_blabla( const struct pt_regs *regs )

anonymous ()
  1. Лучше с примером, непонятно какие конкретно ты действия делаешь (preemption не забыл передернуть?).
  2. Всегда можно сделать сплайсом, см. https://github.com/milabs/khook
  3. Если хочешь менее архитектурно-зависимо, то лучше делать DKOM, то есть искать нужную структуру (какие непосредственно тебе системные вызовы нужно перехватить?), после чего заменять указатели. В этом случае даже CR0 передергивать не нужно будет, ибо оно AFAIR writable.
anonymous ()
Ответ на: комментарий от anonymous

Переделал код на использование pt_regs

В общем, меняю вот таким вот кодом. По адресам смотрел, адреса функций действительно меняются. Т.е. защита от записи снята корректно. Только вот на 4.18 вообще никакой реакции. А 5.6 вешается намертво. Такое чувство, что выдается неправильный адрес таблицы с вызовами. Поэтому меняются неверные адреса.

typedef asmlinkage int (*orig_open_new_t)(const struct pt_regs *);
orig_open_new_t orig_open;

unsigned long cr0;

static inline void
protect_memory(void)
{
   write_cr0(cr0);
}

static inline void
unprotect_memory(void)
{
   write_cr0(cr0 & ~0x00010000);
}


asmlinkage int
hacked_open_new(const struct pt_regs *ptr)
{
   char *filename = (char*) ptr->di;
   printk("open_hook: open_new syscall handled, the file is: %s\n", filename);
   return orig_open(ptr);
}


int replace_open_syscall(void)
{
   __sys_call_table = (unsigned long*) kallsyms_lookup_name("sys_call_table");
   if (!__sys_call_table)
   {
      printk("open_hook: an addr for sys_call_table was not found\n");
      return -1;
   }

   orig_open = (orig_open_new_t)__sys_call_table[__NR_open];
   
   cr0 = read_cr0();
   
   preempt_disable();
   unprotect_memory();
   __sys_call_table[__NR_open] = (unsigned long)hacked_open_new;
	protect_memory();
   preempt_enable();

   return 0;
}

hibou ★★★★★ ()
Ответ на: комментарий от hibou

Еще я попробовал найти адрес sys_call_table прогулкой по памяти с помощью этой функции:

unsigned long *
get_syscall_table_bf(void)
{
	unsigned long *syscall_table;
	unsigned long int i;

	for (i = (unsigned long int)ksys_close; i < ULONG_MAX;
			i += sizeof(void *)) {
		syscall_table = (unsigned long *)i;

		if (syscall_table[__NR_close] == (unsigned long)ksys_close){
			return syscall_table;
      }
	}
	return NULL;
}

Как ни странно, она возвращает совсем другой адрес нежели

kallsyms_lookup_name("sys_call_table")

Но и с ней тоже не работает. Т.е. адреса нормально заменяются, но принтов от вызова моего хакнутого open() я не вижу.

hibou ★★★★★ ()
Ответ на: комментарий от hibou

а с выхлопом sudo cat /proc/kallsyms | grep sys_call_table хоть что-то из приведенного кода вообще совпадает по адресу?

Попробуй подсунуть адрес из этого выхлопа. Из под кого запускается вообще код который пытается произвести хук?

anonymous ()
Ответ на: комментарий от anonymous

Попробовал. Вот эти адреса совпадают:

sudo cat /proc/kallsyms | grep sys_call_table
kallsyms_lookup_name("sys_call_table")

Совпадает, но нифига не работает.

Это код модуля ядра. Соответственно вызывается он самим ядром и в пространстве ядра. Функция замены адресов выполняется, когда модуль вставлен в ядро.

hibou ★★★★★ ()
Ответ на: комментарий от hibou

Как ни странно, она возвращает совсем другой адрес

Мало ли где в памяти оказался адрес ksys_close.

i-rinat ★★★★★ ()
Ответ на: комментарий от hibou

уже не плохо :) Вот эту серию статей читали (она относительно свежая)?

https://www.apriorit.com/dev-blog/544-hooking-linux-functions-1 https://www.apriorit.com/dev-blog/546-hooking-linux-functions-2 https://www.apriorit.com/dev-blog/547-hooking-linux-functions-3

Так как раз есть вот такой интересный абзац.

Some handlers can’t be replaced. In Linux kernels prior to version 4.16, system call processing for the x86_64 architecture has some additional optimizations. Some of these optimizations require the system call handler to be implemented in the assembler. These kinds of handlers are either hard or impossible to replace with custom handlers written in C. Furthermore, the fact that different kernel versions use different optimizations boosts the technical complexity of the task even more.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.