
125 Кібербезпека / 4 Курс / 3.1_3.2_4.1_Захист інформації в інформаційно-комунікаційних системах / Лабораторнi роботи / 5 семестр / ЛР2 Реверс-iнжинiринг ПЗ
.pdfЛАБОРАТОРНА РОБОТА № 2
ОСНОВИ РЕВЕРС-ІНЖИНІРИНГУ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ
Мета: вивчення основ реверс-інжинірингу програмного забезпечення; отримання навичок роботи з інструментами декомпіляції та рефлексії.
Зауваження!
1. Оскільки реверс-інжиніринг програмного забезпечення здійснюють із врахуванням технологій і мов програмування, на основі яких створено продукт, в
лабораторній роботі передбачено дві частини:
а) дизасемблювання консольної програми (відображає процес декомпіляції);
б)* реверс-інжиніринг .NET програм (розглядається рефлексія, характерна для
.NET-технологій).
Для виконання лабораторної роботи достатньо вибрати лише одну із частин.
2. Наведені приклади дизасемблювання програм призначені для виконання лабораторної роботи і закріплення знань із асемблера, технологій та стадій розробки програмного забезпечення, засобів захисту програм. Будь-яке інше застосування інструментарію для декомпіляції не вказаних у роботі програмних продуктів є небажаним і може мати правові наслідки.
ТЕОРЕТИЧНІ ВІДОМОСТІ
І частина. Декомпіляція консольної програми
Необхідність змінити структуру та поведінку готового виконуваного файлу
(зокрема, .ехе) диктує задачі, розв’язання яких потребує дизасемблювання програм.
Найпростішим прикладом таких дій є злам захисту програмного забезпечення,
передбаченого розробниками.
Розглянемо приклад: під час завантаження деякої консольної програми з’являється запит на введення паролю з клавіатури. Пароль зберігається в програмі у вигляді стрічкової змінної із значенням «password». Після правильного вводу на екрані буде виведено повідомлення «ОК», інакше – «Password incorect».
Існує декілька способів зламу такого захисту. Перший спосіб ґрунтується на необхідності лише знайти правильний пароль й авторизуватись, ввівши правильний пароль. Другий спосіб – необхідно зробити так, щоб при введені будь-якого паролю
1
програма вважала його правильним та здійснювала авторизацію (точніше автентифікацію).
1 спосіб. Необхідно через покрокове відлагодження виконуваного файлу знайти місце (адресу) в пам’яті, де знаходиться змінна з паролем, перейти за заданою адресою і виявити пароль. Для цього потрібно спочатку знайти місце в програмі, де відбувається введення паролю і місце, де виводиться результат авторизації. Далі послідовним трасуванням виявити передбачувані критичні точки в програмі між знайденими ділянками, де відбувається будь-яке порівняння з наступним умовним переходом
(найчастіше je або jne). У різних програмах порівняння може бути виконано по-різному:
це або операція CMP, або виклик процедури порівняння, або виконання інших операцій,
котрі здатні виставляти прапорці процесора. Після цього відбувається аналіз знайдених точок залежно від виду порівняння для знаходження адреси змінної з паролем.
Якщо виявлено операцію CMP, то відбувається порівняння значень пароля
(символів, якщо пароль задано у вигляді стрічки, і чисел, якщо задано числовий пароль) із введеним з клавіатури значенням. У цьому випадку необхідно послідовно запам’ятовувати порівнювані значення і в кінці порівняння скласти з них правильний пароль.
Якщо в критичній точці виявлено виклик процедури порівняння, то перед її викликом можна знайти пересилання аргументів процедури в стек (або в регістри).
Аргументи процедури порівняння очевидно і є порівнювані дані, але, на відміну від операції CMP, ці аргументи найчастіше передаються не у вигляді значень, а як адреси на порівнювані змінні. Тому для знаходження паролю необхідно виявити, які адреси передаються в стек, і послідовно переходячи по кожній адресі знайти за однією із них пароль.
Якщо в критичній точці відбуваються будь-які інші дії із виставленням прапорців, то в такій нестандартній ситуації необхідно виявити пароль, виходячи із змісту даних дій.
Оскільки порівняння з використанням процедур виконується найчастіше, то в цій лабораторній роботі наведено приклад програми на мові С++, яка порівнює пароль із введеною стрічкою за допомогою процедури. Параметрами цієї процедури є адреси стрічок, які порівнюються.
Лістинг тестової програми для знаходження паролю lab_password.cpp:
#include <iostream.h>
#include <string.h>
#include <conio.h>
void main()
{
2

char *a,*pass="password";
clrscr();
cout<<"Enter the password: "<<endl;
cin>>a;
if(!strcmp(a,pass))
cout<<"OK";
else
cout<<"Password incorrect";
cin.get();
cin.get();
}
Етапи алгоритму знаходження пароля:
1. Відкрити з допомогою відлагоджувача Turbo debugger (TD.exe) виконуваний файл lab_password.exe.
2. Виконати послідовне трасування програми (в момент запиту введення паролю ввести будь-яку стрічку, наприклад 123456) до знаходження точки виклику процедури порівняння strcmp (рис. 1) .
Рис. 1.
3. Перед знайденою точкою виклику знаходиться пересилання адрес порівнюваних стрічок в стек, а після – операція умовного переходу jne. Ці дві адреси зберігаються в
3

пам’яті, як видно на рис. 1, по зміщенню by-04 і bp-02 сегменту даних. Знайти ці адреси,
перейшовши в пам’яті на ds:0xFFF2 і ds:0xFFF4 відповідно (рис. 2).
Рис. 2.
В даному випадку: ЗМІЩЕННЯ 1 = 00ААh, ЗМІЩЕННЯ 2 = 5845h. 4. Перейти по кожній із знайдених адрес (рис. 3):
Рис. 3.
Як видно із рис. 3, за зміщенням 5845h знаходиться введена із клавіатури стрічка
«123456» з кодом кінця стрічки 0, а за зміщенням 00ААh знаходиться пароль «password».
2 спосіб. Необхідно знайти передбачувані критичні точки програми, як було показано в першому способі. Із знайдених точок визначити істинну критичну точку (в цьому прикладі знайдено лише одну передбачувана критична точка, вона і є істинною). Далі необхідно виявити наступну за знайденою точкою операцію умовного переходу. Цей перехід визначає, куди потрібно перейти залежно від правильності вводу пароля.
Наприклад, якщо пароль введено правильно, то буде виведено повідомлення про успішну авторизацію, інакше – повідомлення про неправильність введеного значення. Тому, щоб при неправильно введеній стрічці з клавіатури програма видала повідомлення про правильність вводу, необхідно замінити у виконуваному файлі умову переходу на протилежну (наприклад, jne на je, jz на jnz і т.д.).
Етапи алгоритму зміни виконуваного файлу:
1.Відкрити у відлагоджувачі Turbo debugger (TD.exe) виконуваний файл.
2.Виконати послідовне трасування програми до знаходження операції умовного переходу після виклику процедури порівняння strcmp (рис. 4). Знайдена операція умовного переходу jne має машинний код 7505h.
4

Рис. 4.
3.Відкрити в редакторі HexView (hiew.exe) виконуваний файл.
4.Перемкнути середовище в режим перегляду коду (F4 для перемикання режиму перегляду –> Decode).
5.Знайти операцію з машинним кодом 7505h (F7 для пошуку –> Hex для введення шістнадцяткових символів).
6.Замінити операцію jne на je (F3 для входу в режим редагування, потім F2 для зміни поточної команди) (рис. 5).
Рис. 5.
5

7. Зберегти зміни (F9).
Тепер, коли виконуваний файл змінено, після введення неправильного пароля,
програма буде сприймати його як правильний (рис. 6).
Рис. 6.
ІІ частина. Реверс-інжиніринг .NET-програм
Концепцію платформи NET можна порівняти з концепцією JAVA і віртуальної машини JAVA (коли ідеться про компіляцію програми). На відміну від «традиційних» мов програмування (наприклад С/С++), де компіляція видає виконуваний машинний код,
програми, розроблені на платформі NET frameworks, компілюються в код проміжною мовою Common Intermediate Language (CIL або Microsoft Common Intermediate Language MSIL), який можна порівняти з байт-кодом Java-програм. Перетворення в машинний код здійснюється середовищем Common Language Runtime (CLR) під час виконання програми.
У такого механізму роботи програм є свої переваги і недоліки. Головний недолік – зменшення швидкості виконання програми. Серед плюсів – в скомпільованій програмі зберігаються імена класів, функцій і методів, що , з точки зору програміста, дуже зручно,
оскільки різні частини програми можна написати на різних мовах, які підтримуються фреймворками.
Під час реверс-інжинірингу NET-програм говорять про «рефлексію» (reflection), а не про «декомпіляцію». Техніка «рефлексії» дає змогу отримати інформацію про класи під час виконання програми, а тому отримати всі властивості, методи, функції з параметрами та аргументами, інтерфейси. Існує значна кількість інструментів для відображення скомпільованого NET-файла. Серед них варто виділити утиліту Reflector, з допомогою якої можна переглядати інформацію про класи, декомпілювати та аналізувати NET-
програми і компоненти.
Зауваження! Викладення всіх відомостей про реверс-інжиніринг NET-програм виходить за межі однієї лабораторної роботи і є завданням підвищеної складності. Тому далі приведено посилання на інтернет-ресурси, звідки можна почерпнути детальну інформацію з даної теми.
http://www.securitylab.ru/analytics/439107.php
http://www.securitylab.ru/analytics/439108.php
http://www.securitylab.ru/analytics/439109.php
6
ЗАВДАННЯ
1.Опрацювати теоретичні відомості.
2.Завантажити необхідне програмне забезпечення, зокрема, для тих, хто обрав першу частину лабораторної роботи: компілятор С++, відлагоджувач Turbo Debagger. Для виконання другої частини зручним буде інтегроване середовище розробки, а також
Reflector.
3.Повторити алгоритми, описані в методичних рекомендаціях.
4.Розробити власне програмне забезпечення із дещо ширшим функціоналом, ніж у наведених матеріалах; здійснити його реверс-інжиніринг за обраною методикою.
Використані Інтернет-джерела:
1.http://homorobot.net/index.php?option=com_content&view=article&id=83:2010-03-15- 17-49-28&catid=54:2010-03-15-17-51-32&Itemid=82
2.http://www.securitylab.ru/analytics/439107.php
7