Наша совместная команда Banwar.org

Связаться с нами

  • (097) ?601-88-87
    (067) ?493-44-27
    (096) ?830-00-01

Статьи

RootKit - принципи і механізми роботи

Головна / Інформаційна безпека / статті

Передмова

Даний цикл статей присвячений досить актуальною в цій момент проблеми - технологіям, застосовуваним розробниками шкідливого програмного коду. Останнім часом з'явилося безліч шкідливих програм, за визначенням не можна вважати вірусами, оскільки вони не мають здатність до розмноження. Йтиметься про RootKit, клавіатурних шпигунів, троянських і шпигунських програмах.

Вступ

Термін RootKit історично прийшов зі світу Unix, де під цим терміном розуміється набір утиліт, які хакер встановлює на зламаному ним комп'ютері після отримання початкового доступу. Це, як правило, хакерський інструментарій (сніфери, сканери) та троянські програми, які заміщають основні утиліти Unix. RootKit дозволяє хакеру закріпитися у зламаній системі і приховати сліди своєї діяльності.

В системі Windows під RootKit прийнято вважати програму, яка впроваджується в систему і перехоплює системні функції, або робить заміну системних бібліотек. Перехоплення і модифікація низькорівневих API функцій в першу чергу дозволяє такій програмі досить якісно маскувати свою присутність в системі, захищаючи її від виявлення користувачем і антивірусним ПЗ. Крім того, багато RootKit можуть маскувати присутність в системі будь-яких описаних в його конфігурації процесів, папок і файлів на диску, ключів в реєстрі. Багато RootKit встановлюють в систему свої драйвери і сервіси (вони природно також є «невидимими»).

Останнім часом загроза RootKit стає все більш актуальною, тому що розробники вірусів, троянських програм і шпигунського програмного забезпечення починають вбудовувати RootKit-технології в свої шкідливі програми. Одним з класичних прикладів може служити троянська програма Trojan-Spy.Win32.Qukart, яка маскує свою присутність в системі за допомогою RootKit-технології (дана програма цікава тим, що її RootKit -механізм прекрасно працює в Windows 95 \ 98 \ ME \ 2000 \ XP).

Для ефективної боротьби з RootKit необхідне розуміння принципів і механізмів його роботи. Умовно всі RootKit-технології можна розділити на дві категорії - працюють в режимі користувача (user -mode) і в режимі ядра (kernel -mode). Перша категорія RootKit заснована на перехопленні функцій бібліотек користувацького режиму, друга - на установці в систему драйвера, що здійснює перехоплення функцій рівня ядра. Далі при описі методів перехоплення функцій опис йде стосовно RootKit, проте потрібно пам'ятати, описані методики універсальні і застосовуються безліччю корисних програм і утиліт.

Методи перехоплення API функцій в режимі користувача (user mode)

Описи методик перехоплення функцій забезпечені схемами їх роботи, при цьому червона пунктирна стрілка показує втручання RootKit в процес роботи програми, червоні стрілки показують відхилення в логіці роботи, викликані втручанням RootKit.

Перехоплення функцій дозволяє RootKit модифікувати результати їх роботи - наприклад, перехоплення функції пошуку файлу на диску дозволяє виключити з результатів пошуку маскуються файли, а перехоплення функцій типу ntdll .ZwQuerySystemInformation дозволяє замаскувати запущені процеси і завантажені бібліотеки.

Принцип виклику API функції

Перед розглядом принципів роботи RootKit призначеного для користувача режиму необхідно коротко і спрощено розглянути принцип виклику функцій, розміщених в DLL.

Відомо два базових способу:

1. Раннє зв'язування (статично імпортовані функції).

Цей метод заснований на тому, компілятору відомий перелік імпортованих програмою функцій. Спираючись на цю інформацію, компілятор формує так звану таблицю імпорту EXE файлу. Таблиця імпорту - це особлива структура (її розташування і розмір описуються в заголовку EXE файлу), яка містить список використовуваних програмою бібліотек і список імпортованих з кожної бібліотеки функцій. Для кожної функції в таблиці є поле для зберігання адреси, але на стадії компіляції адреса не відомий. У процесі завантаження EXE файлу система аналізує його таблицю імпорту, завантажує всі перераховані в ній DLL і виробляє занесення в таблицю імпорту реальних адрес функцій цих DLL. У раннього зв'язування є істотний плюс - на момент запуску програми всі необхідні DLL виявляються завантаженими, таблиця імпорту заповнена - і все це робиться системою, без участі програми. Але відсутність в процесі завантаження зазначеної в його таблиці імпорту DLL (або відсутність в DLL необхідної функції) призведе до помилки завантаження програми. Крім того, дуже часто немає необхідності завантажувати всі використовувані програмою DLL в момент запуску програми. На малюнку показаний процес раннього зв'язування - в момент завантаження відбувається заповнення адрес в таблиці імпорту (крок 1), в момент виклику функції з таблиці імпорту береться адреса функції (крок 2) і відбувається власне виклик функції (крок 3);


На малюнку показаний процес раннього зв'язування - в момент завантаження відбувається заповнення адрес в таблиці імпорту (крок 1), в момент виклику функції з таблиці імпорту береться адреса функції (крок 2) і відбувається власне виклик функції (крок 3);

2. Пізніше зв'язування.

Відрізняється від раннього зв'язування тим, що завантаження DLL проводиться динамічно за допомогою функції API LoadLibrary. Ця функція знаходиться в kernel32.dll, тому якщо не вдаватися до хакерських прийомів, то kernel32.dll доведеться завантажувати статично. За допомогою LoadLibrary програма може завантажити потрібну її бібліотеку в будь-який момент часу. Відповідно для отримання адреси функції застосовується функція kernel32.dll GetProcAddress. На малюнку крок 4 відповідає завантаженні бібліотеки за допомогою LoadLibrary і визначенню адрес за допомогою GetProcAddress. Далі можна викликати функції DLL (крок 5), але природно при цьому таблиця імпорту не потрібна. Щоб не викликати GetProcAddress перед кожним виклику функції з DLL програміст може одноразово визначити адреси цікавих йому функцій і зберегти їх в масиві або деяких змінних.

Незалежно від методу зв'язування системі необхідно знати, які функції експортує DLL. Для цього у кожної DLL є таблиця експорту - таблиця, в якій перераховані експортовані DLL функції, їх номери (ордіналов) і відносні адреси функцій (RVA).

1. Модифікація машинного коду прикладної програми.

Модифікація машинного коду прикладної програми

В цьому випадку модифікується машинний код, який відповідає в прикладній програмі за виклик тієї чи іншої функції API. Це методика складна в реалізації, тому що існує безліч мов програмування, версій компіляторів і програміст може реалізувати виклик API функцій різними методиками. Але теоретично таке можливе за умови, що впровадження буде йти в заздалегідь задану програму відомої версії. В цьому випадку можна проаналізувати її машинний код і розробити перехоплювач.

2. Модифікація таблиці імпорту

Модифікація таблиці імпорту

Дана методика описана в книзі Ріхтера і є однією з класичних. Ідея методу проста - RootKit знаходить в пам'яті таблицю імпорту програми і виправляє адреси цікавих йому функцій на адреси своїх перехоплювачів (природно, він попередньо десь у себе запам'ятовує правильні адреси). У момент виклику API функції програма зчитує її адресу з таблиці імпорту і передає за цією адресою управління. Методика універсальна, але у неї є істотний недолік (і його добре видно на схемі) - перехоплюються тільки статично імпортовані функції. Але є і плюс - методика дуже проста в реалізації і є маса прикладів, які демонструють її реалізацію. Пошук таблиці імпорту в пам'яті не представляє особливої ​​складності, оскільки для цього існують спеціалізовані API функції, що дозволяють працювати з образом програми в пам'яті. Оригінальний текст такого перехоплювача на мові C займає кілька аркушів друкованого тексту;

3. Перехоплення функцій LoadLibrary і GetProcAddress

Перехоплення функцій LoadLibrary і GetProcAddress

Перехоплення функцій LoadLibrary і GetProcAddress може бути здійснене будь-яким методом, в класичній реалізації застосовується методика 2 - модифікація таблиці імпорту. Ідея методики проста - якщо перехопити GetProcAddress, то при запиті адреси можна видавати програмі не реальні адреси цікавлять її функцій, а адреси своїх перехоплювачів. Як і в методі 2 програма «не відчує» різниці. При виклику GetProcAddress вона отримує адресу і виконує виклик функції. У даного методу є мінус - він не дозволяє перехопити статично імпортовані функції;

4. Метод, що поєднує методику 2 і 3

У даній методиці модифікується таблиця імпорту, причому в обов'язковому порядку перехоплюються функції LoadLibrary і GetProcAddress бібліотеки kernel 32. dll. В цьому випадку при виклику статично імпортованих функцій спотворені адреси беруться з таблиці імпорту, при динамічному визначенні адреси викликається перехоплена функція GetProcAddress, яка повертає адреси функцій-перехоплювачів. В результаті у програми не залишається шансів дізнатися правильну адресу функції.

5. Модифікація програмного коду API функції.

Модифікація програмного коду API функції

Дані метод складніше в реалізації, ніж підміна адреси. Методика полягає в тому, що RootKit знаходить в пам'яті машинний код цікавлять його функцій API і модифікує його. При такому методі перехоплення функції вже немає потреби в модифікації таблиці імпорту запущених програм і передачі програм перекручених адрес при виклику GetProcAddress. З точки зору виклику функції все залишається «як є» за одним винятком - тепер уже по «правильному» адресою всередині «правильної» DLL знаходиться машинний код RootKit.

Найчастіше втручання в машинний код перехоплюваних функцій мінімально. На початку функції розміщується не більше 2-3 машинних команд, що передають управління основної функції-перехоплювачі. Щоб здійснити дзвінок модифікованих функцій RootKit повинен зберегти вихідний машинний код для кожної модифікованої їм функції (природно, зберігається не весь машинний код функції, а змінені під час перехоплення байти). Саме така методика перехоплення реалізована в широко відомому HackerDefender і бібліотеці AFX Rootkit ( www .rootkit .com ).

6. Модифікація бібліотек DLL на диску

Дана методика полягає в тому, що системна бібліотека модифікується на диску. Методи модифікації аналогічні описаним вище, тільки зміни виробляються не в пам'яті, а на диску. Подібна методика не отримала широкого розповсюдження.

Перехоплення функцій в режимі ядра (kernel mode)

Для розуміння типовий для методики перехоплення функцій в режимі ядра слід розглянути принципи взаємодії бібліотек користувацького режиму і ядра. Розглянемо це взаємодія на спрощеній схемі:

Основна взаємодія з ядром проводиться через ntdll .dll, більшість функцій якої є перехідниками, які звертаються до ядра через переривання INT 2 Eh (слід зауважити, що прикладній програмі ніщо не заважає безпосередньо викликати INT 2 Eh). Подальше звернення до функцій ядра заснована на структурі, іменованої KeServiceDescriptorTable (або скорочено SDT), розташованої в ntoskrnl .exe. SDT - це таблиця, яка містить адреси точок входу сервісів ядра NT. Опис функцій і методик перехоплення можна знайти в книзі Свена Шрайбера «Недокументовані можливості Windows 2000», там же наведена схема взаємодії, яка послужила прототипом для наведеної тут схеми. Спрощено можна сказати, що для перехоплення функцій необхідно написати драйвер, який зробить модифікацію таблиці SDT. Перед модифікацією драйверу необхідно зберегти адреси перехоплюваних функцій і записати в таблицю SDT адреси своїх обробників. Даний метод чимось нагадує перехоплення переривань в MSDOS або описану вище методику 2.

Цей метод часто називають перехопленням Native API і природно він працює тільки в NT (і відповідно W2K, XP, W2003). Слід зазначити, що перехоплення Native API здійснюють не тільки руткіти - існує маса корисних програм, перехоплюючих функції за допомогою редагування SDT - як приклад можуть служити популярна утиліта RegMon від SysInternals або програма Process Guard.

Слід зазначити, що описаний метод є найбільш простим, але далеко не єдиним. Існує ще ряд способів, зокрема створення драйвера-фільтра. Драйвер-фільтр може застосовуватися як для вирішення завдань моніторингу (класичний приклад - утиліта FileMon від SysInternals), так і для активного втручання в роботу системи. Зокрема, драйвер-фільтр може застосовуватися для маскування файлів і папок на диску. Принцип роботи такого драйвера заснований на маніпуляціях з пакетами запиту вводу-виводу (IRP).

Методики виявлення RootKit в системі

Розглянемо базові методики пошуку RootKit:

  1. Порівняння двох «знімків» системи (наприклад, списку файлів на диску). Перший знімок робиться на перевіреній системі, другий - після завантаження з CD або підключення досліджуваного HDD до свідомо чистому комп'ютера. Подібна методика гарантовано дозволить виявити будь-RootKit, який маскує на диску свої файли.
  2. Порівняння даних, що повертаються API функціями різного рівня і (або) одержуваних низькорівневими методами (наприклад, прямим читанням диска і аналізом файлів реєстру). Дана методика не вимагає перезавантаження досліджуваного ПК і реалізована в безкоштовній утиліті RootkitRevealer від SysInternals (http://www.sysinternals.com). Іншим прикладом може злучити утиліта KLister (www .rootkit .com) для побудови списку запущених процесів, яка складається з драйвера і консольної програми, що використовує цей драйвер;
  3. Аналіз в пам'яті функцій основних бібліотек на предмет наявності змін їх машинного коду. Даний метод найбільш ефективний для боротьби з RootKit в призначеному для користувача режимі. Подібна методика дозволяє не тільки виявити перехоплення функцій, але і відновити нормальну роботу пошкоджених функцій. Крім того, порівняння «знімків» системи, отриманих до і після відновлення функцій API в багатьох випадках дозволяє виявити маскуються процеси, сервіси та драйвери. Дана методика не вимагає перезавантаження і один з варіантів реалізований в моїй утиліті AVZ;
  4. Аналіз і відновлення ServiceDescriptorTable. Дана методика дозволяє боротися з рядом перехоплювачів, які працюють в режимі ядра (власне, з перехоплювачами, заснованими на виправлення SDT). Практична реалізація - утиліта SDTRestore (http: // www .security .org .sg / code / sdtrestore .html). Однак відновлення SDT вплине на роботу всієї системи і може призвести до дуже неприємних наслідків (в найпростішому випадку - повне зависання системи з виходом на BSoD, в гіршому - непередбачуване порушення нормальної роботи додатків, перехоплюючих NativeAPI для реалізації своїх функцій).

висновок

Описані вище базові методики перехоплення функцій пояснюють основні принципи роботи RootKit. Однак слід пам'ятати, що розробники RootKit-технологій не стоять на місці, в результаті постійно з'являються нові розробки, підходи і методи.

Практика показує, що розробники шкідливих програм (вірусів, троянських програм, шпигунського ПЗ) все частіше починають використовувати RootKit-технології, що істотно ускладнює виявлення і видалення створених ними шкідливих програм. Найчастіше застосовуються методики перехоплення функцій в режимі користувача, але останнім часом з'явилися досить ефективні реалізації із застосуванням драйверів. У цьому плані за моєю статистикою найбільш «знаменитий» Backdoor.Win32.Haxdoor, який встановлює в систему кілька драйверів, що дозволяє йому досить ефективно маскуватися від виявлення користувачем.

У наступній статті циклу мова піде про клавіатурних шпигунів - їх пристрої, принципи роботи і методиках виявлення.


Новости

Banwar.org
Наша совместная команда Banwar.org. Сайт казино "Пари Матч" теперь доступен для всех желающих, жаждущих волнения и азартных приключений.