В процессе обратной разработки прошивок иногда возникает задача по ее эмуляции, например, для фаззинг тестирования или детального изучения поведения в динамике. На практике обычно для этого хватает фреймворков avatar2, unicorn, qiling и подобных. Однако они поддерживают далеко не все платформы и имеют ряд ограничений для решения таких задач. При разработке эмулятора PLC я столкнулся с тем, что ни один фреймворк для эмуляции не поддерживал требуемую платформу. Частично эти ограничения снимает разработка эмулятора на базе qemu, однако статей по этой тематике в сети достаточно мало, а официальная документация не содержит примеров реализации простых девайсов. В этой статье я хотел бы восполнить этот недостаток и поделиться своим небольшим опытом по реализации машины в qemu, чтобы сэкономить время начинающих разработчиков и исследователей безопасности, сталкивающихся с похожей задачей.    Полезные статьи по теме:    https://habr.com/ru/post/522378/ https://habr.com/ru/post/466549/  https://airbus-seclab.github.io/qemu_blog/ https://github.com/Gyumeijie/qemu-object-model https://qemu.readthedocs.io/en/latest/devel/index.html   Для начала соберем свежий образ qemu    В качестве примера будем писать машину под платформу aarch64, поэтому собираем только ее  Для проверки доступных машин можно выполнить следующую команду     Итак, приступим. Для начала в файл конфигурации Kconfig в основной папке платформы добавляем новый тип, описывающий конфигурацию нашей машины, сюда в дальнейшем будем добавлять зависимости самой машины     В файл meson.build допишем строчку с параметрами сборки    Далее реализуем саму машину в простейшем варианте:   В этом фрагменте кода происходит примерно следующее: при помощи макроса DEFINE_MACHINE, объявленного в заголовке "hw/boards.h", объявляется новая машина. Макрос регистрирует новый тип данных наследуемый отTYPE_MACHINE, объявляет подобие базового конструктора класса, в котором преобразует переданную область памяти к структуре MachineClass и передает управление в функицю arm_edu_machine_init, где в дальнейшем мы имеем возможность заполнить эту структуру. Приведу наиболее интересный ее фрагмент с небольшими комментариями:    Подробнее с этой структурой можно ознакомиться в том же заголовочном файле где объявлен макрос. Для того, чтобы скрипт сборки добавил и нашу машину, ее необходимо включить в файле конфигурации, например в configs/devices/aarch64-softmmu/default.mak. После этого можно повторно собирать qemu.  После сборки проверяем наличие нашей машины в списке доступных. Если все прошло хорошо, результат будет примерно такой:   Если попытаться запустить машину, то ничего не произойдет, поскольку отсутствует реализация инициализации, т.е. машины как таковой пока еще не существует. Попробуем это исправить дополнив исходный файл с машиной: В заголовочный файл поместим объявление констант и архитектурные зависимости   Часть кода я по возможности постарался прокомментировать, однако более подробно с каждой из используемых функций рекомендую ознакомиться в заголовочных файлах.     Теперь, когда наша машина умеет полноценно запускать код, напишем небольшую прошивку для ее тестирования. Собирать при помощи gcc-aarch64 будем вот такой простенький код  Чтобы не лезть лишний раз в гугл    Наконец, запускаем qemu для теста    Параметры -s -S используются для запуска gdb сервера на порту 1234, -nographic отключает графический дисплей. Для машин собранных с поддержкой такового qemu запускает его автоматически.   В соседнем окне подключаем gdb Готово. На выходе имеем полноценно работающую машину, в которой уже можно частично отлаживать кусочки ассемблерного кода на уровне EL3.  В следующих статьях рассмотрим реализацию MMIO регистров, UART интерфейса, сетевой карты и виртуального таймера.