HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Этичный хакинг или пентестинг > Задания/Квесты/CTF/Конкурсы
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 17.08.2024, 15:05
Don Reverso
Новичок
Регистрация: 17.05.2025
Сообщений: 0
С нами: 524585

Репутация: 0
По умолчанию

  • Название: Android UnCrackable L3
  • Категория: reverse (android)
  • Платформа: mas.owasp.org
Иногда я буду ссылаться на предыдущие две статьи, посвящённые крякми L1 и L2, поэтому рекомендую к ознакомлению. А на очереди третьего уровня уровень сложности крякми от OWASP- уже довольно проблематичный экземпляр. Но обо всём по порядку!

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



Что радует - из приложения нас моментально не выкидывает, как в L2. Можно было бы, как я и раньше делал, воспользоваться модулем DenyListи надеяться, что приложение не задетектит рут... Но сегодня мы пожалеем тех, у кого этого модуля нет, и поступим по другому: пы пропатчим само приложение!

Для начала откроем его в JADX-GUI (сразу MainActivity):



Сразу с самого начала бросается в глаза xorkey- это нам может пригодиться, запоминаем.



А здесь можно видеть один из методов защиты от патчеров - проверка библиотек и classes.dex на CRC-хэш. Запоминаем потенциальное место для патчинга и смотрим дальше.



Здесь идёт проверка на дебаггинг и наличие рута. Методы checkRoot1, 2, и3 остались с прошлых крякми, там всё то же самое. Если посмотреть на этот же код в smali, можно увидеть следующее:



Каждая проверка if-nez ведёт на метку cond_0041, куда нам точно не нужно попасть. В таком случае, можно было бы просто удалить эти строчки, а последнюю - if-eqz v0, :cond_0046 - просто заменить на goto. А можно просто из метки cond_0041сделать пустышку, удалив вызов метода showDialog(). Это куда проще - этим и воспользуемся. И заодно, раз уж мы тут, можно и предоставить себе возможность спокойно дебажить приложение! Для этого понадобится убрать ещё 2 строчки:



Но не забывайте - в таком случае в собранном из отредактированных smali-файлов classes.dex изменитсяCRC-хэш, а значит, нам нужно пропатчить ещё и тот кусок кода. Если хорошенько туда присмотреться, то можно понять, что самое опасное для нас - это последний System.exit():



Можно было бы удалить этот вызов - пускай программа высчитывает хэши и логирует об ошибках на здоровье. А можно просто добавить return-void сразу после объявления метода - и на выходе verifyLibs() окажется просто функцией, которая ничего не делает. Как вы захотите это обойти и захотите ли - дело ваше.

А нам для нашего грядущего патчинга JADXнедостаточно (без плагинов). Для этого нужно самим распаковать приложение в smali через apktool(я буду пользоваться удобной GUI-версией). Декомпилируем наш apk:



После этого рядом с ним у вас должна появиться папка со smali-кодом, ресурсами приложения и прочим. Так как JADXпод капотом использует apktool, то имена классов и методов, что там, что там, совпадают. Поэтому нам нужен тот самый MainActivityпо пути
Код:
smali/sg/vantagepoint/uncrackable3/
, который мы смотрели раньше. В нашем случае он разделился на несколько файлов MainActivity$n. Открываем их в любом текстовом редакторе, ищем непонравившиеся нам строчки (они не в одном файле), и смело их удаляем или комментируем (# в начале).

Когда вы будете пытаться собрать приложение обратно, не забудьте проверить, что в пути к папке с кодом нет символов кириллицы - иначе такая вот петрушка вылезет:



Переместите папку в другое место и соберите всё, как полагается:



Установим приложение на устройство и попробуем зайти в него:



Получилось! Мы успешно пропатчили приложение, обойдя его защиту. Чем не повод для гордости?

Но не стоит забывать о главной цели - нам нужно достать подходящую под формочку строку. В этот раз разнообразим нашу методологию и попробуем frida. Не буду вещать сейчас, как она устанавливается, скажу лишь, что мне помог этот гайд. Подключаем отладку через adb, запускаем на смартфоне frida-server и проверяем его работоспособность с помощью
Код:
frida-ps -Ua
. Если всё прошло хорошо, то на выходе вы получите список пакетов с их названиями (все лишние я замазал):



Если же нет - гугл в помощь, товарищи. Из наблюдаемых нами ивентов, которые могут помочь нам с решением, присутствует только кнопка Verify, с соответствующим метод onClick. Попробуем с помощью frida-trace просмотреть, какой класс отвечает за эту кнопку. Конечная команда будет выглядеть так:
Код:
frida-trace -U -F -i "*!onClick"
(U - usb-устройство, F - текущее открытое приложение,j - паттерн вида class!method). Пробуем:



И получаем такую хренотень. Гугл на такую ошибку ничего дельного не выдаёт, что же делать? После получаса активного поиска причины этой ошибки и листинга логов (
Код:
logcat | grep -i "uncrackable"
) я нашёл её:



Всё-таки фридуприложение видит и защищается от неё. И если в самом приложении мы уже все виды защиты нейтрализовали, остаются только подключаемые библиотеки - не зря же их на CRCпроверяли?

Сначала глянем libfoo.so (x86_64) в IDA, для начала откроем строки:



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



А вот и ещё одна мешающая нам защита - уже от fridaи xposed. Её логика проста: она постоянно читает данные из
Код:
/proc/self/maps
, а когда ей это не удаётся - ругается. Можно пропатчить её так: сразу после начала, до каких-либо пушей (пока сверху в стеке у нас лежит адрес возврата) прописать ret, чтобы функция сразу же умирала. Для этого вам очень поможет этот сайт- он может переводить байткод в ассемблерные инструкции и наоборот. Первой инструкцией в функции идёт push rbp (0x55) - её можно заменить на ret (0xC3). Обратите внимание - когда вы патчите программу, вам необходимо, чтобы общее количество байт было одинаково. Соответственно, если патчить без жутких костылей, то количество байт в заменяющей инструкции должно не превосходить количество байт в заменяемой. Если они равны - прекрасно! Если в заменяющей меньшее количество байт, то добавьте, сколько нужно до равного числа, nop'ов (0x90). В нашем случае обе инструкции занимают 1 байт, соответственно, нам лишь нужно переписать 55на C3:





Если вы всё сделали правильно, то у вас должен смениться код:



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



.
Ну и, конечно, с помощью apktoolсоберите заново приложение с новой библиотекой - думаю, с этим у вас проблем не возникнет, только закройде IDAи удалите все остаточные файлы её базы данных, а то будет ошибка при сборке. И, наконец, попробуем с пропатченным приложением и его пропатченной библиотекой запустить всё ту же frida-trace:



Опять то же самое... Чекаем логи:



А помните, что у нас не одна библиотека, а целых 4? Кажется, нам придётся патчить именно ту библиотеку, архитектура которой совпадает с архитектурой вашего устройства, об этом я сразу как-то не подумал... Чтобы узнать, какая именно архитектура вам нужна, пропишите следующее:

Bash:


Код:
adb shell getprop ro.product.cpu.abi
Я на всякий случай распишу все возможные варианты: для патча Arm-библиотек я пользовался этим сайтом, он мне очень помог. Для библиотеки
Код:
arm64-v8a
достаточно заменить первые 4 байта на
Код:
C0 03 5F D6 (RET)
. А вот при патчинге библиотеки
Код:
armeabi-v7a
не забывайте немножко теории: там инструкции могут распознаваться в двух режимах: ARM и Thumb, каждый со своими опкодами. IDAподдерживает оба и позволяет переключаться между ними через виртуальный регистр, о чём она вас при открытии библиотеки предупредит (переключение на Alt+G). В режиме Thumbнужно заменить первые 2 байта на
Код:
70 47
, чтобы у вас получилась инструкция
Код:
BX LR
(аналог RET).

И теперь, пропатчив всё что только движется, снова собираем этот треклятый apk, устанавливаем, запускаем - и:



И наши старания оправдались!!! Отозвались 40функций - фрида работает! Давайте ещё раз глянем, что нам нужно сделать:





Судя по всему, check_code() загружается как нативная функция из библиотеки libfoo.so. Узреем её логику работы:



В 26-й строчке наглядно видно, что байты одного массива соответствующе ксорятся с другим. Напоминает xorkeyиз начала? Причём v4- судя по всему наш xorkey - мы получаем в 22строчке, а вот второй массив (v9) мелькает только в функции sub_FA0, куда передаётся его адрес. Можно предположить, что там - то, что там будет то, что при XORс xorkeyдаст правильный ответ. И всё было бы хорошо - можно было бы изучить sub_FA0и узнать, как геренируется этот секрет, но ревёрсить эту функцию... Ну...



...не самая лучшая идея. Мы настроили нашу программу под свободный дебаггинг/тамперинг, так что у нас есть 2 пути: либо можно решить через frida(находим базовый адрес libfoo.so, добавляем оффсет функции, и через функции onEnter/onLeave вытаскиваем готовый массив), либо можно отладить это дело через gdb. Признаюсь - этот райтап я писал долгое время, в процессе решения. Изначально я планировал решить крякми черезFrida, но почему-то она отчаянно не хотела находить нужную функцию (мистика =] ), поэтому я представлю своё решение через отладку... Прямо в IDA!

Чтобы вы не искали по всему интернету gdbserverпод arm64, вIDA PRO () в папке dbgsrvлежит любезно предоставленный HexRays android_server64. Его достаточно будет запустить из-под рута, через adbнастроить форвард порта - и можно спокойно дебажить библиотеку android-приложения!

Bash:


Код:
adb push android_server64 /data/local/tmp
adb shell
А затем в самом шелле:

Bash:


Код:
su
cd
/data/local/tmp
chmod
+x android_server64
./android_server64


Затем настройте форвардинг используемого порта:

Bash:


Код:
adb forward tcp:23946 tcp:23946
Надеюсь, вы ещё не удалили папку с патченной библиотекой? Если нет, то круто - напомню, что нас интересует функция, которая вызывается с адресом массива, с которым будет идти проверка - на ней и ставьте бряк:



В качестве дебаггера выберите
Код:
"Remote ARM Linux/Android debugger"
:



И дальше в
Код:
Debugger -> Debugger Options
в качестве адреса ставьте
Код:
127.0.0.1
, а в качестве порта - тот, который вы форвардили



Теперь запускайте приложение на смартфоне, и в
Код:
Debugger -> Attach to process
выбирайте
Код:
owasp.mstg.uncrackable3
:



После этого Ида начнёт судорожно качать библиотеки и скажет: "Я нашла точно такую же библиотеку, как у вас открыта, но она в папке с самим приложением. Хотите её отлаживать?"



Мы, конечно же, хотим, поэтому нажимаем "Same". После этого вы остановитесь в непонятном месте - это лишь инициализация библиотеки, так что смело жмём "Continue Process" (F9). А уже после этого можно ввести что-нибудь в формочку и нажать verify- и вы остановитесь на нужной вам функции:



Перешагните через эту функцию, не заходя внутрь (F8) и посмотрите, что в переменной v8:



Эти 24 байта - и есть наш секретный массив, теперь мы его можем спокойно расшифровать, используя ранее упомянутый xorkey:

Python:


Код:
xor_key
=
"pizzapizzapizzapizzapizz"
memory
=
"""[stack]:0000007FFA7C0CF8 DCB 0x1D
[stack]:0000007FFA7C0CF9 DCB    8
[stack]:0000007FFA7C0CFA DCB 0x11
[stack]:0000007FFA7C0CFB DCB 0x13
[stack]:0000007FFA7C0CFC DCB  0xF
[stack]:0000007FFA7C0CFD DCB 0x17
[stack]:0000007FFA7C0CFE DCB 0x49 ; I
[stack]:0000007FFA7C0CFF DCB 0x15
[stack]:0000007FFA7C0D00 DCB  0xD
[stack]:0000007FFA7C0D01 DCB    0
[stack]:0000007FFA7C0D02 DCB    3
[stack]:0000007FFA7C0D03 DCB 0x19
[stack]:0000007FFA7C0D04 DCB 0x5A ; Z
[stack]:0000007FFA7C0D05 DCB 0x1D
[stack]:0000007FFA7C0D06 DCB 0x13
[stack]:0000007FFA7C0D07 DCB 0x15
[stack]:0000007FFA7C0D08 DCB    8
[stack]:0000007FFA7C0D09 DCB  0xE
[stack]:0000007FFA7C0D0A DCB 0x5A ; Z
[stack]:0000007FFA7C0D0B DCB    0
[stack]:0000007FFA7C0D0C DCB 0x17
[stack]:0000007FFA7C0D0D DCB    8
[stack]:0000007FFA7C0D0E DCB 0x13
[stack]:0000007FFA7C0D0F DCB 0x14"""
.
split
(
)
secret
=
[
]
for
i
in
range
(
len
(
memory
)
)
:
if
memory
[
i
-
1
]
==
"DCB"
:
base
=
10
if
"x"
in
memory
[
i
]
:
base
=
16
secret
.
append
(
int
(
memory
[
i
]
,
base
)
)
for
i
in
range
(
len
(
secret
)
)
:
print
(
chr
(
ord
(
xor_key
[
i
]
)
^
secret
[
i
]
)
,
end
=
""
)
print
(
)
Запускаем:



Пробуем нашу строку:



Получилось! Поздравляю, мы решили уже довольно сложный крякми, в отличие от первых двух. И декомпилили приложение, и патчили smali, и даже обходили антидебаггинг в библиотеках под разные архитектуры, и дебажили одну из них... Но наши старания окупились!

Статья вышла немаленькой - я писал её три дня, в процессе решения самого крякми. Конечно, если бы получилось решить через Фриду, было бы чуточку полегче, но что есть, то есть - может, кто-то захочет решить по-своему =]

Надеюсь, этот немаленький райтап помог вам в нашей нелёгкой стезе.

Удачного ревёрса!

made 4@rev_with_da_boys
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.