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

Фундаментальные основы хакерства

Пятнадцать лет назад эпический труд Криса Касперски «Фундаментальные основы хакерства» был настольной книгой каждого начинающего исследователя в области компьютерной безопасности. Однако время идет, и знания, опубликованные Крисом, теряют актуальность. Редакторы «Хакера» попытались обновить этот объемный труд и перенести его из времен Windows 2000 и Visual Studio 6.0 во времена Windows 10 и Visual Studio 2017.

Читай также:

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

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

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

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

Неплохой сборник, как раз для продолжительной работы
Неплохой сборник, как раз для продолжительной работы
 

Идентификация функций

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

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

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

Инструкция CALL закидывает адрес следующей за ней инструкции на вершину стека, а RET стягивает и передает на него управление. Тот адрес, на который указывает инструкция CALL, и есть адрес начала функции. А замыкает функцию инструкция RET (но внимание: не всякий RET обозначает конец функции!).

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

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

Check Also

Американская компания подверглась редкой атаке через BadUSB

Эксперты компании Trustwave рассказали, что неназванной американской компании прислали по …

6 комментариев

  1. Андрей Письменный

    Андрей Письменный

    26.02.2020 at 13:04

    Предвидя будущие комментарии, спешу сообщить: да, это действительно еще одна статья Криса Касперски. Ее написал Крис Касперски и обновил Юрий Язев. Юрий готовит к переизданию книгу Криса «Фундаментальные основы Хакерства», которая выйдет в «Солон-Пресс». Вчера мы публиковали другой текст Криса, из другой его книги, которую издает другое издательство — BHV. Такое совпадение по времени — случайность. Просто когда нам в руки попадает текст Криса, которого в «Хакере» еще не было, мы теряем волю и публикуем его!

    • Аватар

      rutkit

      27.02.2020 at 12:47

      может стоит создать закрытый раздел с хард статьями какие когда то были в ][?

    • Аватар

      b1nary_gl1tch

      27.02.2020 at 16:00

      Строго говоря, это не статья Криса, а одна из глав его книги «Искусство дизассемблирования».

  2. Аватар

    robotobor

    27.02.2020 at 03:28

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

  3. Аватар

    robotobor

    27.02.2020 at 09:01

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

  4. Юрий Язев

    Юрий Язев

    27.02.2020 at 17:11

    Широко известно, что фамилия из псевдонима «Крис Касперски» произошла от имени доброжелательного привидения Каспер из мультфильма, об этом говорил сам Крис. Однако гораздо меньше известно о происхождении имени «Крис» из псевдонима. И я считаю, что оно не является простым отражением англосаксонского имени. Ведь у Криса ничего не было «просто так». По моему мнению, это имя уходит корнями в литературную вселенную «Хроники Дюны», горячо любимой Николаем Лихачевым. В этой вселенной у аборигенов планеты Арракис — фрименов есть особые ножи — крисы, изготавливаемые из зубов песчаных червей. То есть, острый, как нож, острый, как крис.

Оставить мнение