Дизассемблирование — это формирование из исполняемого кода программы кода на языке ассемблера.
Введение
Дизассемблером является транслятор, который преобразует машинный код, объектный файл или библиотечные модули в текстовый формат программы на языке ассемблера. То есть, дизассемблированием считается операция, которая является обратной ассемблированию, а именно, это восстановление текста программы на языке ассемблера из исполняемой программы в машинных кодах.
Необходимо отметить, что, если выполнить повторное ассемблирование восстановленного текста, то нельзя гарантировать получение того же самого кода. А это означает, что есть вероятность того, что восстановленная таким образом программа может оказаться неработоспособной. Также следует подчеркнуть, что любые попытки модификации дизассемблированного текста способны привести к развалу программы. Проблема состоит в том, что ассемблер выполняет замену всех меток на константы, поэтому при осуществлении изменений в программе, следует откорректировать все ссылки на метки.
Дизассемблирование
По используемому режиму работы дизассемблеры подразделяются на следующие типы:
- Дизассемблеры автоматического типа.
- Дизассемблеры интерактивного типа.
В качестве хорошего примера автоматического дизассемблера можно привести программу Sourcer. Подобные дизассемблеры способны генерировать готовый текст программы, который далее может быть откорректирован при помощи какого-либо текстового редактора.
Примером интерактивного дизассемблера может служить программа IDA, которая позволяет менять правила дизассемблирования и считается достаточно удобным инструментальным набором, предназначенным для исследования программ.
Главной проблемой при работе дизассемблера является реализация способности отличать данные от машинных кодов. По этой причине при первых проходах автоматически или интерактивно выполняется сбор информация о границах процедур и функций, а уже на последнем проходе создается результирующий листинг. Интерактивность предоставляет возможность улучшения этого процесса, поскольку, анализируя дамп дизассемблируемого участка памяти, программист может тут же реализовать выделение строковых констант, присвоить необходимые имена известным точкам входа, оставить комментарии на уже изученные им участки программы.
По количеству просмотров объектного кода дизассемблеры подразделяются на следующие типы:
- Однопроходные дизассемблеры.
- Двухпроходные дизассемблеры.
- Многопроходные дизассемблеры.
Однопроходные, которые также называют «дизассемблерами без меток», применяются главным образом в отладчиках и программных мониторах и проектируются, когда нужно оперативно получить псевдо-ассемблерный текст. Второе название призвано отобразить их главную особенность, а именно, тот факт, что в псевдо-ассемблерном листинге нет меток в командах переходов и вызовов подпрограмм, а указаны их абсолютные шестнадцатеричные адреса. По этой причине после ассемблирования такого восстановленного текста пользователь может получить в общем случае абсолютную программу. За один проход при незначительных размерах оперативной памяти (ОЗУ) нельзя собрать всю информацию о метках, поскольку нет «ссылок назад».
Метки, формируемые дизассемблерами, как правило, представлены в виде Lxxxx, где L является первой буквой английского слова Label (метка), a xxxx является адресом перехода или подпрограммы. Метки данных обладают той же структурой, но начинаются с буквы D, то есть, данные. Подобный вид меток считается наиболее удобным при анализе псевдо-листинга. У пользователя имеется возможность замены при помощи редактора текстов этих меток на более информативные.
Самыми распространенными являются двухпроходные дизассемблеры, позволяющие получать метки в листинге дизассемблирования, но, которые не могут решить полностью проблемы разделения команд и данных. После них пользователь должен в ручном режиме подправить сомнительные места.
Наиболее часто дизассемблер применяют для изучения программы (или ее фрагмента), исходный текст которой является неизвестным, с целью ее изменения, копирования или взлома. Реже дизассемблер используется для обнаружения ошибок в программах и компиляторах, а также для исследования и оптимизации формируемого компилятором машинного кода.
При работе с исполняемым кодом или байт-кодом, сформированным на отдельных языках высокого уровня, таких как, к примеру, java, присутствует возможность восстановления не только текста на языке ассемблера, но даже и структуры классов программы, а если при компиляции исполняемого файла не отключалась информация, связанная с отладкой, то и исходный текст программы.
После установки пользователем необходимых опций и выбора команды Gо, SOURCER выполняет загрузку программы в память и определение размеров сегментов. При первом проходе должно определяться большинство ссылок на подпрограммы и участки данных. Затем SOURCER предполагает, что участки кода и данных являются кодом, пока не будет найдено подтверждение обратного. При начале каждого последующего прохода SOURCER осуществляет анализ ссылок на код и данные для более точного определения участков кода и данных. На последнем проходе должны быть определены требуемые директивы ассемблера, форматы всех строк и комментарии.
Наличие внутреннего имитатора позволяет следить за изменениями содержимого всех регистров и поддерживать отдельный стек для программы. Имитатор также должен следить за тем, чтобы в случае применения нескольких сегментов данных был использован верный сегмент. В задачи имитатора входит отслеживание комментариев, обращений к портам ввода-вывода и разрешение индексных вызовов и переходов. Имитатор способен повторять действия программы. Не имитируются большинство инструкций, корректирующих содержимое памяти, однако поддерживаются инструкции, которые считывают данные из памяти. Специализированная поддержка для регистра CS способна обеспечить полную имитацию работы с RОМ и RAM.