:: Пошук і аналіз «троянських коней» під UNIX ::

Цей документ — спроба дати уявлення про методи аналізу виконуваних файлів ОС UNIX для передбачення дій, які вони можуть зробити у системі. Ці методи застосовні для дослідження виявлених «троянських коней» і іншого шкідливого програмного забезпечення. Вони також будуть корисні для аналізу прекомпилированного програмного забезпечення з метою переконатися в його надійності.

При використанні програмного забезпечення з відкритим вихідним кодом користувач може отримати вихідний код програми і відкомпілювати свою, надійну версію. Однак, вихідний код може містити можливості троянського коня, які нелегко помітити. Деякі з витончених способів виробництва прихованих дій використовують системні виклики system() або exec для передачі команд, що викликають навмисні переповнення або небезпечні ситуації, інтерпретатору shell. Використовується також безпосереднє виконання інструкцій асемблера шляхом створення покажчика«void (*fp)()») на двійкову рядок з наступним його виконанням. Проте, буває, що програми прекомпилированы, наприклад, як частина rpm або подібного двійкового пакета, або частини комерційного програмного забезпечення, або двійкові файли скомпільовані з неперевіреного вихідного коду, до того ж віддаленого після компіляції.

На щастя, більшість UNIX-систем пропонують безліч інструментів для розробки та налагодження, які полегшують аналіз двійкових файлів. Перш за все, все повинно робитися в «чистій», тобто, надійної середовищі, де виявлений виконуваний файл досліджується, але не був виконаний. Естетственно, потрібно використовувати непривилегированную обліковий запис (account). Якщо Вам дійсно потрібно шукати і аналізувати можливі «троянців» ненадійною системою, то потрібно використовувати автономний інтерпретатор shell (sash), який повинен бути об’єднаний статично (statically linked). В такому разі єдиною програмою, що грає роль «троянця» може бути модуль ядра, відповідальний за упаковку системних викликів open і read, але такі «троянці» досить рідкісні. При використанні автономного інтерпретатора shell найбільш значущими є команди ls, more і ed.

Перше, що повинно бути зроблено для пошуку «троянця» — пошук явних кодограм в двійковому файлі. Це може бути зроблено з використанням strings або переглядом за допомогою less. Автор першоджерела воліє редактор joe, який дозволяє переглядати і редагувати майже всі не-ascii символи. Кодограми зазвичай включають жорстко запрограмированные імена використовуваних файлів, ascii-рядки, які програма записує в інші файли та статичні рядки, які вона може шукати, або імена використовуваних бібліотечних функцій, якщо файлу не видалені символи. Вони можуть також містити імена незвичайних бібліотек і бібліотек, які вони не мають наміру використовувати будучи «троянцем». Краще всього перевірити це, використовуючи ldd для визначення залежностей від бібліотек і file для визначення були видалені символи, чи була програма статично пов’язана і інших спеціальних форматів.

На наступному етапі аналізу програми потрібно простежити виклики функцій, що виконуються програмою і порівняти їх з функціями, які програма, за припущенням, повинна виконувати. Системні виклики можуть бути простежені в більшості систем з допомогою strace, ktrace в BSD, або truss в Solaris. Слід звернути увагу на всі спроби доступу до файлів (open/stat/access/read/write), виклику гнізд (socket calls), особливо, виклики listen() і fork(). Породжені процеси можуть бути простежені за допомогою опції -f у всіх цих програмах.

Заслуговує інтересу подібний інструмент для Linux — ltrace, який розпізнає всі бібліотечні виклики, вироблені програмою в обхід системних програм і дозволяє створити дуже докладний список параметрів програми.

Нарешті, важливо те, що програма може і повинна бути дизассемблирована, переважно, з використанням gdb. Дизасемблювання, в основному, означає виявлення функцій в двійковому файлі і переведення двійкового коду назад у команди асемблера. Спочатку повинна бути визначена точка входу в програму. Це — адреса початку функції, яку буде виконано, при запуску програми і яка, якщо програми не було модифіковано або з неї не були видалені символи, завжди називається main або _start. Слідуючи за цією функцією можна простежити процес виконання програми і побачити, що може, а чого не може зробити програма. Особливо цікаві виклики інструкцій (function calls) та інструкції jmp/int, якщо вони використовують небиблиотечные виклики ядра або скомпільовані статично. Типові точки входу для двійкових файлів архітектури x86 виглядають приблизно так:

0x8048f97: call 0x8048eac
0x8048f9d: call 0x8048dcc
0x69662: int $0x80

Останньою деталлю розгляду є рядки, які перебувають у певних частинах програми і аргументи, що передаються функцій. Рядки (які містяться в символьному або іншому буферах) згадуються в програмі певними загальними способами, наприклад:

void do_something (char *y) {};
char *h = «hello world»;
int main() {
char *text = h;
int x = getchar();
do_something(text);
return 0;
}

Це відповідає наступним командам асемблера:

0x804847e: movl 0x804950c,%eax
0x8048483: movl %eax,0xfffffffc(%ebp)

Зберегти покажчик за відносним адресою. Покажчик посилається на статичну, жорстко запрограмовану рядок «hello world» в коді.

0x8048486: call 0x80483cc
0x804848b: movl %eax,%eax
0x804848d: movl %eax,0xfffffff8(%ebp)

Викликати функцію getchar і помістити результат (мабуть, ціле. зберігається в регістрі EAX) у стек. EBP — базовий покажчик, що використовується для посилання на адреси щодо текукщей функції в стеку.

0x8048490: movl 0xfffffffc(%ebp),%eax
0x8048493: pushl %eax
0x8048494: call 0x8048470

Тут отриманий назад покажчик на рядок відправляється як перший і єдиний аргумент функції do_something в стеку. Отже, очевидно, рядок, на яку посилається вказівник, передається функції.

Тепер ми можемо вручну разыменовать покажчик за допомогою команди x:

(gdb) x/a 0x804950c
/* x option /a displays the memory content as an address, to
see which address a pointer actually points to */
0x804950c: 0x80484fc
(gdb) x/s 0x80484fc
/* x option /s displays the memory content as string up to the
point where a terminating