Чем открыть elf файлы прошивки
Чем открыть elf файлы прошивки
Кому приходилось сталкиваться поближе с elf, подскажите в каком направлении копать, пожалуйста.
Заранее спасибо.
mrFox | |||
Карма: 1 |
| ||
eess9 | ||||
Зарегистрирован: Ср фев 29, 2012 01:58:32 | ||||
Страница 1 из 1 | [ Сообщений: 3 ] |
Часовой пояс: UTC + 3 часа
Кто сейчас на форуме
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9
Расширение файла ELF
ELF Executable Format
Что такое файл ELF?
Файлы ELF могут хранить такие данные, как:
Формат ELF был разработан как гибкий, расширяемый и многоплатформенный стандарт, который может быть адаптирован для любых операционных систем или аппаратных платформ. ELF хранит данные с использованием четко определенной структуры, где каждый файл начинается с заголовка, за которым следует раздел данных и ссылки. Ссылки хранятся в двух таблицах: заголовки программ и заголовки разделов. Заголовок ELF содержит всю необходимую информацию о типе данных, хранящихся в файле, и о том, как к ним следует обращаться и интерпретировать.
Хотя стандарт ELF был разработан с учетом систем Unix, он был быстро адаптирован к другим системам, таким как игровые консоли (например, Wii, PlayStation, PowerPC) и некоторым мобильным системам. Содержимое ELF не читается человеком, и такой файл не следует открывать с помощью текстовых редакторов или других программ и приложений, которые не поддерживают этот формат.
Программы, которые поддерживают ELF расширение файла
Ниже вы найдете указатель программ, которые можно использовать для открытия файлов ELF, разделенных на категории 3 в соответствии с поддерживаемой системной платформой. ELF файлы можно встретить на всех системных платформах, включая мобильные, но нет гарантии, что каждый из них будет должным образом поддерживать такие файлы.
Программы, обслуживающие файл ELF
Как открыть файл ELF?
Причин, по которым у вас возникают проблемы с открытием файлов ELF в данной системе, может быть несколько. Что важно, все распространенные проблемы, связанные с файлами с расширением ELF, могут решать сами пользователи. Процесс быстрый и не требует участия ИТ-специалиста. Приведенный ниже список проведет вас через процесс решения возникшей проблемы.
Шаг 1. Получить Dolphin
Шаг 2. Проверьте версию Dolphin и обновите при необходимости
Если у вас уже установлен Dolphin в ваших системах и файлы ELF по-прежнему не открываются должным образом, проверьте, установлена ли у вас последняя версия программного обеспечения. Разработчики программного обеспечения могут реализовать поддержку более современных форматов файлов в обновленных версиях своих продуктов. Причиной того, что Dolphin не может обрабатывать файлы с ELF, может быть то, что программное обеспечение устарело. Все форматы файлов, которые прекрасно обрабатывались предыдущими версиями данной программы, также должны быть открыты с помощью Dolphin.
Шаг 3. Назначьте Dolphin для ELF файлов
Если у вас установлена последняя версия Dolphin и проблема сохраняется, выберите ее в качестве программы по умолчанию, которая будет использоваться для управления ELF на вашем устройстве. Следующий шаг не должен создавать проблем. Процедура проста и в значительной степени не зависит от системы
Процедура изменения программы по умолчанию в Windows
Процедура изменения программы по умолчанию в Mac OS
Шаг 4. Убедитесь, что файл ELF заполнен и не содержит ошибок
Вы внимательно следили за шагами, перечисленными в пунктах 1-3, но проблема все еще присутствует? Вы должны проверить, является ли файл правильным ELF файлом. Проблемы с открытием файла могут возникнуть по разным причинам.
Если случится так, что ELF инфицирован вирусом, это может быть причиной, которая мешает вам получить к нему доступ. Немедленно просканируйте файл с помощью антивирусного инструмента или просмотрите всю систему, чтобы убедиться, что вся система безопасна. Если сканер обнаружил, что файл ELF небезопасен, действуйте в соответствии с инструкциями антивирусной программы для нейтрализации угрозы.
2. Убедитесь, что структура файла ELF не повреждена
Если вы получили проблемный файл ELF от третьего лица, попросите его предоставить вам еще одну копию. Возможно, что файл не был должным образом скопирован в хранилище данных и является неполным и поэтому не может быть открыт. При загрузке файла с расширением ELF из Интернета может произойти ошибка, приводящая к неполному файлу. Попробуйте загрузить файл еще раз.
3. Убедитесь, что у вас есть соответствующие права доступа
Существует вероятность того, что данный файл может быть доступен только пользователям с достаточными системными привилегиями. Переключитесь на учетную запись с необходимыми привилегиями и попробуйте снова открыть файл ELF Executable Format.
4. Проверьте, может ли ваша система обрабатывать Dolphin
Операционные системы могут иметь достаточно свободных ресурсов для запуска приложения, поддерживающего файлы ELF. Закройте все работающие программы и попробуйте открыть файл ELF.
5. Проверьте, есть ли у вас последние обновления операционной системы и драйверов
Современная система и драйверы не только делают ваш компьютер более безопасным, но также могут решить проблемы с файлом ELF Executable Format. Возможно, что одно из доступных обновлений системы или драйверов может решить проблемы с файлами ELF, влияющими на более старые версии данного программного обеспечения.
Вы хотите помочь?
Если у Вас есть дополнительная информация о расширение файла ELF мы будем признательны, если Вы поделитесь ею с пользователями нашего сайта. Воспользуйтесь формуляром, находящимся здесь и отправьте нам свою информацию о файле ELF.
Reverse Engineering ESP8266 — часть 2
Продолжаем исследование модуля ESP8266. В этот раз рассмотрим процесс загрузки прошивки для дизассемблирования.
Первая часть статьи здесь.
Содержание
4. Загрузка прошивки для исследования
Подготовив необходимые инструменты, мы подошли к самой интересной части – загрузке и дизассемблированию прошивки.
Начнем с самого простого – загрузки файла app.out – прошивки в формате ELF, созданной с помощью SDK.
Как правило, файл app.out доступен в случае, когда у вас есть исходный код прошивки, который изучать гораздо проще и логичнее. Однако, чтобы познакомиться с особенностями компилятора, расположением сегментов и увидеть наименования функций, предлагаю начать именно с него.
После компиляции и сборки в папке build у нас появится файл app.out, который представляет собой скомпилированный пользовательский код, данные, библиотеки и отладочную информацию. В таком виде прошивку загрузить в модуль нельзя, поэтому после сборки ELF-файла SDK преобразует app.out в один или два файла в папке firmware – 0x00000.bin и 0x40000.bin, которые можно непосредственно прошить.
Открыв app.out в HIEW и посмотрев на таблицу сегментов (enter, F8, F6) мы увидем следующую картину:
Для загрузки app.out в IDA необходимо проделать следующую последовательность действий:
1. Открываем IDA Pro 6.6 или выше
2. Нажимаем «Go» — никаких файлов пока открывать не будем
3. Открываем пункт меню File – Script file и выбираем скрипт определения процессора xtensa.py
4. Загружаем файл app.out, здесь необходимо выбрать тип процессора и нажать «Set»:
5. В следующих окнах с предупреждением о неизвестном типе машины и предложениями загрузки отладочной информации нажать «Yes»
6. В результате мы получим готовый к исследованию файл:
Чего в нем не хватает? Не хватает системного ROM, содержащего базовые функции модуля. При необходимости его можно загрузить вручную, это мы и проделаем в следующем разделе.
Системная прошивка модуля
Мы рассмотрели довольно простую загрузку в IDA прошивки в виде ELF-файла. Однако на практике зачастую требуется изучить уже готовые прошивки, извлеченные из flash модуля (методом подключения к flash напрямую) или распространяемые в виде файлов 0x00000.bin и 0x40000.bin. Здесь придется проделать немного ручной работы. Начнем с загрузки образа системного ROM. В первой части я давал ссылку на архив с файлом 40000000.bin – это он и есть. Последовательность действий такая:
1. Открываем IDA Pro 6.6 или выше
2. Нажимаем «Go»
3. Открываем пункт меню File – Script file и выбираем скрипт определения процессора xtensa.py
4. Открываем файл 40000000.bin
5. Выбираем тип процессора Tensilica Xtensa [xtensa] и нажимаем «Set»
6. Далее необходимо указать организацию памяти для правильной загрузки двоичного файла. Здесь мы создаем сегмент кода по адресу 0x40000000 и загружаем в него наш файл:
7. Образ ROM загружен, но он плохо читаем из-за отсутствия названий функций. Теперь загрузим скрипт 40000000.idc, который произведет дополнительную работу – определит имена функций и создаст дополнительные сегменты в адресном пространстве: File – Script file – 40000000.idc. Вот результат:
На этом загрузку системного ROM можно считать завершенной, можно переходить к его исследованию. Скрипт определил названия функций системного ROM, теперь можно разобраться, что выплолняет та или иная функция, вызываемая из SDK.
А вот, кстати, функция, которая копирует пользовательскую прошивку из flash в память SoC:
Такой функции в SDK нет, поэтому название я ей дал произвольное.
Но прошивка не полна без загрузки пользовательской части – файлов 0x00000.bin и 0x40000.bin. Поэтому подгрузим эти файлы к системному ROM.
Пользовательская прошивка
Мы загрузили в IDA системный ROM модуля, а скрипт подготовил нам несколько сегментов для загрузки остальных частей. Начнем с простого – загрузки кода библиотек.
Как я говорил выше, файл прошивки 0x40000.bin представляет собой образ сегмента кода без всякой служебной информации и напрямую мапируется в адресное пространство процессора по адресу 0x40240000. Чтобы подгрузить его в IDA проделаем следующее:
1. Убедимся, что у нас открыта база данных 40000000.bin и скрипт 40000000.idc создал дополнительные сегменты: RAM, ROM, IRAM, IROM
2. Выбираем в меню File – Load file – Additional binary file, открываем файл прошивки 40000.bin
3. В следующем окне выбираем параметры загрузки. Обратите внимание, что загрузка производится по смещению в параграфах, т.е. вместо адреса указываем значение в 10h раз меньше (отбрасываем последний ноль). Галку создания сегмента можно снять, он у нас уже создан:
4. Файл загружен. После указания начала кода (в данном случае это 4024000Ch) мы получаем примерно следующую картину:
В отличие от ELF-файла, здесь не будут определены названия функций и переменных, но с этим уже ничего не поделаешь.
1. Найти сигнатуру исследуемой функции в дизассемблере ELF-файла, скомпилированного той же версией SDK. Есть вероятность, что вы ее найдете, и у нее будет имя (из отладочной информации). В том числе для этого я рассматривал загрузку прошивки в ELF.
2. Известные константы – функция может ссылаться на текстовые строки или двоичные данные. С опытом многие такие константы запоминаешь наизусть, если константа незнакома – гуглим. Вот пример:
Видим две примечательные константы. Гугл первой же ссылкой выдает описание алгоритма strlen, использующего эти константы:
Сравнив реализации алгоритма, можно с уверенностью сказать, что по адресу 40100E70h расположена функция strlen.
Или вот такой кусок кода сразу выдает функцию деления:
Теперь переходим к загрузке файла 00000.bin. Мы помним, что это не просто образ, а файл со структурой, описывающий сегменты данных и кода. Вот так он может выглядеть при просмотре в шестнадцатеричном виде:
Сначала идет 8 байт общего заголовка прошивки, в которой определяется количество сегментов и точка входа. Потом идут сами сегменты, также имеющие 8-ми байтовые заголовки с адресом и длиной.
Чтобы правильно загрузить их в IDA я вырезал данные каждого сегмента (без заголовков) в отдельные файлы, назвав их по адресу загрузки:
Теперь остается подгрузить их в IDA. Для каждого файла выполняем последовательность действий, аналогичных загрузке системного ROM:
1. File – Load file – Additional binary file, выбираем файл данных
2. В параметрах загрузки указываем сегмент (по имени файла без последнего нуля), сегмент не создаем.
Все, теперь у нас есть полностью загруженная и готовая к исследованию прошивка!
Создаем ELF-файл с отладочной информацией (DWARF) вручную (для микроконтроллеров ARM)
Введение
С недавнего времени я увлекся микроконтроллерами. Сначала AVR, затем ARM. Для программирования микроконтроллеров существует два основных варианта: ассемблер и С. Однако, я фанат языка программирования Форт и занялся портированием его на эти микроконтроллеры. Конечно, существуют и готовые решения, но ни в одном из них не было того, что я хотел: отладки с помощью gdb. И я задался целью заполнить этот пробел (пока только для ARM). В моем распоряжении была плата stm32vldiscovery с 32-битным процессором ARM Cortex-M3, 128кБ flash и 8 кБ RAM, поэтому я и начал с нее.
Писал я кросс-транслятор Форта конечно на Форте, и кода в статье не будет, так как этот язык считается экзотическим. Ограничусь достаточно подробными рекомендациями. Документации и примеров в сети по предмету почти нет, некоторые параметры подбирались мной путем проб и ошибок, некоторые — путем анализа выходных файлов компилятора gcc. Кроме того, я использовал только необходимый минимум отладочной информации, не касаясь, например, relocation-ов и множества других вещей. Тема очень обширна и, признаюсь, разобрался я с ней только процентов на 30, что оказалось для меня достаточным.
Кого заинтересует этот проект, может скачать код здесь.
Обзор ELF
1. Заголовок (ELF Header)
2. Заголовок программы (Program Header Table)
3. Секции
Секции содержат всю информацию в файле (программа, данные, отладочная информация и т.д)
У каждой секции есть тип, имя и другие параметры. В секции «.text» обычно хранится код, в «.symtab» — таблица символов программы (имена файлов, процедур и переменных), в «.strtab» — таблица строк, в секциях с префиксом «.debug_» — отладочная информация и т.д. Кроме того, в файле должна обязательно быть пустая секция с индексом 0.
4. Заголовок секций (Section Header Table)
Это таблица, содержащая массив заголовков секций.
Более подробно формат рассматривается в разделе Создание ELF.
Обзор DWARF
Узлы, описывающие данные:
Узлы, описывающие код:
Другая информация:
Создание ELF
Инициализация libelf
Сначала вам нужно будет вызвать функцию elf_version(EV_CURRENT) и проверить результат. Если он равен EV_NONE — возникла ошибка и дальнейшие действия производить нельзя. Затем нужно создать нужный нам файл на диске, получить его дескриптор и передать его в функцию elf_begin:
Создание заголовка
Новый заголовок файла создается функцией elf32_newehdr:
Создание заголовка программы
Как уже говорилось, заголовок программы (Program Header Table) — это таблица соответствия секций файла сегментам памяти, которая указывает загрузчику, куда писать каждую секцию. Загоовок создается создаются с помощью функции elf32_newphdr:
Создание секций
После создания заголовков можно приступать к созданию секций. Пустая секция создается при помощи функции elf_newscn:
Специальные секции
Секция содержит описание всех символов (функций) программы и файлов, в которых они были описаны. Она состоит из таких элементов длиной по 16 байт:
Таблицы строк
Таблицы строк содержат идущие подряд строки, оканчивающиеся нулевым байтом, первый байт в этой таблице должен быть также 0. Индекс строки в таблице — это просто смещение в байтах от начала таблицы, таким образом, первая строка ‘name’ имеет индекс 1, следующая строка ‘var’ имеет индекс 6.
Запись файла
Итак, заголовки и секции уже сформированы, теперь их нужно записать в файл и завершить работу с libelf. Запись производит функция elf_update:
Создание DWARF
Инициализация libdwarf producer
Создание Узлов (DIE — Debugging Information Entry)
Создание атрибутов узла
Для создания атрибутов узла есть целое семейство функций dwarf_add_AT_хххх. Иногда проблематично определить, какой функцией нужно создавать необходимый атрибут, так что я даже несколько раз копался в исходном коде библиотеки. Некоторые из функций будут описаны здесь, некоторые ниже — в соответствующих разделах. Все они принимают параметр ownerdie — дескриптор узла, к которому будет добавлен атрибут, и возвращают код ошибки в параметре error.
Функция dwarf_add_AT_name добавляет к узлу атрибут «имя» (DW_AT_name). У большинства узлов должно быть имя (например у процедур, переменных, констант), у некоторых имени может и не быть (например у Compilation Unit)
Создание Единицы Компиляции (Compilation Unit)
В любом дереве должен быть корень — у нас это единица компиляции, которая содержит информацию о программе (например, имя главного файла, используемый язык программирования, название компилятора, чувствительность символов (переменных, функций) к регистру, главную функцию программы, начальный адрес и.т.д). В принципе, никакие атрибуты не являются обязательными. Для примера создадим информацию о главном файле и компиляторе.
Информация о главном файле
Для хранения информации о главном файле используется атрибут «имя» (DW_AT_name), применяйте функцию dwarf_add_AT_name, как показано в разделе «Создание атрибутов узла».
Информация о компиляторе
Используем функцию dwarf_add_AT_producer:
Создание Common Information Entry
Создание типов данных
Создание процедур
Создание символа процедуры
Создание узла процедуры с атрибутами
Создание FDE процедуры
Функция вернет дескриптор нового FDE или DW_DLV_BADADDR при ошибке.
Присоединить новый FDE к списку можно при помощи dwarf_add_frame_fde:
Создание параметров процедуры
Создание параметров процедуры аналогично созданию обычных переменных, см. «Создание переменных и констант»
Cоздание информации о номерах строк
Создание переменных и констант
Для добавления инструкций в выражение нужно использовать функцию dwarf_add_expr_gen:
Создание секций с отладочной информацией
переводит созданную нами отладочную информацию в бинарный формат, но ничего не записывает на диск. Она возвратит нам количество созданных elf-секций или DW_DLV_NOCOUNT при ошибке. При этом для каждой секции будет вызвана callback-функция, которую мы передали при инициализации библиотеки в функцию dwarf_producer_init_c. Эту функцию должны написать мы сами. Ее спецификация такая:
Окончание работы с библиотекой
После формирования секций можно завершать работу с libdwarf функцией dwarf_producer_finish:
Функция возвращает DW_DLV_NOCOUNT при ошибке.
Замечу, что запись на диск на этом этапе не производится. Запись нужно делать посредством функций из раздела «Создание ELF — Запись файла».
Заключение
На этом все.
Повторюсь, создание отладочной информации — тема очень обширная, и многих тем я не коснулся, только приоткрыв завесу. Желающие же могут углубляться до бесконечности.
Если у вас будут вопросы — постараюсь на них ответить.
Рецепты для ELFов
На русском языке довольно мало информации про то, как работать с ELF-файлами (Executable and Linkable Format — основной формат исполняемых файлов Linux и многих Unix-систем). Не претендуем на полное покрытие всех возможных сценариев работы с эльфами, но надеемся, что информация будет полезна в виде справочника и сборника рецептов для программистов и реверс-инженеров.
Подразумевается, что читатель на базовом уровне знаком с форматом ELF (в противном случае рекомендуем цикл статей Executable and Linkable Format 101).
Под катом будут перечислены инструменты для работы, описаны приемы для чтения метаинформации, модификации, проверки и размножения создания эльфов, а также приведены ссылки на полезные материалы.
— Я тоже эльф… Синий в красный… Эльфы очень терпеливы… Синий в красный… А мы эльфы. Синий в красный… От магии одни беды…
(с) Маленькое королевство Бена и Холли
Инструменты
В большинстве случаев примеры можно выполнить как на Linux, так и на Windows.
В рецептах мы будем использовать следующие инструменты:
Тестовые эльфы
В качестве «подопытного» будем использовать ELF-файл simple из таска nutcake’s PieIsMyFav на crackmes.one, но подойдёт любой представитель «эльфийского» семейства. Если готовый файл с требуемыми характеристиками не был найден в свободном доступе, то будет приведён способ создания такого эльфа.
«Свободных» эльфов можно также найти по ссылкам:
Чтение, получение информации
Тип файла, заголовок, секции
В зависимости от задачи интерес могут представлять:
010Editor
HEX-редактор 010Editor предоставляет систему шаблонов. Для ELF-файлов шаблон называется, как ни странно, ELF.bt и находится в категории Executable (меню Templates — Executable).
Интерес может представлять, например, точка входа в исполняемый файл (entry point) (записана в заголовке файла).
readelf
Утилиту readelf можно считать стандартом де-факто для получения сведений об ELF-файле.
Для удобства чтения адреса приведены к 32-битному формату:
Для удобства чтения адреса приведены к 32-битному формату:
Вывод сокращён для удобства чтения:
Прочитать заголовок и информацию о секциях можно с использованием кода на Python и библиотеки LIEF (предоставляет API не только для Python):
Информация о компиляторе
objdump
readelf
Я вычислю тебя по… RPATH
Эльфы могут сохранять пути для поиска динамически подключаемых библиотек. Чтобы не задавать системную переменную LD_LIBRARY_PATH перед запуском приложения, можно просто «вшить» этот путь в ELF-файл.
И будь осторожен, юный разработчик, не «спали» свою директорию проекта!
Как появляется RPATH?
readelf
Для удобства чтения результат команды сокращён:
С помощью библиотеки LIEF также можно прочитать RPATH-запись в эльфе:
Проверка эльфа на безопасность
Скрипт проверки безопасности checksec.sh от исследователя Tobias Klein (автора книги A Bug Hunter’s Diary) не обновлялся с 2011 года. Данный скрипт для ELF-файлов выполняет проверку наличия опций RelRO (Read Only Relocations), NX (Non-Executable Stack), Stack Canaries, PIE (Position Independent Executables) и для своей работы использует утилиту readelf.
Можно сделать свой аналог на коленке Python и LIEF (чуть короче прародителя и с дополнительной проверкой опции separate-code):
Radare2
Спасибо dukebarman за дополнение по использованию Radare2 для вывода информации аналогично checksec:
«Сырой код» из эльфа (binary from ELF)
Бывают ситуации, когда «эльфийские одёжи» в виде ELF-структуры не нужны, а нужен только «голый» исполняемый код приложения.
objcopy
Использование objcopy вероятно знакомо тем, кто пишет прошивки:
Никакой магии. Просто взять содержимое загружаемых секций и слепить из них бинарь:
Mangled — demangled имена функций
В ELF-ах, созданных из С++ кода, имена функций декорированы (манглированы) для упрощения поиска соответствующей функции класса. Однако читать такие имена при анализе не очень удобно.
Для представления имён в удобочитаемом виде можно использовать утилиту nm из набора binutils:
Вывод имён символов в деманглированном виде с использованием библиотеки LIEF:
Сборка, запись, модификация эльфа
Эльф без метаинформации
После того как приложение отлажено и выпускается в дикий мир, имеет смысл удалить метаинформацию:
Удаление символьной информации
Символьная информация — это имена объектов и функций. Без неё реверс приложения немного усложняется.
strip
В самом простом случае можно воспользоваться утилитой strip из набора binutils. Для удаления всей символьной информации достаточно выполнить команду:
sstrip
Для тщательного удаления символьной информации (в том числе ненужных нулевых байтов в конце файла) можно воспользоваться утилитой sstrip из набора ELFkickers. Для удаления всей символьной информации достаточно выполнить команду:
Удаление таблицы секций
Как упоминалось выше, наличие/отсутствие таблицы секций не оказывает влияния на работу приложения. Но при этом без таблицы секций реверс приложения становится чуть сложнее.
Воспользуемся библиотекой LIEF под Python и примером удаления таблицы секций:
Изменение и удаление RPATH
chrpath, PatchELF
Для изменения RPATH под Linux можно воспользоваться утилитами chrpath (доступна в большинстве дистрибутивов) или PatchELF.