Захист мобільного додатку від реверс-інжиніринґу
APK — це zip-архів. apktool d app.apk розбирає його за секунди, jadx перетворює байткод у читаємий Java. Без обфускації зловмисник бачить імена класів, методів, логіку перевірки ліцензії, URL API-кінцевих точок, захардкоджені рядки. На iOS ситуація не набагато краща: class-dump відновлює заголовки Objective-C класів, Ghidra дизассемблює нативний код.
Обфускація коду
Android. R8 (вбудований в Android Gradle Plugin) — мінімальна точка входу. Включається через minifyEnabled = true у build.gradle та переносить класи, методи, поля в a, b, c. Але R8 не шифрує рядки. Серйозна строкова захист вимагає окремого інструменту.
ProGuard правила потрібно писати вручну для кожної використовуваної бібліотеки — інакше сломається рефлексія, Gson-серіалізація, Firebase. Типова біль: @SerializedName на полях моделі не допомагає, якщо сам клас переrename в a, і Gson не може створити його через рефлексію. Рішення — @Keep або явні -keep правила для data-класів, передаваних через API.
Комерційні обфускатори — DexGuard, iXGuard (від Guardsquare) — йдуть далі: шифрування рядків, обфускація control flow (вставка хибних гілок та goto), захист ресурсів, anti-tamper перевірки. DexGuard інтегрується в Gradle як плагін, конфіг схожий на ProGuard, але можливостей на порядок більше. Використовується в банківських додатках.
iOS. Обфускація бінарника Swift/Objective-C складніша — немає проміжного байткода. Варіанти: obfuscator-llvm (LLVM pass для control flow flattening) або комерційний iXGuard. Імена Swift-функцій у публічному API не можна сховати без наслідків для ABI, але приватну логіку можна обфускувати.
Flutter. Dart компілюється в машинний код, що саме по собі дає деякий захист. reFlutter — інструмент для реверс-інжиніринґу Flutter-додатків — вміває відновлювати імена з snapshot, якщо додаток скомпільований без strip symbols. Включаємо у сборці: flutter build apk --obfuscate --split-debug-info=./symbols. Debug symbols йдуть у окремий файл, який не включається в релізе.
Захист рядків
Захардкоджені URL, ключі, імена серверів — перше, що ище strings на бінарнику. Мінімум — не зберігати їх у коді зовсім (витащити у віддалену конфігурацію, наприклад Firebase Remote Config). Якщо рядок все ж таки повинна бути в додатку — шифрувати та розшифровувати в runtime через нативний код (JNI/NDK на Android), щоб plaintext не світився в dex.
Паттерн: рядки зберігаються як XOR-зашифрований масив байт, ключ XOR розбитий на частини в різних нативних функціях. Не криптографічно стійко, але піднімає поріг входу.
Антиотладкові техніки
ptrace(PTRACE_TRACEME, 0, 0, 0) на Android/Linux — процес сам стає tracee, друга ptrace attach від отладчика повертає помилку. На iOS аналог — PT_DENY_ATTACH. Frida це обходить (не через ptrace, а через task_for_pid), але додає складність.
Перевірка через /proc/self/status на Android: TracerPid != 0 означає, що до процесу прилаштований отладчик. Фреймворк appdome автоматично додає такі перевірки без змін коду.
Anti-Frida: Frida внедряє frida-agent у процес через frida-gadget. Детектуємо через перевірку завантажених бібліотек (/proc/self/maps), наявність frida-server порту (27042), імен файлів у /proc/self/fd. Але детектування в userspace Frida же й обходить — гонка озброєнь.
Перевірка цілісності додатку
На Android верифікуємо підпис APK в runtime: PackageManager.getPackageInfo() повертає список signatures. Хешируємо їх та порівнюємо з захардкоджженим значенням. Якщо підпис змінилася — додаток перепакований. Саму перевірку потрібно приховувати в нативному коді, інакше її тривіально патчат у smali.
Google Play Integrity API (замінуювання SafetyNet Attestation) — надійніший варіант: сервер отримує від Google підписаний токен з вердиктом MEETS_DEVICE_INTEGRITY, MEETS_STRONG_INTEGRITY. Неможливо підробити без Google-серверів. Недолік — вимагає мережевого запиту та API-квоти.
На iOS — DCAppAttestService (App Attest). Аналогічний механізм: пристрій отримує аттестацію від Apple, сервер перевіряє через Apple API.
Нативний код та React Native
Бізнес-логіку, яку не можна раскривати, виносимо в NDK (Android) або нативний фреймворк (iOS). Нативний код складніше реверсити, ніж Kotlin/Java або JavaScript bundle.
React Native зберігає весь JavaScript в index.android.bundle — звичайний файл всередині APK, читається будь-яким JS-форматтером. Захист: Hermes bytecode (компіляція через --hermes), шифрування bundle через нативний модуль, який розшифровує його в пам'яті перед завантаженням у рушій. Metro Bundler підтримує користувацький serializer для цього.
Терміни
Базова настройка R8/ProGuard зі строковою захистом та anti-tamper перевірками — 3–5 днів. Інтеграція DexGuard/iXGuard з тонкою настройкою конфігурації — до 2 тижнів (багато ітерацій, щоб не сломати runtime). Нативний перенос критичної логіки — окремена оцінка за обсягом.







