Рассчитать смещение байта для unquashfs

Вопрос или проблема

Я пытаюсь вычислить значение -o для извлечения файла .AppImage, используя unsquashfs на иностранных архитектурах/ОС, но вместо readelf использую objdump для большей совместимости с ОС, такими как macOS.

unsquashfs

Usage:

-o BYTES, -offset BYTES
              skip BYTES at start of FILESYSTEM.  Optionally a suffix of K, M or G can be given to specify Kbytes, Mbytes or Gbytes respectively (default 0
              bytes).

Я следую инструкциям этого решения, которое использует readelf для вычисления значения смещения -o. Это отлично работает на Ubuntu, но не работает для macOS из-за общего отсутствия readelf.

Однако я хотел бы использовать objdump при возможности. Я нашел несколько вопросов, объясняющих, как найти точку входа/смещение исполняемого бинарника, но какие бы значения я ни пробовал, я не могу найти способ получить правильное значение для unsquashfs. Я перевожу шестнадцатеричные значения в десятичные, но ничего из objdump не совпадает с значениями readelf ниже, даже при использовании уравнения Employed Russian: ehdr->e_entry - phdr->p_vaddr + phdr->p_offset.

Например, возьмем AppImage Audacity:

https://github.com/audacity/audacity/releases/download/Audacity-3.7.1/audacity-linux-3.7.1-x64-22.04.AppImage
  • Вызов readelf -h audacity-linux-3.7.1-x64-22.04.AppImage дает мне некоторые полезные значения, такие как Start of section headers, Size of section headers, Number of section headers.
  • Затем, используя логику $START_OF_SECTION + $SECTION_SIZE * $SECTION_NO Мартина Высочила, я могу получить правильное значение 191680 + 64 * 32, которое равно 193728.
  • Следующая команда выполняется успешно (на macOS и Ubuntu):
    unsquashfs -o 193728 audacity-linux-3.7.1-x64-22.04.AppImage squashfs-root
    

… но как я могу вычислить это смещение с помощью objdump вместо readelf?

Пока вы знаете, какие байты читать в заголовке ELF, вы можете применить формулу напрямую с помощью инструмента, который может обрабатывать бинарные файлы (python, perl и т. д.).

Вот как выглядит заголовок ELF (см. man elf):

typedef struct {
    unsigned char e_ident[16]; // байты идентификации ELF
    uint16_t      e_type;      // Тип файла
    uint16_t      e_machine;   // Требуемая архитектура для этого файла
    uint32_t      e_version;   // Должен быть равен 1
    uintN_t       e_entry;     // Адрес для перехода к началу программы
    uintN_t       e_phoff;     // Смещение таблицы заголовков программы, в байтах
    uintN_t       e_shoff;     // Смещение таблицы заголовков секций, в байтах
    uint32_t      e_flags;     // Флаги, специфичные для процессора
    uint16_t      e_ehsize;    // Размер заголовка ELF, в байтах
    uint16_t      e_phentsize; // Размер записи в таблице заголовков программы
    uint16_t      e_phnum;     // Количество записей в таблице заголовков программы
    uint16_t      e_shentsize; // Размер записи в таблице заголовков секций
    uint16_t      e_shnum;     // Количество записей в таблице заголовков секций
    uint16_t      e_shstrndx;  // Индекс таблицы имен секций в таблице заголовков секций
};

Примечание: N в uintN_t может быть 32 или 64, в зависимости от значения e_ident[4]


Вычисление смещения

Следующая “однострочница” на perl рассчитает смещение, необходимое для unsquashfs, но только для ELF64-LSB app изображений (мне было лень обрабатывать возможные размеры адресации и эндиянность):

perl -le '
    read STDIN, $_, 64;
    ($off,$sz,$nb) = unpack "x40Q<x10S<S<";
    print $off + $sz * $nb;
' < audacity-linux-3.7.1-x64-22.04.AppImage

вывод:

193728

Помимо этого

Я решил, что необходимо рефакторить скрипт @MartinVyskočil:

readelf -h file.appimage |
awk '
    /of section headers:/ { h[$1] = $5 }
    END { print h["Start"] + h["Size"] * h["Number"] }
'

Ответ или решение

Теория

Для извлечения файлов из формата .AppImage с использованием unsquashfs на разных операционных системах необходимо вычислить смещение байтов (-o), чтобы правильно пропустить данные в начале файловой системы. Обычно это значение можно получить с помощью утилиты readelf, но в macOS она недоступна. В таких случаях предлагается использовать objdump, который доступен на macOS. Задача заключается в том, чтобы скриптом или командами рассчитать нужное смещение с помощью данных, которые предоставляют эти инструменты.

Пример

При использовании readelf, необходимая информация для расчета смещения байтов может быть получена из заголовков ELF (Executable and Linkable Format), таких как Start of section headers, Size of section headers, и Number of section headers. Эти параметры позволяют вычислить искомое смещение байтов.

Применение

Если мы хотим достичь того же результата с использованием objdump, это возможно за счет перебора и анализа бинарной структуры ELF. Другие инструменты, такие как скрипты Perl, Python и другие языки программирования, могут быть использованы для прямой работы с бинарными данными, извлеченными из ELF.

Возможное Решение

  1. Использование objdump: Узнайте в каком из разделов объектов ELF находится информация, соответствующая смещению, затем проведите необходимые расчеты. За это отвечает флаг --headers у objdump, который выводит данные о разделах.

  2. Скрипт на Perl: Если у вас на руках объект ELF, то смещение можно рассчитать примерно таким образом:

    perl -le '
       read STDIN, $_, 64;
       ($off, $sz, $nb) = unpack "x40Q<x10S<S<";
       print $off + $sz * $nb;
    ' < ваш_файл.AppImage

    Этот скрипт считывает первые 64 байта ELF-файла и делает необходимые вычисления на основе извлеченной информации.

  3. Сравнение результатов: Проверьте полученное значение смещения, запустив unsquashfs с вашим значением:

    unsquashfs -o <ваше_значение_смещения> ваш_файл.AppImage squashfs-root

Это решение позволяет избежать зависимости от конкретных утилит и делает процесс извлечения универсальным для использования на системах, где readelf недоступен, например, на macOS.

Оцените материал
Добавить комментарий

Капча загружается...