• XSS.stack #1 – первый литературный журнал от юзеров форума

Мануал/Книга THE IDA PRO BOOK 2 ИЗДАНИЕ - Неофициальное руководство по самому популярному дизассемблеру в мире

yashechka

Генератор контента.Фанат Ильфака и Рикардо Нарвахи
Эксперт
Регистрация
24.11.2012
Сообщения
2 344
Реакции
3 563
Вам может быть интересно, чего ожидать от книги, посвященной IDA Pro. Хотя эта книга явно ориентирована на IDA, она не предназначена для того, чтобы воспринимать её как Руководство пользователя IDA Pro. Вместо этого мы намерены использовать IDA в качестве вспомогательного инструмента для обсуждения методов реверс инжиниринга, которые вы найдете полезными при анализе широкого спектра программного обеспечения, от уязвимых приложений до вредоносных программ. При необходимости мы предоставим подробные инструкции, которым необходимо следовать в IDA для выполнения конкретных действий, связанных с поставленной задачей. В результате мы сделаем довольно окольный обход возможностей IDA, начиная с основных задач, которые вы захотите выполнить при первоначальном исследовании файла, и заканчивая расширенным использованием и настройкой IDA для решения более сложных задач обратного проектирования. Мы не пытаемся охватить все возможности IDA. Тем не менее, мы рассматриваем функции, которые будут наиболее полезными для решения ваших задач реверс инжиниринга. Эта книга поможет сделать IDA самым мощным оружием в вашем арсенале инструментов.

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


Теория дизассемблирования

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


Языки первого поколения

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


Языки второго поколения

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


Языки третьего поколения

Эти языки делают еще один шаг к выразительной способности естественных языков, вводя ключевые слова и конструкции, которые программисты используют в качестве строительных блоков для своих программ. Языки третьего поколения обычно не зависят от платформы, хотя программы, написанные с их помощью, могут зависеть от платформы в результате использования функций, уникальных для конкретной операционной системы. Часто цитируемые примеры включают FORTRAN, COBOL, C и Java. Программисты обычно используют компиляторы для перевода своих программ на ассемблер или полностью на машинный язык (или какой-то грубый эквивалент, такой как байтовый код).

Языки четвертого поколения

Они существуют, но не имеют отношения к этой книге и не будут обсуждаться.


Что такое дизассембилрование

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

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

Процесс компиляции это процесс с потерями.

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


Компиляция - это операция "многие ко многим".

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


Декомпиляторы очень зависят от языка и библиотеки.

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


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

Любые ошибки или упущения на этапе дизассемблирования почти наверняка распространятся на декомпилированный код.

Hex-Rays, самый сложный декомпилятор на рынке сегодня, будет рассмотрен в главе 23.


Почему дизассемблирование


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

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

В последующих разделах каждая ситуация объясняется более подробно.

Анализ вредоносного ПО

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

Анализ уязвимости

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

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

Совместимость программного обеспечения

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


Проверка компилятора

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


Debugging Displays

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


Как дизассемблировать

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

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


Базовый алгоритм дизассемблирования

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


Шаг 1

Первым шагом в процессе дизассемблирования является определение области кода для дизассемблирования. Это не обязательно так просто, как может показаться. Инструкции обычно смешиваются с данными, и важно различать их. В наиболее распространенном случае, дизассемблировании исполняемого файла, файл будет соответствовать общему формату для исполняемых файлов, такому как формат Portable Executable (PE), используемый в Windows, или Executable and Linking Format (ELF), распространенный во многих Unix системах. Эти форматы обычно содержат механизмы (часто в форме иерархических заголовков файлов) для поиска разделов файла, содержащих код и точки входа в этот код.

Шаг 2

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

Шаг 3

После получения инструкции и декодирования всех необходимых операндов ее эквивалент на языке ассемблера форматируется и выводится как часть списка дизассемблирования. Можно выбрать более одного синтаксиса вывода на языке ассемблера. Например, два преобладающих формата для языка ассемблера x86 - это формат Intel и формат AT&T.

СИНТАКСИС АССЕМБЛЕРА X86: AT&T VS. INTEL

Для исходного кода используются два основных синтаксиса: AT&T и Intel. Несмотря на то, что это языки второго поколения, эти два языка сильно различаются по синтаксису: от доступа к переменным, константам и регистрам до переопределений размера сегмента и инструкции до косвенного обращения и смещений. Синтаксис AT&T отличается использованием символа % для префикса всех имен регистров, использованием $ в качестве префикса для литеральных констант (также называемых непосредственными операндами) и упорядочением его операндов, в котором исходный операнд отображается как левый операнд и операнд-адресат появляются справа. Используя синтаксис AT&T, инструкция по добавлению значения 4 в регистр EAX будет выглядеть так: add $ 0x4, % eax. GNU Assembler (Gas) и многие другие инструменты GNU, включая gcc и gdb, используют синтаксис AT&T.

Синтаксис Intel отличается от AT&T тем, что не требует регистров или буквенных префиксов, а порядок операндов меняется на противоположный, так что исходный операнд отображается справа, а место назначения отображается слева. Та же самая инструкция добавления с использованием синтаксиса Intel будет выглядеть так: add eax, 0x4.Ассемблеры, использующие синтаксис Intel, включают в себя Microsoft Assembler (MASM), Borland's Turbo Assembler (TASM) и Netwide Assembler (NASM).

Шаг 4

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

Линейная развертка

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

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

Основное преимущество алгоритма линейной развертки заключается в том, что он обеспечивает полное покрытие участков кода программы. Одним из основных недостатков метода линейной развертки является то, что он не учитывает тот факт, что данные могут быть объединены с кодом. Это очевидно в листинге 1-1, где показан вывод функции, разобранной дизассемблером с линейной разверткой. Эта функция содержит оператор switch, и используемый в этом случае компилятор решил реализовать switch с помощью таблицы переходов. Более того, компилятор решил встроить таблицу переходов в саму функцию. Оператор jmp по адресу 401250, ссылается на таблицу адресов, начиная с адреса 401257. К сожалению, дизассемблер обрабатывает это как инструкцию и неправильно генерирует соответствующее представление на языке ассемблера:
1.png


Если мы рассмотрим последовательные 4-байтовые группы как значения little-endian, начинающиеся с [2], мы увидим, что каждая из них представляет собой указатель на ближайший адрес, который фактически является местом назначения для одного из различных переходов (004012e0, 0040128b, 00401290, ...) .Таким образом, инструкция loopne в [2] вообще не является инструкцией. Вместо этого это указывает на неспособность алгоритма линейной развертки правильно отличить встроенные данные от кода.

Линейная развертка используется механизмами дизассемблирования, содержащимися в отладчике GNU (gdb), отладчике Microsoft WinDbg и утилите objdump.

Рекурсивный спуск

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


Инструкции по последовательному потоку

Команды с последовательным потоком передают выполнение инструкции, которая следует сразу за ними. Примеры инструкций последовательного выполнения включают простые арифметические инструкции, такие как сложение; инструкции передачи из регистра в память, такие как mov; и операции управления стеком, такие как push и pop. Для таких инструкций дизассемблирование происходит как при линейной развертке.

Условные инструкции ветвления

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

Инструкции безусловного ветвления

Безусловные переходы не следуют модели линейного потока и, следовательно, по-разному обрабатываются алгоритмом рекурсивного спуска. Как и в случае инструкций с последовательным потоком, выполнение может переходить только к одной инструкции; однако эта инструкция не обязательно должна следовать сразу за инструкцией ветвления. Фактически, как видно из Листинга 1-1, нет никакого требования, чтобы инструкция сразу следовала за безусловным переходом. Следовательно, нет причин разбирать байты, следующие за безусловным переходом.

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


Инструкции вызова функций

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

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

2.png


В результате управление фактически не передается инструкции добавления в [1] после вызова foo. Ниже представлена правильный листинг:

3.png


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

Инструкции возврата

В некоторых случаях алгоритм рекурсивного спуска уходить от нужных путей. Команда возврата в функции (например, x86 ret) не предлагает информации о том, какая инструкция будет выполнена следующей. Если бы программа действительно выполнялась, адрес был бы взят из вершины стека времени выполнения, и выполнение возобновилось бы с этого адреса. Дизассемблеры не имеют доступа к стеку. Вместо этого дизассемблер резко останавливается. Именно в этот момент дизассемблер с рекурсивным спуском обращается к списку адресов, которые он оставил для отложенного дизассемблирования. Адрес удаляется из этого списка, и процесс дизассемблирования продолжается с этого адреса. Это рекурсивный процесс, который дает название алгоритму дизассемблирования.

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


4.png

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

Резюме

Необходимо ли глубокое понимание алгоритмов дизассемблирования при использовании дизассемблера? Нет. Это полезно? Да! Сражение с вашими инструментами - последнее, на что вы хотите тратить время при реверс инжиниринге. Одним из многих преимуществ IDA является то, что, в отличие от большинства других дизассемблеров, он предлагает множество возможностей направлять и отменять решения. Конечный результат состоит в том, что готовый продукт, будет намного лучше всего остального.

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

Источник: https://www.amazon.com/IDA-Pro-Book-Unofficial-Disassembler/dp/1593272898
Автор перевода: yashechka
Переведено специально для портала xss.pro (c)
 
Мой перевод книги для тех кто очень бы хотел прочитать книгу по ида про но не может из-за незнания английского. Я Вас понимаю, сам такой, поэтому держите.
 
yashechka, а ты перевел только первую главу, или всю книгу ?

Если всю книгу можно ссылку, интересно почитать.

Сам по себе крякинг мало интересен, но поизучал-бы работу с этим отладчиком, может пригодится в будущем, полезно...)
 
2. РЕВЕРСИНГ И ИНСТРУМЕНТЫ ДЛЯ ДИЗАССЕМБЛИРОВАНИЯ

Имея за плечами некоторую предысторию дизассемблирования, и прежде чем мы начнем наше погружение в специфику IDA Pro, будет полезно понять некоторые другие инструменты, которые используются для реверс инжиниринга двоичных файлов. Многие из этих инструментов появились еще до IDA и продолжают использоваться для быстрого просмотра файлов, а также для двойной проверки работы, которую выполняет IDA. Как мы увидим, IDA включает многие возможности этих инструментов в свой пользовательский интерфейс, чтобы обеспечить единую интегрированную среду для реверс инжиниринга. Наконец, хотя IDA действительно содержит интегрированный отладчик, мы не будем рассматривать отладчики здесь, так как главы 24, 25 и 26 посвящены этой теме.

Инструменты классификации

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

file

Команда file - это стандартная утилита, включенная в большинство операционных систем в *NIX и в инструменты Cygwin или MinGW для Windows. file пытается определить тип файла, исследуя определенные поля в файле. В некоторых случаях file распознает общие строки, такие как #!/Bin/ sh (сценарий оболочки) или <html> (документ HTML). Файлы, содержащие не-ASCII-контент, представляют несколько большую проблему. В таких случаях файл пытается определить, выглядит ли содержимое структурированным в соответствии с известным форматом файла. Во многих случаях он ищет определенные значения тегов (часто называемые магическими числами), которые известны как уникальные для определенных типов файлов. Приведенные ниже шестнадцатеричные листинги показывают несколько примеров магических чисел, используемых для идентификации некоторых распространенных типов файлов.

5.png


file имеет возможность определять большое количество форматов файлов, включая несколько типов текстовых файлов ASCII и различные форматы исполняемых файлов и файлов данных. Проверки магического числа, выполняемые файлом, регулируются правилами, содержащимися в магическом файле. Файл magic по умолчанию зависит от операционной системы, но обычно он расположен в /usr/share/file/magic, /usr/share/misc/ magic и /etc/magic. Пожалуйста, обратитесь к документации к файлу для получения дополнительной информации о волшебных файлах.


СРЕДА CYGWIN

Cygwin - это набор утилит для операционной системы Windows, который предоставляет командную оболочку в стиле Linux и связанные программы. Во время установки пользователи могут выбирать из большого количества стандартных пакетов, включая компиляторы (gcc, g++), интерпретаторы (Perl, Python, Ruby), сетевые утилиты (nc, ssh) и многие другие. После установки Cygwin многие программы, написанные для использования с Linux, могут быть скомпилированы и выполнены в системах Windows.

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

6.png


СТРИППИНГ ДВОИЧНЫХ ИСПОЛНИТЕЛЬНЫХ ФАЙЛОВ

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

file и аналогичные утилиты не являются надежными. Вполне возможно, что файл будет неправильно идентифицирован просто потому, что он имеет идентифицирующие метки какого-либо формата файла. Вы можете убедиться в этом сами, используя шестнадцатеричный редактор для преобразования первых четырех байтов любого файла в последовательность магических чисел Java: CA FE BA BE. file неправильно идентифицирует недавно измененный файл как скомпилированные данные класса Java. Точно так же текстовый файл, содержащий только два символа MZ, будет идентифицирован как исполняемый файл MS-DOS. Хороший подход к любым усилиям по реверс инжинирингу - никогда полностью не доверять выходным данным какого-либо инструмента, пока вы не сопоставите этот результат с несколькими инструментами и ручным анализом.

PE Tools

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


7.png



Из списка процессов пользователи могут выгрузить образ памяти процесса в файл или использовать утилиту PE Sniffer, чтобы определить, какой компилятор использовался для сборки исполняемого файла или был ли исполняемый файл обработан какими-либо известными утилитами обфускации. Меню Tool предлагает аналогичные параметры для анализа файлов на диске. Пользователи могут просматривать поля заголовка PE файла с помощью встроенной утилиты PE Editor, которая также позволяет легко изменять любые значения заголовка. Модификация заголовков PE часто требуется при попытке восстановить действительный PE из обфусцированной версии этого файла.


ОБФУСКАЦИЯ БИНАРНЫХ ФАЙЛОВ

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

PEiD

PEiD - это еще один инструмент Windows, основным назначением которого является определение компилятора, используемого для создания конкретного двоичного файла Windows PE, и определение любых инструментов, используемых для обфускации двоичного файла Windows PE. На рис. 2-2 показано использование PEiD для идентификации инструмента (в данном случае ASPack), используемого для обфускации варианта червя Gaobot.

8.png


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

Другие инструменты

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

nm

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

Когда nm используется для проверки промежуточного объектного файла (файла .o, а не исполняемого файла), выходные данные по умолчанию дают имена любых функций и глобальных переменных, объявленных в файле. Пример вывода утилиты nm показан ниже:

9.png


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


- U Неопределенный символ, обычно ссылка на внешний символ.
- T Символ, определенный в текстовой части, обычно имя функции.
- t Локальный символ, определенный в текстовой части. В программе на C это обычно приравнивается к статической функции.
- D Инициализированное значение данных.
-C Неинициализированное значение данных.

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

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

10.png


На этом этапе некоторым символам (например, main) были назначены виртуальные адреса, новые (frame_dummy) были введены в результате процесса связывания, некоторые (my_unitialized_global) изменили свой тип символа, а другие остались undefined, поскольку они продолжают ссылаться на внешние символы. В этом случае исследуемый двоичный файл динамически связан, а неопределенные символы определены в общей библиотеке C. Более подробную информацию о nm можно найти на соответствующей странице руководства.

LDD

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

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

Преимущества статической компоновки заключаются в том, что (1) она приводит к несколько более быстрому вызову функций и (2) легче распространять двоичные файлы, потому что не нужно делать никаких предположений относительно доступности кода библиотеки в пользовательских системах. К недостаткам статической компоновки можно отнести (1) более крупные исполняемые файлы и (2) большую сложность обновления программ при изменении компонентов библиотеки. Программы сложнее обновлять, потому что их необходимо повторно связывать каждый раз при изменении библиотеки. С точки зрения реверс инжиниринга статическая компоновка несколько усложняет ситуацию. Если перед нами стоит задача анализа статически связанного двоичного файла, не существует простого способа ответить на вопросы "Какие библиотеки связаны с этим двоичным файлом?" и "Какая из этих функций является библиотечной функцией?". В главе 12 обсуждаются проблемы, возникающие при обратном проектировании статически связанного кода.

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

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

11.png

12.png


Чтобы динамическое связывание работало должным образом, динамически связываемые двоичные файлы должны указывать, от каких библиотек они зависят, а также конкретные ресурсы, которые требуются от каждой из этих библиотек. В результате, в отличие от статически связанных двоичных файлов, довольно просто определить библиотеки, от которых зависит динамически подключаемый двоичный файл. Утилита ldd (список динамических зависимостей) - это простой инструмент, используемый для перечисления динамических библиотек, необходимых для любого исполняемого файла. В следующем примере ldd используется для определения библиотек, от которых зависит веб-сервер Apache:

13.png

Утилита ldd доступна в системах Linux и BSD. В системах OS X аналогичные функции доступны при использовании утилиты otool с параметром –L: otool -L filename. В системах Windows утилита dumpbin, часть набора инструментов Visual Studio, может использоваться для вывода списка зависимых библиотек: dumpbin /dependents filename.

objdump

В то время как ldd довольно специализирован, objdump чрезвычайно универсален. Цель objdump - "отображать информацию из объектных файлов". Это довольно широкая цель, и для ее достижения objdump реагирует на большое количество (более 30) параметров командной строки, предназначенных для извлечения различной информации из объектных файлов. objdump можно использовать для отображения следующих данных (и многого другого), связанных с объектными файлами:

Заголовки разделов

Сводная информация по каждому разделу в файле программы.

Частные заголовки

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

Отладочная информация

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

Информация о символах

Выгружает информацию из таблицы символов аналогично утилите nm.

Список дизассемблирования

objdump выполняет дизассемблирование с линейной разверткой разделов файла, помеченных как код. При дизассемблировании кода x86 objdump может генерировать синтаксис AT&T или Intel, и дизассемблирование может быть записано в виде текстового файла. Такой текстовый файл называется мертвым листингом дизассемблирования, и, хотя эти файлы, безусловно, можно использовать для обратного проектирования, по ним сложно эффективно ориентироваться.

objdump доступен как часть набора инструментов GNU binutils9 и может быть найден в Linux, FreeBSD и Windows (через Cygwin). objdump полагается на библиотеку дескрипторов двоичных файлов (libbfd), компонент binutils, для доступа к объектным файлам и, таким образом, способен анализировать форматы файлов, поддерживаемые libbfd (среди прочих, ELF и PE). Для синтаксического анализа ELF также доступна утилита readelf. readelf предлагает большинство тех же возможностей, что и objdump, и основное различие между ними состоит в том, что readelf не полагается на libbfd.

otool

otool проще всего описать как утилиту, подобную objdump для OS X, и она полезна для анализа информации о двоичных файлах OS X Mach-O. В следующем листинге показано, как otool отображает зависимости динамической библиотеки для двоичного файла Mach-O, таким образом выполняя функцию, аналогичную ldd.

14.png

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

dumpbin

dumpbin - это утилита командной строки, включенная в набор инструментов Microsoft Visual Studio. Как и otool и objdump, dumpbin может отображать широкий спектр информации, относящейся к файлам Windows PE. В следующем листинге показано, как dumpbin отображает динамические зависимости программы калькулятора Windows аналогично ldd.

15.png

Дополнительные параметры dumpbin предлагают возможность извлекать информацию из различных разделов двоичного файла PE, включая символы, имена импортированных функций, имена экспортированных функций и дизассемблированный код. Дополнительная информация, касающаяся использования dumpbin, доступна через Microsoft Developer Network (MSDN).

C++ filt

Языки, допускающие перегрузку функций, должны иметь механизм для различия множества перегруженных версий функции, поскольку каждая версия имеет одно и то же имя. В следующем примере C ++ показаны прототипы нескольких перегруженных версий функции с именем demo:

16.png


Как правило, в объектном файле невозможно иметь две функции с одинаковыми именами. Чтобы разрешить перегрузку, компиляторы получают уникальные имена для перегруженных функций, включая информацию, описывающую последовательность типов аргументов функции. Процесс получения уникальных имен для функций с одинаковыми именами называется изменением имен. Если мы используем nm для дампа символов из скомпилированной версии предыдущего кода C ++, мы можем увидеть что-то вроде следующего (отфильтровано, чтобы сосредоточиться на версиях demo):

17.png

Стандарт C++ не определяет стандарты для схем изменения имен, оставляя разработчикам компиляторов самостоятельно разрабатывать это. Чтобы расшифровать искаженные варианты примера, показанные здесь, нам нужен инструмент, который понимает схему изменения имен нашего компилятора (в данном случае g++). В этом и заключается цель утилиты C ++ filt. c++ filt обрабатывает каждое входное слово как искаженное имя, а затем пытается определить компилятор, который был использован для создания этого имени. Когда c++ filt не распознает слово как искаженное имя, он просто выводит слово без изменений.

Если мы передадим результаты nm из предыдущего примера через c++ filt, можно будет восстановить имена функций, как показано здесь:

18.png


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

Инструменты для глубокого осмотра

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

strings

Иногда полезно задавать более общие вопросы о содержимом файла, вопросы, которые не обязательно требуют каких-либо конкретных знаний о структуре файла. Один из таких вопросов: "Содержит ли этот файл какие-либо встроенные строки?" Конечно, сначала мы должны ответить на вопрос "Что именно составляет строку?" Давайте в общих чертах определим строку как последовательность печатаемых символов. Это определение часто дополняется, чтобы указать минимальную длину и конкретный набор символов. Таким образом, мы могли указать поиск по всем последовательностям, по крайней мере, из четырех последовательных печатных символов ASCII и распечатать результаты на консоли. Поиск таких строк обычно никак не ограничивается структурой файла. Вы можете искать строки в двоичном файле ELF так же легко, как вы можете искать строки в документе Microsoft Word.

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

19.png


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

Несколько заключительных замечаний по использованию strings:

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

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

- Во многих файлах используются альтернативные наборы символов. Используйте аргумент командной строки -e, чтобы strings искали широкие символы, такие как 16-битный Unicode.

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

Как упоминалось ранее, существует ряд инструментов для генерации дизассемблирования двоичных объектных файлов в стиле мертвого списка. Бинарные файлы PE, ELF и Mach-O можно дизассемблировать с помощью dumpbin, objdump и otool соответственно. Однако ни один из них не может работать с произвольными блоками двоичных данных. Иногда вы будете сталкиваться с двоичным файлом, который не соответствует широко используемому формату файла, и в этом случае вам понадобятся инструменты, способные начать процесс дизассемблирования с заданными пользователем смещениями.

Двумя примерами таких потоковых дизассемблеров для набора инструкций x86 являются ndisasm и diStorm. ndisasm - это утилита, входящая в состав Netwide Assembler (NASM). В следующем примере показано использование ndisasm для дизассемблирования фрагмента шелл-кода, созданного с помощью платформы Metasploit.

20.png


21.png



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

Резюме

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

Если всю книгу можно ссылку, интересно почитать.

Сам по себе крякинг мало интересен, но поизучал-бы работу с этим отладчиком, может пригодится в будущем, полезно...)
Пока только две, но в планаха всю книгу конечно, я думаю, что я просто должен это сделать, ведь никто не сделает. Посмотрим как пойдет. Потом может и Гидру переведу, которая только вышла. Буду смотреть на лайки =)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
но в планаха всю книгу конечно
Яш, ты лучший! Спасибо бро, как раз подобное искал)
 
А разве от испанца недостаточно материала? Того что ты перевел на васме?
Я думаю, что в книге наверняка найдется что-то чего нет у Рикардо.
 
3. ИСТОРИЯ ПРОГРАММЫ IDA PRO

Профессиональный интерактивный дизассемблер, более известный как IDA Pro или просто IDA, является продуктом компании Hex-Rays, расположенной в городе Льеж, Бельгия. Гений программирования, стоящий за IDA, - Ильфак Гуильфанов, более известный как просто Илфак. IDA начала свою жизнь более десяти лет назад как консольное приложение для MS-DOS, которое важно тем, что помогает нам кое-что понять о природе пользовательского интерфейса IDA. Среди прочего, версии IDA без графического интерфейса пользователя поставляются для всех поддерживаемых IDA платформ и продолжают использовать интерфейс в стиле консоли.

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

Позиция Hex-Rays в отношении пиратства

Как пользователь IDA вы должны знать несколько фактов. IDA - флагманский продукт Hex-Rays; соответственно, он очень чувствителен к несанкционированному распространению IDA. В прошлом компания наблюдала прямую причинно-следственную связь между выпусками пиратских версий IDA и снижением продаж. Бывший издатель IDA, DataRescue, зашел так далеко, что разместил имена пиратов в своем Зале позора. Таким образом, IDA использует несколько методов борьбы с пиратством, чтобы обуздать пиратство и обеспечить соблюдение лицензионных ограничений.

Первый метод, о котором следует знать: каждая копия IDA помечена водяными знаками, чтобы однозначно связать ее с покупателем. Если копия IDA появляется на варезном сайте, Hex-Rays имеет возможность отследить эту копию до первоначального покупателя, который затем попадет в черный список из будущих продаж. Нередко можно найти обсуждения, связанные с “просочившимися” копиями IDA на форумах поддержки IDA в Hex-Rays.

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

Последний метод обеспечения соблюдения лицензий основан на использовании файлов ключей, привязанных к каждому покупателю. При запуске IDA ищет допустимый файл ida.key. Неспособность найти действующий ключевой файл приведет к немедленному завершению работы IDA. Ключевые файлы также используются для определения права на получение обновленных копий IDA. По сути, ida.key представляет собой квитанцию о покупке, и вы должны хранить ее, чтобы иметь право на будущие обновления.

Получение IDA Pro

Прежде всего, IDA не является бесплатным программным обеспечением. Люди из Hex-Rays зарабатывают на жизнь отчасти продажей IDA. Бесплатная версия IDA с ограниченной функциональностью доступна для людей, желающих ознакомиться с ее основными возможностями, но она отстает от самых последних версий. Бесплатная версия, более подробно описанная в Приложении A, представляет собой урезанную версию IDA 5.0 (текущая версия - 6.1). Наряду с бесплатной версией Hex-Rays также распространяет демонстрационную копию текущей версии с ограниченной функциональностью. Если восторженные отзывы, которые встречаются везде, где обсуждается реверс инжиниринг, недостаточны, чтобы убедить вас купить копию, то, потратив некоторое время на бесплатную или демонстрационную версию, вы наверняка поймете, что IDA и поддержку клиентов, которая идет вместе с ним, стоит иметь.

Версии IDA

Начиная с версии 6.0, IDA доступна в графическом интерфейсе и консольных версиях для Windows, Linux и OS X. IDA использует кроссплатформенные библиотеки графического интерфейса Qt для обеспечения согласованного пользовательского интерфейса на всех трех платформах. С точки зрения функциональности IDA Pro предлагается в двух версиях: стандартной и расширенной. Две версии различаются в первую очередь количеством архитектур процессоров, для которых они поддерживают дизассемблирование. Беглый взгляд на список поддерживаемых процессоров показывает, что стандартная версия (примерно 540 долларов США на момент написания этой статьи) поддерживает более 30 семейств процессоров, тогда как расширенная версия (почти вдвое дороже) поддерживает более 50 семейств. Дополнительные архитектуры, поддерживаемые в расширенной версии, включают, среди прочего, x64, AMD64, MIPS, PPC и SPARC.

Лицензии IDA

При покупке IDA доступны два варианта лицензирования. На веб-сайте Hex-Rays: “Именованные лицензии связаны с конкретным конечным пользователем и могут быть используется на таком количестве компьютеров, которое использует этот конкретный конечный пользователь “, в то время как” Компьютерные лицензии связаны с конкретным компьютером и могут использоваться разными конечными пользователями на этом компьютере при условии, что только один пользователь является активным в любое время “. Обратите внимание, что хотя одна именованная лицензия дает вам право устанавливать программное обеспечение на любое количество компьютеров, вы - единственный человек, который может запускать эти копии IDA, а для одной лицензии IDA может работать только на одном из этих компьютеров в любой момент времени.

ПРИМЕЧАНИЕ
В отличие от многих других лицензий на проприетарное программное обеспечение, лицензия IDA специально предоставляет пользователям право на реверс инжиниринг IDA.

Покупка IDA

До версии 6.0 покупки IDA включали версию с графическим интерфейсом для Windows, а также консольные версии для Windows, Linux и OS X. Начиная с версии 6.0, покупатели должны точно указать, в какой операционной системе они хотят запускать свою копию IDA. Каждая копия IDA 6.x включает консольные версии и версии графического интерфейса на основе Qt только для указанной операционной системы. Дополнительные лицензии для альтернативных операционных систем доступны по сниженной цене. Вы можете приобрести IDA у авторизованных дистрибьюторов, перечисленных на странице продаж IDA, или непосредственно у Hex-Rays по факсу или электронной почте. Приобретенные копии могут быть доставлены на компакт-диске или загружены, и они дают покупателю право на поддержку и обновления в течение года. Помимо установщика IDA, дистрибутив на компакт-диске содержит множество дополнительных компонентов, таких как комплект разработки программного обеспечения IDA (SDK) и другие утилиты. Пользователи, решившие загрузить приобретенную копию IDA, обычно получают только пакет установщика и должны загружать другие компоненты отдельно.

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

Обновление IDA

В меню "Справка IDA" есть возможность проверить наличие доступного обновления. Кроме того, IDA будет автоматически выдавать предупреждения о том, что срок поддержки истекает в зависимости от даты истечения срока, указанной в файле ключа. Процесс обновления обычно включает отправку файла ida.key в Hex-Rays, который затем проверит ваш ключ и предоставит вам подробную информацию о том, как получить обновленную версию. Если вы обнаружите, что ваша версия IDA слишком старая, чтобы иметь право на обновление, обязательно воспользуйтесь преимуществами сниженной цены на обновление Hex-Rays для владельцев ключей с истекшим сроком действия.

ПРЕДУПРЕЖДЕНИЕ.
Отсутствие постоянного контроля над ключевым файлом может привести к тому, что неавторизованный пользователь запросит выделенное вам обновление, что помешает вам обновить вашу копию IDA.

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

Ресурсы поддержки IDA

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

Официальная справочная документация

IDA поставляется с активируемой меню справочной системой, но в первую очередь это обзор пользовательского интерфейса IDA и подсистемы сценариев. Для IDA SDK нет справки, равно как и если у вас есть вопросы типа "Как мне сделать x?"

Страница поддержки и форумы Hex-Rays

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

На вопросы, касающиеся использования SDK, часто отвечают "Прочтите включаемые файлы". SDK официально не поддерживается при покупке IDA; однако Hex-Rays предлагает годовой план поддержки за годовую плату в размере 10 000 долларов США (да, это верно: 10 000 долларов США). Отличный ресурс для ознакомления с SDK - "Написание подключаемых модулей IDA на C/C ++" Стива Микаллефа.

OpenRCE.org

На http://www.openrce.org/ существует активное сообщество реверс инжиниринга, которое содержит многочисленные статьи, связанные с новым использованием IDA, а также форумы активных пользователей. Подобно форумам Hex-Rays, OpenRCE.org привлекает большое количество опытных пользователей IDA, которые часто более чем готовы поделиться своими советами о том, как решить практически любую проблему, с которой вы можете столкнуться с IDA.

Форумы RCE

На форумах Reverse Code Engineering (RCE) по адресу http: //www.woodmann.com/ содержится бесчисленное количество сообщений, связанных с использованием IDA Pro. Тем не менее, тематика форумов намного шире, чем использование IDA Pro, они охватывают множество инструментов и методов, полезных для реверс-инжиниринга двоичных файлов.

IDA Palace

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

Блог Ильфака

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

Ваша установка IDA

Как только вы успокоитесь от первоначального возбуждения от получения вашего блестящего нового компакт-диска IDA и приступите к задаче установки IDA, вы увидите, что ваш компакт-диск содержит каталоги с именами utilities и sdk, содержащие различные дополнительные утилиты и комплект для разработки программного обеспечения IDA соответственно. Это будет подробно обсуждено позже в книге. В корневом каталоге компакт-диска вы найдете установочный двоичный файл. Для пользователей Windows этот двоичный файл является традиционным исполняемым файлом установщика Windows. Для пользователей Linux и OS X двоичный установочный файл представляет собой сжатый файл .tar.

Установка Windows

Установить IDA в Windows очень просто. Установщик IDA для Windows требует пароль, который прилагается к вашему компакт-диску или по электронной почте, если вы загрузили свою копию IDA. Запуск установщика Windows проведет вас через несколько информационных диалогов, только один из которых требует размышлений. Как показано на рис. 3-1, вам будет предложена возможность указать место для установки или принять значение по умолчанию, предложенное установщиком. Независимо от того, выберете ли вы место по умолчанию или укажете альтернативное расположение, в оставшейся части этой книги мы будем называть выбранное вами место установки <IDADIR>. В каталоге IDA вы найдете файл ключей ida.key вместе со следующими исполняемыми файлами IDA:

-idag.exe - это версия IDA для Windows с графическим интерфейсом. Начиная с версии 6.2, этот файл больше не будет поставляться с IDA.
- idaq.exe - это версия IDA для Windows Qt с графическим интерфейсом пользователя (версии 6.0 и более поздние).
- idaw.exe - это версия IDA для Windows в текстовом режиме.

22.png


С переходом на кроссплатформенную библиотеку графического интерфейса Qt в IDA версии 6.0 родная версия IDA для Windows (idag.exe) устарела и перестанет поставляться с IDA, начиная с версии 6.2.

Установка OS X и Linux

Для установки в OS X или Linux распакуйте и распакуйте соответствующий архив в любое место по вашему выбору. В системе Linux это может выглядеть так:

# tar -xvzf ida61l.tgz

В системе OS X это будет выглядеть так:

# tar -xvzf ida61m.tgz

В любом случае у вас будет каталог верхнего уровня с именем ida, содержащий все необходимые файлы. И для OS X, и для Linux имя версии графического интерфейса - idaq, а имя версии консоли — idal. Внешний вид консольной версии очень похож на консольную версию IDA для Windows, которая показана на рисунке 3-2. Пользователям Linux может потребоваться проверить (с помощью ldd), что все разделяемые библиотеки, требуемые IDA, доступны в их системах. В частности, один подключаемый модуль, IDAPython, ожидает найти установленный Python версии 2.6. Вам может потребоваться обновить установку Python или создать символические ссылки, если это необходимо для удовлетворения требований IDA.

23.png


IDA и SELinux

Если вы пользователь Linux, у которого включен SELinux, вы можете обнаружить, что IDA жалуется, что "не может включить исполняемый стек как общий объект" при попытке загрузить желаемый модуль процессора. Команду execstack можно использовать для решения этой проблемы для отдельных модулей, как показано здесь:

execstack -c <IDADIR>/procs/pc.ilx

32-битная и 64-битная IDA


Пользователи расширенной версии IDA заметят, что у них есть две версии каждого исполняемого файла IDA, например idag.exe и idag64.exe или idaq и idaq64. Различие между версиями в том, что idax64 может дизассемблировать 64-битный код; однако все исполняемые файлы IDA представляют собой 32-битный код. В результате пользователям, использующим IDA на 64-битных платформах, необходимо убедиться, что любое поддерживающее программное обеспечение, необходимое для IDA, доступно в 32-битной версии. Например, пользователи 64-разрядной версии Linux должны убедиться, что установлена 32-разрядная версия Python, если они хотят использовать IDAPython для написания сценариев. Подробную информацию о смешивании 32- и 64-разрядного программного обеспечения см. в документации к вашей операционной системе.

Структура каталога IDA

Мгновенное знакомство с содержимым вашей установки IDA ни в коем случае не является обязательным требованием перед началом использования IDA. Однако, поскольку на данный момент наше внимание обращено на вашу новую установку IDA, давайте сначала взглянем на базовую схему. Понимание структуры каталогов IDA станет более важным по мере того, как вы перейдете к использованию более продвинутых функций IDA, которые будут рассмотрены далее в книге. Ниже приводится краткое описание каждого из подкаталогов в установке IDA (для пользователей Windows и Linux они находятся в <IDADIR>; для пользователей OS X они будут находиться в <IDADIR> /idaq.app/Contents/MacOS) :

cfg

Каталог cfg содержит различные файлы конфигурации, включая базовый файл конфигурации IDA ida.cfg, файл конфигурации графического интерфейса idagui.cfg и файл конфигурации текстового интерфейса idatui.cfg. Некоторые из наиболее полезных возможностей настройки IDA будут рассмотрены в главе 11.

idc

Каталог idc содержит основные файлы, необходимые для встроенного языка сценариев IDA, IDC. Создание сценариев с IDC будет более подробно рассмотрено в главе 15.

ids

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

loaders

Каталог загрузчиков содержит расширения IDA, которые используются в процессе загрузки файлов для распознавания и анализа известных форматов файлов, таких как файлы PE или ELF. Более подробно загрузчики IDA будут рассмотрены в главе 18.

plugins

Каталог плагинов содержит модули IDA, предназначенные для обеспечения дополнительного и в большинстве случаев определяемого пользователем поведения для IDA. Плагины IDA будут рассмотрены более подробно в главе 17.

procs

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

sig

Каталог sig содержит подписи для существующего кода, который IDA использует для различных операций сопоставления с образцом. Именно благодаря такому сопоставлению с образцом IDA может идентифицировать последовательности кода как известный код библиотеки, потенциально экономя вам значительное количество времени в процессе анализа. Подписи генерируются с использованием технологии быстрой идентификации и распознавания библиотек (FLIRT) IDA, которая будет более подробно рассмотрена в главе 12.

til

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

Мысли о пользовательском интерфейсе IDA

Наследие IDA MS-DOS остается очевидным и по сей день. Независимо от интерфейса (текстового или графического), который вы используете, IDA широко использует горячие клавиши. Хотя это не cовсем плохо, это может привести к неожиданным результатам, если вы считаете, что находитесь в режиме ввода текста, и обнаруживаете, что почти каждое нажатие клавиши заставляет IDA выполнять какое-либо действие с горячими клавишами. Например, это может произойти при использовании графического интерфейса пользователя, если вы устанавливаете курсор для внесения изменений и ожидаете, что все, что вы набираете, появится в месте расположения курсора (IDA не является текстовым процессором).

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

Последний момент, о котором стоит помнить, заключается в следующем: В IDA нет отмены! Если вы случайно нажмете клавишу, которая запускает действие горячей клавиши, не тратьте время на поиск функции отмены в системе меню IDA - вы ее не найдете. Вы также не найдете список истории команд, который поможет вам определить, что вы только что сделали.

Резюме

Разобравшись с обыденными деталями, пора перейти к использованию IDA для достижения чего-то полезного. В течение следующих нескольких глав вы узнаете, как использовать IDA для выполнения базового анализа файлов, научитесь интерпретировать отображение данных IDA и научитесь манипулировать этими отображениями, чтобы лучше понять поведение программы.
 
4. НАЧАЛО РАБОТЫ С IDA

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

В целях стандартизации примеры как в этой главе, так и в оставшейся части книги будут представлены с графическим интерфейсом Windows Qt, если только для примера не требуется конкретная, другая версия IDA (например, пример отладки Linux).

Запуск IDA

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

24.png


Если вы предпочитаете не видеть приветственное сообщение, снимите флажок "Отображать при запуске" в нижней части диалогового окна. Если вы установите этот флажок, будущие сеансы начнутся так, как если бы вы щелкнули кнопку "Go", и вы попадете прямо в пустую рабочую область IDA. Если в какой-то момент вам понадобится диалоговое окно приветствия (в конце концов, оно позволяет вам вернуться к недавно использованным файлам), вам нужно будет отредактировать ключ реестра IDA, чтобы вернуть значение DisplayWelcome равным 1. Кроме того, выбор Windows-> Reset hidden messages восстановит все ранее скрытые сообщения.

ПРИМЕЧАНИЕ. При установке в Windows IDA создает следующий ключ реестра: HKEY_CURRENT_USER\Software\Hex-Rays\IDA. Многие параметры, которые можно настроить в самой IDA (в отличие от редактирования одного из файлов конфигурации), хранятся в этом разделе реестра. Однако на других платформах IDA хранит такие значения в файле двоичных данных ($ HOME /.idapro /ida.reg), который нелегко редактировать.

Каждый из трех вариантов, показанных на рис. 4-1, предлагает несколько иной метод перехода к рабочему столу IDA. Эти три варианта запуска рассматриваются здесь:

New

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


Go

Кнопка "Go" завершает процесс загрузки и вызывает открытие IDA с пустой рабочей областью. На этом этапе, если вы хотите открыть файл, вы можете перетащить двоичный файл на рабочий стол IDA или использовать одну из опций меню "File", чтобы открыть файл. Команда File-> Open приводит к диалоговому окну открытия файла, как описано ранее. По умолчанию, IDA использует фильтр известных расширений, чтобы ограничить представление диалогового окна. Убедитесь, что вы изменили или очистили фильтр (например, выбрали All File), чтобы в диалоговом окне "File" правильно отображался файл, который вы хотите открыть. Когда вы открываете файл таким образом, IDA пытается автоматически определить тип выбранного файла; однако вам следует обратить особое внимание на диалоговое окно "Loading", чтобы увидеть, какие загрузчики были выбраны для обработки файла.

Previous

Вы должны использовать эту кнопку, если хотите открыть один из файлов в списке последних файлов, который находится непосредственно под кнопкой “Previous”. Список недавно использованных файлов заполняется значениями из подраздела History раздела реестра Windows IDA (или ida.reg на платформах, отличных от Windows). Максимальная длина списка истории изначально установлена на 10, но этот предел может быть увеличен до 100, отредактировав соответствующую запись в idagui.cfg или idatui.cfg (см. Главу 11). Использование списка истории - наиболее удобный вариант для возобновления работы с недавно использованными файлами базы данных.

Загрузка файла IDA

При выборе открытия нового файла с помощью команды File -> Open, вам будет представлен диалог загрузки, показанный на рисунке 4-2. IDA генерирует список возможных типов файлов и отображает этот список в верхней части диалогового окна. В этом списке представлены загрузчики IDA, которые лучше всего подходят для работы с выбранным файлом. Список создается путем выполнения каждого из загрузчиков файлов в каталоге загрузчиков IDA, чтобы найти все загрузчики, которые распознают новый файл. Обратите внимание, что на рис. 4-2 и загрузчик Windows PE (pe.ldw), и загрузчик EXE MS-DOS (dos.ldw) заявляют, что распознают выбранный файл. Читатели, знакомые с форматом файлов PE, не будут удивлены этим, поскольку формат файла PE является расширенной формой формата файла MS-DOS EXE. Последняя запись в списке, двоичный файл, всегда будет присутствовать, так как IDA по умолчанию загружает файлы, которые она не распознает, и это обеспечивает метод для загрузки любого файла. Когда предлагается выбор из нескольких загрузчиков, неплохая начальная стратегия - просто принять выбор по умолчанию, если у вас нет конкретной информации, противоречащей определению IDA.


25.png


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

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

Поля Loading Segment и Loading Offset активны только тогда, когда формат ввода двоичного файла выбран в сочетании с процессором семейства x86. Поскольку двоичный загрузчик не может извлечь какую-либо информацию о структуре памяти, введенные здесь значения сегмента и смещения объединяются для формирования базового адреса для содержимого загруженного файла. Если вы забыли указать базовый адрес в процессе начальной загрузки, базовый адрес образа IDA можно изменить в любое время с помощью команды Edit→Segments→Rebase program

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

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

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

Использование загрузчика двоичных файлов

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

Когда модуль процессора x86 соединен с двоичным загрузчиком, отображается диалоговое окно, показанное на рисунке 4-3. При отсутствии распознаваемых заголовков файлов, доступных для помощи IDA, пользователь должен указать, должен ли код обрабатываться как 16-битный или 32-битный код режима. Другие процессоры, для которых IDA может различать 16- и 32-разрядные режимы, включают ARM и MIPS.

26.png


Двоичные файлы не содержат информации о структуре их памяти (по крайней мере, информации, которую IDA знает, как распознать). Если выбран тип процессора x86, информация о базовом адресе должна быть указана в полях Loading Segment и Loading Offset диалогового окна загрузчика, как упоминалось ранее. Для всех других типов процессоров IDA отображает диалоговое окно структуры памяти, показанное на рисунке 4-4. Для удобства вы можете создать раздел RAM, раздел ROM или и то, и другое и назначить диапазон адресов для каждого из них. Параметры входного файла используются, чтобы указать, какая часть входного файла (по умолчанию - весь файл) должна быть загружена и по какому адресу должно быть отображено содержимое файла.

27.png


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

28.png


Файлы базы данных IDA

Когда вас устраивают варианты загрузки и вы нажимаете ОК, чтобы закрыть диалоговое окно, начинается настоящая работа по загрузке файла. На этом этапе цель IDA - загрузить выбранный исполняемый файл в память и проанализировать соответствующие части. Это приводит к созданию базы данных IDA, компоненты которой хранятся в четырех файлах, каждый с базовым именем, соответствующим выбранному исполняемому файлу, и расширениями .id0, .id1, .nam и .til. Файл .id0 содержит содержимое базы данных в стиле B-дерева, а файл .id1 содержит флаги, описывающие каждый байт программы. Файл .nam содержит индексную информацию, относящуюся к именованным программам, отображаемым в окне Nane IDA (подробнее рассматривается в главе 5). Наконец, файл .til используется для хранения информации об определениях локальных типов, специфичных для данной базы данных. Форматы каждого из этих файлов являются собственностью IDA, и их нелегко редактировать вне среды IDA.

Для удобства эти четыре файла заархивированы и, возможно, сжимаются в один файл IDB всякий раз, когда вы закрываете текущий проект. Когда вы обращаетесь к базе данных IDA, вы обычно имеют в виду файл IDB. Несжатый файл базы данных обычно в 10 раз превышает размер исходного входного двоичного файла. Когда база данных закрыта должным образом, вы никогда не должны видеть файлы с расширениями .id0, .id1, .nam или .til в ваших рабочих каталогах. Их присутствие часто указывает на то, что база данных не была закрыта должным образом (например, при сбое IDA) и что база данных может быть повреждена.

ПРЕДУПРЕЖДЕНИЯ ЗАГРУЗЧИКА

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

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

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

Сегмент импорта кажется разрушенным. Это МОЖЕТ означать, что файл был упакован или изменен иным образом, чтобы затруднить анализ. Если вы хотите увидеть сегмент импорта в исходной форме, перезагрузите его, сняв флажок make imports section.

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

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

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

Создание базы данных IDA

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

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

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

Идентификация компилятора

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

Аргумент функции и идентификация локальной переменной

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

Информация о типе данных

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

Закрытие баз данных IDA

Каждый раз, когда вы закрываете базу данных, закрываете ли вы IDA полностью или просто переключаетесь на другую базу данных, вам открывается диалоговое окно Save Database, как показано на рисунке 4-6.

29.png


Если это первоначальное сохранение вновь созданной базы данных, имя файла новой базы данных получается из имени входного файла путем замены входного расширения расширением .idb (например, example.exe дает базу данных с именем example.idb). Если входной файл не имеет расширения, добавляется .idb для формирования имени базы данных (например, httpd дает httpd.idb). Доступные параметры сохранения и связанные с ними последствия приведены в следующем списке:

Don’t pack database

Этот параметр просто сбрасывает изменения в четырех файлах компонентов базы данных и закрывает рабочий стол без создания файла IDB. Этот вариант не рекомендуется при закрытии баз данных.

Pack database (Store)

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

Pack database (Deflate)

Параметр Deflate идентичен параметру Store, за исключением того, что файлы компонентов базы данных сжимаются в архиве IDB.

Collect garbage

Запрос на сборку мусора заставляет IDA удалять любые неиспользуемые страницы памяти из базы данных перед ее закрытием. Выберите эту опцию вместе с Deflate, чтобы создать файл IDB минимального размера. Этот параметр обычно не требуется, если только на диске не хватает места.

DON’T SAVE the database

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

Повторное открытие базы данных

Конечно, повторное открытие существующей базы данных не связано с ракетной наукой (Если только вы не открываете rocket_science.idb. ), поэтому вам может быть интересно, почему эта тема вообще затронута. В обычных обстоятельствах вернуться к работе с существующей базой данных так же просто, как выбрать базу данных с помощью одного из методов открытия файлов IDA. Файлы базы данных открываются намного быстрее во второй (и последующий) раз, потому что нет необходимости выполнять анализ. В качестве дополнительного бонуса IDA восстанавливает ваш рабочий стол IDA до того состояния, в котором он находился на момент закрытия.

А теперь плохие новости. Вы не поверите, но иногда IDA дает сбой. Из-за ошибки в самой IDA или из-за ошибки в каком-то передовом плагине, который вы установили, сбои оставляют открытые базы данных в потенциально поврежденном состоянии. После перезапуска IDA и попытки повторно открыть затронутую базу данных вы, вероятно, увидите одно из диалоговых окон, показанных на рисунках 4-7 и 4-8.

30.png


Когда IDA дает сбой, IDA не может закрыть активную базу данных, а промежуточные файлы базы данных не удаляются. Если вы работали с определенной базой данных не в первый раз, может возникнуть ситуация, в которой одновременно присутствуют как файл IDB, так и потенциально поврежденные промежуточные файлы. Файл IDB представляет собой последнее известное исправное состояние базы данных, а промежуточные файлы содержат любые изменения, которые могли быть внесены с момента последней операции сохранения. В этом случае вам будет предложено вернуться к сохраненной версии или возобновить использование открытой, потенциально поврежденной версии, как показано на рис. 4-7. Выбор Continue with Unpacked Base ни в коем случае не гарантирует, что вы восстановите свою работу. Распакованная база данных, вероятно, находится в несогласованном состоянии, что заставит IDA предложить диалоговое окно, показанное на рис. 4-8.В этом случае сама IDA рекомендует рассмотреть возможность восстановления из упакованных данных, поэтому считайте себя предупрежденным, если вы решите использовать восстановленную базу данных.

31.png


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

Введение в рабочий стол IDA

Учитывая количество времени, которое вы, вероятно, потратите, глядя на свой рабочий стол IDA, вам нужно будет потратить некоторое время на ознакомление с его различными компонентами. На рис. 4-9 показан обзор рабочего стола IDA по умолчанию. Поведение рабочего стола во время анализа файлов обсуждается в следующем разделе.

В этом вводном обзоре интересны следующие области:

1. Область панели инструментов [1] содержит инструменты, соответствующие наиболее часто используемым операциям IDA. Панели инструментов добавляются на рабочий стол и удаляются с него с помощью команды View->Toolbars. Используя перетаскивание, вы можете изменить положение каждой панели инструментов в соответствии со своими потребностями. На рис. 4-9 показана панель инструментов основного режима IDA с одним рядом кнопок инструментов. Панель инструментов расширенного режима доступна с помощью View→Toolbars→Advanced mode. Панели инструментов расширенного режима содержат три полных ряда кнопок инструментов.

32.png


2.Горизонтальная цветная полоса - это обзорный навигатор IDA [2], также называемый полосой навигации. Полоса навигации представляет собой линейное представление адресного пространства загруженного файла. По умолчанию представлен весь диапазон адресов двоичного файла. Вы можете увеличивать и уменьшать масштаб диапазона адресов, щелкнув правой кнопкой мыши в любом месте полосы навигации и выбрав один из доступных вариантов масштабирования. Разные цвета представляют разные типы содержимого файла, например данные или код. Небольшой индикатор текущего положения (по умолчанию желтый) указывает на адрес полосы навигации, который соответствует текущему диапазону адресов, отображаемому в окне дизассемблирования. При наведении курсора мыши на любую часть полосы навигации появляется всплывающая подсказка, описывающая это место в двоичном файле. При нажатии на полосу навигации происходит перемещение в выбранное место в двоичном файле. Цвета, используемые в полосе навигации, можно настроить с помощью команды Options->Colors. Перетаскивание полосы навигации от рабочего стола IDA приводит к отключению обзорного навигатора, как показано на рисунке 4-10. На рис. 4-10 также показан индикатор текущего положения (половина длины, направленная вниз стрелка слева от местоположения [1]) и цветовой ключ, идентифицирующий содержимое файла по функциональным группам.


33.png


3. Возвращаясь к рисунку 4-9, вкладки [3] представлены для каждого из отображаемых в настоящее время открытых данных. Отображение данных содержит информацию, извлеченную из двоичного файла, и представляет различные представления в базе данных. Большая часть вашей аналитической работы, вероятно, будет происходить через взаимодействие с доступными данных. На рис. 4-9 показаны три из доступных окошек данных: IDA->View, Functions, and Graph Overview. Дополнительные окошки данных доступны через меню View->Open Subviews, и это меню также используется для восстановления любых окошек, которые были закрыты намеренно или случайно.

4. Окно дизассемблирования [4] является основным отображением данных. Для представления дизассемблирования доступны два стиля отображения: представление графа (по умолчанию) и представление списка. В виде графа IDA отображает графа отдельной функции в любой момент времени в виде блок-схемы. Когда это объединено с обзором графа, вы можете получить представление о потоке функции, используя визуальную разбивку структуры функции. Когда окно IDA-View активно, пробел переключает отображение между стилем графического представления и стилем листинга. Если вы хотите, чтобы список отображался по умолчанию, вы должны снять флажок Use graph view by default on the Graph tab в меню Options->General, как показано на рисунке 4-11.

34.png


5. В графическом представлении редко возможно разместить весь график функции в области отображения за один раз. Обзор графа [5], доступный только при активном представлении графа, обеспечивает уменьшенный снимок основной структуры графа. Пунктирный прямоугольник обозначает текущее окошко в графическом представлении. Щелчок по обзору графа изменяет положение представления графа соответственно.

6. Output window [6] - это то место, где вы можете ожидать найти любые информационные сообщения, созданные IDA. Здесь вы найдете сообщения о состоянии, относящиеся к этапу анализа файлов, а также сообщения об ошибках, возникающих в результате операций, запрошенных пользователем. Окно вывода примерно соответствует устройству вывода консоли.

7. Functions window [7] будет обсуждаться далее в главе 5.

Поведение рабочего стола во время первоначального анализа

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

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

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


35.png


36.png


Два особенно полезных сообщения о ходе выполнения: You may start to explore the input file right now [1] и The initial autoanalysis has been finished [2] Первое сообщение информирует вас о том, что IDA добилась достаточного прогресса в своем анализе, и вы можете начать навигацию по различным окощкам данных. Однако навигация не подразумевает изменений, и вам следует подождать, чтобы внести какие-либо изменения в базу данных, пока не будет завершена фаза анализа. Если вы попытаетесь изменить базу данных до завершения фазы анализа, механизм анализа может появиться позже и изменить ваши изменения, или вы даже можете помешать механизму анализа правильно выполнять свою работу. Второе из этих сообщений, которое не требует пояснений, указывает на то, что вы не можете ожидать больше автоматических изменений в отображении данных на рабочем столе. На этом этапе можно безопасно вносить любые изменения в базу данных.

Советы и приемы для IDA Desktop

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

- Чем больше экранной площади вы посвятите IDA, тем счастливее вы будете. Используйте этот факт, чтобы оправдать покупку монитора большого размера (или двух)!
- Не забывайте команду View->Open Subviews как средство восстановления дисплеев с данными, которые вы случайно закрыли.
-Команда Windows->Reset Desktop предлагает удобный способ быстро восстановить исходный вид рабочего стола.
- Используйте команду Windows->Save Desktop, чтобы сохранить текущий макет конфигураций рабочего стола, который вы считаете особенно полезным. Команда Windows->Load Desktop используется для быстрого возврата к сохраненному макету.
- Единственное окно, для которого можно изменить шрифт отображения, - это окно дизассемблера (графическое или листинговое). Шрифты устанавливаются с помощью команды Options->Font.

Сообщение об ошибках

Как и в случае с любым другим программным обеспечением, IDA, как известно, содержит случайные ошибки, так чего же вы можете ожидать от Hex-Rays, если вы думаете, что нашли ошибку в самой IDA? Во-первых, у Hex-Rays одна из самых отзывчивых систем поддержки, с которыми вы когда-либо могли иметь дело. Во-вторых, не удивляйтесь, если вы получите ответ от самого Ильфака в течение дня после отправки запроса в службу поддержки.

Для отправки отчетов об ошибках доступны два метода. Вы можете отправить электронное письмо по адресу support@hex-rays.com или, если вы предпочитаете не использовать электронную почту, вы можете отправить сообщение на форум отчетов об ошибках на досках объявлений Hex-Rays. В любом случае вы должны одновременно убедиться, что вы можете воспроизвести свою ошибку, и быть готовым предоставить Hex-Rays копию файла базы данных, связанного с проблемой. Напомним, что Hex-Rays предоставляет поддержку SDK только за дополнительную плату. В случае ошибок, связанных с установленным вами подключаемым модулем, вам необходимо связаться с автором подключаемого модуля. В случае ошибок, связанных с надстройкой, которую вы разрабатываете, вам необходимо воспользоваться форумом поддержки, доступными для пользователей IDA, и надеяться на полезный ответ от других пользователей.

Резюме

Знакомство с рабочим пространством IDA значительно расширит ваш опыт работы с IDA. Параметры, которые вы выбираете на этапе начальной загрузки и последующий автоанализ, выполняемый IDA, создают основу для всего анализа, который вы будете выполнять позже. На этом этапе вы можете быть довольны работой, которую IDA выполнила от вашего имени, и для простых двоичных файлов автоанализ может быть всем, что вам нужно. С другой стороны, если вам интересно, что представляет собой интерактивность в IDA, теперь вы готовы глубже погрузиться в функциональность многих окошек данных IDA. В следующих главах вы познакомитесь с каждым из основных окошек, с обстоятельствами, при которых каждый из них окажется полезным, и с тем, как использовать эти окошки для улучшения и обновления ваших баз данных.
 
Привет.
Работаю на износ, мало сплю, перевожу прям на работе ночью.
 
а почему вам потом со своим авторским переводом в редакцию не обратиться для печати этой книги на русском, наверняка гонорар будет за ваши труды
 
А я обязательно напишу Ильфаку, и покажу как я трудился ???
 
Пока просто читайте, это всё для ВАС
 
5. ОКОШКИ ДАННЫХ IDA

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

В IDA нет отмены.

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

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

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

IDA предлагает хорошие контекстно-зависимые действия меню в ответ на щелчок правой кнопкой мыши.

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

Помня об этих фактах, давайте приступим к рассмотрению основных окошек данных IDA.

Основные окошки IDA

В конфигурации по умолчанию IDA создает семь (начиная с версии 6.1) окон отображения на этапе начальной загрузки и анализа нового двоичного файла. Каждое из этих окон доступно через набор вкладок заголовков, отображаемых непосредственно под полосой навигации (показанной ранее на рисунке 4-9). Три сразу видимых окна - это окно IDA->View, окно Functions и окно Output. Независимо от того, открыты они по умолчанию или нет, все окна, обсуждаемые в этой главе, можно открыть через меню View->Open Subviews. Помните об этом факте, так как очень легко случайно закрыть окошки.

Клавиша ESC - одна из наиболее полезных горячих клавиш во всей IDA. Когда активно окно дизассемблера, клавиша ESC действует аналогично кнопке "Назад" в веб-браузере и поэтому очень полезна при навигации по окошку дизассемблера (навигация подробно описана в главе 6). К сожалению, когда активно любое другое окно, клавиша ESC закрывает окно. Иногда это именно то, что вам нужно. В других случаях вам сразу же захочется вернуть это закрытое окно.

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

Также известное как окно IDA->View, окно дизассемблирования будет вашим основным инструментом для управления и анализа двоичных файлов. Соответственно, важно, чтобы вы хорошо познакомились с способом представления информации в окне дизассемблирования.

Для окна дизассемблирования доступны два формата отображения: представление по умолчанию на основе графа и представление списка с текстовой ориентацией. Большинство пользователей IDA, как правило, предпочитают одно представление другому, и представление, которое лучше соответствует вашим потребностям, часто определяется тем, как вы предпочитаете визуализировать поток программы. Если вы предпочитаете использовать представление текстового списка в качестве представления по умолчанию, вы можете изменить значение по умолчанию, используя диалоговое окно Options→General, чтобы отключить параметр Use graph view by default на вкладке “Graph”. Когда режим дизассемблирования активен, вы можете легко переключаться между графическим и листинговым представлениями в любое время, используя клавишу пробела.

Просмотр графа IDA

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


37.png


На экране вы заметите, что IDA использует стрелки разного цвета, чтобы различать разные типы потоков между блоками функции. Базовые блоки, которые завершаются условным переходом, генерируют два возможных потока в зависимости от тестируемого условия: стрелка YES (да, ветка активна ) по умолчанию зеленая, и стрелка NO (нет, ветка не выполняется), по умолчанию красная. Базовые блоки, которые заканчиваются только одним потенциальным блоком-преемником, используют границу Normal (по умолчанию синий), чтобы указать на следующий блок, который должен быть выполнен.

В графическом режиме IDA отображает по одной функции. Для пользователей с колесиком мыши масштабирование графика возможно с помощью комбинации колесика + CTRL. Для управления масштабированием с клавиатуры требуется нажать CTRL+ для увеличения или CTRL– для уменьшения (с помощью клавиш + и - на цифровой клавиатуре). Большие или сложные функции могут привести к чрезмерному загромождению графического представления, что затруднит навигацию по графику. В таких случаях доступно окно Graph Overview (см. Рис. 5-2), чтобы обеспечить некоторую ситуационную осведомленность. В окне обзора всегда отображается полная блочная структура графа вместе с пунктирной рамкой, которая указывает область графа, просматриваемую в данный момент в окне дизассемблирования. Пунктирную рамку можно перемещать по обзорному окну, чтобы быстро переместить графическое представление в любое желаемое место на графе.


38.png


При отображении графа есть несколько способов, которыми вы можете управлять представлением в соответствии с вашими потребностями:

Панорамирование

Во-первых, помимо использования окна Graph Overview для быстрого изменения положения графа, вы также можете изменить положение графа, щелкнув и перетащив фон представления графа.

Эй, Ничего не пропало?

При использовании графического представления может показаться, что вам доступно меньше информации о каждой строке дизассемблирования. Причина этого в том, что IDA предпочитает скрывать многие из более традиционных частей информации о каждой дизассемблированной строке (например, информацию о виртуальном адресе), чтобы минимизировать объем пространства, необходимого для отображения каждого базового блока. Вы можете выбрать отображение дополнительной информации с каждой линией, выбрав среди доступных частей линии, доступных через вкладку Disassembly в меню Options->General. Например, чтобы добавить виртуальные адреса к каждой строке, мы включаем префиксы строк, преобразуя граф с рисунка 5-1 в граф, показанный на рисунке 5-3.


39.png



Перестановка блоков

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

Группировка и сворачивание блоков

Блоки можно сгруппировать по отдельности или вместе с другими блоками и свернуть, чтобы уменьшить беспорядок в окошке. Свертывание блоков - особенно полезный метод отслеживания блоков, которые вы уже проанализировали. Вы можете свернуть любой блок, щелкнув правой кнопкой мыши строку заголовка блока и выбрав - Group Nodes.

Создание дополнительных окон дизассемблирования

Если вы когда-нибудь захотите просмотреть графики двух функций одновременно, все, что вам нужно сделать, это открыть другое окно дизассемблирования, используя Views->Open Subviews->Disassembly. Первое открытое окно дизассемблирования называется IDA View->A. Последующие окна дизассемблирования называются IDA View->B, IDA View->C и так далее. Каждое окно дизассемблирования независимо от другого, и вполне допустимо просматривать график в одном окне и просматривать текстовый листинг в другом или просматривать три разных графика в трех разных окнах.

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

Текстовое представление IDA

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

На рис. 5-4 показано текстовое представление той же функции, что и на рис. 5-1 и 5-3. Дизассемблирование представлено линейно, по умолчанию отображаются виртуальные адреса. Виртуальные адреса обычно отображаются в формате [НАЗВАНИЕ СЕКЦИИ]: [ВИРТУАЛЬНЫЙ АДРЕС], например .text: 004011C1.

40.png



Левая часть дисплея [1] называется arrows window и используется для изображения нелинейного потока внутри функции. Сплошные стрелки представляют собой безусловные переходы, а пунктирные стрелки - условные переходы. Когда переход (условный или безусловный) передает управление более раннему адресу в программе, используется жирная линия (сплошная или пунктирная). Такой обратный поток в программе часто указывает на наличие цикла. На рис. 5-4 стрелка цикла проходит от адреса 004011CF к 004011C5.

Объявления [2] (также присутствующие в виде графика) представляют собой лучшую оценку IDA относительно структуры фрейма стека функции. IDA вычисляет структуру кадра стека функции, выполняя подробный анализ поведения указателя стека и любого указателя кадра стека, используемого в функции. Окошки стека обсуждаются далее в главе 6.

Комментарии (точка с запятой вводит комментарий) [3] представляют собой перекрестные ссылки. В этом случае мы видим перекрестные ссылки кода (в отличие от перекрестных ссылок данных), которые указывают, что другая программная инструкция передает управление в место, содержащее комментарий перекрестной ссылки. Перекрестные ссылки являются предметом главы 9.

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

Окно функций

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

malloc .text 00BDC260 00000180 R . . . B . .

Эта конкретная строка указывает, что функция malloc может быть найдена в секции .text двоичного файла по виртуальному адресу 00BDC260, имеет длину 384 байта (шестнадцатеричное 180), возвращается к вызывающей стороне (R) и использует регистр EBP (B) для ссылаться на его локальные переменные. Флаги, используемые для описания функции (например, R и B выше), описаны во встроенном файле справки IDA (или при щелчке правой кнопкой мыши по функции и выборе Properties. Флаги отображаются как редактируемые флажки в появившемся диалоговом окне свойств).

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

Окно вывода

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

Вторичные окошки IDA

В дополнение к окнам дизассемблирования, функций и вывода, IDA открывает ряд других окон с вкладками на рабочем столе IDA. Эти вкладки находятся прямо под полосой навигации (см. [3] Рис. 4-9). Эти окна используются для предоставления альтернативных или специализированных представлений в базе данных. Полезность этих окошек зависит как от характеристик анализируемого двоичного файла, так и от ваших навыков работы с IDA. Некоторые из этих окон являются достаточно специализированными, чтобы потребовать более подробного рассмотрения в следующих главах.

Окно Hex View

В данном случае шестнадцатеричный вид используется неправильно, так как окно шестнадцатеричного представления IDA может быть настроено для отображения различных форматов и может использоваться как шестнадцатеричный редактор. По умолчанию окно Hex View предоставляет стандартный шестнадцатеричный дамп содержимого программы с 16 байтами на строку и символами ASCII, отображаемыми рядом. Как и в случае с окном дизассемблера, можно одновременно открыть несколько шестнадцатеричных представлений. Первое окно Hex называется Hex View->A, второе Hex View->B, следующее Hex View->C и так далее. По умолчанию первое окно Hex синхронизируется с первым окном дизассемблирования. Когда представление дизассемблирования синхронизируется с шестнадцатеричным представлением, прокрутка в одном окне заставляет другое окно прокручиваться в то же место (тот же виртуальный адрес). Кроме того, когда элемент выбран в представлении дизассемблирования, соответствующие байты выделяются в шестнадцатеричном представлении. На рис. 5-5 курсор расположен по адресу 0040108C, инструкции вызова, в результате чего пять байтов, составляющих команду, выделяются в окне шестнадцатеричного дампа.

41.png



На рис. 5-5 также показано контекстное меню шестнадцатеричного отображения, доступное при щелчке правой кнопкой мыши в любом месте шестнадцатеричного отображения. В этом контекстном меню вы можете указать, с каким видом дизассемблирования вы хотите синхронизировать конкретное шестнадцатеричное окошко. Отмена выбора параметра синхронизации позволяет прокручивать шестнадцатеричное окно независимо от любого окна дизассемблера. Выбор пункта меню Edit превращает Hex View в шестнадцатеричный редактор. По окончании редактирования вы должны либо зафиксировать, либо отменить свои изменения, чтобы вернуться в режим просмотра. Пункт меню Data Format позволяет вам выбирать из множества форматов отображения, таких как 1-, 2-, 4- или 8-байтовые шестнадцатеричные данные; знаковая десятичная дробь; или беззнаковые десятичные целые числа и различные форматы с плавающей запятой. Параметр меню Columns позволяет вам изменять количество столбцов, используемых на окошке, а параметр Text позволяет включать и выключать дамп текста.

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

Окно экспорта

В окне Exports перечислены точки входа в файл. К ним относятся точка входа в выполнение программы, указанная в разделе заголовка, а также любые функции и переменные, которые файл экспортирует для использования другими файлами. Экспортированные функции обычно находятся в разделяемых библиотеках, таких как файлы Windows DLL. Экспортированные записи перечислены по имени, виртуальному адресу и, если применимо, по порядковому номеру. Для исполняемых файлов окно экспорта всегда содержит как минимум одну запись: точку входа выполнения программы. IDA называет эту точку входа start. Типичная запись в окне экспорта:

LoadLibraryA 7C801D77 578

Как и во многих других окнах IDA, двойной щелчок по записи в окне Exports переместит окно дизассемблирования на адрес, связанный с этой записью. Окно предлагает функции, доступные в инструментах командной строки, таких как objdump (-T), readelf (-s) и dumpbin (/ EXPORTS).

Окно импорта

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

0040E108 GetModuleHandleA KERNEL32

Двойной щелчок по этому импорту переместит окно дизассемблера на адрес 0040E108. Содержимое этой ячейки памяти в шестнадцатеричном представлении будет равно ?? ?? ?? ??. IDA - это инструмент статического анализа, и у него нет способа узнать, какой адрес будет введен в эту ячейку памяти при выполнении программы. Окно Импорт также предлагает функции, доступные в инструментах командной строки, таких как objdump (-T), readelf (-s) и dumpbin (/IMPORTS).

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

Окно структур

Окно Structures используется для отображения макета любых сложных структур данных, таких как структуры C или объединения, которые, по мнению IDA, используются в двоичном файле. На этапе анализа IDA обращается к своей обширной библиотеке сигнатур типов функций в попытке сопоставить типы параметров функций с памятью, используемой в программе. Окно Structures, показанное на рисунке 5-6, показывает, что IDA считает, что программа использует структуру данных sockaddr7.

42.png


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

Двумя основными способами использования окна Структуры являются (1) предоставление готового справочного материала для компоновки стандартных структур данных и (2) предоставление вам средств для создания ваших собственных структур данных для использования в качестве шаблонов компоновки памяти, когда вы обнаружите пользовательские структуры данных в программе. Определение структуры и применение структур в дизассемблерах более подробно описаны в главе 8.

Окно перечислений

Окно Enums несколько похоже на окно Structures. Когда IDA обнаруживает использование стандартного перечислимого типа данных (перечисление C), этот тип данных будет указан в окне Enums. Вы можете сделать свои дизассемблированные файлы более читаемыми, используя перечисления вместо целочисленных констант. Как и окно Structures, окно Enums предлагает средства для определения ваших собственных перечисляемых типов, которые вы можете использовать с вашими дизассемблированными двоичными файлами.

Окошки IDA третьего уровня

Последние окошки, которые мы обсудим, - это те , которые IDA не открывает по умолчанию. Каждое из этих окошек доступно через View-> Open Subviews, но они, как правило, предоставляют информацию, к которой вам может не потребоваться немедленный доступ, и поэтому изначально они не мешают.

Окно строк

Окно Strings - это встроенный в IDA эквивалент утилиты strings и некоторых других. В версиях IDA 5.1 и ранее окно Строки было открыто как часть рабочего стола по умолчанию; однако в версии 5.2 окно Строки больше не открывается по умолчанию, хотя оно остается доступным через View->Open Subviews->Strings.

Назначение окна Строки - отобразить список строк, извлеченных из двоичного файла, вместе с адресом, по которому находится каждая строка. Как и при двойном щелчке по именам в окне Names, при двойном щелчке по любой строке, перечисленной в окне Строки, окно дизассемблирования переходит к адресу выбранной строки. При использовании с перекрестными ссылками (глава 9) окно Строки предоставляет средства для быстрого обнаружения интересной строки и возврата к любому месту в программе, которое ссылается на эту строку. Например, вы можете увидеть в списке строку SOFTWARE\Microsoft\Windows\CurrentVersion\Run и задаться вопросом, почему приложение обращается к этому конкретному ключу в реестре Windows. Как вы увидите в следующей главе, для перехода к месту в программе, которое ссылается на эту строку, требуется всего четыре щелчка мышью. Понимание работы окна Строки необходимо для его эффективного использования. IDA не хранит постоянно строки, извлекаемые из двоичного файла. Поэтому каждый раз, когда открывается окно Строки, необходимо сканировать всю базу данных или повторно сканировать ее на предмет содержимого строки. Сканирование строк выполняется в соответствии с настройками окна Строки, и вы можете получить доступ к этим настройкам, щелкнув правой кнопкой мыши в окне Strings и выбрав Setup. Как показано на рисунке 5-7, окно Setup Strings используется для определения типов строк, которые должна сканировать IDA. Тип строки по умолчанию, который сканирует IDA, - это 7-битная строка ASCII с нулевым символом в конце и длиной не менее пяти символов.

43.png


Если вы ожидаете встретить что-либо, кроме строк в стиле C, вам следует перенастроить окно Setup Strings, чтобы выбрать подходящий тип строки для поиска. Например, программы Windows часто используют строки Unicode, в то время как двоичные файлы Borland Delphi используют строки в стиле Pascal с длиной 2 байта. Каждый раз, когда вы закрываете окно Setup Strings, нажимая ОК, IDA повторно проверяет базу данных на наличие строк в соответствии с новыми настройками. Особого упоминания заслуживают два варианта настройки:

Отображать только определенные строки

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

Игнорировать инструкции/определения данных

Эта опция заставляет IDA сканировать строки в инструкциях и существующих определениях данных. Использование этой опции позволяет IDA (1) видеть строки, которые могут быть встроены в часть кода двоичного файла и были ошибочно преобразованы в инструкции, или (2) видеть строки в данных, которые могут быть отформатированы как нечто иное, чем строка (например, как массив байтов или целых чисел). Этот параметр также приведет к созданию множества ненужных строк, которые представляют собой последовательности, состоящие из пяти или более символов ASCII, независимо от того, читаются они или нет. Эффект от использования этого параметра аналогичен использованию команды strings с параметром -a.

Рисунок 5-8 демонстрирует, что IDA не обязательно показывает все строки в двоичном файле, если настройка не настроена должным образом. В этом случае не выбран параметр Ignore instructions/data.

44.png



В результате строка в местоположении .rdata: 0040C19C (“Please guess a number between 1 and %d“) остается необнаруженной. Мораль здесь заключается в том, чтобы убедиться, что вы ищете все типы строк, которые вы ожидаете встретить, во всех местах, где вы можете их найти.

Окно имен

Окно Names, показанное на рисунке 5-9, предоставляет сводный список всех глобальных имен в двоичном файле. Имя - это не что иное, как символическое описание виртуального адреса программы. Первоначально IDA получает список имен из таблицы символов и анализа сигнатур во время начальной загрузки файла. Имена могут быть отсортированы в алфавитном порядке или в порядке виртуальных адресов (по возрастанию или убыванию). Окно имен полезно для быстрого перехода к известным местам в списке программ. Двойной щелчок по любому элементу в окне Names немедленно перейдет к представлению дизассемблера, чтобы отобразить выбранное имя.

45.png


Отображаемые имена имеют цветовую и буквенную кодировку. Схема кодирования кратко изложена ниже:

F Обычная функция. Это функции, которые IDA не распознает как библиотечные.

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

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

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

D Данные. Расположение именованных данных обычно представляет собой глобальные переменные.

А Строковые данные. Это указанная ячейка данных, содержащая последовательность символов, которая соответствует одному из известных строковых типов данных IDA, например, строке ASCII C с завершающим нулем.

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

46.png


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

Окно сегментов

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

47.png


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

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

Аналогами окна Segments в командной строке являются objdump (-h), readelf (-S) и dumpbin (/HEADERS).


Окно сигнатур

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

Окно Signatures используется для вывода списка сигнатур, которые IDA уже сопоставила с открытым двоичным файлом. Здесь показан пример из файла Windows PE:


48.png


Этот пример показывает, что IDA применила сигнатуры vc32rtf (из <IDADIR> / sigs) к двоичному файлу и при этом смогла распознать 501 функций как библиотечные функцию. Эти 501 функции, которую вам не нужно реверсить!

Как минимум в двух случаях вы захотите узнать, как применять дополнительные сигнатуры к вашим двоичным файлам. В первом случае IDA может не распознать компилятор, который использовался для создания двоичного файла, что приведет к невозможности выбора соответствующих сигнатур для применения. В этом случае вы можете заставить IDA применить одну или несколько сигнатур. Вторая ситуация включает создание ваших собственных сигнатур для библиотек, которые могут не иметь существующих сигнатур, включенных в IDA. Примером может служить создание сигнатур для статической версии библиотек OpenSSL, поставляемых с FreeBSD 8.0. DataRescue предоставляет набор инструментов для создания настраиваемых сигнатур, которые могут использоваться механизмом сопоставления сигнатур IDA. Мы рассмотрим создание пользовательских сигнатур в главе 12. Независимо от того, почему вы хотите применить новые сигнатуры, либо нажатие клавиши INSERT, либо щелчок правой кнопкой мыши в окне Signatures предложит вам опцию Apply new signature, после чего вы сможете выбрать из списка всех сигнатур, известных вашей IDA.

Окно библиотек типов

По концепции аналогично окну "Signatures". Библиотеки типов представляют собой накопленные в IDA знания о предопределенных типах данных и прототипах функций, полученные из заголовочных файлов, включенных в большинство популярных компиляторов. Обрабатывая файлы заголовков, IDA понимает типы данных, которые ожидаются от общих библиотечных функций, и может соответствующим образом комментировать ваши дизассемблированные файлы. Точно так же из этих файлов заголовков IDA понимает как размер, так и структуру сложных структур данных. Вся информация этого типа собирается в файлы TIL (<IDADIR> / til) и применяется при каждом анализе двоичного файла. Как и в случае с сигнатурами, IDA сначала должна иметь возможность определить библиотеки, которые использует программа, прежде чем она сможет выбрать подходящий набор файлов TIL для загрузки. Вы можете запросить, чтобы IDA загрузила дополнительные библиотеки типов, нажав клавишу INSERT или щелкнув правой кнопкой мыши в окне Type Libraries и выбрав Load type. Библиотеки типов более подробно рассматриваются в главе 13.

Окно вызовов функций

В любой программе функция может как вызывать, так и вызываться другими функциями. Фактически, это довольно простая задача - построить график, отображающий отношения между вызывающими и вызываемыми функциями. Такой граф называется графом вызовов функций или деревом вызовов функций (мы покажем, как заставить IDA генерировать такие графы в главе 9). Иногда нас может не интересовать весь граф вызовов программы; вместо этого нас может интересовать только знание ближайших соседей данной функции. Для наших целей мы будем называть Y соседом X, если Y напрямую вызывает X или X напрямую вызывает Y.

Окно дает ответ на этот вопрос соседа. Когда вы открываете окно вызовов функций, IDA определяет соседей функции, в которой находится курсор, и генерирует отображение, подобное показанному на рисунке 5-10.

49.png


В этом примере мы видим, что функция с именем sub_40182C вызывается из шести разных мест в _main, а _main, в свою очередь, выполняет 15 вызовов других функций. Двойной щелчок по любой строке в окне Function Calls немедленно переходит из окна дизассемблирования к выбранной вызывающей или вызываемой функции (или вызывающей и вызываемой). Перекрестные ссылки IDA (внешние ссылки) - это механизмы, лежащие в основе создания окон вызовов функций. Более подробно внешние ссылки будут рассмотрены в главе 9.

Окно проблем

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

50.png

Каждая проблема характеризуется (1) адресом, по которому возникла проблема, (2) типом возникшей проблемы и (3) инструкцией, присутствующей в месте возникновения проблемы. В этом примере мы видим проблемы BOUNDS и DECISION. Проблема BOUNDS возникает, когда пункт назначения вызова или перехода либо не может быть определен (как в этом примере, поскольку значение eax неизвестно IDA), либо кажется, что он находится вне диапазона виртуальных адресов в программе. Проблема DECISION чаще всего вовсе не проблема. DECISION обычно представляет собой адрес, по которому IDA решила дизассемблировать байты как инструкции, а не данные, даже если на этот адрес никогда не ссылались во время рекурсивного обхода инструкций (см. Главу 1). Полный список типов проблем и предложения по их решению доступен во встроенном файле справки IDA (см. Раздел Список проблем).

Резюме

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

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

На этом этапе вы должны начать знакомиться с пользовательским интерфейсом IDA. В следующей главе мы начнем сосредотачиваться на множестве способов, которыми вы можете управлять дизассемблированием, чтобы улучшить ваше понимание его поведения и в целом облегчить вашу жизнь с IDA.
 
6. НАВИГАЦИЯ ПО ДИЗАССЕМБЛЕРНОМУ КОДУ

В этой и следующей главах мы рассмотрим сердце того, что делает IDA Pro интерактивной, а именно простоту навигации и легкость манипуляций. Основное внимание в этой главе уделяется навигации; в частности, мы покажем, как IDA логически облегчает перемещение по дизассемблерному коду. До сих пор мы показали, что на базовом уровне IDA просто объединяет функции многих распространенных инструментов реверс инжиниринга в интегрированное окно дизассемблирования. Навигация по окну - один из основных навыков, необходимых для овладения IDA. Листинги статического дизассемблированного кода не предлагают никаких встроенных возможностей навигации, кроме прокрутки списка вверх и вниз. Даже с лучшими текстовыми редакторами очень сложно ориентироваться в таких мертвых листингах, поскольку лучшее, что они могут предложить, - это, как правило, не что иное, как интегрированный поиск в стиле grep. Как вы увидите, база данных IDA обеспечивает исключительные возможности навигации.

Базовая навигация по IDA

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

Двойной щелчок

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

Как мы обсуждали ранее, IDA генерирует символические имена на этапе анализа, исследуя таблицу символов двоичного файла или автоматически генерируя имя в зависимости от того, имеется ли в двоичном коде ссылка на местоположение. В дополнение к своему символическому назначению любое имя, отображаемое в окне дизассемблирования, является потенциальной целью навигации, подобной гиперссылке на веб-странице. Два различия между этими именами и стандартными гиперссылками заключаются в следующем: (1) имена никогда не выделяются каким-либо образом, чтобы указать, что за ними можно следовать, и (2) для перехода по IDA требуется двойной щелчок, а не один щелчок. Мы уже видели использование имен в различных подокнах, таких как окна Functions, Imports и Exports. Вспомните, что для каждого из этих окон двойной щелчок по имени заставлял представление дизассемблира переходить в указанное место. Это один из примеров работы навигации по двойному щелчку. В следующем листинге каждый из обозначенных символов представляет именованную[1] цель навигации. Двойной щелчок по любому из них заставит IDA переместить окошко в выбранное место.

1.png



2.png


Для целей навигации IDA рассматривает два дополнительных объекта отображения как цели навигации. Во-первых, перекрестные ссылки (показанные здесь [2]) рассматриваются как навигационные цели. Перекрестные ссылки обычно оформляются в виде имени и шестнадцатеричного смещения. Перекрестная ссылка справа от метки loc_40134E в предыдущем листинге относится к местоположению, которое находится на 4D (16-ная) или 77 (10-ная) байт после начала процедуры sub_4012E4. Двойной щелчок по тексту перекрестной ссылки переместит окошко к месту ссылки (в данном случае к 00401331). Перекрестные ссылки более подробно описаны в главе 9.

Второй тип отображаемого объекта, для которого предусмотрена специальная обработка с точки зрения навигации, - это объект, использующий шестнадцатеричные значения. Если отображаемое шестнадцатеричное значение представляет действительный виртуальный адрес в двоичном файле, то двойной щелчок по значению переместит окно дизассемблирования для отображения выбранного виртуального адреса. В приведенном ниже листинге двойной щелчок по любому из значений, обозначенных значком [3], приведет к переходу дисплея, поскольку каждый из них является действительным виртуальным адресом в данном двоичном файле, а двойной щелчок по любому из значений, обозначенных значком [4], не будет иметь никакого эффекта.

3.png


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

4.png


В только что показанном фрагменте окна Output два сообщения, обозначенные значком [5], можно использовать для перехода к адресам, указанным в начале соответствующих сообщений. Двойной щелчок по любому другому сообщению, в том числе по адресу [6], не приведет к никаким действиям.

Переход к адресу

Иногда вы будете точно знать, по какому адресу хотите перейти, но в окне дизассемблера не будет имени, которое предлагало бы простую навигацию по двойному щелчку. В таком случае у вас есть несколько вариантов. Первый и самый примитивный вариант - использовать полосу прокрутки окна дизассемблера для прокрутки окошка вверх или вниз, пока не появится желаемое место. Обычно это возможно только тогда, когда местоположение, к которому вы переходите, известно по его виртуальному адресу, поскольку окно дизассембелра линейно организовано по виртуальному адресу. Если все, что вы знаете, - это именованное местоположение, например такое как подпрограмма с именем foobar, то перемещение с помощью полосы прокрутки становится чем-то вроде поиска иголки в стоге сена. На этом этапе вы можете отсортировать окно Functions по алфавиту, прокрутить до нужного имени и дважды щелкнуть его. Третий вариант - использовать одну из функций поиска IDA, доступных через меню Search, которая обычно включает указание некоторых критериев поиска перед тем, как запросить у IDA поиск. В случае поиска известного местоположения это обычно излишне.

В конце концов, самый простой способ добраться до известного места - использовать диалоговое окно Jump to Address показанное на рис. 6-1.

5.png


Доступ к диалоговому окну Jump to Address можно получить через Jump->Jump to Address или с помощью горячей клавиши G, когда активно окно дизассемблера . Думая об этом диалоговом окне как о диалоге Go, вы можете запомнить соответствующую горячую клавишу. Перейти к любому месту в двоичном файле так же просто, как указать адрес (подойдет имя или шестнадцатеричное значение) и щелкнуть OK, что немедленно переместит окошко в нужное место. Значения, введенные в диалоговом окне, запоминаются и становятся доступными при последующем использовании через раскрывающийся список. Эта функция истории упрощает возврат в ранее запрошенные местоположения.

История навигации

Если мы сравним функции навигации по документам IDA с функциями веб-браузера, мы можем приравнять имена и адреса к гиперссылкам, поскольку по каждой из них можно относительно легко перейти, чтобы просмотреть новое местоположение. Еще одна функция, которую IDA разделяет с традиционными веб-браузерами, - это концепция прямой и обратной навигации на основе порядка, в котором вы перемещаетесь при дизассемблировании. Каждый раз, когда вы переходите к новому месту в дизассемблированном листинге, ваше текущее местоположение добавляется в список истории. Для просмотра этого списка доступны две операции меню. Сначала Jump-> Jump to Previous Position перемещает дизассемблированный листинг к самой последней записи в списке истории. Поведение концептуально идентично кнопке BACK в веб-браузере. Связанная горячая клавиша - ESC, и это одна из самых полезных горячих клавиш, которые вы можете держать в памяти. Однако следует предупредить, что использование ESC, когда активно любое окно, кроме окна дизассемблирования, приводит к закрытию активного окна. (Вы всегда можете повторно открыть окна, которые вы случайно закрыли, через View-> Open Subviews.) Обратная навигация чрезвычайно удобна, если вы проследили цепочку вызовов функций на несколько уровней в глубину и решили, что хотите вернуться в исходное положение.

Jump-> Jump to Next Position - это аналогичная операция, которая перемещает окно дизассемблирования вперед в списке истории аналогично кнопке вперед в веб-браузере. Для полноты картины связанная горячая клавиша для этой операции - CTRL-ENTER, хотя, как правило, она менее полезна, чем использование ESC для обратной навигации.

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

6.png


Стек фреймов

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

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

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

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

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

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

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

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

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

6. Как только функция завершит свои операции, все пространство стека, зарезервированное для локальных переменных, освобождается. Часто это делается путем отмены действий, выполненных на шаге 4.

7. Все регистры, значения которых были сохранены (на шаге 3) от имени вызывающей функции, восстанавливаются до своих исходных значений. Это включает восстановление регистра указателя кадра вызывающей функции.

8. Вызываемая функция возвращает управление вызывающей стороне. Типичные инструкции для этого включают инструкции x86 RET и MIPS JR. В зависимости от используемого соглашения о вызовах эта операция может также служить для очистки одного или нескольких параметров из стека программы.

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

Шаги 3 и 4 настолько часто выполняются при входе в функцию, и вместе они называются прологом функции. Точно так же шаги с 6 по 8 часто выполняются в конце функции, что вместе они составляют эпилог функции. За исключением шага 5, который представляет собой тело функции, все эти операции составляют просто дополнительные действия, связанные с вызовом функции.

Соглашения о вызовах

Имея базовое представление о том, что такое стековые фреймы, мы можем более подробно рассмотреть, как именно они структурированы. Следующие примеры относятся к архитектуре x86 и поведению, связанному с распространенными компиляторами x86, такими как Microsoft Visual C/C++ или gcc/g++ GNU. Один из наиболее важных шагов при создании кадра стека включает размещение параметров функции в стеке вызывающей функцией. Вызывающая функция должна сохранять параметры в точности так, как вызываемая функция ожидает их найти; в противном случае могут возникнуть серьезные проблемы. Функции объявляют способ, которым они ожидают получить свои аргументы, путем выбора и соблюдения определенного соглашения о вызовах.

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

Соглашение о вызовах C

Соглашение о вызовах по умолчанию, используемое большинством компиляторов C для архитектуры x86, называется соглашением о вызовах C. Модификатор _cdecl может использоваться программами C/C++, чтобы заставить компиляторы использовать соглашение о вызовах C, когда соглашение о вызовах по умолчанию могло быть переопределено. С этого момента мы будем называть это соглашение о вызовах соглашением о вызовах cdecl. Соглашение о вызове cdecl указывает, что вызывающая функция помещает параметры функции в стек в порядке справа налево и что вызывающая функция (в отличие от вызываемой) удаляет параметры из стека после завершения вызываемой функции.

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

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

В следующих примерах мы рассматриваем вызовы функции, имеющей следующий прототип:

7.png


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

8.png


Четыре операции push, начинающиеся с [1], приводят к чистому изменению указателя стека программы (ESP) на 16 байтов (4 * sizeof (int) в 32-битной архитектуре), которое отменяется [2] после возврата из demo_cdecl. Если функция demo_cdecl вызывается 50 раз, каждый вызов будет сопровождаться настройкой стека, аналогичной [2]. В следующем примере также соблюдается соглашение о вызовах cdecl, при этом отпадает необходимость для вызывающей функции явно очищать параметры из стека после каждого вызова demo_cdecl.

9.png


В этом примере компилятор предварительно выделил место для хранения параметров demo_cdecl в верхней части стека во время пролога функции. Когда параметры для demo_cdecl помещаются в стек, указатель стека программы не изменяется, что устраняет необходимость настраивать указатель стека после завершения вызова demo_cdecl. Компиляторы GNU (gcc и g ++) используют эту технику для помещения параметров функции в стек.

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

Стандартное соглашение о вызовах

Стандарт в этом случае является немного неправильным, поскольку это имя, которое Microsoft создала для своего собственного соглашения о вызовах, отмеченного использованием модификатора _stdcall в объявлении функции, как показано здесь:

10.png


Как и в случае соглашения о вызовах cdecl, stdcall требует, чтобы параметры функции помещались в стек программы в порядке справа налево. Разница при использовании stdcall заключается в том, что вызываемая функция отвечает за очистку параметров функции из стека, когда функция завершена. Чтобы функция могла это сделать, функция должна точно знать, сколько параметров находится в стеке. Это возможно только для функций, которые принимают фиксированное количество параметров. В результате функции с переменными аргументами, такие как printf, не могут использовать соглашение о вызовах stdcall. Например, функция demo_stdcall ожидает трех целочисленных параметров, занимающих в стеке всего 12 байтов (3 * sizeof (int) в 32-битной архитектуре). Компилятор x86 может использовать специальную форму инструкции RET для одновременного извлечения адреса возврата из вершины стека и добавления 12 к указателю стека, чтобы очистить параметры функции. В случае demo_stdcall мы могли бы увидеть следующую инструкцию, используемую для возврата к вызывающему:

11.png

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

Соглашение о вызовах fastcall для x86

Вариант соглашения stdcall, соглашение о вызовах fastcall передает до двух параметров в регистры ЦП, а не в программный стек. Компиляторы Microsoft Visual C/C++ и GNU gcc/g++ (версия 3.4 и выше) распознают модификатор fastcall в объявлениях функций. Если указан fastcall, первые два параметра, переданные функцией, будут помещены в регистры ECX и EDX соответственно. Любые оставшиеся параметры помещаются в стек в порядке справа налево, аналогично stdcall. Также как и stdcall, функции fastcall отвечают за удаление параметров из стека, когда они возвращаются к вызывающему. Следующее объявление демонстрирует использование модификатора fastcall.

12.png


Компилятор может сгенерировать следующий код для вызова demo_fastcall:

13.png


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

Соглашения о вызовах C++

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

Microsoft Visual C++ предлагает соглашение о вызовах thiscall, которое передает это в регистре ECX и требует, чтобы нестатическая функция-член очищала параметры из стека, как в stdcall. Компилятор GNU g++ рассматривает это как подразумеваемый первый параметр для любой нестатической функции-члена и ведет себя во всех остальных отношениях так, как если бы использовалось соглашение cdecl. Таким образом, для кода, скомпилированного с g++, он помещается в верхнюю часть стека перед вызовом нестатической функции-члена, а вызывающая сторона отвечает за удаление параметров (всегда будет хотя бы один) из стека после возврата из функции. Дополнительные возможности скомпилированного C++ обсуждаются в главе 8.

Другие соглашения о вызовах

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

Когда функции экспортируются для использования другими программистами (например, библиотечные функции), важно, чтобы они придерживались хорошо известных соглашений о вызовах, чтобы программисты могли легко взаимодействовать с этими функциями. С другой стороны, если функция предназначена только для внутреннего использования программой, тогда соглашение о вызовах, используемое этой функцией, должно быть известно только в программе этой функции. В таких случаях оптимизирующие компиляторы могут использовать альтернативные соглашения о вызовах для создания более быстрого кода. Примеры, в которых это может произойти, включают использование параметра /GL с Microsoft Visual C++ и использование ключевого слова regparm с GNU gcc/g ++.

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

Системный вызов - это особый тип вызова функции, используемый для запроса службы операционной системы. Системные вызовы обычно вызывают переход состояния из пользовательского режима в режим ядра, чтобы ядро операционной системы могло обработать запрос пользователя. Способ инициирования системных вызовов зависит от операционной системы и процессора. Например, системные вызовы Linux x86 могут быть инициированы с помощью инструкции int 0x80 или инструкции sysenter, в то время как другие операционные системы x86 могут использовать только инструкцию sysenter или альтернативные номера прерывания. Во многих системах x86 (за исключением Linux) параметры системных вызовов помещаются в стек времени выполнения, а номер системного вызова помещается в регистр EAX непосредственно перед инициированием системного вызова. Системные вызовы Linux принимают свои параметры в определенных регистрах и иногда в памяти, когда параметров больше, чем доступных регистров.

Макет локальной переменной

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

Примеры кадров стека

Рассмотрим следующую функцию, скомпилированную на 32-разрядном компьютере на базе x86:

14.png


Мы вычисляем минимальный объем стека, необходимый для локальных переменных, равный 76 байтам (три 4-байтовых целых числа и 64-байтовый буфер). Эта функция может использовать либо stdcall, либо cdecl, и кадр стека будет выглядеть одинаково. На рисунке 6-3 показана одна из возможных реализаций кадра стека для вызова demo_stackframe, предполагая, что регистр указателя кадра не используется (таким образом, указатель стека ESP служит указателем кадра). Этот фрейм будет установлен при входе в demo_stackframe с однострочным прологом:

15.png


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

16.png


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

17.png


Push [1] правильно поемещает локальную переменную y в соответствии с смещением на рисунке 6-3. На первый взгляд может показаться, что push [2] во второй раз неправильно ссылается на локальную переменную y. Однако, поскольку мы имеем дело с кадром на основе ESP, и push [1] изменяет ESP, все смещения на рисунке 6-3 должны временно корректироваться каждый раз, когда ESP изменяется. После этого [1], новое смещение для локальной переменной z становится [esp + 4], как правильно указано в push [2]. При изучении функций, которые ссылаются на переменные кадра стека с помощью указателя стека, вы должны быть осторожны, чтобы отмечать любые изменения указателя стека и соответствующим образом корректировать смещения всех будущих переменных. Одним из преимуществ использования указателя стека для ссылки на все переменные кадра стека является то, что все остальные регистры остаются доступными для других целей.

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

18.png


За счет выделения регистра для использования в качестве указателя кадра и некоторого кода для настройки указателя кадра при входе в функцию, задача вычисления смещений локальных переменных может быть упрощена. В программах x86 регистр EBP (расширенный базовый указатель) обычно предназначен для использования в качестве указателя кадра стека. По умолчанию большинство компиляторов генерируют код для использования указателя кадра, хотя обычно существуют параметры для указания того, что вместо него следует использовать указатель стека. GNU gcc/g++, например, предлагает параметр компилятора -fomit-frame-pointer, который генерирует функции, которые не полагаются на регистр указателя фиксированного кадра.

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

19.png

Инструкция push [3] сохраняет значение EBP, которое в данный момент использует вызывающий объект. Функции, которые соответствуют двоичному интерфейсу приложения System V для 32-разрядных процессоров Intel, могут изменять регистры EAX, ECX и EDX, но необходимы для сохранения значений вызывающего объекта для всех других регистров. Следовательно, если мы хотим использовать EBP как указатель кадра, мы должны сохранить текущее значение EBP, прежде чем изменять его, и мы должны восстановить значение EBP, прежде чем мы вернемся к вызывающей фунции. Если какие-либо другие регистры необходимо сохранить от имени вызывающей стороны (например, ESI или EDI), компиляторы могут сохранить их одновременно с сохранением EBP или отложить их сохранение до тех пор, пока не будут выделены локальные переменные. Таким образом, в стеке нет стандартного места для хранения сохраненных регистров.

После сохранения EBP его можно изменить, чтобы он указывал на текущее расположение стека. Это выполняется инструкцией mov [4], которая копирует текущее значение указателя стека в EBP. Наконец, как и в кадре стека, не основанном на EBP, пространство для локальных переменных выделяется по адресу [5]. Результирующий макет фрейма стека показан на рисунке 6-4.

20.png

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

21.png


Тот факт, что указатель стека изменился после push[6], не влияет на доступ к локальной переменной z.

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

22.png



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

23.png


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

Представления стека IDA

Фреймы стека явно являются концепцией среды выполнения; фрейм стека не может существовать без стека и без запущенной программы. Хотя это правда, это не означает, что вы должны игнорировать концепцию фрейма стека при выполнении статического анализа с помощью таких инструментов, как IDA. Весь код, необходимый для настройки кадров стека для каждой функции, присутствует в двоичном файле. Путем тщательного анализа этого кода мы можем получить подробное представление о структуре кадра стека любой функции, даже если функция не запущена. Фактически, некоторые из наиболее сложных анализов IDA выполняются специально для определения структуры кадров стека для каждой функции, которую IDA дизассемблирует. Во время первоначального анализа IDA делает все возможное, чтобы отслеживать поведение указателя стека в ходе выполнения функции, записывая каждую операцию push или pop вместе с любыми арифметическими операциями, которые могут изменить указатель стека, например, сложение или вычитание постоянных значений. Первая цель этого анализа - определить точный размер области локальной переменной, выделенной фрейму стека функции. Дополнительные цели включают определение того, используется ли выделенный указатель кадра в данной функции (например, путем распознавания последовательности push ebp/mov ebp, esp) и распознавание всех ссылок памяти на переменные в кадре стека функции. Например, если IDA заметила следующую инструкцию в теле demo_stackframe

24.png


она поймет, что первый аргумент функции (в данном случае a) загружается в регистр EAX (см. Рисунок 6-4). Путем тщательного анализа структуры кадра стека IDA может различать ссылки на память, которые обращаются к аргументам функции (те, которые лежат ниже сохраненного адреса возврата), и ссылки, которые обращаются к локальным переменным (те, которые лежат выше сохраненного адреса возврата). IDA выполняет дополнительный шаг по определению, на какие ячейки памяти в кадре стека напрямую ссылаются. Например, хотя размер кадра стека на рисунке 6-4 составляет 96 байт, есть только семь переменных, на которые мы, вероятно, будем ссылаться (четыре локальных и три параметра).

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

25.png


В этом примере локальные переменные x и y инициализируются параметрами c и b соответственно. Локальная переменная z инициализируется постоянным значением 10, а первый символ в 64-байтовом локальном массиве с именем buffer инициализируется буквой ‘A’. Соответствующая дизассемблированная версия этой функции в IDA отображается здесь.

26.png

27.png


В этом листинге есть много моментов, которые следует затронуть, поскольку мы начинаем знакомиться с нотацией дизассемблирования IDA. Начнем с того, что отметим, что IDA считает [1], что эта функция использует регистр EBP в качестве указателя кадра на основе анализа пролога функции. Мы узнаем[2], что gcc выделил 120 байтов (78h равно 120) пространства для локальных переменных в кадре стека. Это включает в себя 8 байтов для передачи двух параметров в bar [3], но это все еще намного больше, чем 76 байтов, которые мы оценили ранее, и демонстрирует, что компиляторы иногда дополняют пространство локальной переменной дополнительными байтами, чтобы обеспечить конкретное выравнивание в стеке. Начиная c [4] , IDA предоставляет сводное представление стека, в котором перечислены все переменные, на которые имеется прямая ссылка в кадре стека, а также размер переменной и расстояние смещения от указателя кадра.

IDA присваивает имена переменным,в зависимости от их местоположения относительно сохраненного адреса возврата. Локальные переменные располагаются выше сохраненного адреса возврата, а параметры функции - ниже сохраненного адреса возврата. Имена локальных переменных выводятся с использованием префикса var_, соединенного с шестнадцатеричным суффиксом, который указывает расстояние в байтах, на которое переменная находится выше сохраненного указателя кадра. Локальная переменная var_C, в этом случае, представляет собой 4-байтовую (двойное слово) переменную, которая находится на 12 байтов выше сохраненного указателя кадра ([ebp-0Ch]). Имена параметров функций генерируются с использованием префикса arg_ в сочетании с шестнадцатеричным суффиксом, который представляет относительное расстояние от самого верхнего параметра. Таким образом, самый верхний 4-байтовый параметр будет называться arg_0, а последующие параметры будут называться arg_4, arg_8, arg_C и так далее. В этом конкретном примере arg_0 не указан, потому что функция не использует параметр a. Поскольку IDA не может найти какую-либо ссылку в памяти на [ebp + 8] (расположение первого параметра), arg_0 не отображается в сводном стеке. Быстрое сканирование представления сводного стека показывает, что существует много мест стека, которые IDA не смогла назвать, потому что в программном коде нет прямых ссылок на эти места.

ПРИМЕЧАНИЕ. Единственные переменные стека, для которых IDA автоматически сгенерирует имена, - это те, на которые прямо ссылается функция.

Важное различие между листингом дизассемблирования в IDA и анализом кадра стека, который мы выполнили ранее, заключается в том, что нигде в листинге дизассемблирования мы не видим ссылок на память, подобных [ebp-12]. Вместо этого IDA заменила все постоянные смещения символическими именами, соответствующими символам в представлении стека и их относительным смещениям от указателя кадра стека. Это соответствует цели IDA по созданию дизассемблера более высокого уровня. С символьными именами проще работать, чем с числовыми константами. Фактически, как мы увидим позже, IDA позволяет нам изменять имена любой переменной стека на все, что мы пожелаем, что значительно упрощает запоминание имен. Представление итогового стека служит отображением сгенерированных IDA имен с соответствующими смещениями кадров стека. Например, если ссылка на память [ebp + arg_8] появляется при дизассемблировании, вместо нее можно использовать [ebp + 10h] или [ebp + 16]. Если вы предпочитаете числовые смещения, IDA с радостью покажет их вам. При щелчке правой кнопкой мыши по arg_8 at открывается контекстное меню, показанное на рисунке 6-5, которое содержит несколько параметров для изменения формата отображения.

28.png


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

1. Во-первых, demo_stackframe принимает три параметра: a, b и c. Они соответствуют переменным arg_0, arg_4 и arg_8 соответственно (хотя arg_0 отсутствует в дизассемблировании, потому что на него никогда не ссылаются).

2. Локальная переменная x инициализируется параметром c. Таким образом, var_C соответствует x, поскольку он инициализируется из arg_8 [6].

3. Точно так же локальная переменная y инициализируется параметром b. Таким образом, var_5C соответствует y, поскольку он инициализируется из arg_4 [7].

4. Локальная переменная z соответствует переменной var_60, поскольку она инициализируется с помощью значение 10 [8].

5. Буфер с 64-байтовым массивом символов начинается с var_58, поскольку буфер [0] инициализирован с помощью A (ASCII 0x41) [9].

6. Два аргумента для вызова в bar перемещаются в стек, а не помещаются в стек. Это типично для текущих версий gcc (версии 3.4 и новее). IDA признает это соглашение и решает не создавать ссылки на локальные переменные для двух элементов в верхней части фрейма стека.

Помимо сводного представления стека, IDA предлагает подробное представление кадра стека, в котором учитывается каждый байт, выделенный кадру стека. Доступ к подробному представлению можно получить, дважды щелкнув любое имя переменной, связанное с данным кадром стека. Двойной щелчок по var_C в предыдущем листинге вызовет представление кадра стека, показанное на рисунке 6-6 (ESC закрывает окно).

29.png


Поскольку подробное представление учитывает каждый байт в кадре стека, оно занимает значительно больше места, чем сводное представление, в котором перечислены только переменные, на которые есть ссылки. Часть кадра стека, показанная на рисунке 6-6, занимает в общей сложности 32 байта, что составляет лишь небольшую часть всего кадра стека. Обратите внимание, что байтам, на которые нет прямых ссылок внутри функции, не присваиваются имена. Например, параметр a, соответствующий arg_0, никогда не упоминался в demo_stackframe. Без обращения к памяти для анализа IDA предпочитает ничего не делать с соответствующими байтами в кадре стека, которые занимают смещения от +00000008 до +0000000B. С другой стороны, на arg_4 была прямая ссылка [7]в листинге дизассемблера, где его содержимое было загружено в 32-битный регистр EAX. Основываясь на том факте, что было перемещено 32 бита данных, IDA может сделать вывод, что arg_4 представляет собой 4-байтовую величину, и пометит ее как таковую (db определяет 1 байт памяти; dw определяет 2 байта памяти, также называемую словом ; и dd определяет 4 байта памяти, также называемую двойным словом).

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

Представление фрейма стека предлагает подробный взгляд на внутреннюю работу компиляторов. На рисунке 6-6 видно, что компилятор вставил 8 дополнительных байтов между сохраненным указателем кадра s и локальной переменной x (var_C). Эти байты занимают смещения от -00000001 до -00000008 в кадре стека. Кроме того, небольшая математика, выполненная со смещением, связанным с каждой переменной, перечисленной в сводном представлении, показывает, что компилятор выделил 76 (а не 64 на исходный код) байтов для символьного буфера в var_58. Если вы сами не являетесь составителем компилятора или не хотите глубоко копаться в исходном коде gcc, все, что вы можете сделать, - это предположить, почему эти дополнительные байты выделяются таким образом. В большинстве случаев мы можем записать дополнительные байты на заполнение для выравнивания, и обычно наличие этих дополнительных байтов не влияет на поведение программы. В конце концов, если программист запрашивает 64 байта, а ему дается 76, программа не должна вести себя иначе, тем более, что программист не должен использовать более 64 запрошенных байтов. С другой стороны, если вы являетесь разработчиком эксплойтов и узнаете, что можно переполнить этот конкретный буфер, то вас может очень заинтересовать тот факт, что ничего интересного даже не начнется, пока вы не предоставите хотя бы 76 байт. , который является эффективным размером буфера с точки зрения компилятора. В главе 8 мы вернемся к представлению фрейма стека и его использованию при работе с более сложными типами данных, такими как массивы и структуры.

Поиск в базе данных

IDA упрощает переход к тому, о чем вы знаете, и проектирует многие из своих окошек данных для обобщения определенных типов информации (имена, строки, импортированные данные и т. Д.), что также упрощает их поиск. Однако какие функции предлагаются, чтобы помочь вам проводить более общий поиск в ваших базах данных? Если вы потратите время на просмотр содержимого меню “Search”, вы найдете длинный список опций, большинство из которых приведет вас к следующему элементу в какой-либо категории. Например, Search->Next Code перемещает курсор в следующее место, содержащее инструкцию. Вы также можете ознакомиться с опциями, доступными в меню перехода. Для многих из них вам будет представлен список мест на выбор. Jump-> Jump to Function, например, вызывает список всех функций, позволяя вам быстро выбрать одну и перейти к ней. Хотя эти стандартные функции поиска часто могут быть полезны, два типа поиска общего назначения заслуживают более подробного обсуждения: текстовый поиск и двоичный поиск.

Поиск по тексту

Количество поиска по тексту IDA равно количеству поисков подстроки в представлении списка дизассемблирования. Текстовый поиск запускается через Search->Text (горячая клавиша: ALT-T), что открывает диалоговое окно, показанное на рисунке 6-7. Ряд параметров, которые не требуют пояснений, определяют конкретные детали, касающиеся выполняемого поиска. Как показано, разрешены регулярные выражения в стиле POSIX. Поиск по идентификатору назван неверно. На самом деле он ограничивает поиск только целыми словами и может соответствовать любому целому слову на конвейере, включая мнемонику опкодов или постоянные значения. Поиск по идентификатору для 401116 не смог бы найти символ с именем loc_401116.

При выборе “Find all occurences” результаты поиска открываются в новом окне, что позволяет легко переходить к любому совпадению критериев поиска. Наконец, предыдущий поиск можно повторить, чтобы найти следующее совпадение, используя CTRL-T или Search-> Next Text.

30.png


Бинарный поиск

Если вам нужно найти конкретное двоичное содержимое, такое как известная последовательность байтов, то текстовый поиск не является решением. Вместо этого вам нужно использовать средства двоичного поиска IDA. В то время как текстовый поиск выполняет поиск в окне дизассемблирования, двоичный поиск будет искать только часть содержимого окна Hex View. Можно искать либо шестнадцатеричный дамп, либо дамп ASCII, в зависимости от того, как указана строка поиска. Бинарный поиск запускается с помощью Search->Sequence of Bytes или ALT-B. На рисунке 6-8 показано диалоговое окно двоичного поиска. Для поиска последовательности шестнадцатеричных байтов строка поиска должна быть указана как список двухзначных шестнадцатеричных значений, разделенных пробелами, таких как CA FE BA BE, который предлагает такое же поведение, как и поиск ca fe ba be, несмотря на доступность параметра с учетом регистра.

Для альтернативного поиска встроенных строковых данных (эффективного поиска в части дампа ASCII окна Hex View), вы должны заключить строки поиска в кавычки. Используйте опцию Unicode strings для поиска Unicode-версии вашей строки поиска.

Вариант с учетом регистра может вызвать путаницу. Для строкового поиска это довольно просто; поиск “hello” успешно найдет “HELLO”, если регистр не выбран. Все станет немного интереснее, если вы выполните поиск по шестнадцатеричному значению и не установите флажок “Учитывать регистр”. Если вы выполните поиск E9 41 C3 без учета регистра, вы можете быть удивлены, когда ваш поиск совпадет с E9 61 C3. Две строки считаются совпадающими, поскольку 0x41 соответствует символу A, а 0x61 соответствует символу a. Таким образом, даже если вы указали шестнадцатеричный поиск, 0x41 считается эквивалентным 0x61, потому что вы не смогли указать поиск с учетом регистра.

31.png


ПРИМЕЧАНИЕ . При выполнении поиска в шестнадцатеричном формате убедитесь, что вы указали чувствительность к регистру, если хотите ограничить поиск точными совпадениями. Это важно, если вы ищете конкретные последовательности кодов операций, а не текст ASCII.

Поиск последующих совпадений для двоичных данных выполняется с помощью CTRL-B или Search->Next Sequence of Bytes. Наконец, нет необходимости проводить двоичный поиск из окна Hex View. IDA позволяет вам указать критерии двоичного поиска, пока активно представление дизассемблирования, и в этом случае при успешном поиске окно дизассемблирования переместится в то место, базовые байты которого соответствуют указанным критериям поиска.

Резюме

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

Источник https://www.amazon.com/IDA-Pro-Book-Unofficial-Disassembler/dp/1593272898
Автор перевода: yashechka
Переведено специально для https://xss.pro
 
С разрешения администрации оставляю это ссылку - Здесь Вы можете отблагодарить меня за перевод этой книги. Напоминаю что, скорость перевода зависит от Вас. Принимается любая сумма. Кто хочет сделать донат криптой просьба написать в личку.
Как только книга будет переведа, я устрою опрос и голосование по переводу следующей книги специально для !!!XSS!!! Только для этого ресурса будет переведена интересная книжка которая ещё не выпущена на русском!!!
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх