На аудите финтех-приложения за 40 минут статического анализа IPA-файла мы вытащили три захардкоженных API-ключа, endpoint внутреннего микросервиса и HMAC-секрет для подписи запросов. Ключи работали в продакшене больше восьми месяцев - компания узнала об этом только потому, что заказала пентест мобильного приложения. Потенциальный ущерб: несанкционированный доступ к данным 200+ тысяч клиентов и оборотные штрафы по 152-ФЗ.
Этот кейс не исключение, а типовой результат первых часов реверс-инжиниринга iOS-приложения. Эта статья будет полезна для SOC-инженеров, так и для Blue Team. В ней мы разберёмся, что именно делает атакующий, какие артефакты оставляет и как выстроить detection, чтобы реверс вашего приложения не стал задачей на один вечер.
Место в цепочке атаки: зачем реверсить iOS-приложение
Реверс-инжиниринг iOS приложений - не самоцель. Это разведка перед атакой на серверную инфраструктуру. Атакующий разбирает бинарник ради конкретных вещей: извлечь секреты (API-ключи, токены, URL внутренних сервисов), понять бизнес-логику (эндпоинты, параметры запросов, клиентская валидация), обойти защитные механизмы (SSL-pinning, jailbreak detection, биометрию) и подготовить серверную атаку (фаззинг API, abuse бизнес-логики).В терминах MITRE ATT&CK цепочка выглядит так: получение и расшифровка IPA-файла - Deobfuscate/Decode Files or Information (T1140, Defense Evasion) - вызов нативных функций анализа через Native API (T1106, Execution) - перехват методов через Credential API Hooking (T1056.004, Collection / Credential Access) в runtime. При модификации и переподписи приложения добавляется Dylib Hijacking (T1574.004, Defense Evasion / Execution).
| Этап атаки | Инструмент | Техника ATT&CK | Что получает атакующий |
|---|---|---|---|
| Распаковка IPA | frida-ios-dump, bagbak | T1140 (Deobfuscate/Decode Files or Information) | Расшифрованный бинарник без FairPlay DRM |
| Статический анализ | class-dump, otool, strings | T1027 (Obfuscated Files) | Классы, методы, строки, URL, ключи |
| Дизассемблирование | Hopper, Ghidra, IDA Pro | T1106 (Native API) | Логика аутентификации, валидации, шифрования |
| Runtime-перехват | Frida, Cycript | T1056.004 (Credential API Hooking) | Обход pinning, перехват credentials |
| Anti-debug bypass | Frida, lldb | T1622 (Debugger Evasion, описана для Windows; на iOS применяется по аналогии) | Обход ptrace, sysctl-проверок |
Для SOC вывод прямой: реверс iOS-приложения - подготовительный этап к атаке на бэкенд. Если атакующий извлёк API-ключ и endpoint - следующий шаг уже в вашей серверной инфраструктуре.
Требования к окружению
Для воспроизведения техник ниже (в рамках авторизованного аудита):- ОС: macOS 13+ (Ventura или новее) для class-dump, otool, Hopper
- Устройство: джейлбрейкнутый iPhone - checkra1n (чипы A7–A11) или palera1n (checkm8-устройства A8–A11, iOS 15–17). Минимум 3 GB свободной памяти
- Frida 16.x:
pip install frida-toolsна хосте, frida-server соответствующей версии на устройстве - class-dump: оригинальный class-dump (nygard) устарел; для современных iOS нужны форки (class-dump-dyld, ICDump) или встроенные возможности Hopper/Ghidra. Swift-классы class-dump извлекает частично - понадобится
swift-demangle - Дизассемблер: Hopper Disassembler v5 (Personal/Commercial лицензия, актуальные цены на hopperapp.com) или Ghidra (бесплатный)
- Прокси: Burp Suite для перехвата трафика после обхода pinning
- SSH: OpenSSH на устройстве через Cydia/Sileo
Статический анализ IPA файлов iOS: что находит атакующий за первый час
Структура IPA и binary analysis Mach-O
IPA - ZIP-архив с предсказуемой структурой. ВнутриPayload/<AppName>.app/ лежит основной Mach-O бинарник (ARM64-код), рядом - Info.plist, фреймворки, ресурсы. Первые действия атакующего занимают минуты:Распаковка:
unzip app.ipa -d output/. Определение архитектуры: otool -hv <binary> - в выводе будет ARM64 (современные устройства), реже fat binary с armv7 + arm64. Список зависимостей: otool -L <binary> - показывает linked frameworks. Наличие CryptoKit, Security.framework, CommonCrypto указывает на работу с криптографией. Нестандартные .dylib - потенциально интересные сторонние библиотеки.Извлечение строк:
strings <binary> | grep -iE 'api|key|secret|token|http' - в незащищённых приложениях выдаёт URL бэкенда, ключи и иногда пароли открытым текстом. Альтернатива - rabin2 -zz <binary> из набора radare2 (текущая версия 6.1.5, проект активно поддерживается).По данным OWASP MASVS (раздел MASVS-CODE), production-сборки не должны содержать debug-символов и незашифрованных чувствительных строк. На практике - значительная часть аудируемых приложений эту проверку проваливает.
class-dump iOS: чтение Objective-C интерфейсов
class-dump извлекает заголовки классов из Mach-O бинарника. Для Objective-C работает почти идеально: runtime хранит все имена классов, методов и свойств. Для чистого Swift ситуация хуже - Swift-символы используют name mangling и требуютswift-demangle или class-dump-swift. Как отмечают в руководстве Corellium, «the older version of class-dump won't work if there is Swift code within the binary»«Более старая версия class-dump не сработает, если в бинарном файле есть код Swift» - поэтому архитектуру и язык стоит определять заранее через otool.Типичный выход class-dump для приложения на Objective-C:
Код:
@interface AuthenticationManager : NSObject
+ (BOOL)validateToken:(NSString *)token;
- (void)loginWithUsername:(NSString *)user password:(NSString *)pass;
- (BOOL)isJailbroken;
- (void)setupCertificatePinning;
@property (nonatomic, copy) NSString *apiBaseURL;
@property (nonatomic, copy) NSString *apiSecret;
@end
isJailbroken, setupCertificatePinning) дают точную карту защитных механизмов. Свойства типа apiSecret - прямое указание на hardcoded секрет. Метод loginWithUsername:password: - цель для Frida-хука.Если в дампе классов видны читаемые имена вроде
validatePurchase, checkLicenseKey, bypassDetection - приложение, по сути, поставляется с документацией для атакующего. OWASP MASVS-RESILIENCE рекомендует обфускацию символов и strip debug-информации. На деле - мало кто это делает.Hopper дизассемблер iOS: навигация по бизнес-логике
Hopper Disassembler (и бесплатная альтернатива Ghidra) позволяет перейти от списка методов к пониманию их внутренней логики. Как отмечает Y-Security в руководстве по OWASP MASTG, «no decompilers are available for iOS apps»«Не существует декомпилятора для iOS приложений» в полном смысле - псевдокод из Ghidra/Hopper приближён к исходному, но не эквивалентен ему. Для защитников это значит: обфускация замедляет атакующего, но не останавливает.На ARM64-дизассемблере я обычно ищу три вещи.
Первое - ветвления в проверках безопасности. Методы
isJailbroken, checkIntegrity. Типичный паттерн: серия вызовов fileExistsAtPath: с путями /Applications/Cydia.app, /usr/sbin/sshd, /Library/MobileSubstrate/MobileSubstrate.dylib. Если метод возвращает BOOL - в ARM64 это один cmp + b.ne, который патчится за секунды.Второе - криптографические константы. Строки, передаваемые в
CCCrypt, SecKeyEncrypt или кастомные функции шифрования. Ключи часто валяются как статические строки в секции __cstring. Перекрёстные ссылки (cross-references) от этих строк ведут прямо к функциям шифрования.Третье - сетевые вызовы. Xrefs от строк с URL к методам
NSURLSession. Это даёт полную карту API-эндпоинтов, включая внутренние, не документированные публично.Разница между анализом Objective-C и Swift принципиальна: Objective-C бинарники сохраняют полные имена селекторов в
__objc_methname, что делает дизассемблированный код почти читаемым. Swift-бинарники используют name mangling (имена вида $s7MyApp14ViewControllerC), и Hopper/Ghidra восстанавливают их частично. Приложение на Swift получает базовый уровень obfuscation «бесплатно», но полагаться на это как на защиту - иллюзия.Динамическая инструментация Frida iOS: перехват в runtime
Статический анализ даёт карту - динамическая инструментация Frida даёт результат. Frida позволяет внедрять JavaScript-код в работающий процесс на джейлбрейкнутом устройстве, перехватывая любой вызов метода без модификации бинарника.
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Обход jailbreak detection - если class-dump показал метод
isJailbroken, его возврат подменяется за секунды: достаточно переопределить implementation через ObjC.classes. Это техника Credential API Hooking (T1056.004).В корпоративном контексте риск конкретный: скомпрометированное устройство сотрудника, на котором отключена jailbreak-проверка MDM-управляемого приложения, становится вектором утечки корпоративных данных. Атакующему даже не нужно атаковать сервер - достаточно перехватить трафик приложения на подконтрольном устройстве.
Обход биометрии - хук на
evaluatePolicy:localizedReason:reply: класса LAContext (фреймворк LocalAuthentication) подменяет результат проверки Touch ID / Face ID. Атакующий получает доступ к функциям, защищённым биометрией, без физического присутствия владельца.Detection и hardening: что контролировать на стороне защиты
Серверная детекция: что видит SOC
Реверс приложения происходит на устройстве атакующего - напрямую SOC его не увидит. Но последствия заметны в серверных логах:- Аномальные User-Agent и заголовки - после обхода pinning трафик идёт через Burp Suite или mitmproxy. User-Agent может не совпадать с валидным значением приложения. Правило корреляции: алерт на API-запросы с нестандартным UA при валидном токене авторизации
- Replay и манипуляция параметрами - если атакующий понял структуру API через реверс, он подставляет чужие ID, меняет суммы, перебирает параметры. Корреляция: всплеск 4xx/5xx ошибок с одного токена за короткий период
- Использование отозванных или hardcoded ключей - если в бинарнике был захардкожен API-ключ, который вы ротировали, а запросы с ним продолжают приходить - это прямой IOC
- Географические аномалии - запросы от одного пользователя одновременно из разных геолокаций
- Отсутствие device attestation - Apple App Attest позволяет серверу верифицировать, что запрос пришёл с легитимного устройства с неизменённым приложением. Отсутствие attestation-маркера при включённой проверке - IOC
Клиентские проверки и их ограничения
Клиентские проверки замедляют атакующего, но не останавливают. Frida обходит любую проверку - вопрос только в затраченном времени:| Проверка | Что детектирует | Способ обхода | Сложность обхода |
|---|---|---|---|
fileExists /Applications/Cydia.app | Jailbreak (базовый) | Frida hook на NSFileManager + C-функции stat/access/fopen | Лёгкая |
_dyld_image_count - проверка загруженных dylib | Frida/Substrate injection | Frida Stalker, rename dylib | Средняя |
| ptrace(PT_DENY_ATTACH) | Debugger attachment | Frida использует Mach API, не ptrace - PT_DENY_ATTACH на неё не влияет; для lldb - хук syscall ptrace через dyld interpose | Лёгкая (Frida), средняя (lldb) |
| sysctl для обнаружения отладчика | lldb, gdb | Хук sysctl | Лёгкая |
| Проверка порта 27042 | Frida default port | Смена порта при запуске | Тривиальная |
| Integrity check (хеш бинарника) | Патчинг binary | Пересчёт хеша после модификации | Средняя |
| Apple App Attest (server-side) | Модификация приложения | Требует обхода Secure Enclave | Высокая |
Для SOC критичны серверные detection-правила - клиентские проверки покупают время, но гарантий не дают.
Hardening-чеклист по OWASP MASVS-RESILIENCE
Чеклист для передачи команде разработки - конкретные задачи, а не абстрактные пожелания:- Strip debug-символы перед релизом -
strip -S <binary>, включить Strip Debug Symbols в Xcode Build Settings - Шифровать чувствительные строки в runtime: не
let key = "abc123", а расшифровка из зашифрованного массива при первом обращении (MASVS-STORAGE) - Использовать
finalдля критичных классов в Swift - предотвращает swizzling через наследование - Реализовать многослойную jailbreak-detection: не только проверка файлов, но и sandbox integrity, fork() check, dyld-проверки
- Внедрить ptrace(PT_DENY_ATTACH) и sysctl-проверки - блокирует lldb/gdb (обход требует hook syscall), но не влияет на Frida, которая использует Mach API (T1622, Debugger Evasion)
- Подключить Apple App Attest для серверной верификации целостности - единственная проверка с высоким порогом обхода
- Реализовать certificate pinning через
NSURLSessionDelegateс проверкой SPKI-хеша (MASVS-NETWORK) - Не хранить секреты в бинарнике: Keychain для токенов, runtime-получение конфигурации с сервера (MASVS-STORAGE)
- Применить control flow obfuscation для критичных методов - усложняет анализ в Hopper/Ghidra (защита от T1027)
- Провести self-аудит IPA перед релизом: прогнать
class-dumpиstringsна собственной сборке - если вы видите секреты, атакующий тоже их увидит
Заключение
Два года назад я начал включать в отчёты по пентесту мобильных приложений метрику «время до первого секрета» - сколько минут от получения IPA до извлечения первого чувствительного значения. Медиана для корпоративных iOS-приложений - 25 минут. С базовой обфускацией - 2–3 часа. С полноценной защитой уровня MASVS-RESILIENCE L2 - от 8 часов до «не удалось за отведённое время аудита».Проблема не в инструментах атакующего: class-dump, Hopper и Frida доступны каждому. Проблема в том, что большинство команд разработки воспринимают клиентскую защиту как задачу «на потом». Jailbreak detection из пяти строк на проверку пути к Cydia - не защита, а самоуспокоение. Атакующий обходит её быстрее, чем разработчик написал.
Единственная рабочая стратегия - не доверять клиенту вообще ничего: серверная валидация каждого параметра, App Attest, ротация ключей, мониторинг API-аномалий. Клиентские проверки - замедлитель, не барьер. И если SOC не мониторит API на паттерны реверснутого приложения (нестандартные UA, replay, манипуляция ID), об инциденте вы узнаете из тикета клиента, а не из алерта.
Прогоните
strings и class-dump на своей последней production-сборке прямо сейчас. Если в выводе мелькнул хоть один ключ или внутренний URL - у вас та же проблема, что и у финтех-компании из начала статьи. Только вы пока об этом не знаете. Если хочется отработать полную цепочку реверса iOS-приложения в безопасной среде - на codeby.net разбирают конкретные подходы к detection мобильных API-аномалий под разные стеки.
Последнее редактирование модератором: