android studio защита приложения

6 способов спрятать данные в Android-приложении

Привет, дорогой читатель, уже достаточно давно я изучаю мобильные приложения. Большинство приложений не пытаются как-то скрыть от меня свой «секретный» функционал. А я в это время радуюсь, ведь мне не приходится изучать чей-то обфусцированный код.

image loader

В этой статье я хотел бы поделиться своим видением обфускации, а также рассказать про интересный метод сокрытия бизнес-логики в приложениях с NDK, который нашел относительно недавно. Так что если вас интересуют живые примеры обфусцированного кода в Android — прошу под кат.

Под обфускацией в рамках этой статьи будем понимать приведение исполняемого кода Android-приложения к трудному для анализа виду. Существует несколько причин затруднять анализ кода:

Многие разработчики решают проблему простым форком конфига ProGuard. Это не лучший способ защиты данных (если вы первый раз слышите об этом, то см. вики).

Хочу привести показательный пример, почему предполагаемая “защита” с помощью ProGuard не работает. Возьмем любой простенький пример из Google Samples.

image loader

Подключив к нему ProGuard со стандартным конфигом, получим декомпилированный код:

image loader

«Ооо, ничего непонятно» – скажем мы и успокоимся. Но через пару минут переключения между файлами найдём подобные кусочки кода:

image loader

В этом примере код приложения выглядит затрудненным довольно слабо (логирование данных, создание видео захвата), поэтому некоторые методы, использованные в оригинальном коде, легко понятны и после обработки конфигом ProGuard.

Дальше больше, взглянем на data-классы в Kotlin. Data-класс по умолчанию создает метод “toString”, который содержит в себе названия переменных экземпляра и название самого класса.

image loader

Он может превратиться в лакомый кусочек для реверсера:

image loader
(автогенерация метода toString в Kotlin)

Выясняется, что ProGuard прячет далеко не весь исходный код проекта.

Если я все еще не убедил вас в нецелесообразности защиты кода таким способом, то давайте попробуем оставить в нашем проекте атрибут “.source”.

Эта строчка есть во многих opensource проектах. Она позволяет просматривать StackTrace при падении приложения. Однако, вытащив “.source” из smali-кода, мы получим всю иерархию проекта с полными названиями классов.

По определению, обфускация – это “приведение исходного кода в нечитаемый вид для того, чтобы противодействовать разным видам ресерча”. Однако, ProGuard (при использовании со стандартным конфигом) не делает код нечитаемым – он работает как минификатор, сжимающий названия и выкидывающий лишние классы из проекта.

Такое использование ProGuard – это легкое, но не совсем подходящее для хорошей обфускации решение на ”авось”. Хорошему разработчику нужно заставить ресерчера (или злоумышленника) испугаться “китайских символов”, которые трудно деобфусцировать.

Если вам интересно подробнее узнать про ProGuard, то предлагаю следующую познавательную статью.

Что прячем

Теперь давайте посмотрим, что обычно прячут в приложениях.

image loader

image loader

В коде часто может быть спрятано что-то более неожиданное (наблюдения из личного опыта), например:

Теперь мы знаем, что может прятаться в Android-приложениях и можем переходить к главному, а именно к способам сокрытия этих данных.

Способы сокрытия данных

Вариант 1: Ничего не скрывать, оставить все на виду

В таком случае я просто покажу вам эту картинку :)

“Помогите Даше найти бизнес-логику”

image loader

Это нетрудозатратное и совершенно бесплатное решение подойдет для:

Вариант 2: Использовать ProGuard с правильными настройками

Это решение все-таки имеет право на жизнь, потому что, в первую очередь, оно является простым и бесплатным. Несмотря на вышеупомянутые минусы, у него есть весомый плюс: при правильной настройке ProGuard-правил приложение может действительно стать обфусцированным.

Однако, нужно понимать, что такое решение после каждой сборки требует от разработчика декомпиляции и проверки, все ли нормально. Потратив несколько минут на изучение APK файла, разработчик (и его компания) могут стать увереннее в безопасности своего продукта.

Проверить приложение на наличие обфускации достаточно просто.

Для того, чтобы достать APK-файл из проекта существует несколько путей:

После этого, пользуясь утилитой Apktool, получаем Smali-код (инструкция по получению здесь https://ibotpeaches.github.io/Apktool/documentation) и пытаемся найти что-нибудь подозрительно читаемое в строках проекта. Кстати, для поиска читаемых кодов можно запастись уже заранее готовыми bash-командами.

Это решение подойдет для:

Вариант 3: Использовать Open Source Obfuscator

К сожалению, реально хороших бесплатных обфускаторов для мобильных приложений я не знаю. А обфускаторы, которые можно найти в сети могут принести вам много головной боли, поскольку собрать такой проект под новые версии API будет слишком сложно.

Исторически сложилось, что существующие крутые обфускаторы сделаны под машинный код (для C/C++). Хорошие примеры:

Например, Movfuscator заменяет все opcodes mov-ами, делает код линейным, убирая все ветвления. Однако, крайне не рекомендуется использовать такой способ обфускации в боевом проекте, потому что тогда код рискует стать очень медленным и тяжелым.

Это решение подойдет для приложений, у которых основная часть кода — NDK.

Вариант 4: Использовать проприетарное решение

Это самый грамотный выбор для серьезных приложений, так как проприетарное ПО:
а) поддерживается;
б) всегда будет актуально.

Пример обфусцированного кода при использовании таких решений:

image loader

В этом фрагменте кода можно увидеть:

Это решение подойдет для:

Вариант 5: Использовать React-Native

Я решил выделить этот пункт, так как написание кроссплатформенных приложений сейчас стало действительно популярным занятием.

Кроме очень большого community, JS имеет очень большое количество открытых обфускаторов. Например, они могут превратить ваше приложение в смайлики:

image loader

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

Зато, уменьшив требование к обфускации кода, мы можем создать действительно хорошо защищенный проект. Так что гуглим “js obfuscator” и обфусцируем наш выходной bundle-файл.

Это решение подойдет для тех, кто готов писать кроссплатформенное приложение на React Native.

Было бы очень интересно узнать про обфускаторы на Xamarin, если у вас есть опыт их использования – расскажите, пожалуйста, о нем в комментариях.

Вариант 6: Использовать NDK

Мне самому часто приходилось использовать NDK в своем коде. И я знаю, что некоторые разработчики считают, что использование NDK спасает их приложение от реверсеров. Это не совсем так. Для начала нужно понять, как именно работает сокрытие с помощью NDK.

image loader

Оказывается, очень просто. В коде есть некоторая JNI-договоренность, что при вызове C/C++ кода в проекте он будет преобразовываться следующим образом.

Нативный класс NativeSummator:

image loader

Реализация нативного метода sum:

image loader

Реализация нативного статичного метода sum:

image loader

Cтановится понятно, что для вызова нативного метода используется поиск функции Java_

_ _ в динамической библиотеке.

Если заглянуть в Dalvik/ART код, то мы найдём следующие строки:

image loader

Сначала сгенерируем из Java-объекта следующую строку Java_

Так работает JNI. Его основная проблема в том, что, декомпилировав динамическую библиотеку, мы увидим все методы, как на ладони:

image loader

Значит, нам нужно придумать такое решение, чтобы адрес функции был обфусцирован.

Сначала я пытался записать данные напрямую в нашу JNI-таблицу, но, понял, что механизмы ASLR и разные версии Android просто-напросто не позволят мне сделать этот способ работающим на всех устройствах. Тогда я решил узнать, какие методы NDK предоставляет разработчикам.

И, о чудо, нашелся метод “RegisterNatives”, который делает ровно то, что нам нужно (вызывает внутреннюю функцию dvmRegisterJNIMethod).

Определяем массив, описывающий наш нативный метод:

image loader

И регистрируем наш объявленный метод в функции JNI_OnLoad (метод вызывается после инициализации динамической библиотеки, тыц) :

image loader

Ура, мы самостоятельно спрятали функцию “hideFunc”. Теперь применим наш любимый llvm-обфускатор и порадуемся безопасности кода в конечном виде.

Это решение подойдет для приложений, которые уже используют NDK (подключение NDK несет в проект большое количество сложностей, поэтому для не-NDK приложений это решение не так актуально).

Вывод

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

Я считаю, что обфускация – важная структурная часть любого современного приложения.

Обдуманно подходите к вопросам сокрытия кода и не ищите простых путей! :)

Кстати, спасибо пользователю miproblema за помощь в некоторых вопросах. Подписывайтесь на ее телеграм-канал, там интересно.

А так же огромное спасибо пользователям sverkunchik и SCaptainCAP за помощь в редактировании статьи.

Источник

Как защитить свое приложение для Android от реверса и дебага

chain force h

Содержание статьи

— Как украсть приложение для Android?
— Берешь и крадешь.

Для рубрики «Взлом» я написал цикл статей, в которых наглядно показал, насколько на самом деле легко взламываются приложения для Android. Для этого не нужен даже дизассемблер, достаточно поверхностных знаний Java и языка Smali. Поэтому, если твое приложение будет достаточно популярно, знай: его украдут и путем нехитрых манипуляций активируют платные функции. А если ты решил монетизировать его с помощью рекламы — ее отключат.

Защитить приложение сложно, но можно. Во-первых, стоит сразу отказаться от модели распространения Pro/Lite. Приложение очень легко вытащить со смартфона, поэтому вору будет достаточно один раз купить приложение, и дальше его можно распространять as is. Во-вторых, необходимо позаботиться о защите кода от реверса. Декомпиляция Java-кода — дело простое, а изменение бинарного кода не требует каких-то особых навыков или инструментов. В-третьих, нужно сделать так, чтобы в случае даже успешного взлома приложение просто не стало работать. Тогда взломщику придется решать сразу две задачи: взломать приложение и заставить взломанную версию работать.

Итак, отказываемся от Pro-версии и начинаем борьбу.

Скрываем и запутываем код

Лучший способ защиты кода приложения от реверса — это обфускация, другими словами — запутывание байт-кода так, чтобы реверсеру было невыносимо трудно в нем разобраться. Существует несколько инструментов, способных это сделать. Наиболее простой, но все же эффективный есть в составе Android Studio. Это ProGuard.

Для его активации достаточно добавить в раздел android → buildTypes → release файла build.gradle строку minifyEnabled true :

После этого Android Studio начнет пропускать все «релизные» сборки через ProGuard. В результате приложение станет компактнее (благодаря удалению неиспользуемого кода), а также получит некоторый уровень защиты от реверса. «Некоторый» в том смысле, что ProGuard заменит имена всех внутренних классов, методов и полей на одно-двухбуквенные сочетания. Это действительно существенно затруднит понимание декомпилированного/дизассемблированного кода.

1482684553 466d proguard Так выглядят классы в декомпиляторе JADX после применения ProGuard

Xakep #215. Второй фактор

Следующий шаг — шифрование строк. Это особенно полезно в том случае, если внутри приложения ты хранишь какие-либо сенситивные данные: идентификаторы, ключи, REST API endpoints. Все это поможет взломщику сориентироваться в твоем коде или вычленить из него важную информацию.

Зашифровать строки можно разными способами, например используя инструменты Stringer или DexGuard. Преимущество: полностью автоматизированная модификация уже имеющегося кода с целью внедрения шифрования строк. Недостаток: цена, которая доступна компаниям, но слишком высока для независимого разработчика.

Поэтому мы попробуем обойтись своими силами. В простейшем случае шифрование строк средствами Java выполняется так:

А расшифровка — так:

Для генерации ключа достаточно одной строки:

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

Можно пойти еще дальше и воспользоваться одним из инструментов комплексной защиты Android-приложений, например AppSolid. Стоит оно опять же дорого, но позволяет зашифровать все приложение целиком. Это действительно способно отпугнуть многих реверсеров, однако есть ряд инструментов, в том числе платный Java-декомпилятор JEB, который умеет снимать такую защиту в автоматическом режиме.

Также ты можешь попытаться разбить свое приложение на множество небольших модулей, как я уже писал в статье Пишем модульные приложения для Android. Сам по себе это не метод защиты, и он почти не затруднит работу реверсера. Но зато обломает различные автоматизированные системы кракинга приложений. Они просто не смогут понять, где искать находящийся в модуле код.

Крашим взломанное приложение

Окей, жизнь реверсеру мы немного подпортили. Настало время сделать это еще раз! Но как узнать, было ли приложение взломано? Точнее, как оно само может это выяснить? Ведь понятия «взломанное» и «не взломанное» существуют только в наших с тобой головах, то есть это понятия достаточно высокого порядка, которые не описать алгоритмически.

Так оно, да не так. Дело в том, что внутри APK-файла есть набор метаданных, которые хранят контрольные суммы абсолютно всех файлов пакета, а сами метаданные подписаны ключом разработчика. Если изменить приложение и вновь его запаковать, метаданные пакета изменятся и пакет придется подписывать заново. А так как твоего ключа разработчика у реверсера нет и быть не может, он использует либо случайно сгенерированный, либо так называемый тестовый ключ.

Сам Android такое приложение спокойно проглотит (он не держит базу всех цифровых подписей всех возможных Android-разработчиков), но у нас-то есть своя цифровая подпись, и мы можем ее сверить!

Сверяем цифровую подпись

Собственно, метод довольно простой. Тебе необходимо вставить в приложение код, который будет получать хеш ключа текущей цифровой подписи пакета и сравнивать его с ранее сохраненным. Совпадают — приложение не было перепаковано (и взломано), нет — бьем тревогу.

Для начала вставь следующий кусок кода в приложение (чем глубже ты его запрячешь, тем лучше):

Собери, запусти приложение и посмотри лог исполнения. Там ты увидишь строку SIGNATURE: 478uEnKQV+fMQT8Dy4AKvHkYibo=. Это и есть хеш. Его необходимо не просто запомнить, а поместить в код приложения в виде константы, например под именем SIGNATURE. Теперь убери строку Log.e. из кода и добавь следующий метод:

Он как раз и будет сверять сохраненный хеш с хешем ключа, которым в данный момент подписано приложение. Функция возвращает true, если цифровая подпись твоя (приложение не было пересобрано), и false — если оно подверглось модификации. Что делать во втором случае — решать тебе. Ты можешь просто завершить приложение с помощью os.exit(0) либо «уронить» его, например вызвав метод неинициализированного объекта или обратившись к несуществующему значению массива.

Но запомни: взломщик может просто вырезать твой код сверки цифровой подписи и он никогда не сработает (это справедливо и в отношении кода, приведенного далее). Поэтому спрячь его в неочевидном месте, а хеш оригинального ключа зашифруй, как было показано выше.

Проверяем источник установки

Еще один метод защиты — выяснить, откуда было установлено приложение. Тут логика простая: если источник установки — Play Store, то все нормально, это оригинальное неперепакованное приложение. Если нет — варез, скачанный с форума и установленный с карты памяти или из «черного маркета».

Выяснить, откуда было установлено приложение, можно в одну строку, а сама функция, делающая это, может выглядеть так:

Как обычно: true — все нормально, false — Хьюстон, у нас проблемы.

Определяем эмулятор

Некоторые методы реверса приложений предполагают использование эмулятора. Поэтому нелишним будет внести в приложение код, проверяющий, не запущено ли оно в виртуальной среде. Сделать это можно, прочитав значение некоторых системных переменных. Например, стандартный эмулятор Android Studio устанавливает такие переменные и значения:

Поэтому, прочитав значения этих переменных, можно предположить, что код исполняется в эмуляторе:

Обрати внимание, что класс android.os.SystemProperties скрытый и недоступен в SDK, поэтому для обращения к нему мы используем рефлексию (о скрытых API Android я уже писал).

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

Отладка

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

Чтобы защититься от отладки, можно использовать следующий код:

1482684639 49d7 dont Так делать не стоит: код проверок необходимо раскидать по коду и продублировать

Выводы

Создать на 100% защищенное приложение у тебя не получится, можешь даже не пытаться. Но есть достаточно простые способы существенно усложнить жизнь среднестатистическому реверсеру. Да, приложение все равно рано или поздно взломают, но так у тебя хотя бы будет время, чтобы заработать на нем. Ну и стоит почаще обновлять свое творение, чтобы реверсерам жизнь медом не казалась.

Evgenij Zobnin 1

Евгений Зобнин

Редактор рубрики X-Mobile. По совместительству сисадмин. Большой фанат Linux, Plan 9, гаджетов и древних видеоигр.

Источник

Как обезопасить Android приложение

Russian (Pусский) translation by Ellen Nelson (you can also view the original English article)

Вступление

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

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

1. Используйте внутреннее хранилище для важных данных

2. Шифруйте данные на внешнем хранилище

Внутренняя вместимость хранилища Android часто ограничена. Поэтому время от времени у вас может не оказаться выбора, кроме как хранить конфиденциальные данные на внешних носителях, таких как съемная SD-карта.

Поскольку данные на внешних носителях могут быть доступны как пользователям, так и другим приложениям на устройстве, важно хранить их в зашифрованном виде. Одним из самых популярных алгоритмов шифрования, используемых сегодня разработчиками, является AES, сокращение от Advanced Encryption Standard, с размером ключа 256 бит.

3. Используйте Intents для IPC

Опытные программисты, которые плохо знакомы с разработкой приложений для Android, часто пытаются использовать сокеты, именные каналы или общие файлы для асинхронного взаимодействия с другими приложениями, установленными на устройстве Android. Такие подходы не только тяжёлые и не элегантные, но и подвержены угрозам. Более простой и безопасный подход к межпроцессному взаимодействию в операционной системе Android заключается в использовании интентов.

Вот фрагмент кода, который показывает, как отправить строку Hello World в качестве безопасной трансляции:

Обратите внимание, что приведенный выше код работает так, как ожидалось, только если объявлено настраиваемое (custom) разрешение и используется в файлах манифеста как для приложений-отправителей, так и для получателей.

4. Используйте HTTPS

Многие пользователи Android каждый день подключаются к нескольким открытым точкам доступа Wi-Fi в общественных местах. Некоторые из этих точек могут быть скомпрометированы. Злоумышленник может легко изменить содержимое HTTP-трафика так, что ваше приложение начнет вести себя непредсказуемым образом или, что еще хуже, встроит в него рекламу или эксплойты.

Используйте HTTPS, пока сервер настроен на сертификат, выданный доверенным центром сертификации, таким как DigiCert или GlobalSign и вы можете быть уверены в том, что сетевой трафик защищен как от подслушивания, так и от атак типа «человек-по-середине».

Если в вашем приложении много сетевого кода, и вы опасаетесь, что вы можете непреднамеренно отправить некоторые данные в виде простого текста, вам следует рассмотреть возможность использования инструмента с открытым исходным кодом — nogotofail, созданного Google, чтобы находить такие ошибки.

5. Используйте GCM вместо SMS

Раньше, когда GCM (сокращение для Google Cloud Messaging) не существовало, многие разработчики использовали SMS для передачи данных со своих серверов в свои приложения. Сегодня это практически не практикуется.

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

6. Перестаньте запрашивать персональные данные.

В последнее время для пользователя важна конфиденциальность. На самом деле существуют законы, такие как Директива Европейского Союза о защите данных и Закон Канады о защите личной информации и электронных документов, которые предусматривают защиту конфиденциальности пользователя. Поэтому, если у вас нет достаточных оснований и очень надежной инфраструктуры для сбора, хранения и передачи личной информации пользователя, вы должны избегать прямого запроса таких данных в ваших приложениях.

Лучший подход к проверке подлинности пользователей и информации из профиля пользователя — это поиск по Android через платформу Google Identity Platform. Платформа Google Identity Platform позволяет пользователям быстро входить в ваше приложение, используя свою учетную запись Google. После успешного входа на платформу, если это необходимо, ваше приложение может легко просматривать различные сведения о пользователе, такие как имя пользователя, адрес электронной почты, фото профиля, контакты и т.д. Кроме того, вы можете использовать бесплатные службы, такие как Firebase, которые могут управлять аутентификацией пользователя.

Вот небольшой фрагмент кода, который показывает, как создать хеш строки Hello World с помощью хэш-функции SHA-256:

7. Проверяйте информацию, которую вводят пользователи

В системе Android неправильный ввод данных от пользователя обычно не приводит к проблемам безопасности, например, переполнению буфера. Однако, если вы разрешаете пользователям взаимодействовать с базой данных SQLite или поставщиком контента, который использует внутреннюю базу данных SQLite, вы должны либо тщательно обрабатывать (sanitize) ввод пользователя, либо использовать параметры в запросах. В противном случае ваши данные могут стать уязвимыми для атак по методу SQL-инъекций.

По аналогии, проверка и очистка пользовательского ввода также очень важны, если вы используете пользовательский ввод для динамического генерирования кода для работы на встроенном скриптовом движке, таком как Mozilla Rhino.

8. Используйте ProGuard перед публикацией

Меры безопасности, встроенные в приложение Android, могут быть серьезно нарушены, если злоумышленники могут получить доступ к исходному коду. Прежде чем опубликовать свое приложение, рекомендуется использовать инструмент ProGuard, который входит в Android SDK, чтобы запутать (obfuscate) и уменьшить исходный код.

Вывод

Надеюсь, теперь вы лучше понимаете, как сделать ваши приложения для Android безопасными. Большинство рекомендаций, упомянутых в этой статье, применимы только в том случае, если вы используете Android SDK для разработки своих приложений. Если вы используете Android NDK, вы должны быть намного внимательнее, потому что при программировании на языке C вам придется управлять деталями нижнего-уровня, такими как указатели и распределение памяти.

Чтобы узнать больше о безопасности на Android, вы можете обратиться к документации по безопасности AOSP.

Источник

Понравилась статья? Поделить с друзьями:
Добавить комментарий
  • Как сделать успешный бизнес на ритуальных услугах
  • Выездной кейтеринг в России
  • Риски бизнеса: без чего не обойтись на пути к успеху
  • android studio заставка при запуске приложения
  • android studio запуск приложения на эмуляторе