Файл деобфускации что это
При сбоях и ошибках ANR в Android создается трассировка стека – информация о последовательности вложенных функций, которые вызывались в вашей программе вплоть до момента сбоя. С помощью этих данных можно выявлять и устранять ошибки в коде.
Если вы разработали свое приложение или игру на языке Java и используете ProGuard для оптимизации и обфускации приложения, то можете загрузить файл сопоставления ProGuard в Play Console. Для приложений, созданных на основе нативного кода, например С++, можно использовать файлы с отладочными символами. Оба типа файлов необходимо загружать отдельно для каждой версии приложения. Это поможет вам проанализировать и устранить сбои и ошибки ANR.
Важно! Для деобфускации приложений, скомпилированных в Java, поддерживаются только файлы сопоставления, совместимые с ReTrace. Этот же формат используется в файлах ProGuard и R8.
Шаг 1. Сгенерируйте файл деобфускации или файл отладочных символов
Чтобы выполнить деобфускацию или добавление отладочных символов в случае сбоев и ошибок ANR в конкретной версии приложения, сначала нужно сгенерировать необходимые файлы. Каждый файл создается для одной конкретной версии приложения.
Для деобфускации Java-приложений вам потребуется файл сопоставления ProGuard. О том, как его создать, рассказывается на сайте Google Developers.
Плагин Android Gradle 4.1 или более поздней версии
Если для сборки вы используете набор Android App Bundle, файл с отладочными символами может добавляться в нее автоматически. Для этого включите следующую строку в файл build.gradle вашего приложения:
- android.defaultConfig.ndk.debugSymbolLevel = 'FULL'
Примечание. Размер файла отладочных символов не должен превышать 300 МБ. Если отладочные символы занимают слишком много места, размер файла можно уменьшить. Для этого укажите значение SYMBOL_TABLE вместо FULL .
Если же вы выбрали формат APK, добавьте указанный выше параметр в файл build.gradle, и файл отладочных символов будет создан отдельно. Загрузите полученный файл в Google Play Console (см. шаг 2). В процессе сборки плагин Android Gradle создает этот файл в следующем местоположении:
- app/build/outputs/native-debug-symbols/variant-name/native-debug-symbols.zip
Плагин Android Gradle 4.0 или более ранней версии (и другие системы сборки)
В процессе сборки APK-файла или набора App Bundle плагин Android Gradle сохраняет исходные копии библиотек (то есть не обработанные с помощью команды strip) в каталоге проекта. Пример структуры такого каталога:
Примечание. Если вы используете другую систему сборки, внесите изменения, чтобы структура каталогов, в которых сохраняются эти библиотеки, соответствовала указанной выше.
- Заархивируйте содержимое следующего каталога:
- $ cd app/build/intermediates/cmake/universal/release/obj
- $ zip -r symbols.zip
- Загрузите вручную файл symbols.zip в Play Console (см. шаг 2).
Размер файла с отладочными символами не должен превышать 300 МБ. Если он слишком велик, вероятнее всего, в файлах SO содержится таблица имен (названия функций), а также сведения для отладки DWARF (названия файлов и строки кода). Эта информация не нужна для добавления отладочных символов. Чтобы удалить ее, выполните следующую команду:
Примечание. $OBJCOPY указывает на определенную версию двоичного интерфейса приложения, к которой применяется команда strip. Например: ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objcopy .
Шаг 2. Загрузите файл деобфускации или файл отладочных символов
Теперь вам нужно загрузить полученные файлы в Play Console.
Важно! Этот шаг предназначен только для разработчиков APK-файлов. Если вы используете набор Android App Bundle и плагин Android Gradle 4.1 или более поздней версии, выполнять его не требуется. Файл деобфускации будет автоматически взят из набора, поэтому вам можно сразу переходить к шагу 3. Узнайте больше о наборах App Bundle на сайте для разработчиков Android.
Для этого выполните следующие действия:
- Откройте Play Console.
- Выберите приложение.
- В меню слева нажмите Версия > App Bundle Explorer.
- В окне выбора в правом верхнем углу экрана укажите нужный объект.
- Откройте вкладку Загрузки и прокрутите экран вниз до раздела "Ресурсы".
- Нажмите на значок загрузки рядом с нужным типом файла.
Информация о загрузке через API приводится на сайте Google Developers.
Шаг 3. Посмотрите трассировки стека ошибок после деобфускации
После того как вы загрузите эти файлы в Play Console, к последующим сбоям и ошибкам ANR будет применяться деобфускация. Трассировки стека для них можно посмотреть на странице приложения Сбои и ANR.
- Откройте Play Console.
- Выберите приложение.
- В меню слева выберите пункт Качество > Android Vitals > Сбои и ANR.
- Выберите ошибку.
- В разделе "Трассировка стека" вы увидите трассировки после деобфускации и добавления отладочных символов.
Важно! Деобфускация будет применяться только к тем сбоям и ошибкам ANR, которые возникнут после загрузки файла сопоставления. К более ранним сбоям и ошибкам ANR она не применяется.
Часто задаваемые вопросы
Для добавления символов в нативных приложениях в Play Console используется ndk-stack, а в Java-приложениях – ReTrace. При желании вы можете скопировать обфусцированные стеки ошибок из Play Console, а затем добавить отладочные символы в подходящем инструменте. Однако эти действия необходимо выполнять вручную для каждого стека ошибок, что замедляет процесс и отнимает много времени. Просто загрузите файлы деобфускации, а остальное Play Console сделает автоматически.
Деобфускация применяется только к ошибкам ANR и сбоям, возникающим после загрузки файла сопоставления или файла с отладочными символами. Подождите, пока информация о новых сбоях и ошибках ANR будет получена с устройств пользователей. После этого вы сможете просматривать в Play Console данные с деобфускацией.
Потому что файл деобфускации или файл с отладочными символами загружен не полностью. Убедитесь, что вы загружаете файл с отладочными символами для всего приложения, особенно если используете комплексный или многоэтапный процесс сборки. Нередко частичная деобфускация связана с использованием сторонних библиотек. В этом случае нужно запросить файлы деобфускации у поставщика библиотеки.
Без файлов деобфускации одинаковые ошибки ANR или сбои на 32- и 64-разрядных устройствах либо на устройствах ARM и Intel будут показаны отдельно. После загрузки файлов деобфускации мы можем объединить эти сбои в группы, чтобы нагляднее показать наиболее серьезные ошибки ANR и сбои в вашем приложении.
Если вы забудете загрузить файл для новой версии приложения, ошибки ANR и сбои снова будут обфусцироваться. Загрузите файл, следуя инструкциям выше. Деобфускация применяется только к ошибкам ANR и сбоям, возникающим после загрузки файла сопоставления или файла отладочных символов. Подождите, пока информация о новых сбоях и ошибках ANR будет получена с устройств пользователей. После этого вы сможете просматривать в Play Console данные с деобфускацией.
Чтобы не забывать загружать файлы, рекомендуем использовать в процессе сборки наборы App Bundle и плагин Android Gradle 4.1 или более поздней версии. В этом случае вы сможете настроить автоматическое добавление файла отладочных символов в набор App Bundle, как указано на сайте для разработчиков Android.
- Откройте Play Console.
- Выберите приложение.
- В меню слева нажмите Версия > App Bundle Explorer.
- В окне выбора в правом верхнем углу экрана укажите нужный объект.
- Откройте вкладку Загрузки и прокрутите экран вниз до раздела "Ресурсы".
- Нажмите на значок удаления напротив неправильного файла деобфускации или файла отладочных символов.
- После того как он будет удален, нажмите на значок загрузки и выберите файл, подходящий для данной версии приложения.
После того как он будет загружен, деобфускация будет применяться только к последующим ошибкам ANR и сбоям. Подождите, пока информация о новых сбоях и ошибках ANR будет получена с устройств пользователей. После этого вы сможете просматривать в Play Console данные с деобфускацией.
Совет. Чтобы избежать ошибок при загрузке файла, рекомендуем использовать в процессе сборки наборы App Bundle и плагин Android Gradle 4.1 или более поздней версии. В этом случае вы сможете настроить автоматическое добавление файла отладочных символов в набор App Bundle, как указано на сайте для разработчиков Android.
Информация об этом приводится на сайте для разработчиков Android.
Иногда система обнаруживает ошибку ANR, но при этом не получает трассировку стека. В этом случае запись об ошибке ANR сохраняется, чтобы вам было проще выявлять проблемы со стабильностью приложения, а трассировка стека не отображается. Чтобы было удобнее находить и исправлять похожие ошибки ANR без трассировки стека, они объединяются в группы по типу и классу действия.
Или то, почему вы не можете издать свою улучшенную версию Counter Strike и уехать жить на Гавайи.
О чём речь?
Обфуска́ция (от английского obfuscate — делать неочевидным, запутанным, сбивать с толку) в широком смысле - приведение исходного текста или исполняемого кода программы к виду, сохраняющему её функциональность, но затрудняющему анализ, понимание алгоритмов работы и модификацию при декомпиляции.
Красивый пример из Википедии кода, прошедшего обфускацию.
Далее в программе
Зачем это нужно?
Как это должно работать?
Как это работает?
Состояние дел сейчас
Зачем это нужно?
Как известно, одним из основных методов взлома программного обеспечения является исследование кода, полученного в результате работы дизассемблера на предмет уязвимостей. На основе такого когда нетрудно, например, составить программу генерации ключей активации коммерческого программного обеспечения или, наоборот, внести в исполняемый файл изменение - патч, позволяющий злоумышленникам отключить "нежелательные" модули исходной программы.
Всему вышеперечисленному как раз и может противодействовать специальная программа - обфускатор.
Так же, алгоритмы обфускации активно используются не только для затруднения анализа кода, но и для уменьшения размера программного кода, что, в свою очередь, активно используется при разработке различных веб-сервисов и баз данных.
Как это должно работать?
Как понятно из вышесказанного, методы обфускации должны усложнить код, преобразовав его таким образом, чтобы скрыть от третьих лиц логику его работы.
В идеале хотелось бы, чтобы программа, прошедшая обфускацию, давала бы не больше информации нежели чёрный ящик, имитирующий поведение исходной программы. Гипотетический алгоритм, реализующий такое преобразование называется "Обфускация чёрного ящика". Декомпиляция зашифрованной таким образом программы дала бы злоумышленникам не больше информации, чем декомпиляция клиента мессенджера, представляющего собой лишь обёртку над апи "настоящего" приложения, что бы полностью решило поставленную в предыдущем блоке проблему. Однако показано [3] , что реализация такого алгоритма для произвольной программы невозможна.
Как это работает
Большинство методов обфускации преобразуют следующие аспектов кода:
• Данные: делают элементы кода похожими на то, чем они не являются
• Поток кода: выставляют исполняемую логику программы абсурдной или даже недетерминированной
• Структура формата: применяют различное форматирование данных, переименование идентификаторов, удаление комментариев кода и т.д.
Инструменты обфускации могут работать как с source или байт кодом, так и с бинарным, однако обфускация двоичных файлов сложнее, и должна варьироваться в зависимости от архитектуры системы.
При обфускации кода, важно правильно оценить, какие части когда можно эффективно запутать. Следует избегать обфускации кода, критичного относительно производительности.
Методы
1. Преобразование данных
Одним из наиболее важных элементов обфускации является преобразование данных, используемых программой, в иную форму, оказывающее минимальное виляние на производительность кода, но значительно усложняющее хакерам возможность обратного инжинирнга.
По ссылке можно ознакомится с интересными примерами использования двоичной формы записи чисел для усложнения читабельности кода, а так же изменений формы хранения данных и замены значений различными тождественными им выражениями.
2. Обфускация потока управления кодом
Обфускация потока управления может быть выполнена путем изменения порядка операторов выполнения программы. Изменение графа управления путем вставки произвольных инструкций перехода и преобразования древовидных условных конструкций в плоские операторы переключения, как показано на следующей диаграмме.
3. Обфускация адресов
Данный метод изменяет структура хранения данных, так чтобы усложнить их использование. Например алгоритм, может выбирать случайными адреса данных в памяти, а также относительные расстояния между различными элементами данных. Данный подход примечателен тем, что даже если злоумышленник и сможет "декодировать" данные, используемые приложением на каком-то конкретном устройстве, то на других устройствах он всё равно не сможет воспроизвести свой успех.
4. Регулярное обновление кода
Этот метод предотвращает атаки, регулярно выпуская обновления обфусцированного программного обеспечения. Своевременные замены частей существующего программного обеспечения новыми обфусцированными экземплярами, могут вынудить злоумышленника отказаться от существующего результата обратного анализа, так как усилия по взлому кода в таком случае могут превысить получаемую от этого ценность.
5. Обфускация инструкций ассемблера
Преобразование и изменение ассемблерного когда также может затруднить процесс обратного инжиниринга. Одним из таких методов является использование перекрывающихся инструкций (jump-in-a-middle), в результате чего дизассемблер может произвести неправильный вывод. Ассемблерный код также может быть усилен против проникновения за счёт включения бесполезных управляющих операторов и прочего мусорного кода.
6. Обфускация отладочной информации
Отладочную информацию можно использовать для обратного проектирования программы, поэтому важно блокировать несанкционированный доступ к данным отладки. Инструменты обфускации достигают этого, изменяя номера строк и имена файлов в отладочных данных или полностью удаляя из программы отладочную информацию.
Заключение
Я не стал описывать историю развития различных подходов к обфускации, так как на мой взгляд, она неплохо отражена в уже существующей на Хабре статье.
Данная статья была написана в 2015 году, и мне не удалось найти в интернете существенного количества статей и иных материалов на тему моего поста, накопившихся за это время. На мой взгляд, в наш век всё большую популярность приобретает разработка всевозможных веб приложений, которые мало нуждаются в обфускации в качестве метода защиты информации. Однако как раз таки сжатие исходного кода программ, при помощи методов обфускации в таких приложениях зачастую оказывается полезным.
В заключение, хотел бы добавить, что при использовании методов обфускации не следует пренебрегать и прочими методами защиты вашего кода, ведь обфускация далеко не серебряная пуля в вопросе защиты программ от взлома.
Ссылки и источники
[3] Barak B., Goldreich O., Impagliazzo R., Rudich S., Sahai A., Vadhan S. and Yang K. «On the (im) possibility of obfuscating programs.» CRYPTO 2001.
Что такое обфускация? Это процесс «запутывания» кода. Но когда мы размышляем об обфускации, то в любом случае появляется вопрос: а существует ли обратный процесс, чтобы можно было «распутать» «запутанный» код?
Однозначного ответа на этот вопрос нет. То есть, программы для выполнения обфускации есть, а таких программ, чтобы обфусцированный код приводили в первозданный образ – нет. Однако сам процесс деобфускации существует.
Под деобфускацией понимают процесс при котором «запутанный» код становится более читабельным и понятным. По сути, это и есть процесс оптимизации кода, который рассчитан на удаление всего лишнего из кода. А как мы помним, при обфускации добавляется много «мусорного» ненужного кода, который затрудняет чтение кода программы.
В большинстве компиляторов процесс оптимизации кода встроен по умолчанию. Поэтому считается, что обфускация программ на высокоуровневых языках программирования менее продуктивна, так как после прохождения кода программы через компилятор он подвергнется оптимизации.
Получается, что деобфускация кода — это и есть оптимизация кода. Но и это еще не все. К процессу деобфускации кода можно отнести еще процедуру декомпиляции программного кода. При декомпиляции программ из двоичного кода на выходе получается более-менее понятное представление исходного кода программы на каком-либо языке программирования высокого уровня. А это значит, что процед уру реверсивной инженерии после декомпиляции осуществить легче.
Также к процессу деобфускации подключаются дополнительные инструменты в виде статического и динамического анализа программ.
В конечном итоге получаем, что деобфускация — это не какая-то конкретная программа, а это комплекс мер, связанных с оптимизацией, декомпиляцией и анализом обфусцированного кода.
Заключение
Обфускация кода — это всего лишь дополнительный инструмент для защиты кода от постороннего несанкционированного вмешательства. В качестве единственного инструмента защ иты да нный процесс практически не имеет ценности. Но в совокупности с другими инструментами защиты он существенно снижает вероятность изучения исходного кода программы.
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
В прошлых статьях (первая часть, вторая часть) мы узнали, насколько действительно легко взломать и модифицировать приложение для Android. Однако не всегда все бывает так просто. Иногда разработчики применяют обфускаторы и системы шифрования, которые могут существенно осложнить работу реверсера, поэтому сегодня мы поговорим о том, как разобраться в намеренно запутанном коде, а заодно взломаем еще одно приложение.
WARNING
Вся информация предоставлена исключительно в ознакомительных целях. Ни редакция, ни автор не несут ответственности за любой возможный вред, причиненный материалами данной статьи.Обфускаторы
На самом деле ты уже должен быть знаком как минимум с одним методом обфускации (запутывания) кода. В прошлой статье мы внедряли зловредную функциональность в WhatsApp, и если ты внимательно читал статью и сам пробовал декомпилировать WhatsApp, то наверняка заметил, что большинство классов приложения, почти все его методы и переменные имеют странные имена: aa, ab либо что-то вроде 2F323988C, если смотреть код с помощью декомпилятора jadx.
Это и есть обфускация, и я могу с полной уверенностью утверждать, что проделана она с помощью инструмента ProGuard из комплекта Android Studio. Именно он выдает на выходе такие странные имена классов, методов и переменных, а кроме того, удаляет неиспользуемый код и оптимизирует некоторые участки приложения с помощью инлайнинга методов.
Пропущенный через ProGuard код более компактен, занимает меньше памяти и намного более сложен для понимания. Но только в том случае, если это большое приложение. Разобраться, что делает простой обфусцированный код, очень легко:
Но представь, если из подобных буквенных, цифровых или буквенно-цифровых обозначений (ProGuard позволяет использовать любой словарь для генерации идентификаторов) будет состоять громоздкое приложение в десятки тысяч строк кода:
И так на тысячи строк вперед, а дальше твой декомпилятор может поперхнуться кодом и выдать вместо Java нечто вроде этого:
Недурно, не правда ли? А теперь представь, что эти строки состоят не из обычных символов алфавита, а из символов Unicode (так делает DexGuard, коммерческая версия ProGuard) или наборов вроде l1ll1, повторяющихся раз этак пятьдесят. Разработчик вполне может применить и более мощные средства обфускации, нашпиговав приложение бессмысленным кодом. Такой код не будет выполнять никаких полезных функций, но направит тебя совершенно не в ту сторону, что грозит как минимум потерей времени.
Не желая его терять, ты можешь начать с поиска строк, которые приведут тебя к цели: это могут быть различные идентификаторы, с помощью которых приложение регистрирует себя на сервере, строки, записываемые в конфиг при оплате, пароли и так далее. Однако вместо строк ты вполне можешь увидеть нечто вроде этого:
Это зашифрованная строка, которая расшифровывается во время исполнения приложения. Такую защиту предлагают DexGuard, Allatory и многие другие обфускаторы. Она действительно способна остановить очень многих, но соль в том, что если есть зашифрованный текст, значит, в коде должен быть и дешифратор. Его очень легко найти с помощью поиска по имени переменной (в данном случае zb). При каждом ее использовании всегда будет вызываться метод, дешифрующий строку. Выглядеть это может примерно так:
Здесь метод a() класса a и есть дешифратор. Поэтому, чтобы узнать, что внутри зашифрованной строки, нужно просто добавить в дизассемблированный код приложения вызов функции Log.d("DEBUG", a.a(zb)) и собрать его обратно (как это сделать, описано в первой статье цикла). После запуска приложение само выдаст в лог дешифрованную строку. Лог можно просмотреть либо подключив смартфон к компу и вызвав команду adb logcat, либо с помощью приложения CatLog для Android (требует root).
Нередко, правда, придется попотеть, чтобы найти дешифратор. Он может быть встроен во вполне безобидную функцию и дешифровать строку неявно, может состоять из нескольких функций, которые вызываются на разных этапах работы со строкой. Сама зашифрованная строка может быть разбита на несколько блоков, которые собираются вместе во время исполнения приложения. Но самый шик — это класс-дешифратор внутри массива!
DexGuard имеет функцию скрытия классов, которая работает следующим образом. Байт-код скрываемого класса извлекается из приложения, сжимается с помощью алгоритма Gzip и записывается обратно в приложение в форме массива байтов (byte[]). Далее в приложение внедряется загрузчик, который извлекает код класса из массива и с помощью рефлексии создает на его основе объект, а затем вызывает нужные методы. И конечно же, DexGuard использует этот трюк для скрытия дешифратора, а также кода других классов по желанию разработчика. Более того, скрытые в массивах классы могут быть зашифрованы с помощью скрытого в другом массиве дешифратора!
Так что, если ты имеешь дело с приложением, имена классов в котором написаны на китайском или языке смайликов, а по коду разбросаны странные массивы длиной от нескольких сот элементов до десятков тысяч, знай — здесь поработал DexGuard.
С рефлексией вместо прямого вызова методов объекта ты можешь столкнуться и в других обстоятельствах, не связанных со скрытием классов. Рефлексия может быть использована просто для обфускации (как в случае с обфускатором Allatory). Тогда вместо такого кода:
ты увидишь нечто вроде этого:
А если используется шифрование — это:
Но в реальном приложении тебе, скорее всего, придется расшифровать все эти строки с помощью описанного выше способа просто для того, чтобы понять, какие объекты и методы вызывает приложение в своей работе.
Упаковщики
А еще есть упаковщики. Это другой вид защиты, основанный не на запутывании кода, а на его полном скрытии от глаз реверсера. Работает он так. Оригинальный файл classes.dex (содержащий код приложения) переименовывается, шифруется и перемещается в другой каталог внутри пакета APK (это может быть каталог assets, res или любой другой). Место оригинального classes.dex занимает распаковщик, задача которого — загрузить в память оригинальный classes.dex, расшифровать его и передать ему управление. Для усложнения жизни реверсера основная логика распаковщика реализуется на языке си, который компилируется в нативный код ARM с применением средств обфускации и защиты от отладки (gdb, ptrace).
Вычислить наличие упаковщика в APK совсем нетрудно. Для этого достаточно взглянуть на содержимое каталога lib/armeabi. Если ты найдешь в нем файл libapkprotect2.so, значит, применен упаковщик ApkProtect, файл libsecexe.so — Bangle, libexecmain.so — ljiami.
Деобфускаторы
Как видишь, инструментов обмануть тебя и отбить желание расковыривать приложение у разработчиков предостаточно, поэтому и ты должен быть вооружен. В первую очередь нужен хороший декомпилятор. На всем протяжении цикла мы использовали бесплатный jadx, вполне неплохо справляющийся с этой задачей. Кроме этого, он имеет встроенный деобфускатор, трансформирующий идентификаторы вида a, az, l1l1l1l1. или состоящие из символов Unicode в цифро-буквенные идентификаторы, уникальные для всего приложения. Это позволяет никогда не спутать метод a() класса a с методом a() класса b и легко находить нужные идентификаторы с помощью глобального поиска.
Также тебе понадобится инструмент для дампа информации о пакете. Не такой информации, как его содержимое и дата сборки, а информации об используемых в пакете средствах обфускации и защиты. В первую очередь стоит обратить внимание на ApkDetecter. Также можно попробовать APKiD.
Оба инструмента должны показывать, был ли применен тот или иной обфускатор или упаковщик в отношении приложения, но часто не показывают ничего. Это вполне закономерно, обфускаторы эволюционируют, меняя логику своей работы, приемы обфускации и скрытия от подобных инструментов.
По этой же причине нередко оказываются бессильны и деобфускаторы, такие как Java Deobfuscator и Simplify. Но это совсем не значит, что их не стоит применять. Java Deobfuscator работает исключительно с байт-кодом Java, поэтому перед тем, как его использовать, APK нужно перегнать в JAR с помощью dex2jar.
Далее следует натравить на полученный JAR-файл Java Deobfuscator с указанием используемого «трансформера»:
Данная команда применит к приложению трансформер allatori.StringEncryptionTransformer, расшифровывающий зашифрованные с помощью Allatory строки, и запишет результат в Приложениепоследеобфускации.jar. После этого приложение можно декомпилировать, но не с помощью jadx (он работает только с байт-кодом Android Dalvik), а, например, с помощью JD-GUI.
Java Deobfuscator поддерживает более десятка трансформеров, позволяющих расшифровывать строки, зашифрованные другими обфускаторами, конвертировать вызовы с помощью рефлексии в обычные, удалять мертвый код и так далее. Поэтому можно поэкспериментировать.
Если же Java Deobfuscator не дал результатов, стоит попробовать Simplify. Это так называемый динамический деобфускатор. Он не анализирует байт-код, пытаясь найти в нем следы работы обфускаторов и отменить внесенные ими изменения, как это делает Java Deobfuscator. Вместо этого он запускает дизассемблированный код smali внутри виртуальной машины, позволяя приложению самостоятельно расшифровать строки, затем удаляет мертвый неиспользуемый код и рефлексию. На выходе ты получишь dex-файл, который можно декомпилировать с помощью jadx.
Использовать Simplify довольно просто:
Код до применения.
. и после применения Simplify
Но как быть с упаковщиками? Для этого есть инструмент Kisskiss. Для его работы нужен смартфон с правами root и активированным режимом отладки (ADB) в режиме root (в CyanogenMod можно включить в «Режиме для разработчиков»). Также на компе понадобится команда adb:
Далее Kisskiss необходимо установить на смартфон:
Запустить нужное приложение на смартфоне и выполнить команду (на компе)
После этого Kisskiss сделает дамп памяти процесса и запишет его в odex-файл. Его можно сконвертировать в dex с помощью уже знакомого нам baksmali:
И декомпилировать с помощью jadx.
Небольшой (на самом деле большой) пример
Ну и в заключение приведу небольшой пример взлома обфусцированного приложения. Он не очень сложный, без шифрования и упаковки, но позволяет понять логику работы с кодом, по которому трудно ориентироваться из-за измененных идентификаторов. В этот раз мы будем работать с EZ Folder Player, а именно уберем из него рекламу.
Для начала установим приложение на смартфон и внимательно проследим за тем, в каких случаях и на каких экранах появляется реклама. Нетрудно заметить, что она есть только на экране выбора файла. Это важная информация, которая нам очень пригодится. Теперь попробуем включить режим полета, завершить приложение и вновь запустить его. Реклама полностью исчезает. Это тоже важно, приложение явно умеет самостоятельно включать и выключать показ рекламы, а значит, все, что нам требуется, — это просто найти данный код и либо удалить «включатель» рекламы, либо самостоятельно вызвать «выключатель».
Теперь скачиваем приложение на комп с помощью APKPure, кладем его в каталог
/tmp и переименовываем в ez.apk для удобства работы. Открываем пакет в jadx-gui и видим множество каталогов (Java-пакетов). Нужный нам пакет носит имя самого приложения: com.dp.ezfolderplayer.free. Открываем его, внутри множество классов с именами вида C0770p, C0763i и так далее, почти все переменные и методы любого класса носят имена типа f2881, f2284:
Не внушает оптимизма, правда? Совсем непонятно, с чего начать. Точнее, было бы непонятно, если бы мы не знали, что реклама отображается исключительно на экране выбора файла. Проматываем вниз и видим нужный нам класс FilesActivity.
Но почему он не обфусцирован? По простой причине: каждый экран приложения в Android — это так называемая активность (activity), а все активности должны быть явно перечислены в манифесте приложения — Manifest.xml. Если бы обфускатор изменил имя класса-активности, Android просто не смог бы его найти и приложение вывалилось бы с ошибкой.
Открываем FilesActivity и сразу смотрим, работает ли он с провайдером рекламы напрямую (или же делает это через другой класс либо с помощью рефлексии). Для этого взглянем на директивы import:
Да, класс явно вызывает методы пакета com.google.android.gms.ads (стандартный гугловский провайдер рекламы), иначе зачем бы ему его импортировать. Осталось найти место, где он это делает, и просто изменить или удалить код так, чтобы рекламы не было видно. Ближе к концу кода находим это:
Несмотря на применение обфускации, код вполне понятный, мы видим нормальные имена классов (AdView, AdSize, LinearLyout) и методов (setAdUnitId, findViewById). Легко можем понять, что делает этот код: создает новый графический элемент (View) с рекламой, настраивает его вид, а затем загружает в него рекламное объявление. Вопрос только в том, почему мы это видим? Обфускатор настолько плох и не справляется со своей работой?
На самом деле все намного проще: обфускатор работает исключительно с кодом самого приложения и поэтому неспособен запутать код внешних для него классов (а это классы пакета com.google.android.gms.ads и все системные классы). Поэтому зачастую логику работы обфусцированного кода довольно легко проследить по вызовам внешних API. В случае с EZ Folder Player мы не знаем имя загружающего рекламу метода (m4989q) и имя объекта, хранящего View (f2394K), но видим все его методы и обращения к системным API (тот же findViewById), что позволяет сделать вывод о том, зачем весь этот код.
А теперь о том, как все это отключить. Самый простой вариант — просто удалить весь код метода, но это может привести к ошибкам в других участках кода, которые, возможно, обращаются к объекту f2493K. Вместо этого мы пойдем немного другим путем. Обрати внимание на пятую строку кода. Она вызывает метод setVisibility объекта f2493K, который, в свою очередь, хранит View рекламного блока. Метод setVisibility позволяет настраивать отображение View, указав одно из возможных состояний с помощью числа. Если мы взглянем на справку Android, то узнаем, что 8 означает: View должен быть полностью убран с экрана.
Другими словами, данный код формирует View с рекламным блоком, а затем сам же его убирает с экрана. Но зачем? Затем, что нет смысла показывать рекламный блок, если он еще не загружен (помнишь исчезновение рекламы в режиме полета?). Но как приложение узнает, что реклама загрузилась? Согласно документации — с помощью AdListener: разработчик создает класс-наследник AdListener, создает рекламный View, вызывает его метод setAdListener, в качестве аргумента передавая ему объект класса-наследника AdListener, и вызывает loadAd для загрузки рекламы. Когда реклама загрузится, будет вызван метод onAdLoaded() класса-наследника AdListener.
А теперь смотри на строку:
C0766l не может быть ничем иным, кроме класса-наследника AdListener. Открываем его в jadx и видим:
Бинго! Всего одна строка кода, которая делает рекламный View видимым (значение 0). Если мы ее удалим, View останется невидим на все время работы приложения.
Но вот незадача: в дизассемблированном с помощью apktool коде smali нет класса C0766l. Такой идентификатор мы видим только в jadx, потому что он переименовал класс. Но зато он оставил для нас комментарий касательно настоящего имени класса:
Открываем ez/smali/com/dp/ezfolderplayer/free/l.smali и видим следующий код:
Это и есть строка «this.f2868a.f2493K.setVisibility(0);». Чтобы убрать ее, необходимо удалить почти весь метод, оставив только четыре строки:
Остается только собрать APK и установить на девайс:
Выводы
Несмотря на существование большого количества обфускаторов и других средств защиты приложений, подавляющее большинство разработчиков используют исключительно встроенный в Android Studio ProGuard. Разобраться в коде приложения, обфусцированного с его помощью, совсем несложно, но и разбираться в работе более продвинутых обфускаторов тоже необходимо. Хотя бы для того, чтобы уметь реверсить вирусы. Ты же не собираешься заниматься варезом, правда?
Евгений Зобнин
Редактор рубрики X-Mobile. По совместительству сисадмин. Большой фанат Linux, Plan 9, гаджетов и древних видеоигр.
Читайте также: