О чем статья?
Рассказываем, как анализировать вредоносное ПО на macOS. Начнем с настройки тестового окружения, погрузимся в особенности ОС, а затем столкнемся с темной магией злоумышленников и разберем ее на ингредиенты.
Отправляемся на платформу 9¾, или Как настроить окружение
Прежде всего нам понадобится тестовое окружение для исследования ОС и анализа ВПО. Так сложилось, что, когда я начинал свой путь в роли исследователя безопасности приложений macOS, у меня был только компьютер с Windows и x86 процессором. К счастью, есть проверенное решение — средство виртуализации VMware Workstation.
Запускаем, начинаем создавать виртуалку и… сталкиваемся с тем, что в списке гостевых ОС нельзя выбрать macOS. Чтобы такая возможность появилась, можно воспользоваться сторонней утилитой Unlocker, которая легко находится в поиске. «Зря я это сказал…» :)

Теперь нужно где-то раздобыть установочный образ ОС. Можно, конечно, просто скачать один из множества представленных в интернете ISO-образ, но никогда не знаешь, кто в них покопался. Лучше возьмем оригинальный образ с серверов Apple.
Для этого существуют различные скрипты, к примеру, можно воспользоваться вот этим репозиторием. Забираем последний релиз, переходим в каталог \Utilities\macrecovery\, запускаем Python-скрипт macrecovery.py и следуем инструкциям. Пример запуска:
$ python3 macrecovery.py -b Mac-937A206F2EE63C01 -m 00000000000000000 download
После скачивания файла в системе появится каталог \com.apple.recovery.boot\ с образом BaseSystem.dmg. Его нужно сконвертировать в VMDK для VMware Workstation. В этом нам поможет утилита qemu-img и следующая команда:
$ qemu-img convert -O vmdk -o compat6 BaseSystem.dmg recovery.vmdk
Полученный после конвертации файл recovery.vmdk подключаем в качестве жесткого диска к виртуальной машине с macOS и завершаем установку.

Важная ремарка: в 2020 г. Apple перешла на собственные ARM-процессоры, соответственно, все свежие версии ОС разрабатываются под эту архитектуру. Эпоха Intel и x86 закончилась на macOS Catalina (10.15): начиная с macOS Big Sur (11) новые версии выходят только под ARM.
Это нужно иметь в виду, потому что виртуализация новых версий macOS на x86-процессоре будет работать медленно. Можно попробовать установить вторую виртуальную машину с macOS Catalina, но здесь поджидает другая проблема: не все современное ПО, в том числе вредоносное, имеет обратную совместимость, поэтому может попросту не запуститься.
Теперь переходим к компьютерам Apple. «Я почему раньше злой был? Потому что у меня макбука не было…» И правда, в этом случае окружение настраивается гораздо проще. Можно воспользоваться платным решением Parallels или же бесплатным UTM (на базе QEMU). Прелесть в том, что в них прямо из коробки есть функциональность для скачивания образов ОС в нужном формате.

Следующий шаг — необязательный, при необходимости к нему можно вернуться позже. Но раз уж заговорили о настройке окружения, сразу расскажу и о том, как получить больше контроля в гостевой среде, а именно об отключении SIP.
SIP (System Integrity Protection) — это один из встроенных в macOS механизмов безопасности, который контролирует доступ к критически важным компонентам системы и разрешает только чтение (в том числе для root-пользователя). В частности, речь идет о каталогах и подкаталогах /System, /usr, /bin, /sbin, var, а также предустановленных по умолчанию приложениях. Кроме того, SIP:
• контролирует доступ к подсистеме Endpoint Security;
• запрещает отладку и трассировку исполняемых системных файлов;
• проверяет подпись расширений ядра;
• контролирует целостность системного раздела (SSV).
Чтобы узнать, какие файлы защищает SIP, вводим в консоль следующую команду:
$ cat /System/Library/Sandbox/rootless.conf
/Applications/Safari.app
/Library/Apple
CoreAnalytics /Library/CoreAnalytics
…
/sbin
/usr
* /usr/libexec/cups
* /usr/local
* /usr/share/man
* /usr/share/snmp
/etc
/var
Для отключения SIP нужно загрузиться в режиме Recovery, открыть консоль и ввести команду csrutil disable, а затем перезагрузить ОС в обычном режиме.
Магия вне архитектуры процессора: как запускаются Intel-сборки ПО на Apple Silicon
В октябре 2020 г. появились компьютеры с процессорами Apple Silicon и архитектурой ARM. При переходе на новую архитектуру возникла проблема с совместимостью приложений: все, что было создано под Intel, перестало работать. Для решения этой задачи Apple предлагает использовать технологию Rosetta 2, которая позволяет транслировать код из x86 в arm. Возникает вопрос: что тогда такое Rosetta 1? Дело в том, что Apple уже меняла архитектуру процеcсора в 2006 году: Rosetta 1 транслировала код из PowerPC в x86.
Как все это работает? Основные сервисы расположены в каталоге /usr/libexec/rosetta.

При запуске программы, написанной под x86, в дело вступает oahd-демон. Он проверяет, не производилась ли трансляция кода ранее. Для этого демон сканирует каталог /var/db/oah/*/*/ на наличие файла с расширением .aot, в котором должны содержаться результаты трансляции кода. Если такого файла нет, начнется процесс трансляции и его создания. К слову, .aot — это аббревиатура Ahead-Of-Time, которая означает, что трансляция выполняется до фактического запуска потока выполнения.

Папки и файлы в каталоге /var/db/oah защищены SIP, поэтому без его отключения нельзя получить доступ к содержимому.
После того как файл .aot был найден или создан, он попадает в виртуальную память исходного процесса. Далее управление передается в эту секцию, и начинается выполнение кода программы.
Фантастические твари и где они обитают: форматы файлов и базовые инструменты
Предположим, у нас есть некий файл без расширения с неочевидным именем. Нужно его проанализировать и выдать вердикт: вредонос это или нет.
Для начала необходимо определить тип файла — от этого будет зависеть дальнейший выбор инструментов. Задачу можно решить с помощью встроенной утилиты командной строки file (к слову, этот способ подходит и для Linux):
$ file VT_applet/0107f1667048a08ca5fd79e7139f7df5ca9cfbc6085208582011421a1c91156a
VT_applet/0107f1667048a08ca5fd79e7139f7df5ca9cfbc6085208582011421a1c91156a: Mach-O 64-bit executable x86_64
Итак, в macOS есть несколько основных типов файлов:
- образы дисков Apple Disk Images (.dmg);
- установочные пакеты (.pkg);
- различные скрипты: python (.py), shell (.sh), AppleScript (.scpt);
- application bundle, или пакет приложения (.app);
- исполняемый файл Mach-O.
Остановимся на каждом из них подробнее.
Образы дисков Apple Disk Images (.dmg)
Начнем с простого — образа macOS, который мы скачали ранее. Вводим в file следующую команду:
$ file /Utilities/macrecovery/com.apple.recovery.boot/BaseSystem.dmg
И получаем ответ:
Utilities/macrecovery/com.apple.recovery.boot/BaseSystem.dmg: zlib compressed data
Как видно из вывода утилиты, перед нами просто сжатые данные. На Windows содержимое образа можно посмотреть с помощью 7-zip (см. рис. 6).

В macOS есть встроенная утилита hdiutil, которая позволяет смонтировать образ в текущую файловую систему:
$ hdiutil attach /Utilities/macrecovery/com.apple.recovery.boot/BaseSystem.dmg
В конце вывода команды будет указан путь (/Volumes/macOS Base System), по которому можно найти смонтированный образ. Кстати, каталог /Volumes/ скрыт: чтобы отобразить его в Finder, нужно нажать Command + Shift +.

Установочные пакеты (.pkg)
Все установочные пакеты в macOS имеют расширение .pkg — в противном случае ОС не интерпретирует файл как установочный. В качестве примера рассмотрим fake.pkg.
$ file fake.pkg
fake.pkg: xar archive compressed TOC: 760, SHA-1 checksum, contains zlib compressed data
Файл имеет формат XAR (Extensible Archive Format) и обладает следующей структурой:
- header,
- TOC (table of content),
- heap.
Структура заголовка header представлена ниже:
struct xar_header {
uint32_t magic;
uint16_t size;
uint16_t version;
uint64_t toc_length_compressed;
uint64_t toc_length_uncompressed;
uint32_t cksum_alg;
};
На рис. 8 представлен пример заголовка и TOC, сжатого с помощью zlib.

TOC (оглавление) — это XML-документ, который содержит информацию о файлах в архиве. Формат XAR позволяет независимо сжимать и кодировать отдельные файлы. При этом можно использовать разные варианты сжатия, например GZIP, BZIP2. Содержимое TOC выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<xar>
<toc>
<creation-time>2023-07-13T09:10:41</creation-time>
<checksum style="sha1">
<offset>0</offset>
<size>20</size>
</checksum>
<file id="2">
<data>
<length>266</length>
<offset>350</offset>
<size>499</size>
<encoding style="application/x-gzip"/>
<extracted-checksum style="sha1">94e1d1dc91eadb1aaa6d7f4a4a9fe5d41af04489</extracted-checksum>
<archived-checksum style="sha1">3ec9b31d4b25a4e2a519a6ba7fd49528d0a86bcb</archived-checksum>
</data>
<type>file</type>
<name>PackageInfo</name>
</file>
…
</toc>
</xar>
Наконец, Heap — это неструктурированный тип данных, в котором хранятся файлы и на который ссылается TOC.
Подсвечу интересные ноды в TOC:
- xar.toc.file.name == Scripts. Сжатый поток байтов, содержащий скрипты preinstall и postinstall в формате CPIO (Copy Input/Output).
- xar.toc.file.name == Distribution. Сжатый поток байтов, содержащий файл в формате XML. Может содержать скрипт для проверки окружения.
- xar.toc.file.name == Plugins. Вспомогательное ПО, которое вызывается в процессе установки.
- xar.toc.file.name == Payload. Сжатый поток байтов, содержащий основную нагрузку для установки в ОС.
На рис. 9 представлен пример легитимного скрипта в файле Distribution. Скрипт проверяет требования ОС для установки ПО.

А вот на рис. 10 представлен фрагмент подозрительного скрипта. В процессе его выполнения происходит закрепление в системе и скачивание некого файла через утилиту curl.

Аналогично служебные скрипты preinstall и postinstall отвечают за подготовку системы перед установкой и очистку временных файлов после нее, но часто применяются злоумышленниками для выполнения вредоносного кода.
Чтобы извлечь содержимое установочного пакета для дальнейшего анализа, можно воспользоваться встроенной утилитой командной строки pkgutil:
$ pkgutil --expand fake.pkg out
Кроме того, можно просмотреть содержимое установочного пакета с помощью Suspicious Package (отдельного ПО с GUI).


Скрипты: python (*.py), shell (*.sh), AppleScript (*.scpt)
Сегодня остановимся на AppleScript. Это разработанный Apple и встроенный в macOS язык сценариев, который используется на компьютерах корпорации с 1991 г. Одна из ключевых особенностей AppleScript заключается в том, что написанные на нем скрипты читаются как обычный английский текст (также они могут называться OSAScript — Open Scripting Architecture).
Скрипты позволяют управлять приложениями с поддержкой сценариев, а также компонентами самой macOS. Важное условие: приложения должны поддерживать межпрограммное взаимодействие, т. е. воспринимать и реагировать на AppleEvent-сообщения. Они отправляются, когда команда скрипта взаимодействует с приложением: например, когда сценарий tell application 'Finder' get disks запрашивает у файлового менеджера Finder имена примонтированных дисков.
Каждое приложение, понимающее AppleScript, публикует поддерживаемые команды в специальном словаре. Он представляет собой XML-файл с расширением .sdef (scripting difinition) и хранится в отдельной папке среди ресурсов пакета.
Каждая часть информации в AppleEvent связана с четырехзначным кодом, иногда даже с двумя. При этом файлы с определениями кодов разбросаны по всей системе. Приведу несколько примеров:
///AERegistry.h
enum {
cApplication = 'capp', /* 0x63617070 */
cArc = 'carc', /* 0x63617263 */
cBoolean = 'bool', /* 0x626f6f6c */
cCell = 'ccel', /* 0x6363656c */
cChar = 'cha ', /* 0x63686120 */
cDocument = 'docu', /* 0x646f6375 */
cGraphicLine = 'glin', /* 0x676c696e */
...
};
Сценарии можно компилировать и сохранять в файл для последующего запуска. Именно со скомпилированными скриптами и сталкивается вирусный аналитик. Однако стоит отметить, что такие скрипты можно «завернуть» еще и в Application Bundle — тогда они будут выглядеть как обычное приложение (но об этом чуть позже).
Скомпилированные скрипты имеют расширение *.scpt и две магических константы: строку FasdUAS в начале файла и байты \xFA\xDE\xDE\xAD в самом конце. Помимо этого, в них есть строка с версией скрипта (длиной 8 байт).
При сохранении сценария по умолчанию конечный файл будет содержать две формы его представления:
- Сериализованный формат — с сохранением связей и вложенности AppleEvent-кодов.
- Скомпилированный байт-код и список AppleEvent-кодов без сохранения взаимосвязей между ними (связь задается в байт-коде).
Такие файлы можно снова открыть в редакторе сценариев: в результате произойдет декомпиляция на основе п. 1 и вы увидите исходный текст сценария на английском языке. В то же время при сохранении в файл можно выставить флаг RunOnly: в этом случае итоговый файл будет содержать только часть п. 2.
Рассмотрим скрипт, который создает на рабочем столе папку с названием JackDaniels:
tell application "Finder"
make new folder at desktop with properties {name:"JackDaniels"}
end tell
В терминах AppleEvent-кодов сценарий будет выглядеть следующим образом:
core,crel target='psn '[Finder] { //crel ~ kAECreateElement
kocl=cfol, //new folder
insh={ //at
form=prop,
want=prop,
seld=desk, //desktop
from=null
},
prdt={ //with properties
pnam=utxt(22/$4a00610063006b00440061006e00690065006c007300) //JackDaniels
}
}
Если вы откроете файл в hex-редакторе, то увидите все эти core, crel, desk и JackDaniels (см. приложение).
Какой бы вариант сохранения сценария в файл вы ни выбрали, выполнение сценария будет происходить на основе байт-кода виртуальной машины, которая реализована в модуле /System/Library/PrivateFrameworks/AppleScript.framework/Versions/A/AppleScript в функции UASExecute1.



Для анализа подобных файлов можно использовать два инструмента:
В первом реализована часть функций из /System/Library/PrivateFrameworks/AppleScript.framework/Versions/A/AppleScript (а именно считывание скомпилированных файлов, парсинг и дизассемблирование байт-кода виртуальной машины). Во втором есть человекочитаемое описание четырехсимвольных кодов из некоторых словарей в системе (запускается только на macOS, потому что инструмент сначала проводит поиск словарей в системе).
Application bundle, или пакет приложения (.app)
Это каталог со стандартизированной структурой, который содержит исполняемый код и ресурсы, используемые этим кодом. Внутри application bundle есть подраздел Contents, в котором как минимум должны находиться следующие файлы:
- MacOS/<Executable>: исполняемый файл или скрипт.
- Info.plist: файл-манифест для приложения. В нем задается имя исполняемого файла, который запускается при старте приложения, а также различные требования (например, минимальная версия ОС или запрос на права доступа к микрофону и камере).
В качестве примера рассмотрим содержимое application bundle для Telegram (см. рис. 16).

Фрагмент Info.plist представлен ниже:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>23G93</string>
<key>CFBundleExecutable</key>
<string>Telegram</string>
<key>CFBundleGetInfoString</key>
<string>Telegram Desktop messaging app</string>
…
<key>CFBundleVersion</key>
<string>5.9.0</string>
…
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
…
<key>NSCameraUsageDescription</key>
<string>We need access to your camera so that you can record video messages and make video calls.</string>
…
Application Bundle также может содержать необязательные файлы. Приведу несколько примеров:
- Resources/. Вспомогательные файлы: например, иконка, шрифты, локализации строк.
- Plugins/. Небольшие исполняемые файлы, расширяющие функционал основного.
- Frameworks/. Плагины и высокоуровневые фреймворки, необходимые приложению (модули зависимостей).
- _CodeSignature/CodeResources. XML-файл, содержащий сигнатуры для файлов в application bundle.
Вернемся к поднятому выше вопросу «завертывания» скомпилированных файлов в application bundle. Для этого в ОС хранится заготовка скомпилированного исполняемого файла:
/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/OpenScripting.framework/Versions/A/Resources/AppletStub.
При «заворачивании» AppletStub переименовывается в applet. Сама заготовка содержит вызовы нескольких API-функций, которые подгружает и запускает скомпилированный скрипт:
OpenDefaultComponent('aplt', 'scpt')
CallComponentDispatch(…);
Cкомпилированный скрипт должен располагаться в application bundle в папке Scripts и называться main.scpt.

Mach-O
В macOS есть свой формат исполняемых файлов — Mach-O. Такие файлы состоят из трех частей: заголовка (mach_header), команд загрузки (load_commands) и набора сегментов (segments).
- Заголовок содержит магические байты, информацию об архитектуре процессора, для которого скомпилирован файл, типе файла (динамическая библиотека, исполняемый и т. д.) и другие метаданные.
- Команды загрузки содержат информацию, которую динамический загрузчик использует для отображения двоичного файла в памяти. Здесь указаны адрес точки входа (LC_MAIN) для исполняемого файла, динамические зависимости (LC_LOAD_DYLIB) и др.
- За командами загрузки следует оставшаяся часть двоичного файла Mach O: в основном она состоит из байт-кода, переменных и т. д.
Первичную информацию об исполняемом файле можно получить прямо в консоли с помощью встроенных утилит:
- $ otool -L <input> — покажет, какие библиотеки находятся в зависимостях у исполняемого файла.
- $ otool -oV <input> — позволяет узнать, какие методы есть у исполняемого файла.
- $ otool -tV <input> — позволяет дизассемблировать код.
Исполняемый файл Mach-O содержит код только для одной архитектуры процессора. Поэтому приложения часто распространяются в виде бинарных файлов Universal Binary или Fat Binary, которые содержат несколько Mach-O для разных архитектур. В этом случае бинарный файл начинается с fat_header, а его тело содержит несколько склеенных Mach-O. Загрузчик Mach-O выбирает двоичный файл с подходящей архитектурой и загружает его в память для запуска программы.
Отмечу, что файл Fat Binary можно усечь и оставить только нужную архитектуру:
$ lipo <input> -thin x86_64 -output <output>
Важной частью исполняемого файла является подпись. Она позволяет установить авторство и убедиться в целостности файла, но не гарантирует, что это не вредонос. Чтобы посмотреть подпись, нужно ввести следующую команду (чем больше символов v, тем подробнее будет вывод):
$ codesign -dv /Applications/Telegram.app
Executable=/Applications/Telegram.app/Contents/MacOS/Telegram
Identifier=com.tdesktop.Telegram
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20500 size=1361249 flags=0x10000(runtime) hashes=42528+7 location=embedded
Signature size=8980
Timestamp=4 Dec 2024 at 15:25:31
Info.plist entries=32
TeamIdentifier=C67CF9S4VU
Runtime Version=15.1.0
Sealed Resources version=2 rules=13 files=15
Internal requirements count=1 size=184
Вместе с подписью хранятся Entitlements приложения — пары «ключ:значение», которые дают исполняемым файлам разрешения использовать тот или иной сервис либо технологию. Например, com.apple.security.get-task-allow разрешает подключаться к процессу отладчиком. Тем не менее приложение может запрашивать и другие права, не указанные в Entitlements.
Чтобы посмотреть набор прав, используйте команду: $ codesign -d --entitlements - <input>
Внимание к деталям: разбираемся с соглашениями о вызовах x86_64 и arm64
Говоря о реверсе, нельзя не упомянуть соглашения о вызовах. Они определяют, каким образом аргументы передаются в функцию, как возвращается результат и какая функция отвечает за очистку стека. Эти правила сформулированы в двоичном интерфейсе приложения — Application Binary Interface (ABI).
Аргумент | Регистр |
---|---|
1-й аргумент | rdi |
2-ой аргумент | rsi |
3-ий аргумент | rdx |
4-ый аргумент | rcx |
5-ый аргумент | r8 |
6-ой аргумент | r9 |
7-ой аргумент | стек |
Возвращаемое значение | rax |
Аргумент | Регистр |
---|---|
C 1-го по 8-ой аргумент | x0 – x7 |
9-ый аргумент и далее | стек |
Возвращаемое значение | x0 |
Скажите, почему когда что-то происходит, вы трое всегда оказываетесь рядом?
При обратной разработке бинарного файла чаще всего встречаются семплы, скомпилированные с помощью C/C++, Objective-C и Swift. Конечно, бывают и образцы на Go и Rust, но в их анализе нет ничего особенного (впрочем, как и в случае с C/C++): все как на Windows и Linux. А вот при встрече с сеэмплами, скомпилированным на Objective-C и Swift, сразу возникают непривычные языковые конструкции. Поговорим о них подробнее.
Objective-C
Этот язык часто используется для разработки приложений для macOS и iOS. Рассмотрим пример объявления и инициализации числа:
NSNumber *number = [[NSNumber alloc] initWithInt:1];
Если мы скомпилируем, а затем декомпилируем код, то получим следующий результат:
int v1; int v2;
v1 = objc_msgSend(_OBJC_CLASS_$_NSNUMBER, "alloc");
v2 = objc_msgSend(v1, "initWithInt", 1);
Этот пример демонстрирует основы выделения объектов и вызова методов. Каждый вызов метода выполняется путем вызова функции среды выполнения objc_msgSend:
id objc_msgSend(id self, SEL op, …);
Обязательные аргументы self и op — это указатели на объект класса и так называемый селектор; id — ключевое слово, обозначающее указатель на объект. В свою очередь, селектор представляет понятное для человека название метода: в рамках нашего примера это alloc и initWithInt.
Основная цель функции objc_msgSend — найти реализацию метода для данного объекта и селектора, а затем вызвать его и передать все указанные аргументы. Описанный подход привносит специфический нюанс в процесс реверса: человекочитаемый селектор не может быть обфусцирован для системного API, что помогает быстрее понять исполняемый код.
Названия селекторов содержатся в разделе __objc_methname сегмента __TEXT.
Swift
Язык Swift тоже активно применяется для разработки приложений для macOS и iOS. У него есть три интересные особенности…
Первая: помимо вызова привычных функций вида sub_* при реверсе можно встретить что-то невнятное, а-ля $s7SwiftUI3AppPAAE4mainyyFZ. Это вызов Swift-функции, которая представлена в виде «замангленного» имени (Swift mangled name).
В подобных именах закодирован класс, в котором содержится функция, ее имя, а также типы принимаемых аргументов и возвращаемого значения. Отмечу, что в пакете разработчика Swift есть специальная утилита для декодирования «замангленных» имен: swift-demangle.
Начиная с версии 7.7 (ниже не проверял) IDA умеет раскодировать такие имена прямо из коробки — функция включена по умолчанию. В качестве примера рассмотрим вывод декодированного имени Button.init (см. рис. 18).

Итак, функция принимает два аргумента, но что они означают? Мы помним, что в закодированном имени в том числе содержатся типы принимаемых аргументов. Пора испытать swift-demangle, причем в каждом из трех возможных режимов (см. рис. 19).

Выводы в первых двух режимах практически одинаковы: вероятнее всего, в IDA используется один из них. Из вывода в третьем режиме становится ясно, что функция Button.init первым аргументом принимает LocalizatedString с текстом кнопки, а вторым — action() — функцию, которая обрабатывает нажатие на кнопку. Резюмируем: IDA многое умеет из коробки, но за подробностями лучше обращаться в swift-demangle.
Теперь переходим ко второй особенности Swift — это реализация строк, которые здесь представлены в виде структур:
struct _StringObject
{
var _countAndFlagsBits;
var _object;
};
В зависимости от значений флагов в _countAndFlagsBits (60–63-й биты) в _objects может храниться либо непосредственное значение (для коротких строк), либо адрес.

Если посмотреть на биты с номерами 60–63 в 0xE600000000000000 и интерпретировать их согласно документации, то станет ясно, что перед нами короткая строка, а 'lecnaC' — не что иное, как непосредственное значение "Cancel".
Рассмотрим другой пример (см. рис. 21). Что такое 0xD0000000000000002A и 0x80000000010000AD80? Из документации узнаем, что это длинная строка, а младшие значащие биты первого числа 0x2A — это ее размер. Чтобы получить адрес строки, нужно к 0x10000AD80 прибавить 0x20 (nativeBias тоже из документации). В итоге получаем адрес 0x10000ADA0.


Наконец, третья особенность: в коде Swift можно вызывать методы из Objective-C. Для этого нужно сконвертировать данные из одного представления в другое. Например, Swift-строку из struct _StringObject в объект класса NSString в Objective-C. Для этого используются методы с названием class.bridgeToObjectiveC() и class.bridgeFromObjectiveC(). В контексте реверса достаточно понимать, что это обычная конвертация данных.

***
Сегодня мы разобрались, как настроить тестовую среду для исследования вредоносных программ, как использовать статический анализ для реверса двоичных файлов, а также рассмотрели несколько распространенных форматов файлов и инструменты их анализа. Продолжение — в будущих статьях ;)
Если это ваш первый опыт реверс-инжиниринга ВПО для macOS, также рекомендую две полезные ссылки:
Приложение
Hexdump-представление скомпилированного osascript
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 46 61 73 64 55 41 53 20 31 2E 31 30 31 2E 31 30 FasdUAS 1.101.10
00000010 0E 00 00 00 04 0F FF FF 00 01 00 02 00 03 01 FF ......яя.......я
00000020 FF 00 00 0D 00 01 00 03 6C 00 02 00 00 00 15 00 я.......l.......
00000030 04 FF FE FF FD 0D 00 04 00 02 4F 00 00 00 00 00 .яюяэ.....O.....
00000040 15 00 05 00 06 0D 00 05 00 03 49 00 02 00 04 00 ..........I.....
00000050 14 FF FC FF FB 00 07 0A FF FC 00 18 2E 63 6F 72 .яьяы...яь...cor
00000060 65 63 72 65 6C 2A 2A 2A 2A 00 00 00 00 00 00 90 ecrel****......ђ
00000070 00 6E 75 6C 6C 01 FF FB 00 00 06 00 07 00 03 FF .null.яы.......я
00000080 FA 00 08 00 09 0A FF FA 00 04 0A 6B 6F 63 6C 0D ъ.....яъ...kocl.
00000090 00 08 00 01 6D 00 00 00 06 00 07 FF F9 0A FF F9 ....m......ящ.ящ
000000A0 00 04 0A 63 66 6F 6C 06 00 09 00 03 FF F8 00 0A ...cfol.....яш..
000000B0 00 0B 0A FF F8 00 04 0A 69 6E 73 68 0D 00 0A 00 ...яш...insh....
000000C0 01 31 00 00 00 08 00 0B FF F7 0A FF F7 00 04 0A .1......яч.яч...
000000D0 64 65 73 6B 06 00 0B 00 03 FF F6 00 0C FF F5 0A desk.....яц..ях.
000000E0 FF F6 00 04 0A 70 72 64 74 0D 00 0C 00 01 4B 00 яц...prdt.....K.
000000F0 00 00 0C 00 10 00 0D 06 00 0D 00 03 FF F4 00 0E ............яф..
00000100 FF F3 0A FF F4 00 04 0A 70 6E 61 6D 0D 00 0E 00 яу.яф...pnam....
00000110 01 6D 00 00 00 0D 00 0E 00 0F 0E 00 0F 00 01 B1 .m.............±
00000120 00 10 11 00 10 00 16 00 4A 00 61 00 63 00 6B 00 ........J.a.c.k.
00000130 44 00 61 00 6E 00 69 00 65 00 6C 00 73 06 FF F3 D.a.n.i.e.l.s.яу
00000140 00 00 06 FF F5 00 00 0D 00 06 00 01 6D 00 00 00 ...ях.......m...
00000150 00 00 01 00 11 0F 00 11 01 8C 08 00 00 00 00 00 .........Њ......
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001A0 00 00 00 00 00 00 00 00 00 00 00 00 00 4D 41 43 .............MAC
000001B0 53 00 02 01 00 61 6C 69 73 00 00 00 00 01 2E 00 S....alis.......
000001C0 02 00 01 03 4D 61 63 00 00 00 00 00 00 00 00 00 ....Mac.........
000001D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
000001E0 00 00 00 42 44 00 01 FF FF FF FF 0A 46 69 6E 64 ...BD..яяяя.Find
000001F0 65 72 2E 61 70 70 00 00 00 00 00 00 00 00 00 00 er.app..........
00000200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000220 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF 00 ...........яяяя.
00000230 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF 00 ...........яяяя.
00000240 00 0A 20 63 75 00 00 00 00 00 00 00 00 00 00 00 .. cu...........
00000250 00 00 0C 43 6F 72 65 53 65 72 76 69 63 65 73 00 ...CoreServices.
00000260 02 00 29 2F 3A 53 79 73 74 65 6D 3A 4C 69 62 72 ..)/:System:Libr
00000270 61 72 79 3A 43 6F 72 65 53 65 72 76 69 63 65 73 ary:CoreServices
00000280 3A 46 69 6E 64 65 72 2E 61 70 70 2F 00 00 0E 00 :Finder.app/....
00000290 16 00 0A 00 46 00 69 00 6E 00 64 00 65 00 72 00 ....F.i.n.d.e.r.
000002A0 2E 00 61 00 70 00 70 00 0F 00 08 00 03 00 4D 00 ..a.p.p.......M.
000002B0 61 00 63 00 12 00 26 53 79 73 74 65 6D 2F 4C 69 a.c...&System/Li
000002C0 62 72 61 72 79 2F 43 6F 72 65 53 65 72 76 69 63 brary/CoreServic
000002D0 65 73 2F 46 69 6E 64 65 72 2E 61 70 70 00 13 00 es/Finder.app...
000002E0 01 2F 00 FF FF 00 00 01 FF FE 00 00 01 FF FD 00 ./.яя...яю...яэ.
000002F0 00 0E 00 02 00 00 0F 10 00 03 00 03 FF F2 00 12 ............ят..
00000300 00 13 01 FF F2 00 00 10 00 12 00 01 FF F1 0A FF ...ят.......яс.я
00000310 F1 00 18 2E 61 65 76 74 6F 61 70 70 6E 75 6C 6C с...aevtoappnull
00000320 00 00 80 00 00 00 90 00 2A 2A 2A 2A 0E 00 13 00 ..Ђ...ђ.****....
00000330 07 10 FF F0 00 14 FF EF FF EE 00 15 00 16 FF ED ..яр..япяо....ян
00000340 0A FF F0 00 18 2E 61 65 76 74 6F 61 70 70 6E 75 .яр...aevtoappnu
00000350 6C 6C 00 00 80 00 00 00 90 00 2A 2A 2A 2A 0D 00 ll..Ђ...ђ.****..
00000360 14 00 01 6B 00 00 00 00 00 15 00 17 02 00 17 00 ...k............
00000370 02 00 01 FF EC 02 FF EC 00 00 01 FF EF 00 00 02 ...ям.ям...яп...
00000380 FF EE 00 00 10 00 15 00 00 10 00 16 00 0A 00 11 яо..............
00000390 FF EB FF EA FF E9 FF E8 FF E7 FF E6 00 0F FF E5 ялякяйяиязяж..яе
000003A0 FF E4 0A FF EB 00 04 0A 6B 6F 63 6C 0A FF EA 00 яд.ял...kocl.як.
000003B0 04 0A 63 66 6F 6C 0A FF E9 00 04 0A 69 6E 73 68 ..cfol.яй...insh
000003C0 0A FF E8 00 04 0A 64 65 73 6B 0A FF E7 00 04 0A .яи...desk.яз...
000003D0 70 72 64 74 0A FF E6 00 04 0A 70 6E 61 6D 03 FF prdt.яж...pnam.я
000003E0 E5 00 06 0A FF E4 00 18 2E 63 6F 72 65 63 72 65 е...яд...corecre
000003F0 6C 2A 2A 2A 2A 00 00 00 00 00 00 90 00 6E 75 6C l****......ђ.nul
00000400 6C 11 FF ED 00 16 E0 12 00 12 2A E1 E2 E3 2A E4 l.ян..а...*бвг*д
00000410 2C E5 E6 E7 6C 0E E8 0C 00 09 55 0F 61 73 63 72 ,ежзl.и...U.ascr
00000420 00 01 00 0C FA DE DE AD ....ъЮЮ.