Низкоуровневый анализ машинного кода. Для студентов технических специальностей
Қосымшада ыңғайлырақҚосымшаны жүктеуге арналған QRRuStore · Samsung Galaxy Store
Huawei AppGallery · Xiaomi GetApps

автордың кітабын онлайн тегін оқу  Низкоуровневый анализ машинного кода. Для студентов технических специальностей

Иван Андреевич Трещев
Анастасия Сергеевна Ватолина
Владислав Александрович Сериков

Низкоуровневый анализ машинного кода

Для студентов технических специальностей






18+

Оглавление

  1. Низкоуровневый анализ машинного кода
  2. Введение
  3. ЛЕКЦИИ
    1. 1 Роспатент, основные функции, регистрация программ для эвм
    2. 2 Защита ПО
    3. 3 Геометрия диска
    4. 4 Технические средства защиты от копирования
    5. 5 Общий анализ средств защиты ПО от копирования
    6. 6 Исследование дизассемблирования и обфускации
    7. 7 Исследование защиты ПО физическим ключом
    8. 8 ОБРАТНАЯ РАЗРАБОТКА ПО
  4. ЛАБОРАТОРНЫЕ РАБОТЫ
    1. ЛАБОРАТОРНАЯ РАБОТА №0
    2. Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №0
    3. ЛАБОРАТОРНАЯ РАБОТА №1
    4. Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №1
    5. ЛАБОРАТОРНАЯ РАБОТА №2
    6. Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №2
    7. ЛАБОРАТОРНАЯ РАБОТА №3
    8. Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №3
    9. ЛАБОРАТОРНАЯ РАБОТА №4
    10. Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №4
    11. ЛАБОРАТОРНАЯ РАБОТА №5
    12. Пример выполнения ЛАБОРАТОРНАЯ РАБОТА №5
    13. ЛАБОРАТОРНАЯ РАБОТА №6
    14. Пример выполнения ЛАБОРАТОРНАЯ РАБОТА №6
    15. ЛАБОРАТОРНАЯ РАБОТА №7
    16. Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №7
  5. РАСЧЕТНО-ГРАФИЧЕСКАЯ РАБОТА
    1. Пример выполнения РГР
    2. Заключение
  6. Заключение
  7. Список использованных источников

За каждым успешным кодером стоит еще более успешный декодер, который понимает этот код.

Аноним

Введение

Зачастую проектируя программное обеспечение мы задумываемся над созданием и его системы защиты. Существует довольно большое количество способов обфускации программного кода, технологий встраивания антиотладочной информации, полиморфного изменения программного кода и другие разнообразные механизмы.

К сожалению использование всех хитроумных технологий зачастую, при грамотном использовании отладчиков и дизассемблеров, не приводит к желаемому разработчиком результату — защите программного обеспечения от изучения. В данной работе сделана попытка не теоретического описания существующих методик и средств для выполнения низкоуровнего анализа машинного кода, а обобщения практической части курса читаемого автором для студентов.

У читателя предполагаются базовые знания в области программирования на assembler для 16,32,64 разрядных архитектур микропроцессоров и умение читать/разрабатывать код на C++/C#, python. Материалы книги доступны по постоянной ссылке https://yadi.sk/d/gWbKFT4lyIjZKg.

В силу специфики рассматриваемого предмета в данной книге и необходимых знаний, автор хотел бы предостеречь читателей имеющих слабую подготовку по рассматриваемым проблемам от использования материалов данной книги. Очень может быть, что многое просто не получится. В этом случае в качестве рекомендации следует ознакомится с литературой представленной в соответствующем разделе и затем вернуться к материалам книги.

В заключении приведена ссылка на Яндекс. Диск, где содержатся дополнительная информации доступная для изучения, а так же электронные варианты заданий.

ЛЕКЦИИ

1 Роспатент, основные функции, регистрация программ для эвм

1.1 Правовая основа в России

УК РФ Статья 273. Создание, использование и распространение вредоносных компьютерных программ (в ред. Федерального закона от 07.12.2011 N 420-ФЗ) (см. текст в предыдущей редакции)

1. Создание, распространение или использование компьютерных программ либо иной компьютерной информации, заведомо предназначенных для несанкционированного уничтожения, блокирования, модификации, копирования компьютерной информации или нейтрализации средств защиты компьютерной информации, — наказываются ограничением свободы на срок до четырех лет, либо принудительными работами на срок до четырех лет, либо лишением свободы на тот же срок со штрафом в размере до двухсот тысяч рублей или в размере заработной платы или иного дохода осужденного за период до восемнадцати месяцев.

2. Деяния, предусмотренные частью первой настоящей статьи, совершенные группой лиц по предварительному сговору или организованной группой либо лицом с использованием своего служебного положения, а равно причинившие крупный ущерб или совершенные из корыстной заинтересованности, — наказываются ограничением свободы на срок до четырех лет, либо принудительными работами на срок до пяти лет с лишением права занимать определенные должности или заниматься определенной деятельностью на срок до трех лет или без такового, либо лишением свободы на срок до пяти лет со штрафом в размере от ста тысяч до двухсот тысяч рублей или в размере заработной платы или иного дохода осужденного за период от двух до трех лет или без такового и с лишением права занимать определенные должности или заниматься определенной деятельностью на срок до трех лет или без такового.

3. Деяния, предусмотренные частями первой или второй настоящей статьи, если они повлекли тяжкие последствия или создали угрозу их наступления, — наказываются лишением свободы на срок до семи лет.

Статья 1299. Технические средства защиты авторских прав

1. Техническими средствами защиты авторских прав признаются любые технологии, технические устройства или их компоненты, контролирующие доступ к произведению, предотвращающие либо ограничивающие осуществление действий, которые не разрешены автором или иным правообладателем в отношении произведения.

2. В отношении произведений не допускается:

— Осуществление без разрешения автора или иного правообладателя действий, направленных на то, чтобы устранить ограничения использования произведения, установленные путём применения технических средств защиты авторских прав;

— Изготовление, распространение, сдача в прокат, предоставление во временное безвозмездное пользование, импорт, реклама любой технологии, любого технического устройства или их компонентов, использование таких технических средств в целях получения прибыли либо оказание соответствующих услуг, если в результате таких действий становится невозможным использование технических средств защиты авторских прав либо эти технические средства не смогут обеспечить надлежащую защиту указанных прав.

3. В случае нарушения положений, предусмотренных пунктом 2 настоящей статьи, автор или иной правообладатель вправе требовать по своему выбору от нарушителя возмещения убытков или выплаты компенсации в соответствии со статьей 1301 настоящего Кодекса, кроме случаев, когда настоящим Кодексом разрешено использование произведения без согласия автора или иного правообладателя.

За указанные нарушения предусмотрена гражданско-правовая (ст. 1301 ГК РФ) и административная (ст. 7.12 КоАП РФ) ответственность. Отмечается, что закон (часть четвёртая ГК РФ) обладает невысоким техническим уровнем и допускает неоднозначные трактовки. В частности, в том же Гражданском Кодексе (ч. IV, ст. 1280, п. 1) сказано:

Лицо, правомерно владеющее экземпляром программы для ЭВМ или экземпляром базы данных (пользователь), вправе без разрешения автора или иного правообладателя и без выплаты дополнительного вознаграждения:

— Внести в программу для ЭВМ или базу данных изменения исключительно в целях их функционирования на технических средствах пользователя и осуществлять действия, необходимые для функционирования таких программы или базы данных в соответствии с их назначением, в том числе запись и хранение в памяти ЭВМ (одной ЭВМ или одного пользователя сети), а также осуществить исправление явных ошибок, если иное не предусмотрено договором с правообладателем;

— Изготовить копию программы для ЭВМ или базы данных при условии, что эта копия предназначена только для архивных целей или для замены правомерно приобретенного экземпляра в случаях, когда такой экземпляр утерян, уничтожен или стал непригоден для использования. При этом копия программы для ЭВМ или базы данных не может быть использована в иных целях, чем цели, указанные в подпункте 1 настоящего пункта, и должна быть уничтожена, если владение экземпляром таких программы или базы данных перестало быть правомерным.

Таким образом, внесение изменений в технические средства защиты теоретически можно оправдать необходимостью создания резервной копии, поскольку всегда существует вероятность утраты лицензионного оригинала. И хотя это не станет оправданием непосредственного распространения взломанного варианта ПО, однако даёт возможность распространять ПО и просто полезную информацию, позволяющие такой взлом осуществить, под предлогом необходимости создания рабочей резервной копии.

2 Защита ПО

Прежде чем приступить к защите своего продукта разработчику в первую очередь необходимо определиться с его принципом лицензирования: необходимо выбрать, как за ваш продукт будут платить. Существует множество разновидностей, в целом их можно разделить на четыре типа:

— Одноразовый платеж. За ваше ПО платят раз, после чего могут пользоваться неограниченное время;

— Функциональные ограничения. Дополнительные возможности пользователь может открыть за дополнительную плату;

— Временная лицензия. Вы «сдаете приложение в аренду», то есть речь идет о подписке;

— Многоуровневая. Представляет собой комбинацию названных методов. Пользователь получает Silver-, Gold- или Platinum-версию ПО при соответствующей оплате.

После того как разработчик определился со стратегией лицензирования, наступает пора начать поиски программных технологий защиты. И здесь стоит помнить о таких нюансах, как возможность подключения ПО к интернету, его специализация, вид платформы, для которой предназначен софт, и прочее.

Еще раз подчеркнем важность выбора адекватной защиты. Если вы собираетесь защитить свой велосипед методом, который применяется в Форт-Ноксе, это вряд ли можно назвать разумным. Есть и обратная зависимость: если хотите защитить Форт-Нокс, не используйте для этого велосипедный замок, это бесполезно, взлом гарантирован. В целом, стратегия лицензирования должна соответствовать цене самого продукта.

2.1 Виды защиты


Как и говорилось выше, есть различные опции для защиты ПО от взлома и копирования. Они могут отличаться по стоимости, уровню защиты и специализации.

Защита по «доверию». Здесь вы рассчитываете на то, что пользователи будут платить без всяких проблем. Один пользователь — одна лицензия, вечная. В принципе, затрат с вашей стороны практически нет. Как только приложение скомпилировано, его можно начать распространять. Но проблема в том, что если ваш продукт станет популярным, то кто-то точно его взломает, начав раздавать. Защиты от взлома в таком случае нет, она нулевая.

— Офлайн-программная защита. Речь идет о защите без подключения к интернету. Обычно реализуется такая схема сразу после компиляции программы. Чаще всего используется программная оболочка с определенными настройками. Защищенная программа не подключается для проверки целостности ни к каким внешним серверам. В принципе, обойти такую защиту можно без всяких проблем.

— Онлайн-программная защита. Здесь уже речь идет о более серьезном методе — проверке лицензии при помощи сервера лицензирования. В этом случае требуются относительно высокие затраты в начале и периодические расходы позже. Как и в предыдущем варианте, используется программная оболочка, но параметры лицензирования проверяются и настраиваются в онлайне. При желании можно добавить опции проверки ПО, например есть лицензия или нет. Если требуется постоянное подключение к сети, то продукт, скорее всего, будет работать не всегда и не везде. Степень серьезности такой защиты — между средним и высоким уровнем.

— Аппаратная защита. Один из наиболее надежных методов, который сочетает в себе преимущества всех прочих стратегий. За лицензирование отвечает электронный USB-ключ, которому не требуется подключение к сети. Цена каждого ключа для разработчика низкая, нет периодических дополнительных трат. Реализовать можно как при помощи API, так и посредством программной оболочки. Достоинством такого метода является то, что лицензию можно убрать за пределы операционной системы, ключ хранится вне ПК. Ключ либо очень сложно, либо вообще невозможно скопировать. ПО, которое защищено при помощи аппаратного ключа, может использоваться на тех системах, где нет подключения к сети. Это, к примеру, правительственные объекты или промышленность. Еще один плюс в том, что электронному ключу не требуются различные решения для разных программных сред, а возможности лицензирования очень гибкие. Решения на основе аппаратного ключа можно развернуть буквально за минуты, они поддерживаются практически любыми версиями операционных систем. Правда, помните, что поставщик решения, в случае если вы не можете создать аппаратный ключ самостоятельно, должен делать все быстро, чтобы не возникла необходимость ожидать партии ключей и, соответственно, переноса старта продаж. Также поставщик должен предоставить простое и эффективное решение, которое быстро разворачивается.

2.2 Удобство пользователя


Однако стоит упомянуть и об удобстве для пользователя. Поскольку методы защиты разнятся по доступности для конечного пользователя то соответственно пользователь предпочтет долее удобный для себя вариант, в случае если у него есть выбор:

— Офлайн-программная защита. Этот вид является наиболее удобным и приемлемым пользователями поскольку, в отличии от остальных видов, он уверен, что после покупки ему н6е придется задумываться о регулярном подтверждении подлинности купленного им продукта, за редкими исключениями.

— Онлайн-программная защита. Этот вид является менее предпочтительным пользователями поскольку несет в себе неудобство постоянного или периодического, как это часто бывает «в неудобное время» для пользователя, подключения к интернету. Однако этот метод может быть незаметным для пользователя и соответственно не вызывать негативных эмоций, в том случает если ПО по своей сути требует постоянного взаимодействия с интернетом.

— Аппаратная защита. Этот тип является наиболее неудобным для пользователя поскольку при каждом запуске пользователю приходится физически при помощи ключа подтверждать подлинность ПО и все становится еще хуже при утере физического ключа.

Поскольку процесс встраивания защиты зачастую связан с некоторыми трудностями соответственно и о защите ПО стоит задуматься еще на стадии проектирования: после того как проект готов частично или полностью, изменить что-то будет непросто.

3 Геометрия диска

В рамках защиты интеллектуальной собственности стоит упомянуть и о геометрии диска, поскольку зачастую защита либо влияет либо зависима от нее.

Жесткие диски представляют собой несколько пластин с магнитным покрытием, расположенных на одной оси и вращающихся с большой скоростью. Считывание/запись информации осуществляется с помощью головок диска, расположенных одна под другой между пластинами и перемещающихся от центра к краям пластин. Окружность на магнитной пластине, которую описывает головка при вращении пластин, называется дорожкой, а совокупность таких дорожек, расположенных одна под другой (определяемая каждым фиксированным положением головок), называется цилиндром. Каждая дорожка разбита на сектора, и в сектор можно записать 512 байт полезной информации. Поэтому диски часто характеризуются совокупностью трех цифр:

— Числом цилиндров/

— Числом дорожек в цилиндре/

— Числом секторов на дорожке

C/H/S (от первых букв соответствующих английских терминов: Cylinder/Head/Sector, т. е. цилиндр/головка/сектор). Эти три цифры называют «геометрией диска». Диск с геометрией C/H/S имеет объем C*H*S*512 байт.

Диски являются блочными устройствами, т. е. считывание и запись информации производится блоками, и минимальный размер блока равен одному сектору (512 байт). Для того чтобы записать информацию на диск, надо «позиционировать головку», т. е. указать контроллеру, в какой сектор эту информацию записать. Сектора как раз адресуются путем указания номера цилиндра, номера считывающей головки (или дорожки) и порядкового номера сектора на дорожке.

4 Технические средства защиты от копирования

DRM или же технические средства защиты авторских прав — это программные или программно-аппаратные средства, которые намеренно ограничивают, либо затрудняют различные действия (копирование, модификация, просмотр) с данными в электронной форме или позволяют отследить эти действия

В большинстве современных DRM используются криптографическая защита, однако ее нельзя использовать в полной мере, поскольку для доступа к зашифрованной информации требуется секретный ключ. Однако в случае с DRM типична ситуация — когда ограничения обходятся законным владельцем копии, который должен иметь зашифрованную информацию и ключ к ней, для чтения информации, что аннулирует всю защиту. Поэтому системы DRM пытаются скрыть ключ шифрования от пользователя (в том числе с использованием аппаратного обеспечения), однако, поскольку используемые сегодня устройства воспроизведения являются достаточно универсальными и находятся под контролем пользователей, сделать это довольно трудно.

Одновременный доступ к воспроизведению и запрет на копирование — чрезвычайно сложная задача:

— воспроизведение — чтение информации ее обработка и запись на устройство вывода,

— копирование — чтение и запись информации на устройство хранения.

То есть, если возможно воспроизведение информации, то возможно и ее последующее копирование. Следовательно, эффективная техническая защита от копирования во время авторизованного воспроизведения может быть достигнута только тогда, когда устройство целиком находится под контролем правообладателя.

4.1 Звук и музыкальные произведения


Audio-CD

Первые методы защиты музыкальных компакт-дисков от копирования использовали нарушения стандарта записи Audio CD, которые не были заметны для большинства CD-проигрывателей, но не работали на более сложно устроенных компьютерных приводах CD-ROM. Компания Philips отказалась ставить на таких дисках знак Compact Disc Digital Audio, который доказывал соответствие стандарту. К тому же оказалось, что такие диски не могли прочитать некоторые плееры, и, наоборот, некоторые компьютеры уверенно их копировали.

В 2005 году Sony BMG стала использовать новую технологию DRM для защиты своих аудио-CD от копирования при прослушивании на персональном компьютере. Диск можно было воспроизводить на компьютере только с помощью специальной программы, записанной на нём; также можно было создать 3 резервных копии альбома. Помимо этого, на компьютер пользователя устанавливалась программное обеспечение, предотвращающее перехват аудиопотока во время воспроизведения. Устанавливалось это ПО без подтверждения пользователя. Устанавливаемое ПО содержало в себе руткит: оно скрывало файлы и каталоги, использовало вводящие в заблуждение названия процессов и сервисов, и не имело возможности удаления. Это создавало серьёзные уязвимости в безопасности системы пользователя. Поскольку программа представляла угрозу безопасности компьютера, Sony была вынуждена отозвать миллионы компакт-дисков. Позднее была обнаружена троянская программа, использующая уязвимость в DRM компании Sony. В результате подобного использования DRM на Sony было подано несколько коллективных судебных исков, которые, в большинстве своём, были разрешены путём выплаты финансовой компенсации пострадавшим потребителям, а также раздачей музыкальных альбомов в цифровом виде без DRM. При всех этих проблемах DRM от Sony слабо осуществляло свою основную цель — защиту от копирования, так как влияло лишь на проигрывание на компьютерах под управлением систем Microsoft Windows, оставляя «за бортом» другие устройства. Да и Windows-систему легко можно было обойти, например, банально выключив функцию автозапуска, не говоря уже об упомянутой аналоговой бреши.

В январе 2007 года EMI прекратили выпуск аудио-CD с DRM, объявив о нецелесообразности затрат на систему. Sony, после всех судов и проблем, также отказались от DRM-защиты. На данный момент ни один из четырёх крупнейших лейблов не поддерживает DRM.


Музыка в интернет

Многие интернет-магазины США, продающие музыку онлайн, используют DRM. Один из крупнейших — Apple iTunes Store — использовал систему DRM FairPlay вплоть до 2009 года. Система использует обычные аудиофайлы формата MP4. Каждый файл содержит звуковой поток в формате AAC, зашифрованный с помощью AES с использованием основного ключа, а также сам основной ключ, зашифрованный с помощью ключа пользователя. Ключи пользователя генерируются случайно для каждого сеанса, их копии хранятся на серверах Apple и в защищенном репозитории iTunes (клиентской программы, используемой для доступа к iTunes Store). Один и тот же аккаунт iTunes Store можно использовать не более чем на пяти компьютерах. iTunes позволяет копировать аудиофайл на неограниченное количество плееров iPod (при этом ключи пользователя также копируются во внутренний репозиторий плеера), однако на одном iPod можно использовать музыку, полученную не более чем из пяти различных аккаунтов. Apple не выдавала лицензии на собственный DRM сторонним компаниям, в результате чего только устройства от Apple, а также их медиа-проигрыватель QuickTime могли воспроизводить музыку из iTunes. iTunes также позволяет записывать аудиофайлы на компакт-диски. Один и тот же плей-лист можно записать не более семи раз, однако каждый отдельный файл можно записывать неограниченное число раз. Полученные аудио-CD не содержат DRM, поэтому несложно получить аудиофайлы без защиты, сделав копию компакт-диска, однако при этом качество звука может уменьшиться при перекодировании. Программа Requiem позволяет извлекать ключи пользователей из хранилища iTunes, однако Apple регулярно выпускает обновления, меняя способы хранения ключей.

Однако 6 февраля 2007 г. глава Apple Стив Джобс опубликовал открытое письмо «Мысли о музыке», в котором призвал звукозаписывающие компании продавать музыку без DRM. С начала 2009 года музыка в iTunes Store по соглашению с большинством издателей постепенно стала полностью доступна без DRM.

В России, несмотря на вступление в силу IV части Гражданского кодекса, многие музыкальные интернет-магазины до сих пор действуют полулегально, поэтому ни о каких средствах DRM говорить не приходится. Не говоря уже об использовании музыки в социальных сетях, столь популярных в России и странах СНГ.

Помимо стандартных подходов к DRM, некоторые магазины предлагают DRM-схему подписки. Например, сервис Sony Music Unlimited или онлайн музыкальный магазин Napster. Пользователи могут скачивать и прослушивать неограниченное количество музыки до тех пор, пока действует подписка. Однако с окончанием подписки все файлы перестают воспроизводиться.

В связи с тем, что схемы DRM у различных производителей отличаются между собой, иногда становится невозможным проигрывать музыку от разных производителей на одном устройстве, устройство может просто не поддерживаться DRM-схемой. Решением подобных проблем занимаются, например, в Англии.

Так, в 2006 году Эндрю Гауэрс составил список предложений по улучшению политики защиты авторских прав Gowers Review of Intellectual Property, которая содержит 54 пункта. Этот список находится в открытом доступе, и ознакомиться с ним может любой желающий. Среди всех прочих поправок пункты с 8 по 12 содержат предложения по созданию некоторых исключений для добросовестного использования авторских прав, например, библиотеками, также рассматривается возможность перехода от одной схемы DRM к другой. Впоследствии планировалось ввести подобные исключения и для обычных пользователей. Вообще проблема с различными DRM в проигрывателях стояла достаточно остро, например, Apple отказались от DRM-защиты в музыке полностью, благодаря чему музыка из iTunes проигрывается спокойно на любом устройстве, поддерживающем формат AAC. Некоторые магазины, например, немецкий Musicload, также объявили об отказе от DRM, так как выяснилось, что 3 из 4 звонков в их службу поддержки поступало от недовольных системой DRM пользователей.


Рингтоны для мобильных телефонов

Открытый Мобильный Альянс создал специальный стандарт для взаимодействия различных DRM-схем на мобильных устройствах. Изначально данная схема DRM содержала простой язык управления правами и широко использовалась для защиты рингтонов для мобильных телефонов. Данная схема запрещала копировать рингтоны с мобильных телефонов на другие устройства, например ПК. Широкого использования эта схема DRM так и не получила, несмотря на то, что язык был основательно расширен и улучшен.

4.2 Изображения, фильмы и телевиденье


Content Scramble System

Первой технологией защиты DVD от копирования являлась Content Scramble System (CSS). Эта технология использовалась с 1996 года. Каждый производитель лицензировал свой ключ DVD-проигрывателя для использования в своих устройствах у DVD Copy Control Association — организации, основанной DVD Forum. Каждый DVD, защищенный CSS, содержал ключ диска, который расшифровывался с помощью ключа данного DVD-проигрывателя, после чего можно было расшифровать всю остальную информацию на диске. Ключи записывались в lead-in области диска, чтобы сделать невозможным их непосредственное копирование. В 1999 году Джон Лех Йохансен, также известный как DVD Jon, опубликовал программу DeCSS, позволявшую расшифровывать и воспроизводить DVD-диски, защищенные CSS, в операционной системе Linux, для которой ключи проигрывателей не были лицензированы. Он использовал ключи, переданные анонимным хакером, который извлек их из программы XingDVD, хранившей ключи в открытом виде. Позже была найдена уязвимость, которая позволяла взломать защиту методом полного перебора на любом компьютере, мощность которого достаточна для воспроизведения DVD. В этом же году на системах Microsoft Windows появилась своя схема DRM, которая считывала инструкции из мультимедийных файлов на языке управления правами, в которых описывались разрешённые пользователю действия. Язык может определять, сколько раз можно проигрывать файл, можно ли записать его на внешний носитель, распечатать, переслать по интернету или скопировать на жёсткий диск.


Regional Protection Code

Regional Protection Code или региональная защита DVD является средством DRM, позволяющим регулировать продажу DVD, HD DVD и Blu-Ray дисков в различных странах мира. Система призвана решить проблему распространения дисков в странах, где премьера фильма ещё не закончилась и он ещё не вышел на DVD. Однако данная технология позволяет также устанавливать разные цены для розничной продажи дисков в разных странах, что противоречит правилам свободной торговли. Подобный подход позволяет продавать продукцию с DRM-защитой в развивающихся странах, а также странах третьего мира по более низким ценам. Однако в Австралии и Новой Зеландии запрещена продажа DVD-проигрывателей, ограничивающих воспроизведение дисков в каких-либо регионах из-за противоречий, указанных выше.


Advanced Access Content System

Advanced Access Content System (AACS) или же улучшенная система доступа к содержимому — это система DRM, используемая для защиты HD DVD и Blu-ray дисков, опубликованная в апреле 2005 г. и окончательно принятая 5 июня 2009 года консорциумом AACS Licensing Administrator, включающим Disney, Intel, Microsoft, Panasonic, Warner Bros., IBM, Toshiba и Sony. Система сочетает в себе различные методы, предотвращающие незаконное копирование и распространение видеоматериалов.

Система использует более стойкое по сравнению с CSS шифрование AES, а также использует схему широковещательного шифрования на основе дерева разностей подстановок. Последняя использует фиксированный набор ключей носителей, необходимых для расшифрования содержимого диска, и наборы ключей устройств, лицензируемые производителями проигрывателей. Ключи носителей хранятся на диске в специальным образом зашифрованном виде так, что каждый конкретный ключ устройства не может расшифровать все возможные ключи носителей. Это позволяет отзывать скомпрометированные ключи, например, извлеченные посредством отладки из программных плееров, используя в новых выпускаемых дисках только те ключи носителей, которые могут быть расшифрованы только не скомпрометированными ключами. Непосредственное же копирование диска невозможно, поскольку в шифровании участвует уникальный серийный номер, который может записать только завод-изготовитель.

Рисунок 1 — Схема крипто защиты AACS

Система использует цифровые водяные знаки для отслеживания взломанных ключей, а также водяные знаки компании Verance для звуковых дорожек к фильмам, позволяющие обнаруживать звук, записанный на микрофон в кинотеатре, и блокировать его воспроизведение.

Признак ограничения изображения позволяет ограничить максимальное разрешение для аналоговых выходов до 960×540. Полное разрешение 1920×1080 возможно только для выходов HDMI или DVI, которые поддерживают HDCP.

Функция контролируемого копирования, недавно включенная в стандарт AACS, позволяет создавать резервные копии на Blu-ray и DVD-дисках, в виде файлов, совместимых с DRM компании Microsoft, а также делать копии более низкого качества для портативных видеоплееров. Технология доступна только в сравнительно новых видеопроигрывателях и требует подключения к Интернет для учёта количества копий данного диска.

В настоящее время AACS взломана не полностью. В декабре 2006 года хакеры опубликовали в Интернете ключи к защищённому с помощью AACS содержимому HD DVD. После того, как были аннулированы взломанные ключи, постоянно публиковались новые. 16 апреля 2007 ключи плееров WinDVD и PowerDVD были отозваны, поскольку они ранее были опубликованы в Интернете, а соответствующие программы обновлены, однако вскоре в Сети появились новые, до сих пор действующие ключи. Также был произведен аппаратный взлом привода HD DVD, используемого с Xbox 360, для частичного обхода защиты, позволяющего осуществить взлом без использования ключей устройств.


Предотвращение перехвата аудио- и видеопотока.

Интерфейсы DVI и HDMI поддерживают технологию High-bandwidth Digital Content Protection (HDCP) — защита широкополосного цифрового содержимого, которая использует шифрование при передаче сигнала между видеопроигрывателем и монитором/телевизором для предотвращения перехвата видеопотока (например man-in-the-middle), а также позволяет осуществлять вывод только на сертифицированные устройства. Однако оказалось, что эта технология обладает низкой криптостойкостью и может быть взломана.

Компания Microsoft включила в свою операционную систему Windows Vista технологию Protected Media Path, позволяющую шифровать информацию, передаваемую видеокарте или монитору, а также запрещать воспроизведение, если запущены программы без цифровой подписи.


Телевизионные программы

Для защиты телепрограмм, передаваемых по телевидению высокой чёткости, предусматривается наличие флага передачи, позволяющего определить, разрешена ли запись. Эта концепция была разработана компанией Fox Broadcasting в 2001 году и была поддержана MPAA и Федеральным Агентством по связи (ФАС) США. Однако в мае 2005 года Апелляционный Суд США постановил, что ФАС не обладает достаточной властью для наложения подобных ограничений на телеиндустрию в США.

Куда большего успеха эта система добилась, когда была принята Проектом Цифрового Видео Вещания — консорциумом, включающим более 250 вещателей, производителей, операторов сети, разработчиков программного обеспечения и управляющих органов в более чем 35 странах. Этот консорциум пытался разработать новые цифровые стандарты для DRM в телевещании. Одним из наиболее перспективных стандартов является вариант с улучшенным флагом передачи, разработанный для европейского телевидения DVB-Content Protection and Copy Management (DVB-CPCM). Этот стандарт был предоставлен на рассмотрение европейским правительствам в 2007 году. Все нормативные части на данный момент уже одобрены для публикации Руководящим Советом DVB и будут опубликованы ETSI как официальный европейский стандарт ETSI TS 102 825-X (X — номер подразделения). На сегодняшний день ещё никто не взял на себя обеспечения Совместимости и Надёжности для данного стандарта, однако разработки в данном направлении ведутся многими компаниями, что не позволяет сегодня внедрить эту систему повсеместно.

В США поставщиками кабельного телевидения используется стандарт CableCard, ограничивающий доступ пользователя только теми услугами, на которые он подписан.

4.3 Текст, документы и электронные книги


Управление цифровыми правами на предприятии — это применение технологий DRM для управления доступом к корпоративным документам (файлы Microsoft Word, PDF, AutoCAD, электронные письма, страницы внутренней сети интранет). Эти технологии, более известные как Управление Информационными Правами, в основном используются для предотвращения несанкционированного использования документов, являющихся интеллектуальной собственностью предприятия, например, в целях промышленного шпионажа или случайной утечки информации. Обычно эта система встроена в программное обеспечение системы управления содержимым, однако некоторые корпорации такие как Samsung Electronics разрабатывают свои собственные системы DRM.

Электронные книги, предназначенные для чтения на ПК, мобильных устройствах или в специальных приложениях, обычно используют DRM с целью ограничить копирование, печать или выкладывание книг в общий доступ. Обычно такие книги ограничены количеством устройств, на которых их можно прочесть, а некоторые издатели вообще запрещают любое копирование или печать. Некоторые компании и обозреватели считают, что наличие DRM создаёт множество проблем для издания книг.

На сегодняшний день в мире наибольшее распространение получили пять основных форматов электронных книг: Mobipocket, KF8, Topaz, ePub и PDF. Также существует четыре основных DRM-схемы для электронных книг, по одной от Amazon, Adobe, Apple и Martin Trust Management Organization (MTMO):

— DRM от Amazon является адаптацией изначальной кодировки Mobipocket, и используется в электронных книгах от Amazon, которые поддерживаются программой Amazon Kindle, форматы Mobipocket, KF8 и Topaz.

— DRM Adept от корпорации Adobe применяется к ePub и PDF, причём читать книги могут различные программы от сторонних разработчиков, а не только программное обеспечение от Adobe. Формат Adobe PDF поддерживает различные методы защиты содержимого: Полное криптостойкое шифрование документа, требующее ввод пароля для любых операций с документом, включая открытие и просмотр; защита документа, определяющая, возможно ли копирование, извлечение текста, печать или изменение документа. Хотя стандарт ISO требует, чтобы все программы просмотра PDF следовали установленным ограничениям, например, Okular имеет опцию, которая позволяет игнорировать ограничения в просматриваемых файлах; Adobe DRM — технология защиты, используемая в Adobe Reader версии 6.0 и выше. Используется в различных книжных интернет-магазинах, поддерживает привязку возможности просмотра к компьютеру пользователя или другому устройству (например, КПК или электронной книге), позволяет ограниченное количество раз копировать документ с одного устройства на другое авторизованное в Adobe Content Server, позволяет запретить извлечение текста и печать документа, а также ограничить срок, в течение которого возможен доступ к документу.

— DRM FairPlay от Apple Inc. Она применяется к формату ePub, причём прочитать такие файлы могут только устройства Apple с помощью приложения iBook.

— DRM Marlin была создана и поддерживается в открытой отраслевой группе Marlin Developer Community (MDC), основанной компаниями Intertrust, Panasonic, Philips, Samsung и Sony. Эта схема лицензирована MTMO.

Популярный в России открытый формат электронных книг FictionBook не поддерживает DRM.


4.4 Видео игры


DRM в компьютерных играх используется для различных целей, но в целом все схемы направлены на защиту от копирования и распространения пиратских копий игр. Зачастую при запуске таких игр необходимо вставить диск с игрой в оптический привод, при этом проверяются низкоуровневые особенности лицензионных CD и DVD-дисков, которые невозможно воспроизвести при копировании в домашних условиях. Также подобные системы DRM часто устанавливают в систему драйвер для защиты от эмуляторов дисководов, а иногда требуют регистрации через Интернет.

Игровые приставки, такие, как Xbox 360, Xbox One, PlayStation 3 и Playstation 4, также содержат систему проверки диска на лицензионность.


Активация для ограничения количества установок

В некоторых компьютерных играх DRM-защита используется для ограничения числа систем, на которых можно устанавливать данное ПО. Для контроля используется онлайн-аутентификация на серверах издателя. Большинство таких DRM-схем позволяют произвести от 3 до 5 установок, однако некоторые позволяют отменить активацию посредством деинсталляции. Подобные схемы вызывают много критики, так как ограничивают пользователей от законного использования приобретённых продуктов, например, если у пользователя дома более 5 компьютеров, он не может установить приобретённую продукцию на все машины.

Примерно с середины 2008 года выпуск игры Mass Effect запустил целую волну продуктов, использующих DRM-схему SecuROM, которая требует онлайн-аутентификации на серверах издателя. В этом же году использование подобной защиты в игре Spore от Electronic Arts привело к тому, что большинство пользователей предпочло использование пиратской версии игры. Однако независимые исследователи с TweakGuides пришли к выводу, что подобное использование DRM не влияет на количество пиратских копий игры, отметив, что другие игры вроде Call of Duty 4: Modern Warfare, Assassin’s Creed и Crysis, использующие схему SafeDisc, не прибегающую к онлайн-аутентификации, также распространялись в сравнимых со Spore количествах среди пиратов. К тому же игры, использующие онлайн-аутентификацию так же, как и Spore — BioShock, Crysis и тот же Mass Effect, в списках самых скачиваемых игр на различных торрент-трекерах не значатся.


Постоянная онлайн-аутентификация

Многие издатели, среди которых, например, Electronic Arts, Ubisoft, Valve и Atari, использовали онлайн DRM-схемы вплоть до начала 2009 года. В конце 2008 года компания Ubisoft провела эксперимент, выпустив серию игр Prince of Persia без DRM-защиты на вебсайте GOG.com, с целью проверить, насколько правдиво общественное мнение в отношении того, что DRM только усугубляет пиратство и провоцирует людей использовать не лицензионные копии. Хоть сама компания так и не объявила результаты эксперимента, независимые эксперты с Tweakguides заметили, что всего лишь с двух торрентов на Mininova игру скачало более 23 тысяч людей в течение 24 часов после релиза.

Ubisoft официально объявили о возвращении онлайн-аутентификации 9 февраля 2010 года. Они представили свою новую онлайн игровую платформу Uplay, которую начали использовать в таких играх, как Silent Hunter 5, The Settlers 7 и Assassin’s Creed II. Silent Hunter 5 взломали в течение 24 часов с момента релиза. Однако, пользователи пиратской версии могли играть только в начальные уровни игры. Система Uplay работает таким образом, что на пользовательский ПК игра устанавливается не полностью, а докачивает содержимое с игровых серверов Ubisoft по мере прохождения игры. Чуть более, чем через месяц после релиза на ПК, в первую неделю апреля, было выпущено ПО, с помощью которого можно было обойти DRM-защиту в Assassin’s Creed II. ПО являло собой эмулятор сервера Ubisoft для игры. Чуть позже, в этом же месяце, была выпущена версия, которая убирала необходимость в соединении с серверами полностью.

В начале марта 2010 года сервера Ubisoft подверглись масштабной DDoS-атаке, что привело к закрытию доступа к играм для ~5% игроков. В качестве компенсации за принесённые неудобства, компания предоставила пострадавшим пользователям по бесплатной скачиваемой игре. С марта 2010 года сервера Ubisoft больше не падали.

Примеру Ubisoft последовали и другие разработчики, такие, как Blizzard Entertainment. Они также перешли на вариант защиты, когда большая часть игровой логики находится «на стороне», или обрабатывается серверами создателя игры. Blizzard использует подобный подход в своей игре Diablo III. Electronic Arts использовали такой подход в своей перезагрузке сериала SimCity. Надо сказать, что подобный подход отрицательно повлиял на обе компании, ибо они просто не смогли справиться с количеством игроков на серверах, что привело к многочисленным жалобам и растущему недовольству пользователей. Electronic Arts пытается убрать необходимость постоянного подключения к серверам, но пока это не представляется возможным, ибо вся игра была создана с учётом этого.


Вмешательство в ПО

Некоторые студии в качестве защиты используют не совсем стандартные подходы. Bohemia Interactive использует DRM-схему, которая при запуске нелегальной копии игры просто мешает играть, начиная с 2001 года, с выходом Operation Flashpoint: Cold War Crisis. Игра начинает создавать ситуации, в которых у игроков снижается точность оружия, или, например, сами игроки превращаются в птиц. Компания Croteam в своей игре Serious Sam 3: BFE использовала похожий подход, натравливая на игроков, использующих нелегальные копии игры, монстра, которого невозможно было убить.

5 Общий анализ средств защиты ПО от копирования

В большинстве случаев наиболее надежными и эффективными остаются технические способы защиты, но для успешного противостояния всем угрозам разработчики коммерческого ПО должны озаботиться вопросами информационной безопасности еще на старте разработки нового продукта. А вопросов здесь по большому счету два: как защитить свои ноу-хау и как противостоять нелегальному копированию?

Методы защиты софта от нелегального копирования развивались и эволюционировали последние 30 лет. В эпоху, когда не было Интернета, сканеры и ксероксы являлись экзотической редкостью, а операционные системы были однозадачными, производители компьютерных игр привязывали свой софт к поставляемому с ним печатному мануалу. В какие-то моменты использования программы требовалось найти что-то в руководстве пользователя.

Когда этот метод потерял актуальность, стали использоваться более продвинутые технические методы (например, ключевые дискеты). Использовались искусственно созданные сбойные секторы дискет, нестандартное форматирование и «плавающие» биты. И хотя некоторые производители (например, российская компания Abbyy) использовали этот метод защиты вплоть до недавнего времени, на смену им пришли новые технологии.

Недорогой софт, выпускаемый в промышленных масштабах (особенно компьютерные игры), проще всего защищать, привязывая к носителю (CD- или DVD-дискам). Там используются, по сути, те же методы, которыми раньше защищали дискеты: нестандартное форматирование, сбойные секторы на диске, специально закодированный таким образом ключ. В качестве дополнительной меры защиты в системе может устанавливаться специальный защищенный драйвер, призванный бороться с различными эмуляторами. Этот метод защиты сравнительно дешев и подходит для широко тиражируемых продуктов. К ограничениям можно отнести не самую высокую степень защиты и неудобство, вызванное привязкой к физическому носителю. Самые известные системы защиты по такой технологии: SecuROM, StarForce, SafeDisk, Tages.

5.1 Электронные ключи


Для защиты более дорогого программного обеспечения применяются электронные ключи или интернет-активация с привязкой к оборудованию. Электронные ключи выигрывают здесь с точки зрения защищенности: в отличие от ключевой дискеты или привязки к CD, электронный ключ в домашних условиях невозможно скопировать, а изучить «внутренности» довольно затруднительно без специального оборудования. Кроме того, современные микропроцессоры в электронных ключах позволяют шифровать трафик между ключом и защищенным приложением криптографическим алгоритмом на одноразовых сессионных ключах, что уничтожает возможность применения целого класса эмуляторов. При использовании этого метода защиты надо понимать, что благодаря технологиям современных ключей можно построить очень эффективную и взломостойкую защиту, но для этого нужно проектировать защиту вместе с проектированием архитектуры самого приложения.

Отдельной строкой идут электронные ключи с возможностью загрузки внутрь произвольного пользовательского кода. Если при разработке приложения хотя бы часть уникальных алгоритмов приложения перенести в такой ключ, а оставшуюся «снаружи» часть приложения заставить постоянно общаться с ключом с помощью асимметричной криптографии (например, в ключ периодически посылаются произвольные данные для выполнения электронно-цифровой подписи), то можно выстраивать защиту с гарантированной взломостойкостью.

5.2 Интернет-активация


Неудобство распространения физических носителей и электронных ключей, а также развитие Интернета и цифровой дистрибуции привели к взрывному росту популярности различных методов онлайн-защиты.

Компания Microsoft с 1999 г. начала применять интернет-активацию в большинстве своих продуктов, и вот уже более 10 лет сотни миллионов копий ее программного обеспечения успешно защищаются таким образом. Суть защиты состоит в том, что приложение вычисляет параметры оборудования, на которое оно установлено (серийные номера материнской платы, процессора и т.д.), в зашифрованном виде пересылает их на сервер активации и после получения ключа приложение начинает работать в полную силу, но оказывается привязанным к «железу», куда оно установлено.

Преимуществ у онлайн-за-щиты множество. Например, отсутствие физических носителей, что означает как отсутствие проблем с пересылкой электронных ключей и дисков, так и невозможность их механических поломок. Также можно отметить относительную дешевизну внедрения и поддержки этого метода защиты и, конечно, возможность широкой цифровой дистрибуции и «мгновенной» покупки ПО из любой точки Земли.

Однако стойкость всех вышеперечисленных методов защиты упирается в сложность реверсинга приложения и его технологий привязки к диску, электронному ключу или онлайн-активации. Поэтому крайне необходимо защитить приложение не только от копирования, но и от изучения и отладки.

5.3 Обфускация кода


Несмотря на то что ассемблер современных процессоров не так прост для понимания, как высокоуровневый С-код, опытный взломщик с большой долей вероятности сможет при наличии времени и сил воспроизвести любые алгоритмы в приложении, включая и те, что обеспечивают защиту от копирования. И если где-то существует заблуждение, что сама по себе компиляция в машинный код — это уже хорошая защита, то в современном мире это не так, не говоря уже о том, что множество технологий не предусматривает компиляции в машинный код, а анализировать байт-код или промежуточное представление куда легче (например,.NET, Java или ActionScript).

Здесь на помощь приходят технологии обфускации (запутывания) кода. Обфускация может выполняться на разных уровнях в зависимости от языка. Для Web-технологий (например, клиентского JavaScript) есть возможность только запутывания исходного кода. Если речь о языке с компиляцией в некий промежуточный код (например, у Java или. NET), то обфусцируется этот код. Но на сегодняшний день в большинстве своем коммерческий софт пишется на классических языках (например, С) и компилируется в машинный код, в связи с чем встает задача обфускации машинного кода.

5.4 Псевдокод и полиморфные технологии


Любая обфускация на уровне машинного кода уменьшает скорость выполнения программы. Ведь в лучшем случае для запутывания кода приходится добавлять туда ненужные инструкции (не влияющие, впрочем, на результат). А для более продвинутой защиты используется технология так называемого псевдокода. Так для обычного x86-процессора разрабатывается некий псевдоязык, оперирующий совершенно другими командами и логическими конструкциями, после чего исходный код защищенного приложения инструкция за инструкцией преобразуется в псевдокод. Для выполнения этого псевдокода генерируется «виртуальная машина», которая на лету преобразовывает команды псевдокода в машинные инструкции и исполняет их. Результат остается тот же, но код приложения меняется до неузнаваемости, и «отреверсить» искомые алгоритмы защищенного приложения можно лишь после вскрытия всей логики псевдокода.

Для повышения стойкости псевдокода могут использоваться полиформные технологии. Это означает, что псевдокод каждый раз новый и виртуальная машина для его исполнения тоже генерируется моментально.

Эти технологии сами по себе не защищают приложение от нелегального копирования, но позволяют надежно скрыть алгоритмы и ноу-хау разработчика, а также прочие важные места программы (вроде того, где осуществляется обмен с электронным ключом или процедура проведения и проверки онлайн-активации).

5.5 Перспективы


За последние 30 лет появлялись и погибали различные технологии. И сейчас многим кажется, что с развитием Интернета и цифровой дистрибуции право на существование имеет только онлайн-активация для защиты от копирования и обфускация кода для защиты от реверсинга. Однако есть и противоположная тенденция — развитие рынка SaaS и переход приложений в «облако». Если считать эту тенденцию потенциальным победителем, то защита вообще никому не нужна, ведь приложение не распространяется. Для «облаков» важна аутентификация, безопасность передачи данных и доступность сети.

Выбирая защиту для своего программного продукта, необходимо учитывать множество факторов: каналы дистрибуции (физические или цифровые), стоимость защиты, требования к надежности и отказоустойчивости. В некоторых случаях приложению вполне допустимо «уйти в облако», где защита осуществляется организационными мерами, но уже не обойтись без надежной аутентификации. Если же софт распространяется вместе с оборудованием (например, кассовые аппараты, терминалы и т.д.), то электронный ключ — это лучший и практически единственный вариант защиты. Электронные ключи (особенно с загружаемым кодом) незаменимы при защите особо ценного ПО с уникальными ноу-хау. Если приложение стоит десятки тысяч долларов, то экономить на защите не стоит, да и проблема физического распространения не столь актуальна — такое ПО зачастую внедряется армией консультантов и всегда есть «физический» контакт с клиентом.

В остальных же случаях для тиражного и недорогого софта технология онлайн-активации — это наиболее современное, надежное и относительно недорогое средство защиты. Исключением является ситуация, когда продажи осуществляются через партнерскую сеть. Софтверные лицензии не так хорошо защищают от мошенничества со стороны партнеров, электронные ключи же решают эту проблему полностью.

6 Исследование дизассемблирования и обфускации

Наверное каждый программист сталкивался с проблемой необходимости что-то изменить в чужой программе. Если это предусматривает просто замену информации, то можно обойтись любым HEX эдитором и менять то что нужно. Однако не всегда для достижения результата удается сохранить размер программы. В этом случае программист переходит к дизассемблированию

Дизассемблирование — это процесс и/или способ получения исходного кода программы на ассемблере из программы в машинных кодах.

Ha сегодняшний день известно множество хороших дизассемблеров, таких как:

— IDA Pro,

— Periscope,

— Bubble

— Chamber,

— Sourcer,

И тому подобные.

Самой простой для освоения является IDA Pro (Interactive DisAssembler Pro),

Рисунок 2 — Внешний вид программы IDA Pro

В полученных с помощью программы ASM файлах менялось что необходимо, и затем из них снова собирали работающую программу. Наиболее умелые программисты часто из полученных исходных файлов пытаются собрать программы для языков высокого уровня, будь то С, Fortran или даже Basic и Pascal. Этот процесс называется декомпиляцией, из-за сложности этого процесса автоматические реализации встречаются крайне редко. Декомпилируют файлы обычно вручную, при этом ищут конец и начало функций. Например, встретив строки «push ebp; mov ebp, esp» можно утверждать, что это начало функции, а «pop ebp; retn» — ее конец. Такие продвинутые дизассемблеры как IDA уже выделяют все функции, и задача ставится только понять, что они делают.

Однако в некоторых случаях программа дизассемблер может выдавать очень маленький код и сильно заполненный функциями db с непонятным содержимым. Если произошло что-то подобное, вероятнее всего программа закодирована или защищена. Это значит, что в процессе ее выполнения она сама себя раскодирует чтобы работать. Далее остается только действовать. Если программа себя дешифрует или распаковывает, то можно эту часть программы запустить и взять уже распакованный код. Есть и другой подход, по своей сути не сильно отличающийся от предыдущего: Необходимо запустить программу, и во время ее работы записать используемую ей память на диск.

Как правило, шифруемые программы, в том числе и полиморфные вирусы, шифруют себя несколько раз, при этом они могут переносить или даже изменять свой код, запускать расшифрованную информацию для дальнейшей распаковки, а также применять и другие запутывающие подходы. Отсюда следует, что дизассемблером пользоваться невыгодно. Для этой цели выглядит выгодно последовательно выполнять программу по одной инструкции или выполнять программу до заданной инструкции или области памяти. Такими функциями обладают практически все отладчики. Практически у любого языка программирования есть отладчик:

— У Borland-овских языков (Turbo Assembler (TASM), Borland’s C++) — это серия TD (Turbo Debugger). TD — для DOS-овских программ, TDW — для программ под windows. Однако TDW не распознает программу с заголовком PE/NE 32bit. В этом случае стоит пользоваться TD32.

— У продуктов Microsoft (MicroSoft Assembler, MASM) можно найти отладчик CodeView (CV, CVW) и относительно недавно появился пакет утилит NuMega фирмы Compuware. Отладчик NuMega SoftIce позволяет отладить даже ядро системы, а также с легкостью просматривать все процессы и окна. Часто он входит в комплект BoundsChecker.

Для некоторого упрощения процесса можно пользоваться breakpint-ами, поставив breakpoint на выходе из цикла и запустив программу, передаст управлению отладчику перед выполнением инструкции, помеченной breakpoint-ом. Чаще всего breakpoint-ы представляют собой прерывания, которые заменяют помеченные инструкции. Однако не стоит терять бдительность, поскольку программа может заменила инструкцию, на которой стоит breakpoint, и в итоге так и не остановиться выполняясь до конца. Теперь можно сохранить полученный файл как EXE-шник. При этом стоит учитывать новую точку входа и позаботиться о том, чтобы значение регистров сохранилось. Заголовок можно посмотреть с помощью утилиты HIEW (Hacker’s View) by SEN. Если программа DOS-овская — заголовок должет быть MZ, если для Windows, то чаще всего PE.

Теперь рассмотрим некоторые способы защиты программ от дизассемблирования. Первое, что приходит на ум — это зашифровать ее. Можно пользоваться различными методами криптографии, но в итоге понять, что распаковщик слишком прост. Также можно не только зашифровать, но и запаковать информацию. Для этих целей лучше всего подходят модификации алгоритма LZW. Они используются во многих архиваторах (RAR, ZIP), в графических файлах GIF, даже в PDF, им часто запаковываются EXE-шники (PKLITE). Это была основа, далее необходимо задуматься о более серьезной защите.

Тут есть несколько вариантов. Можно зашифровать часть распаковщика, таким образом можно шифровать программу по частям, и по несколько раз зашифровывать расшифровщики, и в итоге зашифровать все вместе. Можно спокойно перемешивать части программы, это также может привести в замешательство потенциального взломщика.

Однако и это не предел, возможно придумать и более действенные способы защиты. Например подобными участками кода:


Label1: mov ax,1ab8h

mov bx,06bbh

mov cx,00b9h

mov dx,01bah

mov si,0ffbeh

mov di,32bfh

jmp Label1+1


Результатом его работы будет:

bx = 0x0b906;

cx = 0x0ba00;

dx = 0x0be01;

si = 0x0bfff;

di = 0x0eb32.

Чтобы убирать оставленные breakpoint-ы можно изменять выполняемый код, например, увеличивать или уменьшать следующую инструкцию, можно ставить на них маски, складывать, да и просто перезаписывать. Таким образом каждый раз последующая инструкция может быть изменена:


push cs

pop ds

mov ch,0ebh

mov esi, offset $ или Label2: mov esi, offset Label2

add byte ptr [esi+07],08

sub byte ptr [esi+10],5

db Rel


Этот фрагмент выполняет относительный переход на Rel байтов (равносильно Jmp short ptr Rel). Защищать программы от трассирования это необходимость. Поскольку трассирование гораздо дольше обычного выполнения программы. Это и можно использовать против злоумышленника. Ниже приведен фрагмент, вызывающий функцию DOS «GetTime»:


mov ah,2ch; Get Time

int 21h; call DOS services

push dx; dh — seconds, dl — hundredths of a second (0—99)

mov ah,2ch; Get Time

int 21h; call DOS services

pop ax; ah — seconds

cmp dh, ah

jz continue;


Если время в секундах не изменилось, то осуществляется переход на метку continue, иначе продолжается выполнение программы. В этом фрагменте кода можно поставить и низкоуровневое форматирование диска, дабы еще больше усложнить жизнь злоумышленнику, либо же черезмерно нагрузить систему.

Даже вышеприведенный фрагмент, на самом деле, можно протрассировать гораздо быстрее секунды, поэтому желательно вставлять подобные запросы времени в разные участки программы, в идеале даже по-разному запакованные, так как распаковка гораздо быстрее трассирования.

Более того, сравнение полученных секунд можно отложить на следующий участок кода, так чтобы он не особо выделялся. Часто у взломщиков вызывают подозрения команды условного перехода, поэтому уместнее было бы написать так:


fragment 1

xor ecx, ecx

xor edx, edx

mov ah,01

int 1ah

;установить счетчик тиков на 0

;каждую секунду происходит примерно 18.2 тика

;поэтому предположим, что 2 тика уже слишком много

;fragment 2

xor eax, eax; здесь можно использовать ax, bx, cx,

;но для 32х разрядной машины 32х разрядные регистры занимают меньше памяти

int 1ah; взять число тиков

mov ax, cx

shl eax,16

mov ax, dx; конвертируем 32-битное число CX: DX в EAX

and al, -1;Один тик — не страшно, очистим первый бит

mov edx, eax

mov ecx,31

Label3: shr edx,1

or eax, edx

loop Label3

and eax,2

shl eax,1

add ebx, eax; допустим, в ebx нами был рассчитан какой-то адрес

call [ebx+xxx]; ebx+xxx — по этому адресу — нормальная процедура

;ebx+xxx+4 — а по этому адресу происходит перехват трассировщиков

7 Исследование защиты ПО физическим ключом

Наиболее распространенным и надежным способом защиты дорогостоящего программного обеспечения от несанкционированного запуска стали программно-аппаратные ключи, подключаемые к COM-, LPT- или USB-портам.

Почти все коробочные варианты серьезного коммерческого ПО используют программно-аппаратные комплексы защиты, более известные как аппаратные ключи защиты или же ключ-флэшка (рисунок 3).

Рисунок 3 — Содержимое коробки с диском под защитой (слева ключ-флэшка)

Такие способы защиты основаны на том, что в компьютер добавляется специальное физическое защитное устройство, к которому при запуске защищаемой программы обращается ее контролирующая часть, проверяя наличие ключа доступа и его параметров.

Рисунок 4 — Содержимое документа «Read Me» на диске с программами

Если ключ не найден (устройства обычно формируют еще и код ответа, который затем анализируется программой), то программа не запустится (или не будет разрешен доступ к данным).

При попытке запустить программы без установленного драйвера видим следующее (рисунок 5):

Рисунок 5 — Предупреждение об отсутствии драйвера

Соответственно теперь необходимо приступить к установке драйвера (рисунки 6—7):

Рисунок 6 — Приветственный экран установки драйвера

Далее подтверждаем согласие с установкой и ждем ее окончания.

Рисунок 7 — завершение установки

По завершению установки пробуем запустить ПО без физического ключа и видим следующее (рисунок 8):

Рисунок 8 — ошибка запуска ПО в связи с отсутствием ключа

После этого пробуем запустить программы со вставленным в ПК ключом и как и ожидалось программа запускается без запинок (рисунок 9).

Общий принцип работы компьютера в этом случае следующий. После запроса на выполнение защищаемой программы происходят ее загрузка в оперативную память и инициализация контролирующей части. На физическое устройство защиты, подсоединенное к компьютеру, посылается запрос. В ответ формируется код, посылаемый через микропроцессор в оперативную память для распознавания контролирующей частью программы. В зависимости от правильности кода ответа программа либо прерывается, либо выполняется.

Рисунок 9 — Окно запущенной программы

Что характерно в системе ключ-флэшка отображается не как хранилище информации, а как отдельное устройство.

Рисунок 10 — Окно со списком устройств в проводнике


Рисунок 11 — Ключ-флэшка в диспетчере устройств


Рисунок 12 — Свойства ключа флэшки

Защита какого-либо ПО при помощи физического ключа заключается не в том чтобы не возможно скопировать само ПО, а в том что обычный пользователь без обширных технических познаний и возможностей не сможет скопировать физический ключ, без которого отказывается работать программа. Таким образом, фактически защита физическим ключом для программного обеспечения — это невозможность выполнения программы на большем числе компьютеров, чем разрешено ее разработчиками и распространителями по данному договору.

При этом в любом случае следует помнить, что абсолютно надежной защиты не существует. Любую защиту можно сломать, обойти или перехитрить, поэтому необходимо искать оптимальное соотношение затрат на создание защиты и прогнозируемых затрат на ее взлом, учитывая также ценовое соотношение с самими защищаемыми продуктами.


Перехват и эмуляция


Идея перехвата ключа состоит в перезаписи обработчиков IRP-пакетов. Для этого необходимо иметь возможность изменять поля структуры DRIVER_OBJECT. К счастью, существует функция IoGetDevicePointer, которая возвращает указатель на объект вершины стека именованных устройств и указатель на соответствующий файловый объект. Вот фрагмент кода функции, устанавливающей ловушку:


NTSTATUS HookDevice (LPWSTR lpDevice)

UNICODE_STRING DeviceName;

PDEVICE_OBJECT DeviceObject;

PFILE_OBJECT FileObject;

RtlInitUnicodeString (&DeviceName, lpDevice);

IoGetDeviceObjectPointer (&DeviceName,1u,&FileObject, &DeviceObject);


Получив указатель на структуру DEVICE_OBJECT, имеем указатель на DRIVER_OBJECT. Теперь заменим адреса обработчиков и функций выгрузки драйвера на свои:

NTSTATUS HookDevice (LPWSTR lpDevice)

gDriverObject=DeviceObject-> DriverObject;

gDeviceControl=gDriverObject-> MajorFunction

[IRP_MJ_DEVICE_CONTROL];

gDriverObject-> MajorFunction

[IRP_MJ_DEVICE_CONTROL]

=HookDispatch;

gInternalDeviceControl=gDriverObject-> MajorFunction

[IRP_MJ_INTERNAL_DEVICE

_CONTROL];

gDriverObject-> MajorFunction

[IRP_MJ_INTERNAL_DEVICE

_CONTROL] =HookDispatch;

gDriverUnload=gDriverObject-> DriverUnload;

gDriverObject-> DriverUnload=HookUnload;

ObfDereferenceObject (FileObject);


В последней строчке вызывается функция ObfDereferenceObject, которая уменьшает количество ссылок на файловый объект. Это необходимо делать для корректной выгрузки драйвера, чтобы не было утечки ресурсов и аналогичных ошибок.

Так как указатель на объект драйвера защиты сохранен, то чтобы снять ловушку, нужно просто восстановить прежние обработчики IRP-пакетов:


void UnhookDevice (void)

gDriverObject-> MajorFunction [IRP_MJ_DEVICE_CONTROL]

=gDeviceControl;

gDriverObject-> MajorFunction [IRP_MJ_INTERNAL_DEVICE

_CONTROL] =gInternalDeviceControl;

gDriverObject-> DriverUnload = gDriverUnload;


Конечно, необходимо добавить соответствующие проверки на допустимость указателей и прочее.

Теперь необходимо реализовать правильную выгрузку драйверов. Так как система защиты по каким-либо причинам может закончить свою работу раньше нашего драйвера, то чтобы избежать краха системы из-за неверных указателей, обработаем это событие в функции HookUnload:


void HookUnload (PDRIVER_OBJECT DrvObj)

UnhookDevice ();

gDriverUnload (DrvObj);


Здесь происходит восстановление полей структуры DRIVER_OBJECT, и передается управление на оригинальный код выгрузки драйвера перехваченного устройства.

Аналогично поступаем, если наш драйвер завершает работу раньше системы защиты. Только нужно высвободить захваченные ресурсы и не вызывать сохраненный gHookUnload.


Перехватчик


Теперь можно приступить к реализации перехватчика для дальнейшего анализа. Для этого создадим объект драйвера, который содержит символьное имя (например DosDevicesHook) и точки входа CREATE, CLOSE, READ.

IoCreateDevice (DriverObject,0,&usDeviceName, FILE_DEVICE_NULL,0,

0,&pDeviceObject);

IoCreateSymbolicLink (&usSymbolicDeviceName, &usDeviceName);

DriverObject-> MajorFunction [IRP_MJ_CREATE] = DriverDispatch;

DriverObject-> MajorFunction [IRP_MJ_CLOSE] = DriverDispatch;

DriverObject-> MajorFunction [IRP_MJ_READ] = DriverDispatch;

DriverObject-> DriverUnload = DriverUnload;


Это нужно для того, чтобы работать с нашим перехватчиком как с файлом, используя функции CreateFile ReadFile CloseHandle. При такой реализации обмена данными между приложением и перехватчиком невозможно сразу же отправить их пользовательской программе, поэтому необходимо создать некоторую структуру для хранения необходимых данных о пойманном пакете. Например односвязный список. Далее следует определиться, какую информацию нужно буферизировать. Это общая информация о пакете (тип, флаги, прочее) и, конечно, буферы. Также можно добавить время перехвата. При копировании содержимого буферов нужно помнить об их типе, иначе придется начинать с начала. Стоит отметить, что драйвер защиты использует буферизированный ввод-вывод, это немного упрощает код.

Код HookDispatch:


if (idlTail->IrpData.InputLength)

{

idlTail-> InputBuffer=ExAllocatePool (NonPagedPool, idlTail-

IrpData.InputLength);

RtlCopyMemory(idlTail->InputBuffer,Irp-AssociatedIrp.SystemBuffer,

idlTail->IrpData.InputLength);

}


if (IoSL-> MajorFunction == IRP_MJ_DEVICE_CONTROL)

Status=pHookedDriverDispatch [IRP_MJ_DEVICE_CONTROL]

(DeviceObject, Irp);

if (idlTail-> IrpData. OutputLength)

{

idlTail-> OutputBuffer=ExAllocatePool (NonPagedPool, idlTail->

IrpData. OutputLength);

RtlCopyMemory (idlTail-> OutputBuffer, lpBuffer,

idlTail-> IrpData. OutputLength);

}


Осталось реализовать чтение из драйвера. Так как пакет содержит буферы, чье содержимое представляет интерес, то размер сообщений заранее не известен. Поэтому поступаем следующим образом: при первом чтении получаем общую информацию о пакете и размере буферов; при повторном читаем содержимое, удаляем звено из списка пакетов и не забываем про спиновые блокировки для последовательной работы с данными:

Код DriverDispatch:


Length = IoSL->Parameters.Read. Length;

if (Length == sizeof (IRP_DATA) && idlHead)

RtlCopyMemory (Irp-> UserBuffer, &idlHead-> IrpData, Length);

else if (idlHead && Length == (idlHead-> IrpData.InputLength + idlHead->

IrpData. OutputLength))

{

RtlCopyMemory (Irp-> UserBuffer, idlHead-> InputBuffer, idlHead->

IrpData.InputLength);

RtlCopyMemory ((PVOID) ((ULONG) Irp-> UserBuffer+idlHead->

IrpData.InputLength),idlHead->


OutputBuffer, idlHead->

IrpData. OutputLength);

}

else if (Length == 1 && idlHead)

{

if (idlHead-> InputBuffer)

ExFreePool (idlHead-> InputBuffer);

if (idlHead-> OutputBuffer)

ExFreePool (idlHead-> OutputBuffer);

idlTemp = idlHead-> ldlNext;

ExFreePool (idlHead);

idlHead = idlTemp;

if (!idlTemp)

idlTail = NULL;

}


Когда перехватчик готов, запускаем сначала его, а затем — защищенное приложение с ключами и без. Из полученных логов становится видно, какие управляющие коды посылаются и их результаты. Также можно видеть, что запросы и ответы на два различных кода (9c402450, 9c4024a0) не изменяются. Казалось бы, можно построить табличный эмулятор, но после серии запусков убеждаемся, что это невозможно, так как содержимое буферов различно, и неизвестно, как оно образуется.

Затем возможны несколько вариантов дальнейших действий:

— Изучать дебри драйвера защиты;

— Воспользоваться информацией самих разработчиков системы.

Оба варианта дают необходимую информацию. Таким образом, оказывается, что содержимое пакетов шифруется публичным симметричным алгоритмом AES (Advanced Encryption Standard). Логичной целью является получение ключа шифрования.

Однако если еще больше углубиться в изучение устройства системы защиты, то окажется, что аппаратный ключ имеет уникальный номер и содержит всю необходимую информацию, но для доступа к нему требуются программные ключи.

Поэтому первое, что нужно сделать, это получить ключ. Поставленную задачу может решить обычный перебор:


unsigned short Key;

unsigned char RefKey [8], VerKey [8];

for (Key = 0; Key <= 0x7fff, Key++)

{

if (!HL_LOGIN (Key, 1, RefKey, VerKey))

{

HL_LOGOUT ();

Break;

}

}

return Key;


Далее ключ (MODAD) используется для снятия дампа: тип, идентификатор, порт подключения и так далее. Для этого есть функции, определенные разработчиками.

Функции HL_LOGIN, HL_LOGOUT доступны из HASP SDK для разработчиков приложений, защищенных на этой платформе, и имеют следующие прототипы:


WORD HL_LOGIN (WORD ModAd, Word Access, Byte *RefKey,

Byt *VerKey);

WORD HL_LOGOUT (void);


Первая функция служит для открытия сессии работы с ключом защиты посредством драйвера, вторая — завершает сессию. Это прототипы старых версий HASP SDK, но работают они и с новыми типами ключей, так как разработчики обеспечили обратную совместимость.

Новый API мало отличается от старого, и это никак не сказывается на принципе работы перебора.


Обработчик


Теперь есть все необходимое для корректной работы модуля. Осталось реализовать подстановку лицензионной информации. Причем можно перехватывать лишь некоторые IRP-пакеты. Здесь все уже зависит от конкретной версии ключа и защищаемой программы.

Дамп ключа лучше не встраивать в драйвер, а загружать динамически из реестра. Лучше основываться на уже готовом перехватчике запросов, так будет проще отладить драйвер, отправляя перехваченные или подставленные пакеты на анализ пользовательскому приложению.

Принципиально логика перехватчика будет иметь такой вид:


NTSTATUS HookDispatch ():


PIO_STACK_LOCATION Stack=Irp-> Tail.Overlay.CurrentStackLocation;

ULONG IoControlCode;

if (Stack-> MajorFunction == 14)

{

IoControlCode = Stack.DeviceIoControl.IoControlCode;

If (IoControlCode!= 0x9c402458)

{

Return gDeviceControl (DeviceObject, Irp);

}

else

{

Encrypt(Irp->AssociatedIrp.SystemBuffer);

Crypt(Irp->AssociatedIrp.SystemBuffer, Key, DumpMemory);

}

}

Return STATUS_FAILED;


Пакет запроса к драйверу находится в зашифрованном виде, поэтому для доступа к содержимому требуется его расшифровать, а затем зашифровать. Однако нам не известно каким алгоритмом и каким ключом выполнено шифрование. Покопавшись в исходниках от создателей системы, можно получить следующий первичный алгоритм шифрования пакета:


Код Encrypt ():


void Encrypt (BYTE * Buffer)

{

WORD Seed = ((WORD) Buffer +0x5e);

WORD Ver = ((WORD) Buffer +0xba);

if (Ver)

{

for (int i = 0; i <0xB9; i++)

{

(WORD) (Buffer + i) += Seed;

Seed = (Seed>> 15) | (Seed <<1);

Seed -= (WORD) (Buffer + i) ^ i;

}


for (int i = 0xBE; i <0xFF; i++)

{

(WORD) (Buffer + i) -= Seed;

Seed = (Seed>> 15) | (Seed <<1);

Seed += (WORD) (Buffer + i) ^ i;

}

((WORD) Buffer +0xba) = Seed;

}

}


Видно, что алгоритм гораздо сложнее, чем обычный сдвиг и исключающее «или». Далее следует алгоритм дешифрования:


Код Decrypt ():


void Decrypt (BYTE* Buffer)

{

WORD Seed = ((WORD) Buffer +0x5e);

WORD Ver = ((WORD) Buffer +0xba);

if (Ver)

{

for (int i = 0xFE; i> 0xBD; i — )

{

Seed -= (WORD) (Buffer + i) ^ i;

Seed = (Seed <<15) | (Seed>> 1);

(WORD) (Buffer + i) += Seed;

}


for (int i = 0xB8; i> = 0; i — )

{

Seed += (WORD) (Buffer + i) ^ i;

Seed = (Seed <<15) | (Seed>> 1);

(WORD) (Buffer + i) -= Seed;

}

((WORD) Buffer +0xba) = Seed;

}

}


Затем следует ещё один этап преобразования данных, более сложный и уже полностью зависящий от структуры запроса. Тут не обойтись без дизассемблера, придется покопаться в бине и позаимствовать немного кода у создателей. Это непросто, так как код драйвера защиты сильно обфусцирован, но он не отличается разнообразием уловок. Достаточно будет дизассемблировать драйвер не полностью, а только лишь некоторые кусочки кода.

В заключение стоит отметить, что построение табличного эмулятора, основанного на перехвате DeviceIoControl — достаточно трудная задача. Но такой принцип эмулятора можно использовать и на другом уровне взаимодействия, например создать виртуальную USB-шину. И это значит, что все подобные методы взлома требуют обширных познаний у взломщика и, соответственно, большие временные затраты с его стороны.

8 ОБРАТНАЯ РАЗРАБОТКА ПО

Reverse engineering

8.1 Основные задачи:

— Установить логику программы с закрытым исходным кодом.

— Воссоздать программу, аналогичную проприетарной.

— Избавить проприетарную программу от ненужного функционала (проверка производителя/лицензии).

8.2 Что такое программа?

— Исполняемый файл популярных ОС и архитектур.

— Байткод виртуальной машины (Java/.NET).

— Интерпретируемый код (PHP/Python/Perl).

8.3 Исполняемый файл

Это, собственно, набор инструкций процессора, смешанный с данными, необходимыми для работы программы. На разных ОС приняты разные форматы исполняемых файлов: для Windows это PE (Portable Executable), для Linux ELF (Executable and Linkable Format). Расширения файлов. exe и <ничего> для Windows и Linux соответственно.

Важно помнить, что разделяемые библиотеки (.dll/.so) имеют схожий формат, хотя их обратная разработка затруднена не столь простой отладкой.

8.4 Структура исполняемого файла

Исполняемый файл состоит из сегментов, секций и всего такого. Вкратце они позволяют понять, где код, где данные, где константы и все такое.

В Linux это всё можно посмотреть командой readelf, в Windows –это не очень нужно.

IDA (о ней далее) покрасит все секции разными цветами сам.

8.5 Как понять что происходит?

Рисунок 13 — Reverse engineering


Рисунок 14 — Reverse engineering

8.6 Interactive DisAssembler (IDA):

— Стоит всего лишь от $1200. И это без декомпиляторов.

— Умеет, тем не менее, дизассемблировать почти всё.

— Стандарт индустрии.

— Обладает декомпилятором HexRays.

— Его автор параноик и думает, все его покупатели — пираты.

— А они и правда пираты… ну или неудачники. В интернете доступна версия 6.8, которую украли у HackingTeam.

8.7 Hexrays

Рисунок 15 — Reverse engineering


Рисунок 16 — Reverse engineering

8.8 Что же теперь делать?

— Заходите в подозрительную функцию (обычно это main).

— Жмете F5.

— Готово, теперь вы можете читать «код».

— Двойным щелчком можно переходить между функциями, X выводит список ссылок на объект под курсором в программе.

8.9 Как, тем не менее, понять что происходит?

— Просто прочитать. Это же легко, правда?

— Загуглить встреченные константы.

— Загуглить названия функций. Макрос assert () выдает имена оригинальных файлов, их можно гуглить.

— Отладить подряд.

8.10 Отладчик

— Позволяет выполнять программу пошагово, смотреть регистры, инструкции и всё такое. Только ассемблер.

— Под Windows самыми известными являются OllyDbg и x64dbg (слышали о Denuvo? Его официальный «спонсор»).

— GNU Debugger (gdb). Вообще не только для Linux, но в винде не очень хорош. А вообще крут, еще и плагины есть (PEDA).

— IDA. Ходят слухи, она умеет отлаживать даже линукс через удаленный gdb, но это неточно. Под Windows отладчик даже и неплох.

ЛАБОРАТОРНЫЕ РАБОТЫ

ЛАБОРАТОРНАЯ РАБОТА №0

Тема: Дисассемблеры и отладчики

Вам выдан рабочий модуль программы (COM файл). При запуске этой программы производится запрос пароля, после чего дается заключение о правильности прохода через пароль. Ваша задача:

1) Используя отладчик AFD или TD пройти по программе, найти место, где происходит дешифровка пароля и расшифровать его, после чего снова запустить программу, ввести правильный пароль и получить подтверждение о правильности прохода через пароль.

2) Используя дизассемблер SOUSER

— дизассемблировать выданную программу

— автоматически построить блок схему алгоритма ее работы

— найти в тексте программы место проверки пароля и подавить проверку

— заново ассемблировать программу и представить ее преподавателю, продемонстрировав, что программа теперь не запрашивает пароль (или успешно завершается при любом пароле).

3) Оформить электронный отчет, в котором отразить:

— титульный лист;

— тему лабораторной работы и задание на лабораторную работу;

— описание этапов дешифровки пароля и экранные формы отладчика, использованные при дешифровке пароля;

— описание этапов дизассемблирования программы и экранные формы дизассемблера, использованные при этом, в отчет включить УЧАСТОК дизассемблированной программы, в котором происходит дешифровка и обработка пароля;

— описание этапов автоматического построения блок-схемы алгоритма программы, в отчет включить УЧАСТОК блок-схемы алгоритма, в котором происходит дешифровка и обработка пароля;

— описание приемов, примененных для подавления обработки пароля, в отчет включить УЧАСТОК дизассемблированной программы измененный Вами с целью подавления обработки пароля;

— описание порядка ассемблирования программы;

— вид экрана после срабатывания откорректированной программы.

Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №0

Реверс программы OOO_07.COM

Введение

Цель работы: произвести обратную разработку программы OOO_07.COM.

Для выполнения цели поставлен ряд задач:

— Разобраться в структуре программы OOO_07.COM;

— Найти правильный пароль;

— Сделать вывод по результатам проведенной работы.

1 Знакомство с программой

Программа OOO_07.COM (в дальнейшем программа) представляет из себя консольное приложение для DOS. Запустим его в DOS-Box и введем пароль 123 (рисунок 17).

Рисунок 17 — Внешний вид программы

Давайте попробуем отладить программу при помощи AFD.

2 Отладка программы в AFD

Откроем программу в AFD и найдем то место, где обрабатывается пароль (рисунок 18).

Рисунок 18 — Поиск по тексту

Как видно из рисунка, то место, в котором обрабатывается пароль представляет из себя цикл, состоящий из 5-ти итерации. На каждой итерации регистру BL присваивается символ кодовой фразы, защитой в программу. Далее каждый символ складывается по модулю 2 со значением 0x76 (118). После чего результат операции сравнивается с очередным введенным символом и если они не равны, то выполнение программы завершается. Давайте посмотрим память, по смещению 0x201 (513) (рисунок 19).

Рисунок 19 — Память с зашифрованным паролем

Таким образом наш пароль представляет из себя 5 символов 0xF2 (242), 0xF8 (248), 0xFA (250), 0xFE (254), 0xFC (252), каждый из которых необходимо сложить по модулю 2 со значением 0x76 (118):

— 0xF2 ^ 0x76 = 0x84 (132 = «Д»);

— 0xF8 ^ 0x76 = 0x8E (142 = «О»);

— 0xFA ^ 0x76 = 0x8C (140 = «М»);

— 0xFE ^ 0x76 = 0x88 (136 = «И»);

— 0xFC ^ 0x76 = 0x8A (138 = «К»).

Мы получили кодовую фразу «ДОМИК». Введем ее, чтобы проверить нашу гипотезу (рисунок 20).

Рисунок 21 — Ввод правильного пароля

3 Работа с Sourcer

Дизассемблируем программу при помощи Sourcer (рисунок 22—24).

Рисунок 22 — Внешний вид Sourcer с загруженной программой


Рисунок 23 — Запуск процесса дизассемблирования


Рисунок 24 — Сгенерированный Sourcer листинг

Сконвертируем полученный листинг в. asm файл (рисунки 25—26).

Рисунок 25 — Процесс обработки листинга


Рисунок 26 — .asm файл

Исправим исходный код так, чтобы он всегда выводил правильный ответ без ввода пароля (рисунки 27—28).

Рисунок 27 — Исправленная программа


Рисунок 28 — Компиляция, линковка и проверка программы

Заключение

При выполнении работы на практике была произведена обратная разработка программы OOO_07.COM при помощи интерактивного дизассемблеро IDA Pro Freeware.

По итогам работы были выполнены следующие задания:

— Разобрался в структуре программы OOO_07.COM;

— Нашел правильный пароль;

— Сделал вывод по результатам проведенной работы.

ЛАБОРАТОРНАЯ РАБОТА №1

Тема: Olly dbg 32

Описать функционал приложения по отладке программного обеспечения. Обязательно подробно описать одну из функций, не пересекаясь с другими студентами из группы по описываемой функции.

Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №1

Отладчик OllyDbg

Введение

Цель работы: рассмотреть функционал отладчика OllyDbg и выполнить его детальное описание.

Для выполнения цели поставлен ряд задач:

— Описать функционал отладчика OllyDbg;

— Рассмотреть возможности отладчика OllyDbg;

— Сделать вывод по результатам проведенной работы.

1 Описание

OllyDbg — shareware 32-битный отладчик уровня третьего кольца защиты (ring-3) для операционных систем Windows, предназначенный для анализа и модификации откомпилированных исполняемых файлов и библиотек, работающих в режиме пользователя (ring-3).

OllyDbg выгодно отличается от классических отладчиков (таких, как SoftICE) интуитивно понятным интерфейсом, подсветкой специфических структур кода, простотой в установке и запуске. Для того, чтобы разобраться в принципе работы OllyDbg, достаточно лишь базовых знаний в области языка ассемблера. По этим причинам OllyDbg рекомендуют к использованию даже новичкам.

Последняя версия программы на старом движке — 1.10, не обновлялась с мая 2004 года. Однако 12 ноября 2006 года на официальном сайте был опубликован анонс новой, второй версии продукта. Со 2 июня 2010 года доступна первая новая версия OllyDbg 2.0 без приставки «бета».

В октябре 2013 года была анонсирована 64-битная версия отладчика. В декабре 2013 на сайте появилась информация о прогрессе в разработке.

Как уже было описано ранее, на данный момент имеется две версии программы: релизная старая версия 1.10 и новая, полностью переписанная c нуля, версия 2.01. В данной работе будет рассматриваться новая версия 2.01.

1.1 Возможности

— Поддерживаемые процессоры: вся серия 80x86, Pentium и совместимые; расширения MMX, 3DNow! И SSE до версии SSE4 включительно (SSE5 пока не поддерживается).

— Поддерживаемые форматы отображения данных: hex-код, ASCII, юникод, 16- и 32-битные целые числа со знаком и без знака, 32-, 64- и 80-битные числа с плавающей запятой (float).

— Способы отображения дизассемблированного кода: MASM, IDEAL, HDA.

— Мощный анализатор кода, распознающий процедуры, циклы, ветвления, таблицы, константы и текстовые строки.

— Развёрнутая система поиска: поиск всех возможных констант, команд, последовательностей команд, текстовых строк и ссылок в коде на адрес.

— Распознание и расшифровка более двух тысяч типичных функций Windows API и языка C.

— Распознание и расшифровка PE-заголовка.

— Эвристический анализ стека, распознание адресов возврата в родительскую процедуру.

— Простые, условные и протоколирующие точки остановки (breakpoints).

— Пошаговая отладка с протоколированием хода выполнения (run trace).

— Индивидуальный файл конфигурации (UDD) для каждого отлаживаемого приложения.

— Поддержка большого количества плагинов.

2 Работа с отладчиком OllyDbg

2.1 Основная функциональность

2.1.1 Форматы данных

Окна дампа отображают данные во всех обычных форматах: шестнадцатеричный, ASCII, Unicode, 16-и 32-разрядные целые числа со знаком/без знака/шестнадцатеричные, дизассемблеры (MASM, IDEAL или HLA).

2.1.2 Запуск отладчика

Мы можем определить исполняемый файл в командной строке, выбрать в меню, перетаскивать файл в OllyDbg, перезапускать последнюю отлаживаемую программу или присоединяться к уже выполняющемуся процессу. Инсталляция не необходима, поэтому можно запустить OllyDbg с внешнего носителя.

2.1.3 Отладка DLL

С OllyDbg мы можем отладить автономные библиотеки динамической связи (DLL). OllyDbg автоматически запускает маленькую выполнимую программу, которая загружает библиотеку и позволяет нам вызывать её экспортируемые функции.

2.1.4 Анализ

Анализатор — одна из наиболее значительных частей OllyDbg. Он распознает процедуры, циклы, таблицы, константы и строки, внедренные в код, хитрые конструкции, запросы к функциям API, номера параметров функции, секции импорта и так далее. Анализ делает двойной код намного более читаемым, облегчает отладку и уменьшает вероятность сбоев. Анализатор не ориентируется на компилятор и одинаково хорошо работает со всеми Windows программами.

2.1.5 Объектный сканер

OllyDbg просматривает объектные файлы или библиотеки (форматы OMF И COFF), извлекает из них код, сегментирует и определяет местонахождение их в отлаживаемой программе.

Полная поддержка Unicode`а. Почти все операции, доступные для строк ASCII также доступны для строк Unicode`а, и наоборот.

2.2 Горячие клавиши

Горячие клавиши позволяют уменьшить временные затраты на поиск нужной функциональности в меню. Без этой возможности отладчик потеряет свое удобство. Начнём с панели управления:

— Первая кнопка — открыть файл (гор. кл. F3)

— Вторая кнопка — перезапустить файл (гор. кл. Ctrl+F2)

— Третья кнопка — закрыть файл (гор. кл. Alt+F2)

— Четвёртая кнопка — запустить программу (гор. кл. F9)

— Пятая кнопка — приостановить запуск (гор. кл. F12)

— Шестая кнопка — трассировать с заходом в подпрограммы (гор. кл. F7)

— Седьмая кнопка — трассировать без захода в подпрограммы (гор. кл. F8)

— Восьмая кнопка — запустить автоматическую трассировку заходя в подпрограммы (гор. кл. Ctrl+F11)

— Девятая кнопка — запустить автоматическую трассировку без захода в подпрограммы (гор. кл. Ctrl+F12)

— Десятая кнопка — выполнить программу до выхода из подпрограммы (гор. кл. Ctrl+F9)

— Одиннадцатая кнопка — перейти на адрес (гор. кл. Ctrl+G)

Все остальные кнопки на панели управления будут рассмотрены позже.

Необходимые команды:

— Ctrl+A — провести анализ кода

— Ctrl+C — копировать данные

— Ctrl+F7 — включить режим, когда код будет выполняться, как будто бы мы нажали и не отпускаем кнопку F7

— Ctrl+F8 — включить режим, когда код будет выполняться, как будто бы мы нажали и не отпускаем кнопку F8

— Shift+F8 — продолжить трассировку программы, даже если возникла исключительная ситуация

— Shift+F9 — продолжить запуск программы, даже если возникла исключительная ситуация

— Ctrl+T — настройки авто-трейсера

— Ctrl+F11 — Запуск автоматической трассировки с заходом в подпрограммы

— Ctrl+F12 — Запуск автоматической трассировки без захода в подпрограммы

— F2 — Поставить брейкпоинт на выделенной строке

2.3 Плагины

Плагины — неотъемлемая часть OllyDbg. Без них отладка программы выполняется намного сложнее. Ниже приведен список плагинов, позволяющих упростить отладку приложений с кратким описанием:

— OllyExt — прячет отладчик от обнаружения при помощи различных техник.

— Olly Script — позволяет писать скрипты для помощи в отладке.

— Olly Dump — позволяет дампить отлаживаемый процесс и за одно восстанавливает у него импорт.

— Command Bar — в отладчике появляется строка, где можно вводить команды для отладчика. Справка приведена в приложении А.

2.4 Внешний вид

С отладчиком OllyDbg очень легко работать. На рисунке 29 приведен внешний вид с загруженной тестовой программой.

Рисунок 29 — Внешний вид OllyDbg

Детальное описание каждого пункта:

— (желтый) Виртуальные адреса.

— (зеленый) Машинный код.

— (синий) Дизассемблированный листинг (команды ассемблера).

— (красный) Комментарий отладчика.

— (фиолетовый) Регистры общего назначения.

— (серый) EIP регистр (показывает виртуальный адрес следующей выполняемой команды).

— (розовый) Флаги процессора.

— (оранжевый) Регистр флагов.

— (светло зеленый) Сегментные регистры.

— (бардовый) FPU (Floating Point Unit) регистры.

— (охра) Дамп памяти.

— (ультрамариновый) Стек.

2.4.1 Главное окно

В этом окне происходит сама отладка. Все инструкции приведены в дизассемблированном виде. Мы можем перемещать указательную строку при помощи курсора. При помощи указательной строки мы можем выбирать, какие данные скопировать, какую изменить команду, куда поставить брейкпоинт и т. д. Сбоку выделен адрес, который должен выполниться следующим. Между колонкой адресов и колонкой дизассемблированного листинга есть колонка с машинным кодом инструкции. Самая последняя колонка содержит в себе комментарии.

Рисунок 30 — Главное окно отладчика

2.4.2 Окно регистров

В окне регистров отображаются все 32-битные регистры, регистры флагов и различные другие регистры. Для того, чтобы изменить регистр надо щёлкнуть по его значению 2 раза и ввести новое значение. Реверсировать регистр флага можно путём двойного щелчка по одному из них.

Рисунок 31 — Окно регистров

2.4.3 Панель стека

В панели стека, можно изменить нужные нам байты в памяти, ставить брейкпоинты, подсматривать правильные рег. коды и т. д.

Рисунок 32 — Панель стека

2.4.4 Панель дампа оперативной памяти

В панели дампа памяти приведен слепок оперативной памяти, с загруженной в него отлаживаемой программой и всеми ее данными. В данной панели можно изменять нужные нам байты, а также выводить содержимое памяти в разнообразных форматах (ASCII, HEX, Unicode и т.д), кликнув по панели правой кнопкой мыши и выбрав нужный пункт меню.

Рисунок 33 — Дамп оперативной памяти

2.5 Знакомство с главным меню

2.5.1 Меню File

Рисунок 34 — Меню File

— Open — открыть файл для отладки;

— Set new arguments — задать новые аргументы выполнения программы;

— Attach — присоединиться к уже запущенному процессу для отладки;

— Detach — отсоединиться от процесса;

— Exit — выйти.

2.5.2 Меню View

Рисунок 35 — Меню View

— Log — Просмотреть лог о загрузке файла и т. д. (горячая клавиша: Alt+L);

— Executable modules — Посмотреть все модули, которые использует отлаживаемое приложение. (горячая клавиша: Alt+E);

— Memory map — Просмотреть карту памяти. На рисунке приведен ее внешний вид;

— List of windows — Просмотреть огромное количество информации об окнах, классах и т. д. используемых программой;

— Threads — Посмотреть все потоки программы, заморозить их, изменить их приоритет, убить их;

— CPU — Открыть главное окно. (горячая клавиша: Alt+C);

— Handles — Просмотреть Handle`ы;

— Watches — Просмотр значения какого-либо выражения;

— Search results — Вывод результатов поиска;

— Run Trace — Просмотреть лог трассировки;

— Patches — Просмотреть список всех изменений, которые мы сделали в программе, отменить все изменения и т. д. (горячая клавиша: Ctrl+P);

— INT3/Memory/Hardware Breakpoints — Просмотреть все брейкпоинты, отключить, удалить их. (горячая клавиша: Alt+B, Alt+Y, Alt+H);

— VEH/SEH Chain — Посмотреть, поставить брейкпоинт на все объявленные Seh`и или Veh`и;

— Call Stack — Просмотреть все вызовы выполнения код в стеке. (горячая клавиша: Alt+K);

— Source files — просмотр всех исходных файлов отлаживаемой программы4

— File — Шестнадцатеричный редактор файлов;

— Drive — Шестнадцатеричный редактор томов.

Рисунок 36 — Внешний вид memory map

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

— Вторая колонка — размер в памяти секции.

— Третья колонка — обычно название модуля.

— Четвёртая колонка — название секций.

— Пятая колонка — что содержится в секции.

Все остальные колонки не важны, т.к. в них отражены атрибуты секций в памяти. (горячая клавиша: Alt+M)

2.5.3 Меню Debug

Рисунок 37 — Меню Debug

— Run — Запуск приложения;

— Run tread — Запуск потока;

— Step into — Эквивалент F7;

— Step over — Эквивалент F8;

— Execute till return — Выполнить программу до выхода из подпрограммы;

— Restart — Перезапуск отлаживаемой программы;

— Close — Закрытие отлаживаемой программы;

— Set affinity — привязать процесс отладки к определенному ядру (определенным ядрам);

— Create function library — создать функциональную библиотеку

2.5.4 Меню Trace

Рисунок 38 — Меню Trace

— Clear run trace — Очистить контекст авто трассировки;

— Close run trace — Остановить авто трассировку;

— Animate into — Эквивалент постоянно нажатой F7;

— Animate over — Эквивалент постоянно нажатой F8;

— Trace into — Авто трассировка с заходом в подпрограммы;

— Trace over — Авто трассировка без захода в подпрограммы;

— Run hit trace — Запуск трассировки до первого breakpoint;

— Discard hit trace — Отмена трассировки до breakpoint;

— Set condition — Назначить условие для авто трассировки;

— Set protocol — Задать цели протоколирования во время авто трассировки.

2.5.5 Меню Plugins

Рисунок 39 — Меню Plugins

Показывает текущие установленные плагины и их параметры.

2.5.6 Меню Options

Рисунок 40 — Меню Options

— Options (гор. кл — Alt+O) — Все настройки отладчика;

— Load oprions — Импорт настроек;

— Save options — Экспорт настроек;

— Edit shortcuts — Редактирование горячих клавиш.

Остальные пункты меню не представляют технического интереса, по

Заключение

При выполнении работы на практике был рассмотрен и изучен многофункциональный отладчик OllyDbg, проведен обзор его основных функций. С помощью данного отладчика возможна отладка 32-битных приложений на базе операционной системой Windows.

По итогам работы были выполнены следующие задания:

— Описан функционал отладчика OllyDbg;

— Рассмотрены возможности отладчика OllyDbg;

— Сделан вывод по результатам проведенной работы.

ПРИЛОЖЕНИЕ А

Помощь по плагину Command Bar


Объяснение команд для Command Bar. Все команды, которые я посчитал лишними, были удалены из данного списка.

Выражения

— CALC [выражение] — Вычеслить значение выражения

Дизассемблер

— AT [выражение] — Перейти на адрес в дезассемблере

— FOLLOW [выражением] — Перейти на адрес в дезассемблере

— ORIG — Перейти на текущий адрес (EIP)

— — Перейти на текущий адрес (EIP)

Дамп и стек

— D [выражение] — Перейти на адрес в дампе

— DUMP [выражение] — Перейти на адрес в дампе

— DA [выражение] — Дамп в формате ассемблера

— DB [выражение] — Дамп в шестнадцатеричной системе

— DC [выражение] — Дамп в ASCII кодировке

— DD [выражение] — Дамп как адреса (стек формат)

— DU [выражение] — Дамп в UNICODE кодировке

— DW [выражение] — Дамп в шестнадцатеричном word формате

— STK [выражение] — Перейти на адрес в стеке

Трансляция

— A [выражение] [, команда] — Дезассемблировать адрес

Метки и комментарии

— L выражение, метка — Связывает символическую метку с адресом

— C выражение, комментарий — Устанавливает комментарий для адреса

Брейкпоинты

— BP [выражение] [,условие] — Устанавить брейкпоинт

— BPX [имя функции] — Установить брейкпоинты на все инструкции в модуле, которые вызывают [имя функции]

— BC [адрес] — Удалить контрольную точку по адресу

— MR expression1 [,expression2] — Установить брейкпоинт на память на доступ на определённый участок

— МВТ expression1 [, expression2] — Установить брейкпоинт на память на запись на определённый участок

— MD — Удалить брейкпоинт на память

— HR [адрес] — Установить Hardware брейкпоинт на один байт на доступ на адрес

— HW [адрес] — Установить Hardware брейкпоинт на один байт на запись по адресу

— HE [адрес] — Установить Hardware брейкпоинт на выполнение комманды по адресу

— HD [номер брейкпоинта] — Удалить Hardware брейкпоинт под номером

Команды трассировки

— STOP — Сделать паузу в трассировке

— PAUSE — Сделать паузу в трассировке

— RUN — Запустить программу

— G [адрес] — Выполнить до адреса

— GE [expression] — Выполнить до адреса

— S — Эквевалент F7

— SI — Эквевалент F7

— SO — Эквевалент F8

— TR — Выполнить программу до выхода из подпрограммы

OllyDbg окна

— LOG — Окно просмотра лога

— MOD — Посмотреть выполняемые модули

— MEM — Открыть окно карты памяти

— CPU — Открыть главное окно программы

— BRK — Открыть окно просмотра брейкпоинтов

— OPT — Настройки

Разные команды

— EXIT — Выйти из Olly

— QUIT — Выйти из Olly

— OPEN [имя файла] — Открыть файл для отладки

— CLOSE — Закрыть отлаживаеммую программу

— RST — Перезапустить отлаживаеммую программу

— HELP — показывают справку (данный текст, но непереведённый)

— HELP — Olly показывают справку Oll

— HELP APIfunction — справка по API функциям

ПРИЛОЖЕНИЕ Б
Подробная информация о брейкпоинтах

Olly поддерживает несколько видов брейкпоинтов:

— Обычный брейкпоинт, где первый байт команды, на которой Вы хотите прерваться заменяется на INT3 (Trap to Debugger). Мы можем разместить брейкпоинт, выбирая команду в дизассемблере и нажимая F2, или через всплывающее меню. Когда мы нажимаем F2 второй раз, когда брейкпоинт уже установлен, он будет удалён. Количество брейкпоинтов INT3 неограниченно. Когда мы закрываем отлаживаемую программу, или отладчик, Olly автоматически сохраняет брейкпоинты. Запрещено устанавливать брейкпоинт на данных или в середине команды! Olly предупредит, если произойдет попытка установки брейкпоинта вне секции кода. Мы можем выключить это предупреждение в настройках защиты. В некоторых случаях Отладчик может вставить собственные временные контрольные точки брейкпоинты INT3.

— Условный брейкпоинт (гор. кл. Shift+F2) — обычный брейкпоинт INT3 с условием. Каждый раз, когда отладчик сталкивается с таким брейкпоинтом, оценивает его выражение и, если результат является ненулевым, или выражение недействительно, останавливает отлаживаемую программу.

— Условный брейкпоинт с ведением лога (гор. кл. Shift+F4) — условный брейкпоинт с ведением лога, чтобы регистрировать значение выражения или параметров известной функции каждый раз, когда брейкпоинт выполняется.

— Брейкпоинт на память. Olly позволяет ставить единственный брейкпоинт на память одновременно. Мы выбираем некоторую часть памяти в дезассемблере или дампе центрального процессора и используем всплывающее меню, чтобы установить брейкпоинт на ней. Предыдущий брейкпоинт на память, если таковой вообще имеется, будет автоматически удален. У нас есть два варианта: остановка на доступе к памяти (чтение, запись или выполнение) и только на запись. Чтобы установить брейкпоинт, Olly изменяет атрибуты блоков памяти, содержащих данные.

— Аппаратный брейкпоинт (доступен только при использовании отладчика под Windows ME, NT, 2000 или XP). 80x86-совместимые процессоры позволяют нам устанавливать 4 аппаратных брейкпоинта. В отличие от брейкпоинта на память, аппаратные брейкпоинты не замедляют скорость выполнения, но охватывают только до 4 байтов.

— Однократная остановка на доступе к памяти (доступна только под Windows NT, 2000 и XP). Мы можем установить его в окне Memory на целый блок памяти через всплывающее меню или нажимая F2. Этот брейкпоинт особенно полезен, если мы хотим перехватить запросы к некоторому модулю.

— Автотрассировка — мы должны указать условие (гор. кл. Ctrl+T), при котором отладчик остановит программу. Следует обратитт внимание, что эта опция может значительно (до 20%), замедлить скорость выполнения программы.

OllyDbg также может остановить выполнение программы на некоторых событиях, например при загрузке или выгрузке DLL, зарождению или завершению потока.

ЛАБОРАТОРНАЯ РАБОТА №2

Тема: X64dbg

Описать функционал приложения по отладке программного обеспечения. Обязательно подробно описать одну из функций, не пересекаясь с другими студентами из группы по описываемой функции. Обязательно найти отличия не пересекающиеся с другими студентами.

Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №2

Отладчик x64dbg

Введение

Цель работы: рассмотреть функционал отладчика x64dbg и выполнить его детальное описание.

Для выполнения цели поставлен ряд задач:

— Описать функционал отладчика x64dbg;

— Рассмотреть возможности отладчика x64dbg;

— Сделать вывод по результатам проведенной работы.

1 Описание

x64dbg — современный отладчик с открытым исходным кодом. В отличие от ollydbg, x64dbg может использоваться для отладки как 32-битных, так и 64-битных приложений. Он имеет простой в использовании графический интерфейс с возможностью перевода на русский язык и предлагает различные функции отладки.

Данный отладчик (в настоящее время) состоит из трех частей:

— DBG;

— GUI;

— Bridge.

DBG — это отладочная часть отладчика. Он обрабатывает отладку (с использованием TitanEngine) и предоставляет данные для графического интерфейса.

GUI — это графическая часть отладчика. Он построен поверх Qt и обеспечивает взаимодействие с пользователем.

Bridge — это коммуникационная библиотека для части DBG и GUI (и, возможно, для частей, которые появятся в будущем). Bridge можно использовать для работы над новыми функциями без необходимости обновлять код других частей.

1.1 Основные возможности

— Полнофункциональная отладка файлов DLL и EXE (TitanEngine Community Edition);

— Поддержка 32-битной и 64-битной Windows от Windows XP до Windows 10;

— Встроенный ассемблер (XEDParse / Keystone / asmjit);

— Быстрый дизассемблер (Zydis);

— C-подобный синтаксический анализатор выражений;

— Логирование;

— Заметки;

— Просмотр карты памяти;

— Представление модулей и символов;

— Просмотр исходного кода;

— Просмотр потоков;

— Контенточувствительный просмотр реестра;

— Просмотр стека вызовов;

— SEH просмотр;

— Перечисление дескрипторов, привилегий и TCP-соединений;

— Дамп памяти с несколькими типами данных;

— Динамическое представление стека;

— Исполняемый патч;

— Динамически распознавать модули и строки;

— База данных пользователей (JSON) для комментариев, ярлыков, закладок и т. Д.;

— Поддержка базового отладочного символа (PDB);

— Расширяемый, отлаживаемый язык сценариев для автоматизации;

— Поддержка плагинов с растущим API;

— Базовая поддержка анти-отладки.

1.2 Продвинутые возможности

— Декомпилятор (snowman);

— Встроенный реконструктор импорта (Scylla);

— Анализ;

— Условные точки останова и трассировка с большой гибкостью;

— Сбор данных во время трассировки.

1.3 Возможности GUI

— Интуитивно понятный и знакомый, но новый пользовательский интерфейс;

— Боковая панель в стиле IDA со стрелками перехода;

— IDA-подобная подсветка токенов инструкций (выделение регистров, команд и т. д.);

— Полностью настраиваемая цветовая схема и быстрые клавиши;

— График потока управления;

— Встроенная мнемоника и реестр помощи;

— Сворачивание кода;

— Простая интеграция с пользовательскими инструментами (меню избранного).

2 Работа с отладчиком x64dbg

2.1 Внешний вид

С отладчиком x64dbg очень легко работать. На рисунке 41 приведен внешний вид с загруженной тестовой программой.

Рисунок 41 — Внешний вид x64dbg

Детальное описание каждого пункта:

— (красный) Окно дизассемблирования.

— (желтый) Окно регистров.

— (зеленый) Окно дампа.

— (синий) Окно стека.

2.1.1 Окно дизассемблирования

Рисунок 42 — Окно дизассемблирования

Данное окно показывает дизассемблирование всех инструкций отлаживаемой программы. Это окно представляет дизассемблирование в линейном режиме и синхронизируется с текущим значением регистра указателя инструкции (eip для x86 / rip для x64).

Окно дизассемблирования делится на 5 колонок:

— (красный) Графические указатели, регистровые и указатели на точку останова;

— (желтый) Виртуальные адреса памяти;

— (оранжевый) Машинный код;

— (зеленый) Дизассемблерный листинг (команды ассемблера);

— (синий) Комментарии отладчик (или наши комментарии).

2.1.2 Окно регистров

Рисунок 43 — Окно регистров

В окне регистров отображаются все 32-битные или 64-битные регистры (в зависимости от разрядности отладчика), регистры флагов и различные другие регистры. Для того, чтобы изменить регистр надо щёлкнуть по его значению 2 раза и ввести новое значение. Реверсировать регистр флага можно путём двойного щелчка по одному из них.

Приведем описание каждого типа регистров:

— (красный) — Регистры общего назначения;

— (оранжевый) — Дополнительные регистры общего назначения;

— (желтый) — RIP регистр (показывает виртуальный адрес следующей выполняемой программы);

— (зеленый) — Регистры флагов и значений каждого флага;

— (голубой) — Указатели на SEH (Structured Exception Handling);

— (синий) — Сегментные регистры;

— (фиолетовый) — FPU (Floating Point Unit) регистры;

— (коричневый) — Регистры тегов сопроцессора;

— (розовый) — Регистры управления сопроцессором;

— (охра) — Регистры состояния сопроцессора;

— (пурпурный) — регистр управления/статуса SIMD (single instruction, multiple data) и состояния используемых флагов;

— (светло зеленый) — Регистры блока XMM;

— (лазурный) — Регистры блока YMM;

— (ультрамарин) — Отладочные регистры.

2.1.3 Окно дампа

Рисунок 44 — Окно дампа

Данное окно отображает стандартный шестнадцатеричный дамп памяти. Можно использовать окно дампа для проверки содержимого любого действительного адреса памяти в отлаженном процессе. Форму представления данных можно менять, нажав правой кнопкой мыши на окно и выбрав нужный тип представления.

Описание колонок:

— (красный) — Виртуальный адрес программы в оперативной памяти;

— (оранжевый) — Данные в формате HEX;

— (желтый) — Данные в формате ASCII.

2.1.4 Окно стека

Рисунок 45 — Окно стека

В данном окне отображается содержимое стэка по мере выполнения программы. В стэк могут помещаться как адреса, так и какие-то строковые, числовые значения и другие значения. Аргументы функций также помещаются в стэк перед вызовом самой функции. Некоторые упаковщики кладут в стэк адрес на OEP (оригинальную точку входа).

Описание колонок:

— (красный) — Виртуальный адрес;

— (оранжевый) — Данные, расположенные по виртуальному адресу;

— (желтый) — Комментарии.

2.2 Главное меню

2.2.1 Меню File

Рисунок 46 — Меню File

Меню файла содержит следующие подменю:

— Open. Действие Open позволяет открыть исполняемый файл для его отладки. Это может быть EXE-файл или DLL-файл. (Команда для этого действия — InitDebug / initdbg / init)

— Recent Files. Подменю «Recent Files» содержит несколько ранее отлаженных записей. Оно не включает файлы, которые не могут быть отлажены программой. Записи для этого подменю можно найти в разделе «Recent Files» INI-файла конфигурации. Данный файл можно редактировать, чтобы удалить записи.

— Attach. Attach позволяет подключаться к запущенному процессу. Он покажет диалоговое окно со списком запущенных процессов и позволит выбрать один из них для присоединения. В настоящее время можо подключаться только к исполняемому файлу той же архитектуры, что и программа. (например, мы не можем подключиться к 64-битному процессу с помощью x32dbg). Если какой-либо исполняемый файл в данный момент отлаживается, то присоединение к другому процессу завершит работу предыдущей отлаживаемой программы. (Команда для этого действия — AttachDebugger / attach)

— Detach. Это действие отключает отладчик от отлаживаемого процесса, позволяя отладчику работать без управления. Это действие невозможно выполнить, если отладка исполняемого файла не запущена. (Команда для этого действия — DetachDebugger / detach)

— Import database. Данное действие позволяет импортировать базу данных. (Соответствующая команда для этого действия — dbload / loaddb)

— Export database. Данное действие позволяет экспортировать несжатую базу данных. (Команда для этого действия — dbsave / savedb)

— Patch File. Открывает диалог патча. Мы можем просмотреть свои патчи и применить их к файлу в диалоговом окне.

— Change Command Line. Отображение текущих аргументов командной строки отлаживаемой программы в диалоговом окне и возможность их изменения. Аргументы командной строки будут сохранены в базе данных для дальнейшего использования.

— Restart as Admin. Перезапуск x64dbg и текущий отладчик с правами администратора.

— Exit. Завершение отладчика. Если какой-либо процесс отлаживается этой программой, он также будет остановлен.

2.2.2 Меню Views

Рисунок 47 — Меню View

Меню Views будет рассмотрено в пункте 2.3

2.2.3 Меню Debug

Рисунок 48 — Меню Debug

Это меню содержит действия, показанные на рисунке 48. Мы не можем использовать какие-либо из этих пунктов меню, кроме «Restart», когда не отлаживаем.

— Run. Освобождает блокировку и позволяет программе запуститься. (Команда для этого действия — run / go / r / g)

— Run until selection. Освобождает блокировку и позволяет программе работать, пока не встретится первая точка останова.

— Pause. Попытка приостановить отлаживаемую программу, когда она запущена, или попытка остановить анимацию. (Команда для этого действия — pause)

— Restart. Выполняет команду InitDebug / initdbg / init с самым последним использованным файлом.

— Close. Завершает текущую отлаживаемую программу и прекращфет ее отладку. (Команда для этого действия — StopDebug / stop / dbgstop)

— Step into. Выполняет шаг отладки, используя Trap-Flag. (Команда для этого действия — StepInto / sti)

— Step over. Когда инструкция EIP / RIP не является вызовом, выполняется StepInto, иначе программа продолжает отладку до тех пор, пока не покинет вызываемую функцию. (Команда для этого действия — StepOver / step / sto / st)

— Execute till return. Переходит по инструкциям, пока текущая инструкция, на которую указывает EIP или RIP, не станет инструкцией ret. (Команда для этого действия — StepOut / rtr)

— Run to User Code. Запуск отладчика, пока не будет достигнут код пользователя. Эквивалентно RunToParty 0. (Команда для этого действия — RunToUserCode/rtu)

Подменю Advanced содержит немного расширенные функции, описанные выше, поэтому их описание не приводится.

2.2.4 Меню Trace

Рисунок 49 — Меню Trace

Это меню содержит действия, показанные на рисунке 49. Ни один из пунктов не будет работать, если не запущена отладка.

— Animate into. Выполнение команды StepInto / sti автоматически с постоянной частотой.

— Animate over. Автоматическое выполнение команды StepOver / step / sto / st с постоянной частотой.

— Animate Command. Открывает диалоговое окно для ввода команды и выполняет ее с постоянной частотой.

— Trace into. Вводим выражение. Отладчик выполняет команду StepInto, пока не будет выполнено указанное условие или пока не будет достигнуто максимальное количество шагов.

— Trace over. Вводим выражение. Отладчик выполняет команду StepOver, пока не будет выполнено указанное условие или пока не будет достигнуто максимальное количество шагов.

Остальные пункты данного меню узконаправлены, а поэтому было принято решение их не описывать.

2.2.5 Меню Plugins

Рисунок 50 — Меню Plugins

Это меню включает в себя все доступные меню плагинов. Когда плагин устанавливается, то он может зарегистрироваться в этом меню. Мы можем обратиться к документации плагина для получения дополнительной информации.

2.2.6 Меню Favourites

Рисунок 51 — Меню Favourites

Это меню можно настроить. Когда мы нажимаем пункт меню «Manage Favourite Tools», появляется диалоговое окно. Мы можем добавлять в меню свои собственные инструменты, а также назначать им горячие клавиши. По умолчанию путь к инструменту или скрипту будет отображаться в меню, но если мы зададим его описание, оно будет отображаться в меню.

— Если добавить %PID% в командную строку инструмента, он будет заменен (десятичным) PID отлаживаемого кода (или 0, если не отлаживается).

— Если добавить %DEBUGGEE%, он добавит (без кавычек) полный путь отлаживаемого объекта.

— Если добавить %MODULE%, он добавит (без кавычек) полный путь к модулю, который сейчас находится в дизассемблированном виде.

— Если добавить %-???? -% он выполнит форматирование строки для всего, что помещено вместо»????». Пример: %- {cip} -% будет заменено шестнадцатеричным значением cip.

В настоящее время в это меню можно вставить три типа записей: Инструмент, Сценарий и Команда.

2.2.7 Меню Options

Рисунок 52 — Меню Options

Меню опций содержит следующие записи:

— Preferences. Показать диалог настроек. Можно изменять различные настройки в диалоговом окне.

— Appearance. Показать диалог Appearance. Можно настроить цветовую схему или шрифт в диалоговом окне.

— Shortcuts. Показать диалог shortcuts. Можно настроить сочетания клавиш для большинства операций.

— Customize menus. Показать диалог «Customize menus». Можно щелкнуть по узлам, чтобы развернуть соответствующее меню и установить или снять отметку с пунктов меню. Отмеченный пункт появится в разделе «Дополнительные команды» меню, чтобы сократить отображаемое меню. Можно убрать все пункты меню, которые не используются.

— Topmost. Фиксирует главное окно над другими окнами (или перестаньте это делать).

— Reload style. css. Если этот файл присутствует, будет применена новая цветовая схема, указанная в этом файле.

— Set Initialization Script. Установите сценарий инициализации глобально или для отлаживаемого приложения. Если указан глобальный сценарий инициализации, он будет выполняться, когда программа находится в системной точке останова или точке останова присоединения для каждого отлаживаемого кода. Если указан сценарий инициализации для каждого отлаживаемого объекта, он будет выполнен после завершения глобального сценария инициализации. Можено очистить настройку скрипта, очистив путь к файлу и щелкнув «OK» в диалоговом окне просмотра.

— Import settings. Импортировать настройки из другого файла конфигурации. Соответствующие записи в файле конфигурации переопределят текущую конфигурацию, но отсутствующие записи останутся неизменными.

— Theme. Выбор внешнего вида отладчика.

— Languages. Разрешить выбирать язык для программы. «Американский английский — Соединенные Штаты» — родной язык программы.

2.2.8 Меню Help

Рисунок 53 — Меню Help

— Calculator. Показывает калькулятор, который может выполнять оценку выражений, преобразование шестнадцатеричного числа в десятичное и многое другое.

— Check for Updates. Подключение к серверу, чтобы узнать, доступна ли обновленная версия этого программного обеспечения.

— Blog. Посещение официальный блог.

— Donate. Сделать пожертвование команде разработчиков.

— Report Bug. Сообщить об ошибке в этом программном обеспечении.

— Manual. Открыть руководство пользователя.

— FAQ. Посмотреть решение часто задаваемых вопросов.

— About. Информация об этом программном обеспечении.

— Generate crash dump. Создать исключение для создания аварийного дампа. Это может помочь, если программное обеспечение зависнет. Можное отправить этот аварийный дамп команде разработчиков, чтобы они помогли исправить ошибку.

2.3 Views

В данном пункте приведено описание некоторых пунктов меню View/

2.3.1 CPU

Рисунок 54 — Вид CPU

Этот вид является основным. Он включает в себя представление регистров, представление разборки, представление дампа и представление часов, представление стека и информационное окно.

2.3.2 Graph

Рисунок 55 — Вид Graph

Представление Graph содержит граф потока управления. Когда мы используем команду graph или контекстное меню (горячая клавиша G по умолчанию), отображается граф потока управления.

Есть два режима отображения графа потока управления: нормальный режим и режим обзора.

В режиме обзора программа будет рисовать весь граф потока управления в области окна, но не выводить дизассемблированный код. Когда выполняется трассировка первой инструкции, когда на этой странице памяти включена запись трассировки, весь базовый блок будет показан другим цветом (по умолчанию — зеленый).

Представление графа теперь является частью представления ЦП.

2.3.3 Log

Рисунок 56 — Вид Log

Это представление включает все сообщения журнала. Когда адрес выводится в сообщении журнала, он отображается в виде гиперссылки. Можно щелкнуть по нему, чтобы просмотреть его в разборке или в дампе, в зависимости от его прав доступа к памяти.

Рисунок 57 — Контекстное меню Log

В представлении журнала есть следующее контекстное меню:

— Clear. Очистить представление журнала.

— Select All. Выделить весь текст журнала.

— Copy. Скопировать выделенный текст.

— Save. Сохранить журнал в текстовый файл.

— Copy To Notes. Скопировать выделенный текст в глобальные заметке или заметки отлаживаемой программы.

— Disable Logging / Enable Logging. Отключает или включает вывод журнала. Когда ведение журнала отключено, в журнал больше не выводятся сообщения.

— Auto Scrolling. Включает или отключает автопрокрутку. Если этот параметр включен, представление журнала будет прокручиваться вниз по мере поступления новых сообщений журнала.

— Redirect Log. Перенаправить сообщение журнала в файл. Если включить эту функцию, все сообщения будут сохраняться в текстовом файле в кодировке UTF-16. Сообщение будет сохранено в текстовый файл независимо от того, включено ли ведение журнала.

2.3.4 Notes

Рисунок 58 — Вид Notes

В представлении «Notes» есть два текстовых поля для редактирования, одно глобальное и одно для отлаживаемого приложения. Любой введенный здесь текст будет сохранен и будет восстановлен в будущих сеансах отладки, чтобы пользователь мог удобно делать заметки. Глобальные заметки будут храниться в файле «notes. txt» в рабочем каталоге. Примечания отладчика будут храниться в базе данных отладки.

Нельзя редактировать заметки для каждого отлаживаемого приложения, пока не запущена отладка.

2.3.5 Call Stack

Рисунок 59 — Вид Call Stack

В представлении Call Stack отображается стек вызовов текущего потока. В нем 6 столбцов.

— (красный) Address — это базовый адрес кадра стек:

— (оранжевый) To — это адрес кода, на который нужно вернуться:

— (желтый) From — вероятный адрес процедуры, которая будет возвращена;

— (зеленый) Size — это размер кадра стека вызовов в байтах;

— (голубой) Comment — это краткое описание кадра стека вызовов;

— (синий) Party — описывает, является ли процедура, к которой нужно вернуться, пользовательским или системным модулем.

Когда активна опция «Show Suspended Call Stack Frame» в контекстном меню в представлении стека вызовов, он будет искать возможные адреса возврата по всему стеку. Когда он неактивен, он будет использовать стандартный алгоритм обхода стека для получения стека вызовов. Обычно он дает больше результатов, когда активна опция «Show Suspended Call Stack Frame», но некоторые из них могут не быть фактическими кадрами стека вызовов.

Заключение

При выполнении работы на практике был рассмотрен и изучен многофункциональный отладчик x64dbg, проведен обзор его основных функций. С помощью данного отладчика возможна отладка 64-битных приложений на базе операционной системой Windows.

По итогам работы были выполнены следующие задания:

— Описан функционал отладчика x64dbg;

— Рассмотрены возможности отладчика x64dbg;

— Сделан вывод по результатам проведенной работы.

По итогам работы были выявлены следующие основные отличия от OllyDbg:

— Имеется возможность построить граф вызовов, не устанавливая дополнительных плагинов.

— Возможность добавления собственных сторонних инструментов и скриптов через меню Favourites> Manage Favourite Tools.

— Есть возможность импорта и экспорта базы данных настроек и отлаживаемых проектов.

— Присутствует больше возможностей для отладки приложений, благодаря командам в подменю Debug> Advanced.

— Есть возможность мониторить TCP-соединения, открываемые отлаживающимся приложением.

ЛАБОРАТОРНАЯ РАБОТА №3

Тема: IDA Free

Описать функционал приложения по отладке программного обеспечения. Обязательно подробно описать одну из функций, не пересекаясь с другими студентами из группы по описываемой функции.

Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №3

Интерактивный дизассемблер IDA Freeware

Введение

Цель работы: рассмотреть функционал интерактивного дизассемблера IDA Pro Freeware и выполнить его детальное описание.

Для выполнения цели поставлен ряд задач:

— Описать функционал интерактивного дизассемблера IDA Freeware;

— Рассмотреть возможности интерактивного дизассемблера IDA Freeware;

— Сделать вывод по результатам проведенной работы.

1 Описание

IDA Pro Disassembler (Interactive DisAssembler) — интерактивный дизассемблер, который широко используется для реверс-инжиниринга. Он отличается исключительной гибкостью, наличием встроенного командного языка, поддерживает множество форматов исполняемых файлов для большого числа процессоров и операционных систем.

Позволяет строить блок-схемы, изменять названия меток, просматривать локальные процедуры в стеке и многое другое. В последних версиях имеет встроенный отладчик x86 и ARM.

IDA, до определенной степени, умеет автоматически выполнять анализ кода, используя перекрестные ссылки, знание параметров вызовов функций стандартных библиотек, и другую информацию. Однако вся сила его проявляется в интерактивном взаимодействии с пользователем. В начале исследования дизассемблер выполняет автоматический анализ программы, а затем пользователь с помощью интерактивных средств IDA начинает давать осмысленные имена, комментировать, создавать сложные структуры данных и другим образом добавлять информацию в листинг, генерируемый дизассемблером, пока не станет ясно, что именно и как делает исследуемая программа.

Дизассемблер имеет консольную и графическую версии. Поддерживает большое количество форматов исполняемых файлов. Одной из отличительных особенностей IDA Pro является возможность дизассемблирования байт-кода виртуальных машин Java и. NET. Также поддерживает макросы, плагины и скрипты, а последние версии содержат интегрированный отладчик.

Существует несколько версий IDA Pro — бесплатная (freeware), стандартная (standard) и расширенная (advanced). Бесплатная версия обладает ограниченными возможностями по сравнению со стандартной и расширенной версиями — поддерживается только архитектура x86 и отсутствует поддержка подключаемых модулей.

2 Работа с интерактивным дизассемблером IDA Pro

2.1 Начало работы

В данной работе рассматривается версия IDA Pro Freeware, в которой, как упоминалось ранее, присутствуют некоторые ограничения. Первым делом выберем программ для дизассемблирования и откроем ее в IDA Pro (рисунок 60).

Рисунок 60 — Загрузка файла в IDA Pro

В данном меню мы выбираем в каком формате загрузить исследуемую программу. В нашем случае присутствует 2 варианта: бинарный и совместимый с процессором 80386. Так же можем явно выбрать тип процессора, на котором программа будет запущена.

Теперь разберем некоторые флаги секции Options:

— Create FLAT group — данная опция означает, что сегментные регистры будут использовать flat имена, вместо реальных сегментных имен. Помимо этого, так же создается группа, которая будет отображать flat память.

— Load resources — данная опция включает сегмент. rsrc в дизассемблерный листинг.

— Manual Load — данная опция позволяет задать базовый адрес образа и предупреждает пользователя, перед включением это секции в дизассемблерный листинг. Она также позволяет нам выделить необычные или переименованные секции.

Поставим галочки напротив всех, описанных выше опций и запустим IDA Pro. После того, как вы прокликали везде далее мы попадаем на главный экран.

2.2 Главный экран

Рисунок 61 — Главный экран

Разберем все основные области главного экрана:

— (красный) Полное представление графа выполнения программы (в данный момент там изображен белый квадрат, так как данная часть исполняемой программы содержит только один исполняемый узел).

— (оранжевый) Перечень всех имен функций, которые смог обнаружить дизассемблер.

— (желтый) Основное окно, в котором отображается основная информация об отлаживающей программе (в данный момент — укрупненный граф выполнения).

— (зеленый) Консольная строка, показывающая сообщения, генерируемые IDA Pro и строка ввода команд.

— (голубой) Разметка отлаживаемой программы по секторам (каждый сектор имеет свои цвет, легенда расположена ниже).

2.3 Виды представления

Над основным окном присутствуем множество вкладок, каждая из которых показывает новый данные об дизассемблированной программе.

2.3.1 IDA View-A

Основное представление, показывающее граф выполнения и ассемблерный код.

2.3.2 Hex View-1

Рисунок 62 — Представление Hex View-1

Данное представление выводит все символы программы в Hex-кодах.

2.3.3 Structures

Рисунок 63 — Представление Structures

В данном представлении приведен перечень структур, с которыми работает дизассемблированная программа.

2.3.4 Enums

Рисунок 64 — Представление Enums

Данное представление выводит все перечисления, присутствующие в программе.

2.3.5 Imports

Рисунок 65 — Представление Imports

В данном представлении приведены адреса импортируемых функций, их названия, а также название импортируемой библиотеки.

2.3.6 Exports

Рисунок 66 — Представление Exports

В данном представлении приведены названия экспортируемых функций, их адреса, а также функции, из которых они экспортируются.

2.4 Меню

Рассмотрим более подробно пункты меню.

2.4.1 Меню File

Рисунок 67 — Меню File

Рассмотрим все пункты меню:

— New instance — Запустить заново IDA Pro;

— Open — Открыть файл для дизассемблирования;

— Load file — Загрузка файлов в разных форматах;

— Produce file — Сгенерировать файл, на основе открытого в редакторе;

— Script file — Загрузка файла скрипта для IDA Pro;

— Script command — диалоговое окно, в котором вводятся скрипы для IDA Pro;

— Save — Быстрое сохранение;

— Save as — Новое сохранение;

— Take database snapshot — Сделать снимок базы данных;

— Close — Закрыть;

— Quick start — Новый запуск IDA Pro;

— Exit — Выход из программы.

2.4.2 Меню Edit

Рисунок 68 — Меню Edit

Рассмотрим все пункты меню:

— Copy — Копировать выделение;

— Begin selection — Начать выделение (аналог зажатой кнопки Shift);

— Select all — Выделение всего;

— Select identifier — Выделить идентификатор, если на него наведен курсор;

— Export data — экспортировать выделенные данные в нужно формате в файл;

— Code — Преобразовать выделенный блок в код;

— Data — Преобразовать выделенный блок в данные;

— Struct var — Преобразование выделенного блока, в дну из структур, обнаруженных при анализе кода приложения;

— Strings — Преобразовать выделенные данные в строку;

— Array — Преобразовать выделенные данные в массив байт;

— Undefine — Отменить выполненное преобразование;

— Rename — Переименовать выделенную строку;

— Operand Type — Перевести выделенный фрагмент в другую систему счисления;

— Comments — Вставка комментария;

— Segments — Работа с сегментами (создание и редактирование сегментов кода);

— Structs — работа со структурами;

— Functions — Работа с функциями;

— Patch program — Произвести патч программы;

2.4.3 Меню Jump

Рисунок 69 — Меню Jump

Команды в данном меню аналогичны командам из отладчиков, а потому рассматриваться не будут.

2.4.4 Меню Search

Рисунок 70 — Меню Search

Рассмотрим все пункты меню:

— Next code — Переход к следующей строке кода;

— Next data — Переход к следующим данным;

— Next explored — Переход к следующей видимой команде;

— Next unexplored — Переход с следующей неисследованной команде;

— Immediate value — Переход к следующему введенному значению;

— Next immediate value — Переход к следующему значению, равному выделенному;

— Text — Поиск текста;

— Next text — Поиск следующего вхождения выделенного текста;

— Sequence of bytes — Поиск следующей последовательности введенных байт;

— Next sequence of bytes — Переход к следующей последовательности байт, равной выделенной;

— Next function — Переход к следующей строке выполнения;

— Next void — Переход к следующей пустой команде;

— Error operand — Переход к следующей ошибке в исходном коде;

— All void operands — Показать все вхождения пустых команд;

— All error operands — Показать все вхождения ошибок исходного кода;

— Search direction — Смена направления поиска.

2.4.5 Меню View

Рисунок 71 — Меню View

Основные элементы данного меню описывались в главе 3.

2.4.6 Меню Debugger

Рисунок 72 — Меню Debugger

Команды в данном меню аналогичны командам из отладчиков, а потому рассматриваться не будут.

2.4.7 Меню Options

Рисунок 73 — Меню Options

В данном меню приведены опции программы, отвечающие в основном за визуальное оформление.

2.4.8 Меню Windows

Рисунок 74 — Меню Windows

Данное меню отвечает за визуальное представление окон на главном экране.

2.4.9 Меню Help

Рисунок 75 — Меню Help

В данном меню приведена справка по IDA Pro.

Заключение

При выполнении работы на практике был рассмотрен и изучен многофункциональный интерактивный дизассемблер IDA Pro Freeware и проведен обзор его основных функций. С помощью данного интерактивного дизассемблера возможна отладка исполняемых приложений на базе операционной системы Windows.

По итогам работы были выполнены следующие задания:

— Описан функционал интерактивного дизассемблера IDA Freeware;

— Рассмотрены возможности интерактивного дизассемблера IDA Freeware;

— Сделан вывод по результатам проведенной работы.

ЛАБОРАТОРНАЯ РАБОТА №4

ЗАДАНИЕ ПО ВАРИАНТАМ

1. Изменить 1 байт продемонстрировать что программа приняла серийный номер.

2. Изменить ключевой условный переход

3. Изменить ключевой безусловный переход

4. Описать процесс формирования серийного номера.

5. Описать процесс распаковки серийного номера.

6. Изменить 2 байта продемонстрировать что программа приняла серийный номер

7. Построить граф работы программы

8. Исследовать и определить длины серийного номера, имени

9. Исследовать и определить адерса имени и серийного номера

10. Изменить произвольное количество байт (более 2), продемонстрировать что программа приняла серийный номер

11. Определить константы для упаковки серийного номера

12. Определить ключевые участки кода ответственные за упаковку серийного номера.

13. Определить константы для распаковки серийного номера

14. Определить константы для распаковки серийного номера


15.* Получить действительную пару имя, серийный номер (это задание может сделать любой если затрудняется сделать свой вариант)

16.* Написать патч для приложения (это задание может сделать любой если затрудняется сделать свой вариант)

17.** Написать кейген для приложения (это задание может сделать любой если затрудняется сделать свой вариант).


Задания с одной звездой это средний уровень.

Задание с двумя звездами это высокий уровень.

Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №4

Реверс d2k2_crackme01.exe

Введение

Цель работы: Произвести обратную разработку программы d2k2_crackme01.exe.

Для выполнения цели поставлен ряд задач:

— Разобраться в структуре программы d2k2_crackme01.exe;

— Построить граф работы программы;

— Написать кейген для приложения;

— Сделать вывод по результатам проведенной работы.

1 Знакомство с программой

Запустим программу d2k2_crackme01.exe (в дальнейшем программу) и посмотрим, что она из себя представляет (рисунок 76).

Рисунок 76 — Внешний вид программы

Как можно заметить, мы имеем дело с графическим приложением. Давайте попробуем ввести имя «Админ» и серийный номер «1234» и посмотрим на ответ (рисунок 77).

Рисунок 77 — Неверное имя пользователя и серийный номер

Мы не угадали. Давайте посмотрим на разрядность программы. Для этого откроем ее в Hex-редакторе и обратим внимание на смещение 0xB0 (рисунок 78).

Рисунок 78 — Вид программы в Hex-редакторе

Данная программа 32-х битная. Откроем ее в IDA Pro Freeware и начнем изучение.

2 Изучение программы в IDA Pro

2.1 Первый взгляд

После того, как мы открыли программу в IDA Pro, то попали в функцию start. Она нас особо не интересует. Мы знаем вывод при неправильном вводе, давайте попробуем найти его в программе (рисунки 79—80).

Рисунок 79 — Параметры поиска


Рисунок 80 — Результат поиска

Мы нашли код, который выполняется при неверном вводе данных. Давайте посмотрим на полный граф выполнения (рисунок 81).

Рисунок 81 — Граф работы программы

Давайте определим какой путь выполнения нужен для успешного ввода кода. Для этого попытаемся найти что-то, похожее на строку успеха (рисунок 82).

Рисунок 82 — Корректное завершение программы

2.2 Разбор алгоритма

Перейдем к началу функции и попробуем восстановить алгоритм проверки пары «Имя — Серийный номер». Когда пользователь нажимает кнопку Try, то управление передается на инструкции, приведенные на рисунке 83.

Рисунок 83 — Действия, после нажатия кнопки Try

В этом блоке кода вызывается функция GetDlgItemA с параметрами hDlg, nIDDlgItem, lpString, cchMax (согласно конвекции, параметры передаются функции через стек, причем в обратном порядке). Рассмотрим передаваемые параметры более подробно:

— cch — максимальное количество символов в строке (в нашем случае оно равно 0x28 = 40 символов);

— lpString — адрес буфера, в который запишется введенная строка (для удобства переименуем в pName);

— nIDDlgItem — дескриптор виджет, из которого получаем текст (в нашем случае строка ввода имени);

— hDlg — дескриптор диалогового окна, содержащего виджет.

Далее идет проверка, возвращаемого значения на 0, и если количество введенных символов равно 0, то мы переходи к коду, представленному на рисунке 84.

Рисунок 84 — Выполнение программы, если имя содержит 0 символов

Таким образом, можно сделать вывод, что поле ввода имени не должно быть пустым. Пройдем далее по ходу выполнения алгоритма (рисунок 85).

Рисунок 85 — Продолжение алгоритма

Мы видим, что если al строго больше 0x20 = 32 (число символов в имени), то выполнение переходит по адресу loc_40137C (рисунок 86).

Рисунок 86 — Имя превышает 32 символа

Таким образом, на данный момент мы знаем, что наше имя не должно быть пустым и должно содержать не более 32 символов. Продолжаем анализ (рисунок 87).

Рисунок 87 — Продолжение алгоритма

Мы видим, что если al строго меньше 0x05 = 5 (число символов в имени), то выполнение переходит по адресу loc_401391 (рисунок 88).

Рисунок 88 — Имя имеет длину от 1 до 4

Теперь мы знаем, что имя может иметь длину в диапазоне от 5 до 32 символов. Смотрим далее (рисунок 89).

Рисунок 89 — Продолжение алгоритма

Теперь в регистр ebx загружается адрес введеного нами имени, значение в регистре ecx зануляется, регистру al присваивается значение 5 (раньше там хранилась длина имени) и зануляется edx. Пока ничего интересного идем дальше (рисунок 90).

Рисунок 90 — Продолжение алгоритма

Теперь мы работам с циклом. Из последнего блока цикла (а именно из команд dec al, cmp al, 0, jz …) можем сделать вывод, что он работает столько раз, сколько указано в al, т.е. 5 раз.

На каждом шаге цикла в регистр cl записывается очередное значение по адресу [pName + edx], т.е. очередной байт из введенного имени, производится сложение по модулю 2 с числом 0x29 = 41 и сравнивается с числом 0x41 = 65.

Если полученное значение больше, либо равно данному, то оно далее сравнивается с числом 0x5a = 90. И если меньше или равно ему, то выполнение переходит по адресу loc_40128f.

В любом другом случае вместо данного числа в регистр cl записывается значение 0x52 = 82. После этого к нему добавляется значение al (5 минус порядковый номер символа, считая с 0) и управление передается по адресу loc_40128f.

Далее по адресу byte_40313c [edx] (переименуем в pResultOne) записывается полученное значение из регистра cl, а по адресу byte_40313d [edx] записывается 0, после чего значение в регистре edx увеличивается на 1, в регистре al уменьшается на 1 и происходит проверка выхода из цикла.

Как только обработаны первые 5 байт введенного имени, то значение в регистре edx обнуляется, а в регистр eax записывается 5 и программа продолжает работу далее (рисунок 91).

Рисунок 91 — Продолжение алгоритма

Очередной цикл. Из последнего блока цикла снова делаем вывод, что он работает 5 раз.

На каждом шаге цикла в регистр cl записывается очередное значение по адресу [pName + edx], т.е. очередной байт из введенного имени, производится сложение по модулю 2 с числом 0x27 = 39, после чего к полученному значению прибавляется значение al (5 минус порядковый номер символа, считая с 0), потом увеличиваем результат на 1 и сравниваем с числом 0x41 = 65.

Если полученное значение больше, либо равно данному, то оно далее сравнивается с числом 0x5a = 90. И если меньше или равно ему, то выполнение переходит по адресу loc_4012c8.

В любом другом случае вместо данного числа в регистр cl записывается значение 0x4d = 77. После этого к нему добавляется значение al (5 минус порядковый номер символа, считая с 0) и управление передается по адресу loc_40128f.

Далее по адресу byte_403142 [edx] (переименуем в pResultTwo) записывается полученное значение из регистра cl, а по адресу byte_403142 [edx] записывается 0, после чего значение в регистре edx увеличивается на 1, в регистре al уменьшается на 1 и происходит проверка выхода из цикла.

Как только обработаны первые 5 байт введенного имени, то снова вызывается функция GetDlgItemA, с теми же параметрами, что и ранее, только с номером виджета, равным 4 (id для виджета ввода серийного номера) и снова производится проверка на то, равна ли длина введенной строки 0.

Если она равна 0, то управление передается по адресу loc_401352 (рисунок 92).

Рисунок 92 — Длина введенного серийного номера равна 0

Если серийный номер не равен 0, то управление передается далее (рисунок 93).

Рисунок 93 — Продолжение алгоритма

Здесь сначала происходит проверка на то, чтобы длина не была больше 0x0a = 10, а затем и меньше этого значения, иначе управление передается на команды из рисунка 2.14. То есть, получается, что длина серийного номера всегда равно 10. Продолжаем анализ (рисунок 94).

Рисунок 94 — Продолжение алгоритма

Теперь обнуляются регистры eax, ebx, ecx и edx, а в регистр eax записывается адрес буфера с серийным номером. После этого в регистр bl, загружается первый байт серийного номера, в регистр dl — первый байт результата из первого цикла, после чего значение первого символа серийного номера сравнивается с 0, и если это условие выполнилось, то выполнение переходит по адресу loc_4013a6 (рисунок 95).

Рисунок 95 — Выполнение алгоритма, если первый байт серийного номера равен 0

Как видим, это то, что мы хотим. Однако не существует печатного символа с кодом 0, поэтому придется разобрать оставшуюся часть алгоритма (рисунок 96).

Рисунок 96 — Продолжение алгоритма

К значению dl добавляется 5 и оно сравнивается с 0x5a = 90. Если полученное значение строго больше, то выполнение передается по адресу loc_401341, иначе из dl вычитаем 0x0d = 14.

После этого складываем dl по модулю 2 с 0x0c = 12 и сравниваем с 0x41 = 65.

Если полученное значение меньше, то dl присваиваем 0x4b = 75, добавляем значение из cl и переходим по адресу loc_40133a.

Иначе сравниваем dl с 0x5a = 90 и если оно меньше, либо равно, то dl присваиваем 0x4b = 75, вычитаем значение из cl и переходим по адресу loc_40133a.

Увеличиваем значение ecx на 1, сравниваем dl и bl и если они не равны, то получаем вывод как на рисунке 2.14, а иначе повторяем все действия с момента на рисунке 2.17.

Таким образом обобщим информацию, которую мы имеем:

— Имя должно содержать от 5 до 32 символов;

— В первом цикле for для получения массива pResultOne участвуют всегда только первые 5 байт имени;

— Во втором цикле for для получения массива pResultTwo участвуют всегда только первые 5 байт имени;

— Серийный номер содержит ровно 10 символов;

— Последняя часть алгоритма представляет из себя цикл while и работает до тех пор, пока не обработает все байты серийного номера и значений из массивов pResultOne и pResultTwo. При этом после очередного цикла while значение очередного байта серийного номера не должно быть равно очередному преобразованному байту из массива pResultOne и pResultTwo.

Напишем Keygen, который всегда будет генерировать правильные значения пары «Имя — Серийный номер». Результат работы Keygen’а представлен на рисунках 97—98.

Рисунок 97 — Результат работы Keygen. exe


Рисунок 98 — Пара «Имя — Серийный номер» принята программой

Заключение

При выполнении работы на практике была произведена обратная разработка программы d2k2_crackme01.exe при помощи интерактивного дизассемблеро IDA Pro Freeware.

По итогам работы были выполнены следующие задания:

— Разобрался в структуре программы d2k2_crackme01.exe;

— Построил граф работы программы;

— Написал кейген для приложения;

— Сделал вывод по результатам проведенной работы.

ПРИЛОЖЕНИЕ А

Исходный код Keygen

Листинг 1 — Исходный код Keygen на C++

ЛАБОРАТОРНАЯ РАБОТА №5

Тема: Лаборатории Касперского (ЗАДАНИЕ ПО ВАРИАНТАМ)

1. Изменить 1 байт продемонстрировать что программа приняла серийный номер.

2. Изменить ключевой условный переход

3. Изменить ключевой безусловный переход

4. Описать процесс формирования серийного номера.

5. Описать процесс распаковки серийного номера.

6. Изменить 2 байта продемонстрировать что программа приняла серийный номер

7. Построить граф работы программы

8. Исследовать и определить длины серийного номера, имени

9. Исследовать и определить адерса имени и серийного номера

10. Изменить произвольное количество байт (более 2), продемонстрировать что программа приняла серийный номер

11. Определить константы для упаковки серийного номера

12. Определить ключевые участки кода ответственные за упаковку серийного номера.

13. Определить константы для распаковки серийного номера

14. Определить константы для распаковки серийного номера


15.* Получить действительную пару имя, серийный номер (это задание может сделать любой если затрудняется сделать свой вариант)

16.* Написать патч для приложения (это задание может сделать любой если затрудняется сделать свой вариант)

17.** Написать кейген для приложения (это задание может сделать любой если затрудняется сделать свой вариант).


Задания с одной звездочкой это средний уровень.

Задание с двумя звездами это высокий уровень.

Пример выполнения ЛАБОРАТОРНАЯ РАБОТА №5

Реверс CrackMe от Лаборатории Касперского

Введение

Цель работы: произвести обратную разработку программы crackme01_x64.exe.

Для выполнения цели поставлен ряд задач:

— Разобраться в структуре программы crackme01_x64.exe;

— Построить граф работы программы;

— Написать кейген для приложения;

— Сделать вывод по результатам проведенной работы.

1 Знакомство с программой

Запустим программу crackme01_x64.exe (в дальнейшем программу) и посмотрим, что она из себя представляет (рисунок 99).

Рисунок 99 — Внешний вид программы

Как можно заметить, мы имеем дело с графическим приложением. Давайте попробуем ввести серийный номер «1234» и посмотрим на ответ (рисунок 100).

Рисунок 100 — Неверный серийный номер

Мы не угадали. Давайте посмотрим на разрядность программы. Для этого откроем ее в Hex-редакторе и обратим внимание на смещение 0xD8 (рисунок 101).

Рисунок 101 — Вид программы в Hex-редакторе

Данная программа 64-х битная. Откроем ее в IDA Pro Freeware и начнем изучение.

2 Изучение программы в IDA Pro

2.1 Первый взгляд

После того, как мы открыли программу в IDA Pro, то попали в функцию start. Она нас особо не интересует. Мы знаем вывод при неправильном вводе, давайте попробуем найти его в программе (рисунки 102—103).

Рисунок 102 — Параметры поиска


Рисунок 103 — Результат поиска

Мы нашли код, который выполняется при неверном вводе данных. Давайте посмотрим на полный граф выполнения (рисунок 104).

Рисунок 104 — Граф работы программы

Давайте определим какой путь выполнения нужен для успешного ввода кода. Для этого попытаемся найти что-то, похожее на строку успеха (рисунок 105).

Рисунок 105 — Корректное завершение программы

2.2 Разбор алгоритма

Перейдем к началу функции и попробуем восстановить алгоритм проверки серийного номера. Когда пользователь нажимает кнопку Check, то управление передается на инструкции, приведенные на рисунке 106.

Рисунок 106 — Действия, после нажатия кнопки Try

В этом блоке кода вызывается функция GetDlgItemTextA с параметрами hDlg, nIDDlgItem, lpString, cchMax (согласно конвенции, параметры передаются функции через регистры, причем сначала заполняются регистры RCX, RDX, R8, R9 для целых чисел, а после заполняется стек https://docs.microsoft.com/ru-ru/cpp/build/x64-calling-convention?view=vs-2019#parameter-passing). Рассмотрим передаваемые параметры более подробно:

— cchMax — максимальное количество символов в строке (в нашем случае оно равно 0x40 = 64 символа) (регистр R9);

— lpString — адрес буфера, в который запишется введенная строка (регистр R8);

— nIDDlgItem — дескриптор виджет, из которого получаем текст (в нашем случае строка ввода серийного номера) (регистр RDX);

— hDlg — дескриптор диалогового окна, содержащего виджет (регистр RCX).

Скалярное возвращаемое значение не больше 64 бит возвращается посредством RAX (сюда входит тип __m64). Нескалярные типы, включая типы с плавающей точкой, тип Double и векторные типы, такие как __m128, __m128i, и __m128d, возвращаются в XMM0. Состояние неиспользуемых битов в возвращаемом значении в RAX или XMM0 не определяется.

Далее адрес введенной строки передается в регистр RCX, а значение, которое вернула функция GetDlgItemTextA (количество введенных символов) — в регистр RDX, после чего происходит вызов функции, расположенной по адресу sub_140001000.

Если функция возвращает 0 (посредством регистра RAX), то программа завершается неуспешно (рисунок 107), иначе выполнение программы переходит к инструкциям, показанным на рисунке.

Рисунок 107 — Выполнение программы, если функция вернула не 0

2.3 Патчинг

Давайте явно поменяем инструкцию jz на jnz, чтобы программа принимала любой номер. Для этого найдем ее смещение относительно начала сегмента кода (рисунок 108).

Рисунок 108 — Адрес команды в памяти

Смещение в данном случае равно 0x140001167 — 0x140001000 = 0x167. Откроем исполняемый файл в Hex-редакторе и изменим код команды jz (0x74 0x28) на jnz (0x75 0x28) (рисунок 109).

Рисунок 109 — Измененная программа

Теперь запустим ее с серийным номером 1234 и посмотрим на результат (рисунок 110).

Рисунок 110 — Программа приняла серийный номер

Теперь программа способна принимать любой серийный номер (ну почти). Данное решение не является красивым, поэтому вернемся к разбору функции проверки серийного номера.

2.4 Функция sub_140001000

Посмотрим на граф выполнения (рисунок 111).

Рисунок 111 — Граф выполнения функции

Посмотрим на первый блок выполнения (рисунок 112).

Рисунок 112 — Начало выполнения функции

Первым делом в регистр r8 записывается адрес введенной строки, и ее длина сравнивается со значением 0x13 (19). Если длина не равна 0x13, то выполнение переходит к инструкциям на рисунке 113.

Рисунок 113 — Длина строки не равна 0x13

Значение в регистре EAX приравнивается к 0 и происходит возврат из функции. Этот результат нас не устраивает, а значит теперь мы знаем, что длина серийного номера должна быть равна 0x13. Продолжаем анализ алгоритма (рисунок 114).

Рисунок 114 — Длина строки равна 0x13

Здесь мы приравниваем к 0 значение в регистре EDX, записываем в регистр RAX адрес 4-го символа в строке (отчет ведем с 0) и обнуляем значение в регистре ECX. Остальные 3 команды мне непонятны, потому что на первый взгляд они ничего не делают. Продолжаем анализ (рисунок 115).

Рисунок 115 — Продолжение алгоритма

На данном рисунке происходит проверка значение по адресу из регистра RAX и сравнивается со значением 0x2d (» -»). Если оно не равно, то происходит переход к операциям из рисунка 2.12. Данное сравнение происходит 2 раза (пока значение в регистре ECX не станет равным 3). Значение ECX увеличивается на 1 перед каждой проверкой, а значение в регистре RAX увеличивается на 5. Таким образом мы получаем, что в нашем серийном номере на позициях 4, 9 и 14 должны стоять символы ‘-», т.е. наш серийный номер должен соответствовать маске «XXXX — XXXX — XXXX — XXXX», где «X» — неизвестный пока символ. Продолжим анализ кода (рисунок 116).

Рисунок 116 — Продолжение алгоритма

В этом блоке кода происходит присваивание локальной переменной var_8 (локальная переменная хранится на стеке) значения регистра RBX, зануление регистров r10d и r11d, присваивание регистру RBX адреса локальной переменной var_18 и присвоения адреса введенной строки регистру r9. Ничего интересно, поэтому продолжим анализ (рисунок 117).

Рисунок 117 — Продолжение алгоритма

Первым делом значение в регистре RCX становится равным 0. После чего символ с индексом ECX из введенной строки записывается в регистр EAX, к нему прибавляется значение 0xFFFFFFD0 (4 294 967 248) и оно сравнивается со значением 0x09 (9) и если результат сложения его превышает, то происходит переход к операциям из рисунка 118. Такая проверка проводится для первых четырех элементов серийного номера.

Рисунок 118 — Выход из функции со значением 0

Из этого блока кода мы можем сделать вывод, что коды первых четырех элементов серийного номера должны быть больше 0x2f и меньше 0x3a. Данный диапазон соответствует символам «1» — «9». Из этого мы делаем вывод, что первые четыре символа представляют из себя цифры. Продолжаем анализ (рисунок 119).

Рисунок 119 — Продолжение алгоритма

Регистру EAX присваивается значение по адресу из регистра r9 (первый символ строки), после чего к нему прибавляется значение двух последующих символов. После этого еще трижды прибавляется символ, находящийся на расстоянии 3, от того, что находится по адресу из регистра r9. Далее к регистру RBX прибавляется 4, к регистру r11d прибавляется 1, к регистру r9 прибавляется 5. В регистр ECX записывается адрес, который находится как сумма значения из регистра RAX (вышеописанная сумма), значения из регистра RCX и значения -0x150 (-336). Это значение записывается по адресу RBX-4 и прибавляется к регистру r10d. Далее значения из регистра r11d сравнивается с 4, и если оно строго меньше, то происходит переход по адресу loc_140001050.

Из этого блока мы видим, что операции на рисунков 2.16 и 2.18 выполняются 4 раза (по 1 разу для каждого блока). Каждый блок проверяется на то, чтобы он состоял только из цифр, после чего для каждого блока высчитывается сумма первых трех цифр и последней, умноженной на 3. После этого к данной сумме прибавляется еще раз значение последней цифры и вычитается 336, после чего оно запоминается отдельно на стеке, а также их общая сумма сохраняется в регистре r10d. Продолжаем анализ (рисунок 120).

Рисунок 120 — Продолжение алгоритма

Значение из регистра r10d сдвигается вправо на 2 двоичных разряда (делится на 4 нацело), значение в регистре ECX обнуляется, регистр RAX начинает указывать на массив сумм блоков серийного номера. Продолжаем анализ (рисунок 121).

Рисунок 121 — Продолжение алгоритма

Теперь мы видим, что значения, на которые указывает регистр RAX сравниваются со значение r10d, и если они не равны, то происходит переход к инструкциям из рисунка.

Таким образом сумма каждого блока должна быть равна общей сумме, деленной на 4. Это значит, что суммы всех четырех блоков должны быть равными. Продолжаем анализ (рисунок 122).

Рисунок 122 — Продолжение алгоритма

Последняя часть нашего анализа. Первым делом значение в регистре RAX становится равным 0. После этого в последующих трех блоках сравниваются значения символов в каждой группе серийного номера на позиции из регистра RAX. И есть хотя бы двое их них совпали, то функция завершается с выходным значением 0. Теперь мы знаем, что символы в каждом блоки на с одинаковым смещение не должны быть равны.

Таким образом мы разобрали алгоритм. Теперь обобщим полученные сведения о строении серийного номера:

— Правильный серийный номер состоит из 19 символов.

— Серийный номер делится на блоки по 4 символа (начиная с 0-го смещения), между которыми расположен символ ‘-».

— Каждый блок состоит из цифр.

— Суммы первых трех цифр и учетверенной последней цифры за вычетом 336 каждого блока равны между собой.

— Цифры, находящиеся на одинаковой позиции внутри каждого блока (от 0 до 3) попарно различны.

Напишем Keygen, который всегда будет генерировать правильные серийные номера. Результат работы Keygen’а представлен на рисунках 123—124.

Рисунок 123 — Результат работы Keygen. exe


Рисунок 124 — Серийный номер принят программой

Заключение

При выполнении работы на практике была произведена обратная разработка программы crackme01_x64.exe при помощи интерактивного дизассемблеро IDA Pro Freeware.

По итогам работы были выполнены следующие задания:

— Разобрался в структуре программы crackme01_x64.exe;

— Построил граф работы программы;

— Написал кейген для приложения;

— Сделал вывод по результатам проведенной работы.

ПРИЛОЖЕНИЕ А

Исходный код Keygen

Листинг 1 — Исходный код Keygen на C++

ЛАБОРАТОРНАЯ РАБОТА №6

Тема: Пароль на архив crackmes.de (ЗАДАНИЕ ПО ВАРИАНТАМ)

1. Изменить 1 байт продемонстрировать что программа приняла серийный номер.

2. Изменить ключевой условный переход

3. Изменить ключевой безусловный переход

4. Описать процесс формирования серийного номера.

5. Описать процесс распаковки серийного номера.

6. Изменить 2 байта продемонстрировать что программа приняла серийный номер

7. Построить граф работы программы

8. Исследовать и определить длины серийного номера, имени

9. Исследовать и определить адерса имени и серийного номера

10. Изменить произвольное количество байт (более 2), продемонстрировать что программа приняла серийный номер

11. Определить константы для упаковки серийного номера

12. Определить ключевые участки кода ответственные за упаковку серийного номера.

13. Определить константы для распаковки серийного номера

14. Определить константы для распаковки серийного номера


15.* Получить действительную пару имя, серийный номер (это задание может сделать любой если затрудняется сделать свой вариант)

16.* Написать патч для приложения (это задание может сделать любой если затрудняется сделать свой вариант)

17.** Написать кейген для приложения (это задание может сделать любой если затрудняется сделать свой вариант).


Задания с одной звездочкой это средний уровень.

Задание с двумя звездами это высокий уровень.

Пример выполнения ЛАБОРАТОРНАЯ РАБОТА №6

Реверс программы level_2.exe

Введение

Цель работы: произвести обратную разработку программы level_2.exe.

Для выполнения цели поставлен ряд задач:

— Разобраться в структуре программы level_2.exe;

— Построить граф работы программы;

— Написать кейген для приложения;

— Сделать вывод по результатам проведенной работы.

1 Знакомство с программой

Программа level_2.exe (в дальнейшем программа) представляет из себя консольное приложение, поэтому запустим ее через консоль (рисунок 125).

Рисунок 125 — Внешний вид программы

Как можно заметить, ничего не произошло, поэтому сразу откроем данную программу в IDA Pro.

2 Изучение программы в IDA Pro

2.1 Первый взгляд

Откроем функцию main и посмотрим, что она из себя представляет (рисунок 126).

Рисунок 126 — Граф выполнения функции main

Приступим к разбору.

2.2 Разбор алгоритма

Перейдем к началу функции (рисунок 127).

Рисунок 127 — Начало функции main

Из этого блока кода можно понять, что программа принимает на вход 3 аргумента. Нужно помнить, что первый аргумент в командной строке — название программы, поэтому при запуске программы дополнительно требуется ввести еще 2 аргумента.

Рисунок 128 — Продолжение алгоритма

После получения 3-х аргументов при помощи функции calloc на куче выделяется один блок памяти размером 0x100 (256) байт и указатель на него помещается на стек (локальная переменная) по смещению +0x34 (52). Переименуем это смещение на pArr.

Рисунок 129 — Продолжение алгоритма

Далее идет цикл по всем введенным параметрам на каждом шаге которого ищется последовательность “-f». Как только данная последовательность найдена, флаг на стеке по смещению +0x3C (60) устанавливается в 1, а в переменной по смещению +0x38 (56) хранится индекс следующего параметра командной строки.

Рисунок 130 — Продолжение алгоритма

После того, как был найден аргумент “-f», при помощи функции memset все элементы выделенного ранее массива становятся равными 0, после чего в него копируется значение параметра, указанного после “-f».

Рисунок 131 — Продолжение алгоритма

После копирования проверяется первый символ строки, и если он не равен 0, то происходит открытие файла и его handle помещается по смещению +0x30 (48). После чего производится проверка на корректность открытия файла. Если файл не открылся, то программа завершается.

Рисунок 132 — Продолжение алгоритма

После успешного открытия файла, его дескриптор передается функции _construct_key. Результат ее выполнения записывается по смещению +0x2C (44), и если он равен, нулю, то выводится сообщения об ошибке, в ином случае на консоль выведутся правильные маркеры.

Рисунок 133 — Условные переходы после работы функции _construct_key

Наша задача заключается в том, чтобы функция _construct_key вернула не 0. Исследуем как она работает.

2.3 Функция _construct_key

Рисунок 134 — Граф выполнения функции _construct_key


Рисунок 135 — Начало функции _construct_key

Первым делом вызывается функция __prepare_key, и если результат ее работы равен 0, то происходит выход из функции. Рассмотрим функцию __prepare_key.

2.4 Функция __prepare_key

Рисунок 136 — Граф работы функции __prepare_key


Рисунок 137 — Начало работы функции

Первым делом выделяется 1 блок памяти размером 8 байт на куче при помощи функции calloc и указатель на этот блок сохраняется по смещению -0x0C (-12). Причем смещение берется от начала стекового кадра, т.е. по факту, мы работаем с локальной переменной var_10 (так как дополнительные 4 байта занимает база стекового кадра) функции _construct_key.

Рисунок 138 — Продолжение алгоритма

Если выделение прошло успешно, то происходит выделение еще одного блока на куче размером 0x540 (1344) байта и указатель на этот блок записывается в предыдущий блок. Таким образом, получить доступ к большому блоку мы может только перейдя по адресу, записанному в малом блоке, адрес которого хранится на стеке по смещению -0x0C.

Далее выделяется еще один блок размером 8 байт, указатель на который сохранятся со смещением +4, от предыдущего большого блока. После этого записываем внутрь блока адрес строки «VOID», находящейся в памяти. В последующие 2 байта записываем 5, и в оставшиеся 2 байта — 4.

После этого программа работает с большим блоком. По смещению 0x00 записываем два байта со значением 0x62 (98), по смещению +0x104 (260) записываем байт 3, по смещению +0x218 (546) — байт 0x57 (87), по смещению +0x324 (804) — байт 0x70 (112), по смещению +0x10C (268) — байт 0x6C (108), по смещению +0x430 (1072) — байт 0x98 (152), по смещению +0x53C (1340) — 4 байта со значением 0x462 (1122).

После всех действий функция завершается и управление передается обратно функции _construct_key.

2.5 Возвращение в функцию _construct_key

Рисунок 139 — Продолжение функции _construct_key

После возвращения в данную функцию мы знаем, что по смещению var_10 находится адрес блока памяти, с которым мы работали в функции __prepare_key.

Первым делом считываются первые 4 байта файла по адресу var_15 при помощи функции fread (нужно помнить, что каретка внутри файла движется по мере считывания). После этого в регистр EAX записывается адрес строки «VOID» (описано в предыдущем пункте) и первые 4 байта это строки сравниваются со считанными байтами из файла. Если строки не равны, то работы функции завершается. Таким образом в указанном файле первые четыре символа, записанные в файл, должны быть равны «VOID».

Рисунок 140 — Продолжение алгоритма

Если проверка на предыдущем шаге прошла успешно, то из файла считываются следующие 2 байта и записываются сразу же после адреса «VOID», тем самым перезаписывая значение 5. После этого считываются еще 2 байта файла, которые записываются на место 4 (сразу после предыдущей записи). Далее происходит сравнения последних считанных 2-х байтов с 4 и если программа считала другое число, то происходит выход из функции.

Рисунок 141 — Продолжение алгоритма

После этого происходит проверка первого считанного байта, и если он не равен 5, то происходит выход из функции.

Рисунок 142 — Продолжение алгоритма

В локальную переменную по смещению var_2C записывается адрес начала большого блока. Теперь в локальные переменные функции записываются значение из этого блока памяти, полученные в функции __prepare_key. В переменную по смещению var_2C записывается значение из большого блока по смещению 0x00, т.е. 0x62 (98), по смещению var_28 — значение по смещению 0x10C (268), т.е. 0x6C (108), по смещению var_24 — значение по смещению 0x218 (546), т.е. 0x57 (87), по смещению var_20 — значение по смещению 0x324 (804), т.е. 0x70 (112), по смещению var_1C — значение по смещению 0x430 (1072), т.е. 0x98 (152). Переменной по смещению var_C присваиваем значение 0.

Рисунок 143 — Продолжение алгоритма

Далее идет цикл с таким предусловием, пока значение по смещению var_C меньше либо равно 4, то выполняются команды из рисунка 144.

Рисунок 144 — Цикл

Мы видим, что происходит считывание одного байта из файла и производится его сравнение с одной из локальных переменных в зависимости от счетчика цикла, т.е. либо с var_2C, либо с var_28, либо с var_24, либо с var_20, либо с var_1C. Если считанный байт не равен рассматриваемому, то программа выходит из функции, иначе цикл продолжает выполнение.

Рисунок 145 — Цикл

Считывается следующий байт файла и сравнивается с 0-м, и если он равен, то происходит выход из функции.

Рисунок 146 — Цикл

Теперь в большой блок по смещение 0x104 (260) от адрес, который получается на основе индекса массива записывается только что считанное значение. После этого из файла считывается ровно столько байт, сколько было записано по смещению 0x104 (260), причем все эти байты записываются сразу за текущим смещением на основе индекса цикла. Теперь с помощью функции strlen находится длина этой строки и сравнивается со считанным перед этим число. Если эти значения не равны, то происходит выход из функции.

Рисунок 147 — Цикл

Теперь в локальную переменную по смещению var_38 считывается еще 1 байт файла и к считанному значению прибавляется 7. После этого считывается положение указателя внутри файла при помощи функции ftell и сравнивается с предыдущим числом. Если индекс указателя внутри файла больше, чем считанный байт, то функция завершает работу.

Рисунок 148 — Цикл

Теперь значение индекса каретки, полученное раннее, записывается после считанной длины строки и при помощи функции fseek указатель внутри файла перемещается на эту позицию. После этого счетчик цикла увеличивается на 1.

Рисунок 149 — Продолжение алгоритма

После того, как цикл выполнился 5 раз, выполнение переходит к инструкциям на рисунке 149. Считываются 4 байта файла и сравниваются со значением из большого блока, находящегося по смещению 0x53C (1340), т.е. 0x463 (1122). Если эти значения равны, то функция завершается успешно.

2.6 Обобщение полученных данных

Таким образом, чтобы получить верный код необходимо создать файл с любым именем и запустить программу с аргументами “-f» ПУТЬ_ДО_ФАЙЛА.

Содержимое файла должно иметь следующую структуру:

— Первые 4 символа — слово «VOID».

— Два байта со значением 0x0005.

— Два байта со значением 0x0004.

— Пять блоков данных. Каждый блок представляет из себя:

— Байт с одним из значений в зависимости от номера цикла (0x62, 0x6C, 0x57, 0x70, 0x98);

— Ненулевой байт;

— Строка, длина которой в точности равна значению предыдущего байта;

— Байт, значение которого подобрано таким образом, что при прибавлении к нему 7, его значение будет равно его индексу внутри файла.

— Четыре байта, равные 0x00000462.

Напишем Keygen, который всегда будет генерировать правильные файлы. Результат работы Keygen’а представлен на рисунках 150—151.

Рисунок 150 — Результат работы Keygen


Рисунок 151 — Сгенерированный файл

Заключение

При выполнении работы на практике была произведена обратная разработка программы level_2.exe при помощи интерактивного дизассемблеро IDA Pro Freeware.

По итогам работы были выполнены следующие задания:

— Разобрался в структуре программы level_2.exe;

— Построил граф работы программы;

— Написал кейген для приложения;

— Сделал вывод по результатам проведенной работы.

ПРИЛОЖЕНИЕ А

Исходный код Keygen

Листинг 1 — Исходный код Keygen на C++

ЛАБОРАТОРНАЯ РАБОТА №7

При запуске программ производится запрос пароля (или организуется регистрация программы), после чего дается заключение о правильности прохода через пароль.

Ваша задача:

Знакомство с отладчиком уровня ПРИЛОЖЕНИЯ

Используя отладчик OlleDebuger пройти по программе, найти место, где происходит дешифровка пароля и расшифровать его, после чего снова запустить программу, ввести правильный пароль и получить подтверждение о правильности прохода через пароль.

Знакомство с дизассемблером

Используя дизассемблер IDA

— ознакомиться с методикой дизассемблирования Win приложений;

— дизассемблировать выданную программу;

— найти в тексте программы место проверки пароля;

— исправить ассемблерный код так, чтобы программа срабатывала при любом пароле, определить вид изменений в коде исполняемого файла;

— внести изменения в код исполняемого файла любым способом, чтобы программа срабатывала при любом введенном пароле.

Оформить электронный отчет, в котором отразить:

— титульный лист;

— тему лабораторной работы и задание на лабораторную работу;

— описание этапов дешифровки пароля на OLLEDEDUGER;

— описание использования дизассембелра IDA;

— и экранные формы из дизассемблера, использованные при дешифровке пароля;

— вид экрана после срабатывания откорректированной программы.

Пример выполнения ЛАБОРАТОРНОЙ РАБОТЫ №7

Реверс программы LAB2C_07.exe

Введение

Цель работы: произвести обратную разработку программы LAB2C_07.exe.

Для выполнения цели поставлен ряд задач:

— Разобраться в структуре программы LAB2C_07.exe;

— Построить граф работы программы;

— Сделать вывод по результатам проведенной работы.

1 Знакомство с программой

Программа LAB2C_07.exe (в дальнейшем программа) представляет из себя графическое приложение (рисунок 152).

Рисунок 152 — Внешний вид программы

Попробуем ввести пароль «123» и посмотрим на реакцию программы (рисунок 153).

Рисунок 153 — Введенный пароль «123»

Запустим данную программу в IDA Pro и посмотрим, как она работает.

2 Изучение программы в IDA Pro

2.1 Первый взгляд

Откроем программу в IDA Pro и найдем то место, где генерируется сообщение о неудаче (рисунки 154—155).

Рисунок 154 — Поиск по тексту


Рисунок 155 — Место, в котором программа проверяет правильность пароля

Посмотрим на граф работы функции (рисунок 156).

Рисунок 156 — Граф работы функции

Приступим к разбору.

2.2 Разбор алгоритма

Данная программа представляет из себя обращения к WinAPI, а потому кода, который несет смысловую нагрузку в ней довольно мало. Давайте перейдем сразу к нему (рисунок 157).

Рисунок 157 — Начало алгоритма

Каждый раз, когда пользователь вводит что-то в окно ввода, то срабатывает callback, который начинает выполнения данного кода. Здесь выполняется функции GetWindowTextLengthA для нашего поля ввода, в регистр EAX записывается длина строки, которая затем присваивается регистру ESI. Если длина не равна нулю, программа продолжает выполнение.

Рисунок 158 — Продолжение алгоритма

В этом блоке кода происходит вызов функции GetWindowTextA, который принимает дескриптор окна, указатель на буфер, в который записывается введенная строка и максимальное количество символов в строке. Функция возвращает количество считанных символов. После этого проверяется последний символ введенной строки и если он равен 0x0A (10 = ‘\n’), то алгоритм продолжает выполнение.

Рисунок 159 — Продолжение алгоритма

В данном блоке происходит проверка длины строки. Если длина строки равна 7, то выполнение продолжается. Однако нужно о том, что символы переноса тоже считаются как элементы строки, причем в системе Windows перенос занимает 2 байты, поэтому фактическая длина строки должна быть равна 5.

Рисунок 160 — Продолжение алгоритма

Здесь мы видим простой цикл, который проходит по всем пяти символам введенной строки, складывает их по модулю 2 с числом 0x25 (37) и сравнивает с какими-то локальными переменными. Если хотя бы одна сумма не совпадает с исходной, то алгоритм завершается неудачей. Давайте посмотрим на начало функции и найдем значения этих локальных переменных.

Рисунок 161 — Начало функции

Нас интересуют переменные var_14, var_10, var_C, var_8, var_4 именно в такой последовательности. Они равны 0x14 (20), 0x0F (15), 0x08 (8), 0x0F (15) и 0x14 (20) соответственно. Таким образом, сложим их по модулю 2 с числом 0x25 (37) и получим правильную строку.

— 0x14 ^ 0x25 = 0x31 (49 = «1»);

— 0x0F ^ 0x25 = 0x2A (42 = «*»);

— 0x08 ^ 0x25 = 0x2D (45 = ‘-»);

— 0x0F ^ 0x25 = 0x2A (42 = «*»);

— 0x14 ^ 0x25 = 0x31 (49 = «1»).

Таким образом входная строка должна быть равна «1*-*1». Давайте введем и проверим правильность выполненного анализа (рисунок 162).

Рисунок 162 — Ввод верной строки

Заключение

При выполнении работы на практике была произведена обратная разработка программы LAB2C_07.exe при помощи интерактивного дизассемблеро IDA Pro Freeware.

По итогам работы были выполнены следующие задания:

— Разобрался в структуре программы LAB2C_07.exe;

— Построил граф работы программы;

— Сделал вывод по результатам проведенной работы.

РАСЧЕТНО-ГРАФИЧЕСКАЯ РАБОТА

Для реально существующего приложения для которого закончился период поддержки и больше оно не производится, но предполагает ограниченность лицензии, описать процедуру получения доступа в обход серийного номера. Например Win Rar v1.0.

Пример выполнения РГР

Введение

Цель работы:

Решить задачу Terminal от Лаборатории Касперского.

Задачи:

— Описать выполнение задания;

— Оформить отчет.

1 Первый взгляд

Посмотрим, что из себя представляет программа. Для этого запустим ее (рисунок 163).

Рисунок 163 — Внешний вид программы

Программа требует ввод e-mail, после чего просит ввести пароль. Давайте введем пару «sample@mail.ru», «123456Qq» и посмотрим, что из этого выйдет (рисунок 164).

Рисунок 164 — Ввод email и пароля

Программа на какое-то время зависает, после чего закрывает, создавая в текущей директории файл apof.bin. Посмотрим на него (рисунок 165).

Рисунок 165 — Файл apof.bin

Данный файл представляет из себя программу, упакованную UPX. Распакуем его при помощи UPX_Control (рисунки 166—167).

Рисунок 166 — Программа UPX_Control


Рисунок 167 — Распакованная программа

Рассмотрим теперь алгоритм работы программы.

2 Terminal

Загрузим программу в IDA и посмотрим, как она ведет себя (рисунок 168).

Рисунок 168 — Граф работы программы


Рисунок 169 — Процесс ввода e-mail

На рисунке показан алгоритм ввода e-mail. Ничего необычного. Процесс ввода пароля абсолютно идентичный, поэтому пропустим его и перейдем к основной части (рисунок 170).

Рисунок 170 — Создание apof.bin и запуск процесса

После ввода пароля создается файл apof.bin, handle которого записывается в esi. После создания в него записывается код из буфера lpBuffer. Далее создается процесс, в котором запускается данный файл на исполнение.

Рисунок 171 — Создание именованного канала

Если процесс был успешно запущен, то создается именованный канал «\\.\pipe\KasperskyLabOffZone».

Рисунок 172 — Подключение к созданному каналу

После создания канала происходит подключение к нему.

Рисунок 173 — Общение между процессами

Начинается интересная часть. Сразу после подключения к каналу в него передается введенный e-mail и пароль. После того, как эти данные были переданы из канала считывается 1 байт, и если он равен 0x19, то программа завершается успешно (рисунок 174).

Рисунок 174 — Успешное завершение программы

Из всего вышесказанного можно сделать вывод, что Terminal. exe выступает в роли сервера, который общается с клиентом (apof.bin). Если после передачи клиент возвращается 0x19, то все хорошо. Таким образом задача сводится к рассмотрению алгоритма в файле apof.bin.

3 Apof.bin

Рассмотрим процесс работы программы apof.bin (рисунок 175).

Рисунок 175 — Граф выполнения программы


Рисунок 176 — Попытка подключения к именованному каналу

Первым делом программа пытается подключится к именованному каналу, создаваемому сервером.

Рисунок 177 — Считывание данных из канала

Как только подключение произошло программа считывает переданный e-mail и пароль. E-mail записывается по адресу unk_41A898, а пароль — по адресу unk_41A8C0.

Рисунок 178 — Вычисление MD5-хеша от строки ka$per$ky_1a8

В данной секции есть две неизвестные функции sub_4012CD и sub_4019AC. Первая занимается тем, что делает копию сроки, адрес которой передается в функцию через стек, и возвращает адрес на новую строку через регистр eax (рисунок 178). Вторая функция вычисляет MD5-хеш от строки, адрес которой передается через стек, и записывает его прямо на адрес строки (рисунки 179—182). Таким образом в этом блоке кода происходит копирование строки ka$per$ky_1a8, вычисляется ее MD5-хеш. После этого происходит копирование введенного e-mail и пароля.

Рисунок 179 — Функция sub_4012CD


Рисунок 180 — Функция sub_4019AC


Рисунок 181 — Создание MD5-хеша


Рисунок 182 — Преобразование e-mail

На рисунке 183 показан цикл преобразования e-mail. В данном цикле на каждой итерации очередной символ e-mail вычитается из 0x102, и результат сдвигается вправо на 2. Цикл выглядит громоздким, потому что он засорен огромным количеством бесполезных инструкций (впрочем, как и вся программа в целом).

Рисунок 183 — Генерация правильного пароля

Генерация верного пароля происходит на рисунке. Мы видим, что здесь трижды вычисляется MD5-хеш. Первый раз над преобразованным e-mail, второй раз над полученным из канала e-mail, а третий раз над результатом функции sub_401000. Данная функция занимается тем, что конкатенирует две строки, адреса которых переданы через стек (к первой строке приписывается вторая) (рисунок 184). От результата работы этой функции вновь считается MD5-хеш.

Рисунок 184 — Функция sub_401000


Рисунок 185 — Проверочный цикл

В этом сегменте кода происходит посимвольное сравнение введенного пароля и MD5-хеша, полученного от конкатенации строк, описанной выше. Переменная dword_41A000 изначально содержит 0x239, и на каждой итерации алгоритма уменьшается на 1.

Рисунок 186 — Окончание алгоритма

После сравнения паролей младший байт переменной dword_41A000, который после успешной проверки будет равен как раз 0x19 отправляется в именованный канал. После этого Terminal. exe принимает его, и программа завершается успешно.

4 Keygen.py

После написания Keygen.py выглядит следующим образом (листинг 1).

Листинг 1 — Исходный код Keygen на Python

Пример выполнения кода приведен на рисунке 187.

Рисунок  187 — Результат работы Keygen.py

Заключение

В ходе данной работы я выполнил задание Terminal. exe от лаборатории Касперского тем самым углубив свои навыки в области обратной разработки ПО.

В процессе выполнения работы были выполнены следующие задачи:

— Описано выполнение задания;

— Оформлен отчет.

Заключение

Реверс инжиниринг программного кода сегодня уже представляет из себя не просто «горы» распечатанного кода, а выработанные методологии, обилие инструментария, помогающего существенно снизить трудоемкость процесса.

Естественно, что использование дизассемблеров, отладчиков, декомпиляторов требует наличия определенных знаний, навыков и умений. Но по мнению автора данная область инженерии программного обеспечения все еще, на сегодня, похожа на искусство.

Конечно есть таланты, способные видеть, подобно программистским «багам», недоработки программного обеспечения, но в большей массе мы, все же должны развивать в себе умение проводить обратную разработку программ, для совершенствования имеющихся техник отладки программ без известного кода.