Сегодня расскажу о том, как при пентесте приложений Android и iOS, получить конфиденциальную информацию из нативных библиотек. Речь пойдет о так называемой «отладке нативного кода Android или iOS».
Еще по теме: Как защитить нативную библиотеку
Способы отладки нативной библиотеки
Существует несколько способов извлечения данных из нативных библиотек, включая бесплатные и коммерческие отладчики:
- GDB (GNU Debugger) — бесплатный отладчик, требующий настройки и компиляции для Android. Позволяет отлаживать нативный код в реальном времени, предоставляя глубокий анализ выполнения программы.
- LLDB — встроенный отладчик в macOS, используемый для отладки iOS приложений. Предоставляет функциональность, схожую с GDB, и хорошо интегрируется с инструментами разработки Apple.
- IDA Pro — коммерческий дизассемблер и отладчик, поддерживающий множество архитектур, включая ARM и x86. Обладает мощными возможностями анализа и отладки нативного кода, популярен среди исследователей безопасности.
- JEB Decompiler — коммерческий декомпилятор и отладчик, поддерживающий отладку Android и iOS приложений. Предоставляет удобный интерфейс для анализа нативного кода и возможность декомпиляции в более читаемый вид.
- Frida — инструмент динамического инструментирования, позволяющий внедрять JavaScript код в работающие процессы. Может использоваться для отладки и модификации нативного кода, обеспечивая гибкость в анализе приложений.
- Android Studio + NDK — официальная среда разработки для Android, поддерживающая отладку нативного кода с помощью LLDB. Интегрируется с Android NDK для работы с C/C++ кодом, предоставляя комплексное решение для разработчиков.
- Xcode — официальная среда разработки для iOS, включающая встроенные инструменты для отладки нативного кода. Поддерживает отладку Objective-C и Swift кода, обеспечивая полный набор инструментов для разработки iOS приложений.
- Radare2 — открытый фреймворк для реверс-инжиниринга, поддерживающий анализ и отладку нативных библиотек. Предоставляет CLI интерфейс для продвинутых пользователей, позволяя выполнять глубокий анализ бинарного кода.
В нашем случае, для получения данных во время выполнения приложения Android будет использован GDB.
Нативный код в создании приложений
Нативный код в Android-разработке часто пишется на C/C++ и компилируется в бинарные файлы (.so), которые затем используются в мобильных приложениях. Эти библиотеки могут храниться в папке libs в структуре проекта.
Разработчики используют нативные библиотеки для выполнения критически важных задач, таких как обработка криптографических операций, генерация одноразовых паролей (OTP), и обнаружение рута устройства. Основная причина использования нативного кода — это как оптимизация производительности, так и защита кода от реверс-инжиниринга, поскольку бинарные файлы труднее анализировать, чем Java-код.
Для взаимодействия Java-кода с нативными библиотеками используется Java Native Interface (JNI) — фреймворк, который позволяет вызывать нативные функции из Java и наоборот. Это обеспечивает возможность интеграции высокопроизводительных нативных функций с удобством Java-разработки.
Отладка нативной библиотеки Android с GDB
Теперь давайте перейдем к практике. Я буду использовать уязвимое приложение HPAndro и его активность backdoor7.
Шаг 1: Перекомпилируем приложение с отладочными разрешениями.
Шаг 2: Открываем приложение в JADX-GUI. Используем функцию поиска, чтобы найти код активности backdoor7. Обращаем внимание на использование метода system.loadlibrary("backdoor7") и вызов init().
Шаг 3: В коде находим метод «hello», который принимает пользовательский ввод, передает его в нативную функцию и получает булево значение. Если значение true, приложение показывает скрытый флаг.
Шаг 4: Открываем файл библиотеки в Ghidra, radare2, IDA Pro или JEB. Анализируем код: он загружает пользовательский ввод, генерирует 4-значное число с помощью методов strcat, ldr и т.д. В конце видим метод strcmp, который сравнивает ввод пользователя и сгенерированный код, после чего возвращает флаг true или false в Java-код.
Код, который загрузит инструмент, будет на языке ассемблера, а значения хранятся в регистрах или памяти. Значения в левой части — это значения регистров, из которых мы будем получать данные. Я открыл файл lib.so архитектуры x86_64 в IDA Pro. Чтобы увидеть реальный код на языке C/C++, вы можете использовать Ghidra или IDA Pro.
Теперь переходим к отладке с помощью GDB:
Шаг 1: Копируем файл gdbserver из папки Android NDK в /data/local/tmp на устройстве Android через команду adb push.
Шаг 2: Открываем активность backdoor7 в приложении, вводим любое значение и нажимаем Enter. Это загрузит нужную нам библиотеку.
Шаг 3: Выполняем следующие команды:
1 2 3 4 |
su chmod +x gdbserver ./gdbserver :8000 --attach adb forward tcp:8000 tcp:8000 |
Шаг 4: После установки Cygwin и MSYS/mingw64 добавляем пути в системные переменные среды.
Шаг 5: Запускаем GDB командой:
1 |
gdb.exe -ex "set solib-search-path ./libs/x86_64" -ex "directory ./jni" --data-directory=C:/gdb/data-directory |
Шаг 6: Подключаемся к устройству Android:
1 |
target remote :8000 |
Проверяем загрузку необходимой библиотеки libbackdoor7 командой info sharedlibrary.
Шаг 7: Переходим в директорию lib приложения на компьютере и запускаем radare2 с соответствующей библиотекой.
Шаг 8: Анализируем библиотеку командами aa и afl в radare2, находим JNI-вызов.
Шаг 9: Копируем JNI-вызов и добавляем точку останова в GDB.
Шаг 10: Если шаг 9 не сработал, используем альтернативный метод: копируем адрес JNI-вызова из radare2, загружаем символы в GDB, находим реальный адрес библиотеки и добавляем точку останова.
Шаг 11: Выполняем команду continue, вводим случайное значение в приложении и ждем остановки в GDB. Используем команду disassemble для просмотра нативного кода.
Шаг 12 В нативном коде находим значение в регистре r12. Также добавляем точку останова на метод сравнения ( test eax eax).
Шаг 13: Продолжаем выполнение, вводим случайное значение. Проверяем и удаляем лишние точки останова.
Шаг 14: Когда GDB остановится, выполняем info registers. Находим адрес регистра r12 и конвертируем его в строку:
1 |
x/s 0x74876edebbb8 |
Таким образом, мы получаем секретную строку из нативной библиотеки Android-приложения.
Этот метод позволяет извлекать важную информацию из нативного кода, что может быть полезно при взломе или анализе безопасности приложений.
ПОЛЕЗНЫЕ ССЫЛКИ:
- Перехват трафика Android-приложения в Burp и Frida
- Пример реверс-инжиниринга в Eclipse-CDT GDB и IDA Pro