- Название: Android UnCrackable L2
- Категория: reverse (android)
- Платформа:
Ссылка скрыта от гостей
This app holds a secret inside. May include traces of native code.
Продолжение серии райтапов на небольшие андроид-крякмисы от OWASP! Сегодня будем разбирать второй уровень, райтап на первый советую посмотреть тут, сегодня автор часто будет на него ссылаться.
Итак, наша задача - достать "секрет" из приложения, что бы под ним не подразумевалось. Попробуем запустить его (я буду использовать рутированное устройство):
Как и на прошлом уровне, наше приложение детектит наличие рута на устройстве. Единственное различие - оно сразу же вылетает после этого виджета (поверьте, я минуту пытался успеть его заскринить XD). Как и в прошлый раз, я воспользуюсь плагином Magisk'а для скрытия рута от приложения - DenyList:
Получилось! Видимо, в этом уровне авторы не стали улучшать прошлые механизмы обнаружения прав суперпользователя. Нам же лучше - теперь можно свободно потыкать приложение: в распоряжении имеется поле для ввода текста, кнопка проверки и благодарность авторам. По традиции попытаем удачи:
Эх, опять не повезло... Ладно, тогда займёмся делом - закинем наш apk в JADX и сразу же заглянем в MainActivity:
Как и в прошлый раз, здесь есть проверка на наличие рута. Функции здесь точно такие же, как в прошлом уровне: несколько тривиальных проверок на наличие бинарника su и связанных с ним файлами, и проверка ядра на test-keys. А вот с дебаггингом неловко вышло: в прошлой статье я принял 34-ю строчку за защиту от дебаггинга - оказалось, что это лишь уведомление, а защита, появившаяся в этом крякмисе, будет дальше:
Но мы народ простой: сначала пойдём лёгким путём - простой статикой, а если не получится, то уже будем пытаться дебажить. Давайте посмотрим на что-то, что связано с нашим полем для ввода строки:
Секрет нашего будущего успеха весьма банален: он заключается в this.m.a(obj), а если быть точнее, в результате работы этой функции, получаемую на вход нашу строку. Заглянем в функцию a():
Э... Что-то тут не то, не так ли? Этого явно недостаёт до проверки нашей строки. Раз с функцией a() мы прогорели, то заглянем в класс m, может, там будет что-то интересное:
А вот с этим уже можно работать! Судя по всему, у нас загружается некая библиотека foo, в которой присутствует интересующая нас функция проверки. И если поискать в ресурсах приложения, мы, в конечном итоге, действительно наткнёмся на эту библиотеку:
Побайтово её прочитать, увы, не получится. Но на то мы и ревёрсеры (по крайней мере, я пытаюсь им казаться), не так ли? Загрузим эту библиотеку в IDA.
Перед вами список всех функций, обнаруженных декомпилятором. При ревёрсе всегда важно помнить контекст ваших действий; и наш, в данном случае - поиск функции, отвечающий за проверки введённой строки на правильность. Согласитесь, лучше всего для нас подойдёт маячащая в списке _strncmp, не правда ли? Посмотрим, где идёт обращение к этой функции:
Самый сок! Согласитесь, выглядит вполне подходяще - загрузка строки в v4 и последующее сравнение v4 с v6, где фигурирует число 23 - длина этой строки. Давайте попробуем ввести её в приложении:
Получилось, второй уровень пройден! Имхо, совру, если скажу, что было нелегко, но планка сложности постепенно поднимается - появился какой-никакой антидебаггинг и сторонняя библиотека.
И ещё, дорогие пытливые читатели, напоминаю, что статический анализ - далеко не единственный способ решать такие крякмисы; вы всегда можете попробовать что-то своё (например, Frida, XPosed и т.д.) и поделиться своим решением: уверен, остальным будет интересно, если не ещё интереснее =]
Надеюсь, этот небольшой райтап поможет вам в нашей нелёгкой стезе.
Удачного ревёрса!
made 4 @rev_with_da_boys