• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Змей и Яблоко. Часть 1. Mach-O файлы.

Norbert Beaver

CD-диск
Пользователь
Регистрация
29.02.2024
Сообщения
15
Реакции
22
Автор перевода: Norbert Beaver
Переведено специально для форума xss.pro
Источник:
github.com/Karmaz95/Snake_Apple/blob/main/README.md

Детальный разбор файлов Mach-O на архитектуре x64 MacOS с помощью Python.

0.png


ВВЕДЕНИЕ

Добро пожаловать в первую часть цикла статей о средствах безопасности MacOS.

В данной статье предоставляется детальная информация о формате файлов Mach-O, а также кратко описывается процесс его загрузки в виртуальную память. В данной статье вы узнаете о: определении подлинного Mach-O файла; порядке следования его байтов; различных типов файлов Mach-O; сегментации; концепции последовательных исправлений и многом другом.

К тому-же, мы расскажем о том, каким образом можно извлечь важную информацию из рассматриваемых файлов в читабельном виде с помощью Python и других инструментов.

Mach-O

Формат файла, используемый на системах macOS в следующих видах:
  • Исполняемый файл. Формат, который понимается системой и может быть исполнен. Конечный вид ПО, используемый пользователями.
    clang -o hello hello.c
  • Код объекта (.o). Скомпилированный исходный код, который должен быть связан с другими кодами и библиотеками для создания исполняемого файла или разделяемой библиотеки.
    clang -c -o hello.o hello.c
  • Динамическая библиотека (.dylib). Предварительно компилированный код, доступный многим программам, загружаемым в память в момент запуска программы.
    clang -shared -o libmylib.dylib mylib.c
  • Пакет загрузки (плагин). Пакеты исполняемого кода и соответствующих ресурсов, которые могут быть запущены с помощью NSBundle и dlopen в момент исполнения программы.
    clang -bundle MyBundle.c -o MyBundle
  • dSYM. Файл, генерируемый, когда Strip Debug Symbols включены в настройки проекта, содержащего в себе символы отладки.
    clang -g -o hello_dsym hello.c


1.png

Пять самых распространенных типов файлов
Структура Mach-O

Mach-O состоит из Заголовка, которому предшествует последовательность Команд загрузки, а затем один или более Сегментов, разделяемых на Секции.

Основная структура содержит в себе Команды загрузки переменной длины, указывающие на страницы данных в файле. Ниже представлена упрощенная схема:

2.png

Упрощенная структура Mach-O
  • Заголовок – метаданные, такие как тип файла и архитектура процессора.
  • Команды загрузки – информируют XNU и dyld о том, как загружать Mach-O файл.
  • Сегменты – информируют ядро о том, каким образом следует отображать Mach-O в виртуальной памяти и как указывать средства защиты памяти.
  • Секции – Данные в Сегментах, которые наследуют средства защиты памяти.
Универсальный бинарный формат (Толстый двоичный формат) – множество Заголовков Mach-O.

Универсальный бинарный формат – это концепт, в котором используется файл Mach-O в системах macOS для создания единого исполняемого файла, содержащего в себе скомпилированный код для множества архитектур. Вы можете рассмотреть его структуру ниже:

3.png


4.png

Пример Универсального бинарного формата
Ядро загружает самый подходящий для архитектуры машины бинарный формат. Для загрузки другой архитектуры из Толстого двоичного формата используйте команду arch:
5.png

Python:
arch -x86_64 PATH

Страницы памяти

Все биты из заголовков, сегментов, секций и бинарных данных хранятся в страницах памяти, - самых маленьких единицах в дисциплине управления памятью.

Это блок памяти фиксированной длины, который в среднем весит несколько килобайт. Для macOS и 64-разрядных архитектур, их вес составляет 16 килобайт. Однако macOS может содержать в себе как 4 так и 16-килобайтные страницы. Сама информация хранится в vm_param.h:
6.png

Обычно, macOS работает с 16-килобайтными страницами памяти. Однако, существуют ситуации, в которых он работает и с 4-килобайтными страницами, например, вычисление хэша для подписи кода.

Загрузка в память

Когда пользователь запускает приложение на macOS, то файл Mach-O загружается в память с помощью ядра XNU, чтобы процессор смог выполнить его инструкции.
Следующие шаги описывают общий процесс работы XNU ядра:
Затем, Dynamic Linker обрабатывает загрузку библиотек и разрешение символов:
  • Преобразовывает Mach-O файл, чтобы тот мог читать определенные команды запуска в dyld
  • Перераспределяет все относительные ссылки на адреса внутри файла
  • Связывает общие библиотеки (dylibs)
  • Разделяет символьные ссылки на функции и переменные
  • Передает управление точке входа исполняемого файла
Вы можете посмотреть информацию, загруженную Dynamic Linker с помощью команды dyld_info:
7.png

Последнюю версию исходного кода dyld и XNU можно найти на apple-oss-distributions.

Заголовок

Структурой mach_header_64 является 64-битный заголовок Mach-O, который появляется в начале файла или в смещении, указанном в заголовке толстого двоичного формата.
8.png


Это используется для определения Mach-O файла и предоставления информации о том, каким образом следует загрузить его в памяти. Снизу приведены примеры подлинных заголовков Mach:
9.png

10.png


Вы можете использовать команду otool с флагами –hv для того, чтобы посмотреть информацию из командной строки:
11.png


Magic

Поле magic используется для определения формата файла и порядка битов.

12.png

Если двоичный файл был скомпилирован для машины с «младшеконечным» форматом следования байтов, и затем переведен на машину со «старшеконечным» форматом следования байтов, то значение magic будет MH_CIGAM_64. В ином случае, значение magic будет MH_MAGIC_64.
13.png

Скомпилировано на машине с «младшеконечным» форматом для машины с «младшеконечным» форматом.

XNU читает значение magic с помощью собственного порядка байтов хоста. В случае, если значение совпадает с MH_CIGAM_64, он изменяет порядок байтов двоичного файла с помощью функции ядра NXSwapInt которая принимает целое число без знака в качестве аргумента и возвращает значение замены байтов
14.png


CPU Type

В поле cputype указывается целевая архитектура:
15.png


Переменная типа cpu_type_t является псевдонимом целого числа и может быть найдена в machine.h в репозитории. Ниже представлены все типы и их значения:
16.png

На системах macOS с 64-разрядными процессорами, размер integer_t составляет 4 байта.
CPU Subtype

Значение cpusubtype определяет конкретного участника семейства ЦП и используется в сочетании с cputype для проверки совместимости аппаратного обеспечения.
17.png


В machine.h описано множество subtypes (подтипов), но для 64-разрядной архитектуры подходят лишь немногие. Снизу показаны доступные:
18.png


К тому-же, cpusubtype используется для извлечения версии аутентификации указателя с помощью побитового процесса ANDing в cpusubtype с маской 0x0f000000 и последующего сдвига результата на 24 бита вправо:
19.png


File Types

filetype определяет структуру файла.
20.png

Устаревшие типы файлов были выделены серым цветом

Flags

В 32-битном поле flags в заголовке файла Mach-O хранятся константы, которые определяют дополнительные параметры для компоновщика (ld) или динамического компоновщика (dyld).

21.png

Самые распространенные flags
Все flags с дополнительными комментариями к ним вы можете найти в loader.h.

Команды загрузки

Структура load_command следует прямо за заголовком Mach. Каждая команда загрузки должна начинаться с двух полей: cmd, которое является типом команды загрузки и cmdsize, которая хранит его размер.
22.png


К примеру, размер типа команды LC_SEGMENT_64 составляет 72 байта:
23.png

Все константы для типов команд запуска (cmd) описаны в loader.h.
Выравнивание на 64-разрядной архитектуре

В 64-разрядной архитектуре все части Mach-O должны быть кратны 8 байтам и дополняться 0x00 байтами. В частности, я имею в виду заголовок, команды загрузки, сегменты, секции и таблицы в части данных.

Продолжая эту логику, поскольку команды загрузки отвечают за указание Dynamic Linker-у (dyld), как загрузить весь файл Mach-O в память, поле cmdsize всегда должно быть кратно 8 байтам.
24.png

Пример размера команды загрузки LC_MAIN

Защита памяти на 64-разрядной архитектуре

Файл Mach-O, загружаемый с помощью XNU в виртуальную память, разделен на сегменты, связанные с определенными атрибутами защиты памяти.
25.png


Они устанавливаются с помощью mprotect() во время отображения памяти с помощью mmap():
26.png

Функция архитектуры, называемая eXecute Never (NX), не позволяет одновременно устанавливать защиту какой-либо области памяти как для записи, так и для выполнения (W ^ X).
Сегменты

Первыми командами запуска в файле Mach-O являются сегменты: segment_command_64
27.png

28.png


Различные сегменты. Менее распространенные отмечены серым:
29.png


Секции

Сегменты подразделяются на секции (section_64):
30.png

Значения Flags можно найти здесь: loader.h

Каждая секция имеет свой собственный размер и содержимое загружаемого файла, но она наследует защиту памяти от сегмента, к которому принадлежит. Разделы с суффиксами __object относятся к Objective-C, а __swift5 - к Swift.
31.png

Секция __text в сегменте __TEXT

Существует также множество других секций. Вот некоторые из самых распространенных
32(2).png


__PAGEZERO

Указывает ядру зарезервировать начальные 4гб (0x100000000) виртуальной памяти. Может также занять больше места (slide), в случае, если используется флаг MH_PIE.
33.png


Поскольку к данной (---) области не применяются никакие права защиты, то любая попытка доступа через нулевой указатель будет считана и в последствии приведет к сбою.
34.png

Этот сегмент не занимает места на диске.

__TEXT

Поскольку размер файла сегмента __PAGEZERO равен нулю, то __TEXT является первым «настоящим» сегментом и находится в начале файла.

В виртуальной памяти, он начинается с 0x100000000 (+slide, если используется MH_PIE) и отмечен как читабельный и исполняемый. Он хранит данные только для чтения и код исполнения. Также, он состоит из заголовка и команд запуска Mach-O.
35.png


__DATA_CONST

Данный сегмент хранит глобальные переменные, которые помечены как постоянные данные. Во время выполнения mmap, __DATA_CONST доступен для чтения и записи. Однако, после инициализации, dyld управляеятся флагом сегмента SG_READ_ONLY для того, чтобы сделать его только для чтения через mprotect.
36.png

Одним из вариантов использования этого является неленивое связывание __got.

__DATA

Содержит данные для чтения и записи. Является хранилищем для глобальных и статичных переменных, а также для неисполняемых структур данных во время выполнения.
37.png


__RESTRICT

Пустой сегмент с пустой секцией __restrict, только для чтения. Указывает dyld подтвердить подпись для всего загружаемого кода.
38.png


__LINKEDIT

Не имеет секций и описывается командами запуска, запускаемыми после него, таких как: LC_SYMTAB, LC_MAIN, LC_LOAD_DYLIB и т.д. Содержит данные только для чтения, используемые dyld во время связки символов.
39.png


Сегмент __LINKEDIT, к примеру, начинается с 0xC000 и заканчивается 0xC000 + 0x4EC0 == 0x10EC0, что является последним байтом в двоичном файле:
40.png

__LINKEDIT должен быть последним сегментом. Dynamic Linker (dyld) отклонит любые двоичные файлы с данными сегмента после __LINKEDIT.

Цепные исправления

После множества команд загрузки (LC_SEGMENT_64), ответственных за загрузку сегментов в виртуальную память, пришло время поговорить о привязке и перемещении.
  • Привязка разрешает символьные ссылки в двоичном файле. Это процесс замены символов, которые относятся к коду или данным, фактическими адресами.
  • Перемещение следит за тем, чтобы все указатели указывали на правильное местоположение, путем добавления базового адреса динамической библиотеки, из которой они пришли, к их сдвигу.
Fixups (Исправления) == Binding (Привязка) && Rebasing (Перемещение)

К сожалению, MachOView пока не поддерживает цепные исправления. До macOS 12 информация, необходимая для выполнения этой задачи, использовалась LC_DYLD_INFO.
41.png

Пример цепных исправлений
Они обрабатываются с помощью LC_DYLD_CHAINED_FIXUPS, на которую ссылается linkedit_data_command. Комментарии к структуре связаны с приведенным выше примером:
42.png


Значение dataoff является сдвигом dyld_chained_fixups_header, который определяет цепные исправления.
43.png

Значения в комментариях относятся к ниже приведенному signed_ad_hoc_example.

Обратите внимание на пример dyld_chained_fixups_header, помеченного зеленым цветом в данных LC_DYLD_CHAINED_FIXUPS, помеченных красным цветом:
44.png


Благодаря выравниванию, dyld_chained_starts_in_image начинается с 0xC020, после четырех идущих байтов 0x00 в 0xC016–0xC020, как указано в starts_offset.
45.png


Структура указывает количество сегментов в бинарном файле и местоположение их dyld_chained_starts_in_segment. Поле seg_count определяет фактическое количество элементов в этом массиве. Для нашего примера бинарного файла структура будет выглядеть следующим образом:
46.png


  • dyld_chained_starts_in_image помечено желтым
  • dyld_chained_starts_in_segment[2] помечено голубым
  • dyld_chained_starts_in_segment[3] помечено серым
47.png

Пример dyld_chained_starts_in_image

Каждый dyld_chained_starts_in_segment описан ниже. Числа в комментариях относятся к segment[2] (выделенного голубым цветом).
48.png

Значения, основанные на signed_ad_hoc_example

Изображение ниже показывает эту структуру, разобранную с помощью команды dyld_info:
49.png


В каждом dyld_chained_starts_in_segment:
  • Массив page_start[0] указывает на первое исправление на странице, а следующее исправление находится на текущей позиции плюс значение следующего поля, умноженное на 4.
  • Эти исправления 64-битные и могут быть либо повторным базированием, либо связыванием, при этом тип указывается младшим битом.
Существуют и многие другие значения для pointer_format. Все они описаны в fixup-chains.h. Ниже вы можете увидеть структуру исправления для pointer_format == 0x6:

***Достигнуто максимальное количество загружаемых файлов, продолжение ниже***
 
50.png


Ниже вы можете увидеть цепные исправления, разобранные с помощью команды dyld_info:
51.png

Пример изменений

С момента введения Chained Fixups, ленивые связывания больше не используются.

Экспортированные символы

Следующая команда загрузки LC_DYLD_EXPORTS_TRIE используется для указания структуры данных trie, которая содержит список экспортированных символов.

Экспортируемые символы ссылаются на linkedit_data_command, которая содержит смещение первого узла, также как и в цепных исправлениях.
52.png


53.png

Пример LC_DYLD_EXPORTS_TRIE

Полная структура помечена фиолетовым:
54.png

Таблица ниже показывает, как разбирается вышеупомянутая структура trie:
55.png

  • Структура trie начинается с Root, который хранит число дочерних узлов (CHILD NUMBER), данные, завершающиеся байтом 0x00, и смещение дочерних узлов (CHILD OFFSET).
  • Если SIZE == 0, то DATA является частью имени символа.
  • Если SIZE > 0, то узел является терминальным (+28, +2C, +57, +5D).
  • Полное имя символа можно получить, обходя структуру trie и объединяя узлы.
  • Терминальный узел похож на нулевой байт для строки, но при этом он может иметь дочерние узлы (когда одно имя символа является частью имени другого).
56.png

Структура trie, представленная в иерархическом графе

Используйте dyld_info для разбора структуры экспортируемых символов.
57.png

Экспортируемые символы - это символы, которые могут быть связаны без ошибок и доступны глобально. Они являются символами, на которые можно ссылаться в заголовочных файлах на языке C.


Символы

LC_SYMTAB загружает таблицу символов и строк, используемых отладчиками, а также статическими и динамическими компоновщиками. Он описывается структурой symtab_command:
58.png

Она предоставляет расположение таблицы символов и строк для динамической компоновки:
59.png

Таблица строк хранит имена символов в виде строк, завершаемых нулевым символом. Записи в таблице символов ссылаются на эти строки:
60.png

Таблица символов содержит записи, которые отображают имена символов на соответствующие адреса памяти или смещения внутри файла.

Таблица символов представляет собой список nlist, определенный структурой nlist_64:
61.png

ntype определяет тип символа:
62.png

63.png

  • Исходя из указанного выше, поле n_type может содержать несколько значений N_TYPE:
64.png

Формат значений поля n_type и N_TYPE.​
Поле n_desc представляет собой двухбайтное описание символа и может принимать следующие значения:
  • REFERENCE_TYPE — описывает, является ли неопределенный символ ленивым или нет:
65.png

  • REFERENCED_DYNAMICALLY — символы, на которые ссылаются динамически загружаемые общие библиотеки или пакеты с такой меткой, не будут удалены:
66.png

  • N_NO_DEAD_STRIP — появляется только в реляционных (relocatable) файловых объектах (типа MH_OBJECT .o) и указывает статическому редактору связей не удалять символ:
  • N_DESC_DISCARDED — никогда не появляется в связанном образе, используется в редких случаях динамическим редактором связей для пометки символа в памяти как отброшенного:
67.png

  • N_WEAK_REF — неопределенный символ может отсутствовать (адрес 0):
68.png

  • N_WEAK_DEF — определяет слабый символ, который может быть переопределен или заменен неслабым (сильным) символом, если оба существуют в программе.
Поддерживается только для символов в секциях кода или данных, которые могут быть объединены в одну секцию в процессе связывания — секции слияния (coalesced sections).
  • N_REF_TO_WEAK — неопределенный, слабый символ, который должен быть разрешен с использованием поиска в плоском пространстве имен (без строгой иерархии).
69.png

Плоский поиск в пространстве имен подходит для сценариев, где используются опциональные, слабые символы, и их присутствие или отсутствие не вызывает ошибок во время связывания.
  • LIBRARY_ORDINAL — применяется только к бинарным файлам с флагом MH_TWOLEVEL в заголовке. Это индекс библиотеки, где определен символ:
70.png

По умолчанию в связывателе включено двухуровневое пространство имен. Первый уровень — это имя библиотеки, а второй — имя символа, который она содержит.
  • Исходя из вышеуказанного, поле n_desc может иметь следующие значения:
71.png

Визуализация формата n_desk
Вы можете просмотреть сочетания таблицы символов и таблицы строк во вкладке Symbols в программе MachOView:​
72.png

Динамическая таблица символов

LC_DYSYMTAB дополняет LC_SYMTAB для улучшения организации символов с большей точностью. Если существует LC_DYSYMTAB, то обязательно должен существовать и LC_SYMTAB.

Он описывается структурой dysymtab_command и предоставляет информацию о динамической таблице символов, используемой Dynamic Linker-ом:
73.png

  • Локальные символы — используются для отладки и связаны с конкретным модулем.
  • Внешне определённые символы — определены в других модулях или библиотеках.
  • Неопределённые символы — упоминаются в бинарном файле, но не определены в нём. Они должны быть разрешены во время динамической линковки.
  • Косвенные/непрямые символы — разрешают ссылки на символы, предоставляя индексы в таблице символов.
После введения цепных исправлений, я не могу найти в данных LC_DYSYMTAB следующую информацию:
  • Таблица содержимого (ToC) — отображает определенные внешние символы на модули, где они определены.
  • Таблица модулей — ассоциирует модули с их соответствующими таблицами символов и другой информацией.
  • Таблица ссылок на символы — указывает внешние ссылки, сделанные каждым модулем.
  • Внешние релокации — используются для корректировки адресов при загрузке кода или данных по разным адресам во время выполнения.
  • Локальные релокации — используются для перераспределения кода и данных в пределах одного модуля.
74.png

Динамическая таблица символов предоставляет данные о том, где можно найти определённый тип символа и сколько их существует. Она также хранит информацию о косвенных символах:
75.png

Запись в таблице косвенных символов представляет собой 32-битное значение, которое служит индексом в таблице символов. Этот индекс указывает на указатель символа или заглушку в соответствующем бинарном файле.
76.png



DYNAMIC LINKER И ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ

LC_LOAD_DYLINKER указывает путь Dynamic Linker-а, который XNU использует для выполнения бинарного файла. Он описывается структурой dylinker_command:
77.png

78.png

Такая же структура используется для LC_ID_DYLINKER, которая идентифицирует Mach-O как Dynamic Linker, а также для LC_DYLD_ENVIRONMENT, которая используется для переменных окружения, встроенных в файл Mach-O:
79.png

80.png

Пример команды LC_ID_DYLINKER в dyl​
Подробнее об идентификаторах и окружении описано в статье о динамических библиотеках (Dylibs).
UUID

Команда LC_UUID указывает 128-битный универсальный уникальный идентификатор (UUID) файла и описывается структурой данных uuid_command:
81.png

82.png

Вы можете создать такой UUID, используя команду uuidgen:
83.png

Они используются в различных местах macOS, например, Gatekeeper отслеживает приложения в карантине по их UUID. Подробнее о UUID можно прочитать здесь.

BUILD VERSION

Команда LC_BUILD_VERSION указывает минимальную версию ОС и платформу, для которой был создан бинарный файл. Она описывается структурой build_version_command:
84.png

Список инструментов (build_tool_version) следует за структурой build_version_command.
85.png


Source Version

Команда LC_SOURCE_VERSION указывает версию исходных кодов, использованных для создания бинарного файла. Она описывается структурой source_version_command:
86.png

Поле версии представляет собой 64-битное целое число в упакованном формате, используемом для представления номеров версий следующим образом:
87.png

Это полезно для отслеживания версий и идентификации версий исходного кода.
88.png



Entry Point

Команда LC_MAIN указывает местоположение (сдвиг в файле) функции main() и описывается структурой entry_point_command:
89.png

Во время загрузки, dyld добавляет значение смещения входа (Entry Offset) к базовому адресу бинарного файла и выполняет код бинарного файла, переходя к точке входа (Entry Point):
90.png

Пример entry_point_command
Точка входа по умолчанию - функция main(), однако её можно изменить.
Динамические библиотеки

Несколько загрузочных команд предоставляют dyld информацию о динамических библиотеках, и все они используют структуру dylib_command:

91.png

92.png

Динамические библиотеки загружаются и используются для разрешения символов во время выполнения. Я напишу об этом подробнее в статье «Змей и Яблоко. Часть 4. Dylibs.».

Адреса функций

Команда LC_FUNCTION_STARTS представляет собой таблицу адресов начала функций. Она описывается структурой linkedit_data_command:
93.png

94.png

Имена функций являются отладочной информацией и не отображаются в выпускаемых сборках для защиты от обратной разработки и сокращения размера приложения:
95.png


DATA_IN_CODE

Команда DATA_IN_CODE указывает смещение и размер сегмента, который записывает местоположения определённых данных, встроенных в сегмент __TEXT.

Загрузочная команда использует общую структуру linkedit_data_command, и каждая запись данных имеет формат, описанный в структуре data_in_code_entry:
96.png

Это редко используемая функция, которая облегчает обратную разработку.

LC_CODE_SIGNATURE

Указывает сдвиг и размер подписи кода.
Описано в Змей и Яблоко. Часть 2. Подпись кода.

Разбор файла Mach-O с помощью Python

Я решил не копировать всю программу сюда, так как она доступна в репозитории с подробными комментариями. Я сосредоточусь на основах, сложных моментах и использовании инструмента CrimsonUroboros.

Библиотека Lief предоставляет классы для работы с файлами Mach-O.
Python:
pip install lief

РАЗБОР ФАЙЛА

Для разбора Mach-O с использованием Python и Lief требуется выполнить три начальных шага:
  • Импортировать библиотеку Lief.
  • Указать путь к файлу Mach-O для открытия.
  • Разобрать файл Mach-O как универсальный бинар (Fat Binary).
Python:
import lief

file_path = './binary'
binaries = lief.MachO.parse(file_path)
Для возврата списка объектов lief.MachO.binary вместо одного используется функция lief.MachO.parse вместо функции lief.parse.

ЗАГОЛОВКИ

Извлечение заголовка из объекта Mach-O:
Python:
header = binaries[0].header
  • Работа с универсальным бинарным файлом для извлечения объекта ARM64:
97.png

Python:
for binary in binaries:
    if binary.header.cpu_type == lief.MachO.CPU_TYPES.ARM64:
        return binary
98.png


ТИП ФАЙЛА

Проверка, является ли тип бинарного файла исполняемым:
Python:
binary.header.file_type == lief.MachO.FILE_TYPES.EXECUTE
99.png

  • Для поиска подлинных Mach-O файлов используйте MachoFileFinder:
***Достигнуто максимальное количество загружаемых файлов, продолжение ниже***
 
100.png


ПОРЯДОК БАЙТОВ

Сравнивание порядка байтов системы с magic байтами бинарного файла:
Python:
magic = arm64_bin.header.magic.name
endianness = sys.byteorder
if endianness == 'little' and magic == 'MAGIC_64':
    print 'litte'
else:
    print 'big'
101.png

ФЛАГИ ЗАГОЛОВКА

Извлечь флаги заголовка в виде списка:
Python:
binary.header.flags_list
102.png


КОМАНДЫ ЗАПУСКА

Извлечь команды запуска:
Python:
for cmd in binary.commands:
    print(cmd)
103.png


СЕГМЕНТЫ

Извлечь сегменты:
Python:
for segment in binary.segments:
    print(segment)
104.png


СЕКЦИИ

Извлечь секции:
Python:
for section in binary.sections:
    print(section)
105.png


ЦЕПНЫЕ ИСПРАВЛЕНИЯ

Извлечение информации о цепных привязках:
Python:
binary.dyld_chained_fixups
106.png


Exports Trie

Извлечение Exports Trie:
Python:
binary.dyld_exports_trie.show_export_trie()
107.png


СИМВОЛЫ

Извлечение символов:
Python:
for symbol in binary.symbols:
    print(symbol)
108.png


СТРОКИ

Извлечение строк из таблицы строк (CSTRING_LITERALS):
Python:
for section in binary.sections:
    if section.type == lief.MachO.SECTION_TYPES.CSTRING_LITERALS:
        extracted_strings.update(section.content.tobytes().split(b'\x00'))
109.png

  • Для извлечения строк из всех секций:
Python:
byte_set = set()
for section in binary.sections:
    byte_set.update(section.content.tobytes().split(b'\x00'))

for byte_item in byte_set:
    try:
        ascii_string = byte_item.decode('utf-8')
        print(ascii_string)
    except UnicodeDecodeError:
        pass

UUID

Python:
for cmd in binary.commands:
    if isinstance(cmd, lief.MachO.UUIDCommand):
        uuid_bytes = cmd.uuid
        break

uuid_string = str(uuid.UUID(bytes=bytes(uuid_bytes)))
print(uuid_string)
110.png


MAIN

Определение точки входа исполняемого файла:
Python:
binary.main_command
111.png


ЗАКЛЮЧЕНИЕ

Программы, созданные в результате этой статьи (CrimsonUroboros.py и MachOFileFinder.py), можно найти в репозитории Snake-Apple I. Mach-O. Я планирую добавить дополнительные функции по мере разработки проекта.
112.png

Текущая версия CrimsonUroboros
Это только начало, несколько простых вещей, чтобы познакомиться с библиотекой Lief и форматом Mach-O.

Если вам понравилась статья, поделитесь ею. Если у вас есть предложения, напишите их в комментариях.

В следующей статье будут рассмотрены механизмы подписи кода, которые предотвращают несанкционированное выполнение кода с помощью надежного программного обеспечения.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх