Обфускація коду мобільного додатку (Swift Shield для iOS)
Бінарні файли iOS-додатків можна декомпілювати. Hopper Disassembler та IDA Pro відновлюють імена класів, методів та рядкових констант із Swift/Obj-C символів у .ipa. Якщо в коді жорстко прописаний API endpoint, секретний ключ або логіка верифікації покупок — це читається без особливих зусиль. SwiftShield переносить символи на етапі компіляції, робячи декомпільований код значно складніше для аналізу.
Що вміває SwiftShield та чого не вміває
SwiftShield працює на рівні вихідних файлів: парсить .swift-файли, генерує випадкові імена для класів, структур, енумів, протоколів та методів, потім запускає сборку з переносованими символами. У результаті PaymentVerificationService у дизассемблері стає a3kX9mQp, а validateReceiptLocally() — f7nW2sLo.
Обмеження, які потрібно знати до починання:
- Рядкові літерали SwiftShield не трогає.
"https://api.example.com/secret"залишається в бінарі як є. Для захисту рядків потрібен окремий підхід — шифрування констант на етапі компіляції (наприклад, черезobfuscate-swiftабо користувацький build script зCryptoKit). - Не працює з Objective-C кодом — Obj-C runtime вимагає реальних імен селекторів для
@selector()таrespondsToSelector:. - SwiftUI, CoreData generated code,
@objc-аннотовані методи — ці символи неможливо переносити, їх потрібно явно виключити. - Xcode 15+ періодично ломає сумісність: SwiftShield залежить від виходу
sourcekitd, який змінюється між версіями Xcode.
Як це інтегрується в проект
Встановлення через Mint (рекомендую, уникає конфліктів версій):
mint install rockbruno/[email protected]
Базовий запуск:
swiftshield obfuscate \
--project-root /path/to/MyApp \
--automatic-filter
--automatic-filter пробує автоматично виключити публічне API та @objc символи. На практиці це працює на 80% — решта 20% потрібно додати в exclusions вручну.
Файл виключень swiftshield-ignore.txt:
// Виключаємо все, що торчить наружу
AppDelegate
SceneDelegate
// CoreData-сутності
UserEntity
OrderEntity
// @objc-методи
handleNotification
applicationDidBecomeActive
Типова проблема при першому запуску — краш на NSInternalInconsistencyException або unrecognized selector через переносування методу, викликаного через рядковий літерал (NSSelectorFromString("someMethod")). Ищемо через grep -r "NSSelectorFromString\|#selector\|@objc" та додаємо до exclusions.
Інтеграція в CI: обфускація запускається тільки для Release-конфігурації. SwiftShield генерує mapping-файл (swiftshield-output/), який потрібно зберігати: без нього не отримається символізувати краш-репорти з Firebase Crashlytics.
# GitHub Actions
- name: Obfuscate (Release only)
if: github.ref == 'refs/heads/main'
run: |
mint run swiftshield obfuscate \
--project-root . \
--automatic-filter
Symbolication обфускованих крешів — це біль, яку часто ігнорують. Firebase Crashlytics завантажує dSYM файл та розвертає адреси стека. Але імена класів у стеку вже будуть обфускі. Потрібно: зберігати mapping SwiftShield + dSYM в одному архіві з тегом версії, та при разборі краш застосовувати mapping назад.
Додатковий шар: захист рядків
SwiftShield не трогає рядки, тому для API-ключів та кінцевих точок використовуємо compile-time шифрування. Простий варіант через GYB або build phase script:
// Зашифровані константи генеруються скриптом
let apiKey = Obfuscated.reveal([0x4F, 0x7A, 0x2B, 0x91, ...])
Для серйозного захисту — swift-crypto (CryptoKit-обгортка) або інтеграція з iOS Keychain для зберігання ключів, отриманих з сервера при першому запуску.
Що захист не гарантує
Обфускація ускладняє реверс-інжиніринґ, але не робить його неможливим. Frida підключається до процесу в runtime та перехоплює виклики незалежно від імен символів. SSL unpinning через objection працює на jailbroken пристроях. Обфускація — один шар захисту, а не срібна куля.
Процес роботи
Аудит кодової бази: визначення символів для виключень, пошук @objc-залежностей, Obj-C bridge.
Настройка SwiftShield: конфігурація, файл виключень, тестовий прогон на Debug-сборці для виявлення проблем.
Інтеграція в CI: Release-only pipeline, зберігання mapping-файлу, symbolication воркфлоу.
Додатково: аналіз рядкових констант, рекомендації по зберіганню секретів.
Орієнтири по термінам
Базова настройка SwiftShield для проекту без Obj-C — 1 день. Якщо проект використовує Obj-C код, CoreData generated files, складні @objc залежності — 2–3 дні з повним тестуванням Release-сборки.







