Как написать дизассемблер?
Мне интересно писать x88-дизассемблер как образовательный проект.
Единственный реальный ресурс, который я нашел, это Spiral Space, " Как написать дизассемблер". Хотя это дает хорошее описание высокого уровня различных компонентов дизассемблера, я заинтересован в более подробных ресурсах. Я также быстро посмотрел на исходный код NASM, но это немного тяжелый, чтобы учиться.
Я понимаю, что одной из главных задач этого проекта является довольно большой набор команд x86, с которыми мне придется справиться. Меня также интересуют базовая структура, базовые ссылки дизассемблера и т.д.
Может ли кто-нибудь указать мне какие-либо подробные ресурсы при написании дизассемблера x86?
Ответы
Ответ 1
Посмотрите раздел 17.2 80386 Справочник по программисту. Дисассемблер - это просто прославленный конечный автомат. Шаги в разборке:
- Проверьте, является ли текущий байт байтом префикса команд (
F3
, F2
или F0
); если да, то у вас есть префикс REP
/REPE
/REPNE
/LOCK
. Перейти к следующему байту.
- Убедитесь, что текущий байт является байтом размера адреса (
67
). Если это так, декодировать адреса в остальной части инструкции в 16-битном режиме, если в настоящее время находится в 32-битном режиме, или декодировать адреса в 32-битном режиме, если в настоящее время в 16-разрядном режиме
- Убедитесь, что текущий байт является байтом размера операнда (
66
). Если это так, декодируйте непосредственные операнды в 16-битном режиме, если в настоящее время в 32-битном режиме, или декодируйте непосредственные операнды в 32-битном режиме, если в настоящее время в 16-битном режиме
- Проверьте, является ли текущий байт байтом переопределения сегмента (
2E
, 36
, 3E
, 26
, 64
или 65
). Если это так, используйте соответствующий регистр сегментов для декодирования адресов вместо регистра сегмента по умолчанию.
- Следующий байт - это код операции. Если код операции
0F
, то это расширенный код операции и считывает следующий байт в виде расширенного кода операции.
- В зависимости от конкретного кода операции читайте и декодируйте байт Mod R/M, байт индекса индекса (SIB), смещение (0, 1, 2 или 4 байта) и/или немедленное значение ( 0, 1, 2 или 4 байта). Размеры этих полей зависят от кода операции, переопределения размера адреса и переопределения размера операнда, предварительно декодированного.
Код операции сообщает вам о выполняемой операции. Аргументы кода операции могут быть декодированы в виде значений Mod R/M, SIB, смещения и немедленного значения. Существует множество возможностей и множество особых случаев из-за сложного характера x86. См. Ссылки выше для более подробного объяснения.
Ответ 2
Я бы рекомендовал проверить некоторые дизассемблеры с открытым исходным кодом, желательно distorm и особенно "disOps (Instructions Sets DataBase)" (ctrl + find это на странице).
Документация сама по себе наполнена сочной информацией о кодах операций и инструкциях.
Цитата из https://code.google.com/p/distorm/wiki/x86_x64_Machine_Code
80x86 Инструкция:
Инструкция 80x86 делится на количество элементов:
- Префиксы инструкций влияют на поведение инструкции работа.
- Обязательный префикс, используемый в качестве байта кода операции для инструкций SSE.
- Окод байтов может быть один или несколько байтов (до 3 целых байтов).
- Модем ModR/M является необязательным и иногда может содержать часть сам код операции.
- Байт SIB является необязательным и представляет собой сложную память. формы.
- Смещение необязательно, и это значение разного размера байтов (байт, слово, длинный) и используется как смещение.
- Immediate является необязательным и используется как общее числовое значение, построенное от разного размера байтов (байт, слово, длинное).
Формат выглядит следующим образом:
/-------------------------------------------------------------------------------------------------------------------------------------------\
|*Prefixes | *Mandatory Prefix | *REX Prefix | Opcode Bytes | *ModR/M | *SIB | *Displacement (1,2 or 4 bytes) | *Immediate (1,2 or 4 bytes) |
\-------------------------------------------------------------------------------------------------------------------------------------------/
* means the element is optional.
Структуры данных и фазы декодирования описаны в https://code.google.com/p/distorm/wiki/diStorm_Internals
Цитата:
Фазы декодирования
- [Префиксы]
- [Fetch Opcode]
- [Фильтровать опкод]
- [Извлечь операнды (ов)]
- [Форматирование текста]
- [Hex Dump]
- [Декодированная инструкция]
Также объясняется каждый шаг.
Исходные ссылки хранятся по историческим причинам:
http://code.google.com/p/distorm/wiki/x86_x64_Machine_Code и http://code.google.com/p/distorm/wiki/diStorm_Internals p >
Ответ 3
Начните с некоторой небольшой программы, которая была собрана, и которая дает вам как сгенерированный код, так и инструкции. Получите ссылку на архитектура команд и проработайте с помощью некоторого сгенерированного кода с помощью ссылки на архитектуру. Вы обнаружите, что инструкции имеют очень стереотипную структуру inst op op op с различным количеством операндов. Все, что вам нужно сделать, это перевести шестнадцатеричное или восьмеричное представление кода в соответствии с инструкциями; немного поиграет, покажет это.
Этот процесс, автоматизированный, является ядром дизассемблера. В идеале вам, вероятно, захочется построить n массив структур инструкций внутри (или извне, если программа действительно большая). Затем вы можете перевести этот массив в инструкции в формате ассемблера.
Ответ 4
Для загрузки требуется таблица кодов операций.
Фундаментальная структура данных поиска - это trie, однако таблица будет достаточно хорошо, если вам не все равно о скорости.
Чтобы получить базовый тип кода операции, начните с соответствия таблице.
Существует несколько способов хранения аргументов регистратора; однако есть достаточно особых случаев, требующих выполнения большинства из них индивидуально.
Так как это образовательный, посмотрите на ndisasm.
Ответ 5
Оформить заказ objdump источники - это отличный инструмент, он содержит много таблиц опкодов, и его источники могут стать хорошей базой для создания вашего собственного дизассемблера.