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

Лет пять назад мне понадобилось подправить синтаксический анализатор компилятора Turbo C 2.0 Prof, а для этого нужно было найти в немаленьком (что-то около 180 кб) по тем временам EXE-файле нужный фрагмент. Трассировать отладчиком не было никакого терпения, популярный в то время дизассемблер Sourcer его не брал по причине этой самой величины, а DisDoc, который брал, выдавал настолько "непричесанный" результат, что невольно вспоминалось из Жванецкого - "...лекарство, которое не берет микроб, а наоборот - с ним сотрудничает". В тот момент мне на глаза и попалась IDA - интерактивный дизассемблер москвича Ильфака Гильфанова с его заманчивым "объем исходного файла - не ограничен". Однако, успев уже привыкнуть к максимально вылизанным выходным текстам Sourcer'а, я после запуска IDA обнаружил на экране полное отсутствие интеллекта - как я тогда его понимал - выразившееся в нежелании дизассемблера сразу же выдавать готовый результат, как это делал Sourcer. И, поленившись вникнуть в непривычную идеологию нового инструмента (а она оказалась поистине революционной) я забросил его на целых два года - и, как понял впоследствии, потерял из-за этого кучу времени и сил. Для сравнения скажу, что вскоре после того, как я все же разобрался с IDA и в полном смысле слова полюбил ее (а ее мощность тогда была чуть ли не вполовину ниже теперешней), я снова взялся за компилятор - ради интереса, ибо в прошлый раз нашел-таки нужное место за пару дней плотной работы). IDA сделала первичное дизассемблирование минут за пятнадцать (на DX2-66), еще пара часов ушла на основное причесывание программы, после чего требуемые фрагменты отыскивались элементарно.

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

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

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

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

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

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

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

При загрузке программ в форматах Windows и OS/2 - NE, PE, LX - IDA автоматически определяет тип файла (EXE/DLL/VXD и т.п.), находит все DLL, на которые ссылается файл, и загружает для них таблицы входов в виде символических имен.

Профессиональная версия - IDA Pro - обладает и вовсе уникальными возможностями: при помощи технологии FLIRT (Fast Library Identification and Recognition Technology) она способна автоматически определять компилятор и служебные библиотеки, использованные при построении программы, и посредством специального набора сигнатур находить в программе стандартные функции из этих библиотек, тут же присваивая им соответствующие имена и атрибуты. Если версия RTL-библиотеки опознана по сигнатуре - в программе уже в самом начале анализа выделяются характерные служебные функции - printf, strcpy, malloc и им подобные. Разбираться в программе с уже найденными основными функциями RTL на порядок проще, чем в совершенно неисследованной.

Кроме этого, в последних версиях IDA Pro реализована поддержка локальных переменных, формируемых в стековом кадре - в каждой функции анализируются обращения к стековому кадру через BP/EBP и создается список переменных в кадре. Эти переменные аналогичны обычным статическим переменным, и с ними могут работать все операции IDA - смена имени, типа данных, создание ссылки и т.п. IDA также поддерживает структуры - заранее описанный формат структуры можно привязать к переменной, и тогда IDA будет трактовать все адреса в заданном диапазоне, как поля указанной структуры - и именованные константы (enums), имена которых могут отображаться вместо числовых констант с заданными значениями. Для программ на C++ выполняется восстановление имен перегруженных функций (demangling).

IDA имеет великолепную навигационную систему. Многооконный интерфейс позволяет одновременно наблюдать несколько фрагментов программы - при этом результаты изменений, сделанные в одном из окон, тут же отображаются во всех остальных. Простым нажатием Enter или щелчком мыши на операнде команды или ссылке можно перейти к месту определения операнда, метки или ссылающемуся объекту, оттуда - на другую ссылку, а потом, как угодно далеко углубившись в структуру программы, последовательным нажатием Esc вернуться к исходной точке. Можно перейти к заданной метке/переменной или сегменту, месту модификации сегментного регистра, функции, перекрестной ссылке или закладке - заранее помеченной позиции; можно искать заданное значение операнда, очередной неисследованный или, наоборот, исследованный фрагмент, фрагмент кода или данных, двоичный образец в файле или текстовую строку уже в дизассемблированном представлении (например, поиск "DX, AX" найдет все команды с этими операндами - разумеется, если все кодовые участки в программе полностью проанализированы.

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

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

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

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

Встроенный C-подобный язык программирования IDC (у меня язык не поворачивается назвать его командным языком, ибо по мощности он почти не уступает ранним версиям полного C), содержащий более двухсот разнообразных функций, позволяет описать любой по сложности алгоритм анализа и обработки программы. В комплекте имеются также готовые IDC-программы - например, для обработки образа AWARD BIOS 4.51 или расшифровки структуры Windows VxD.

И наконец - после завершения исследования и "причесывания" программы ее можно вывести во внешний файл - в виде текста, ассемблерного листинга, карты компоновщика (MAP), списка различий исходного и исправленного файла (DIF) и даже исправленной версии исходного файла (EXE). В отличие от пакетных дизассемблеров, эти возможности реально нужны только для печати или перекомпиляции текста, ибо изучать структуру и работу программы несравненно удобнее в самой IDA, нежели по сгенерированному ею тексту. В ранних версиях IDA функции вывода блокировались до ввода регистрационного ключа, и многие обладатели незарегистрированных версий сильно комплексовали по этому поводу; мне же за три года обладания честно оплаченным ключом всего дважды потребовалось вывести фрагменты текста в файл, и то - для их отправки в телеконференции. Для всех программ, исследованием которых мне приходится заниматься, я храню только базы данных IDA - как наиболее информативное представление их структуры. Единственное, на мой взгляд, полезное применение функций вывода при чистом исследовании программ, не сопряженном с их модификацией - формирование карты компоновщика, из которой утилита TDMAP может сделать файл с отладочной информацией для Turbo Debugger, после чего по программе можно лазить и в TD, пользуясь символическими именами вместо адресов.

IDA работает под DOS, Windows 95/NT и OS/2. Для нее существует набор разработчика (SDK), позволяющий создавать дополнительные модули - дизассемблирования файлов для новых процессоров, загрузки модулей особой структуры, внесения дополнительного интеллекта и т.п. Существуют также утилиты для построения файлов сигнатур (FLAIR - Fast Library Acquisition for Identification and Recognition) и генерации списков входных точек для файлов форматов NE/LE/LX/PE.

В заключение можно сказать, что IDA, помимо исполняемых файлов для процессоров x86 под DOS, Windows и OS/2, может дизассемблировать код для процессоров Intel 8080, 860, 8051, Motorola 680x0, 6502, 6301, 6810, DEC PDP-11, а также модули NLM, библиотечные, архивные и объектные файлы, модули JAVA. О существовании в мире другого программного продукта, хотя бы близкого по возможностям к IDA, мне неизвестно.

Информация об IDA доступна на www.idapro.com и www.datarescue.com (почтовый адрес - ida@datarescue.com). Там же можно взять демонстрационную версию IDA Pro, в которой сохранена вся функциональность полной, за исключением запрета на загрузку существующих баз данных, обработки файлов более 64 кб и записи результатов в файл. Упрощенная бесплатная версия доступна на www.simtel.com/pub/simtelnet/msdos/disasm.

Евгений Музыченко, eugene@muzychenko.net