Ссылка скрыта от гостей
, это динамический фреймворк для взаимодействия с бинарными приложениями. Сначала инструмент просто показался мне интересным, чуть позже я понял насколько это веселая вещь. Помните режим бога в играх? Frida позволяет делать тоже самое, только уже с нативными приложениями. В этом посте я расскажу о использовании Frida для игры с Android приложениями. И раз уж вы здесь, мы дополнительно решим несложный Android CrackMe во второй части.Что такое динамическая бинарная инструментация
Динамическая бинарная инструментация (Dynamic binary instrumentation) позволяет внедрять сторонний код в уже запущенное приложение, для того чтобы оно делало то, что не делало раньше. Это не эксплуатация инъекции кода через ранее найденные уязвимости. Это не отладка приложения, ведь на самом деле вы не подключаетесь отладчиком к приложению, но это позволяет делать в общем-то похожие вещи. Какие возможности открывает динамическая бинарная инструментация:
- Доступ к памяти процесса
- Переопределение функций во время исполнения приложения
- Вызов функций из импортированных классов
- Поиск экземпляров объектов в куче и взаимодействие с ними
- Перехват и трассировка функций
Frida "позволяет внедрять JavaScript сниппеты или вашу собственную библиотеку в нативное приложение на Windows, MacOS, Linux, iOS, Android или QNX". Первоначально инструмент работал на движке Google V8 JavaScript Runtime, но начиная с 9 версии Frida использует
Ссылка скрыта от гостей
, при этом у вас есть возможность перейти обратно к V8, если вам это понадобиться. Frida определяет
Ссылка скрыта от гостей
для взаимодействия с приложениями (включая возможность использования инструментария даже на устройстве без прав супер-пользователя), но сейчас мы рассмотрим самые частые примеры использования, не особо затрагивая методов их работы.Для начала вам понадобиться:
- Frida
- frida-server, исполняемый файл скаченный со страницы релизов (на момент написания это frida-server-9.1.16-android-arm.xz. Версия frida-server должна совпадать с версией Frida.
- Android Emulator или устройство с root. Frida была разработана для Android 4.4 ARM, но работает и с более поздними версиями. Я успешно использовал Android 7.1.1 ARM для этого руководства. Для CrackMe во второй части статьи вам в любом случае понадобиться, что-то современнее, чем Android 4.4.
Если вы планируете повторить решение OWASP Unbreakable Crackme Level 1, который решается во второй части статьи, вам так же следует загрузить:
- OWASP Uncrackable Crackme Level 1 (APK)
-
Ссылка скрыта от гостей
- dex2jar
Установите Frida, если еще не сделали этого (посмотрите README для других способов установки):
Код:
pip install frida
npm install frida
Код:
michael@sixtyseven:~$ adb devices
List of devices attached
emulator-5556 device
Код:
adb push /home/michael/Downloads/frida-server-9.1.16-android-arm /data/local/tmp/frida-server
Код:
adb shell
su
cd /data/local/tmp
chmod 755 frida-server
./frida-server
В другом терминале, на хостовой системе проверьте, что Frida запустилась и вы можете посмотреть список процессов на Android:
Код:
frida-ps -U
Код:
michael@sixtyseven:~$ frida-ps -U
PID Name
---- --------------------------------------------------
696 adbd
5828 android.ext.services
6188 android.process.acore
5210 audioserver
5211 cameraserver
8334 com.android.calendar
6685 com.android.chrome
6245 com.android.deskclock
5528 com.android.inputmethod.latin
6120 com.android.phone
6485 com.android.printspooler
8355 com.android.providers.calendar
5844 com.android.systemui
7944 com.google.android.apps.nexuslauncher
6416 com.google.android.gms
[...]
Например, вы можете отслеживать нужные вам вызовы функций в Chrome (запустите Chrome на эмуляторе, если он еще не запущен):
Код:
frida-trace -i "open" -U com.android.chrome
Код:
michael@sixtyseven:~$ frida-trace -i open -U -f com.android.chrome
Instrumenting functions...
open: Loaded handler at "/home/michael/__handlers__/libc.so/open.js"
Started tracing 1 function. Press Ctrl+C to stop.
/* TID 0x2740 */
282 ms open(pathname=0xa843ffc9, flags=0x80002)
/* TID 0x2755 */
299 ms open(pathname=0xa80d0c44, flags=0x2)
/* TID 0x2756 */
309 ms open(pathname=0xa80d0c44, flags=0x2)
/* TID 0x2740 */
341 ms open(pathname=0xa80d06f7, flags=0x2)
592 ms open(pathname=0xa77dd3bc, flags=0x0)
596 ms open(pathname=0xa80d06f7, flags=0x2)
699 ms open(pathname=0xa80d105e, flags=0x80000)
717 ms open(pathname=0x9aff0d70, flags=0x42)
742 ms open(pathname=0x9ceffda0, flags=0x0)
758 ms open(pathname=0xa63b04c0, flags=0x0)
Код:
[...]
onEnter: function (log, args, state) {
log("open(" + "pathname=" + args[0] + ", flags=" + args[1] + ")");
},
[...]
Ссылка скрыта от гостей
. Мы можем изменить наш скрипт, что бы он выводил содержимое по адресу памяти, где размещена UTF8 строка и мы получали более понятный вывод. После изменения код будет выглядеть примерно так:
Код:
onEnter: function (log, args, state) {
log("open(" + "pathname=" + Memory.readUtf8String(args[0])+ ", flags=" + args[1] + ")");
},
Код:
michael@sixtyseven:~$ frida-trace -i open -U -f com.android.chrome
Instrumenting functions...
open: Loaded handler at "/home/michael/__handlers__/libc.so/open.js"
Started tracing 1 function. Press Ctrl+C to stop.
/* TID 0x29bf */
240 ms open(pathname=/dev/binder, flags=0x80002)
/* TID 0x29d3 */
259 ms open(pathname=/dev/ashmem, flags=0x2)
/* TID 0x29d4 */
269 ms open(pathname=/dev/ashmem, flags=0x2)
/* TID 0x29bf */
291 ms open(pathname=/sys/qemu_trace/process_name, flags=0x2)
453 ms open(pathname=/dev/alarm, flags=0x0)
456 ms open(pathname=/sys/qemu_trace/process_name, flags=0x2)
562 ms open(pathname=/proc/self/cmdline, flags=0x80000)
576 ms open(pathname=/data/dalvik-cache/arm/system@app@Chrome@Chrome.apk@classes.dex.flock, flags=0x42)
Еще одна вещь о которой стоит рассказать, вы можете либо запустить приложение перед внедрением Frida, либо передать аргумент -f для Frida, чтобы приложение было запущено автоматически.
Теперь используем интерфейс командной строки Frida, frida-cli:
Код:
frida -U -f com.android.chrome
В обоих случаях вы получаете shell (который не закрывается автоматически), куда вы можете вводить команды Frida следуя Frida JavaScript API. Нажмите TAB для просмотра доступных команд. Оболочка так же поддерживает автодополнение команд.
Большинство возможностей хорошо документированы. Для Android особенно внимательно посмотрите на секцию
Ссылка скрыта от гостей
(Я буду говорить о "Java API", хотя технически это просто обертка на JavaScript для доступа к Java объектам). Мы сосредоточимся на Java API, поскольку это наиболее удобный способ взаимодействия с Android приложениями. Вместо перехвата функций из libc мы будем работать напрямую с функциями и объектами из Java. (Примечание: Если вы заинтересованы, что вы можете делать с помощью Frida за пределами Java API, перехватывая более низкоуровневые C функции на Android, как мы делали с помощью frida-trace, посмотрите раздел документации посвященный
Ссылка скрыта от гостей
. Я не рассматриваю это здесь.)Начиная работу с Java API просто получим версию Android на устройстве:
Код:
[USB::Android Emulator 5556::['com.android.chrome']]-> Java.androidVersion
"7.1.1"
Код:
[USB::Android Emulator 5556::['com.android.chrome']]-> Java.perform(function(){Java.enumerateLoadedClasses({"onMatch":function(className){ console.log(className) },"onComplete":function(){}})})
org.apache.http.HttpEntityEnclosingRequest
org.apache.http.ProtocolVersion
org.apache.http.HttpResponse
org.apache.http.impl.cookie.DateParseException
org.apache.http.HeaderIterator
Это тело функции, находящейся внутри обертки Java.perform:
Код:
Java.enumerateLoadedClasses(
{
"onMatch": function(className){
console.log(className)
},
"onComplete":function(){}
}
)
Код:
{
"onMatch":function(arg1, ...){ ... },
"onComplete":function(){ ... },
}
Сейчас мы углубимся в магию Frida и перезапишем функцию. Кроме того мы будем загрузим код из внешнего скрипта, вместо того что бы набирать его в консоли, это намного удобнее. Сохраните следующий код, например, как chrome.js:
Код:
Java.perform(function () {
var Activity = Java.use("android.app.Activity");
Activity.onResume.implementation = function () {
console.log("[*] onResume() got called!");
this.onResume();
};
});
Открой ваш эмулятор, откройте Chrome и выполните внедрение кода передав -l.
Код:
frida -U -l chrome.js com.android.chrome
Код:
[*] onResume() got called!
Прежде чем мы продолжим, предостережение: Когда наша эмуляция достаточно медленная Frida может останавливается по тайм-ауту. Для предотвращения этого оберните свои скрипты в функцию setImmediate или
Ссылка скрыта от гостей
. По умолчанию RPC во Frida не имеют тайм-аутов. setImmediateавтоматически перезапускает ваши скрипты во Frida, после того как вы изменили исходный файл, поэтому это еще и удобно. Также это запускает ваши скрипты в фоновом режиме. Это означает, что сразу получите cli, хотя Frida все еще обрабатывает ваши скрипты. Просто подождите и не покидайте cli, пока Frida не показала вам вывод ваших скриптов. Еще раз отредактируем chrome.js:
Код:
setImmediate(function() {
console.log("[*] Starting script");
Java.perform(function () {
Java.choose("android.view.View", {
"onMatch":function(instance){
console.log("[*] Instance found");
},
"onComplete":function() {
console.log("[*] Finished heap search")
}
});
});
});
Код:
[*] Starting script
[*] Instance found
[*] Instance found
[*] Instance found
[*] Instance found
[*] Finished heap search
Код:
setImmediate(function() {
console.log("[*] Starting script");
Java.perform(function () {
Java.choose("android.view.View", {
"onMatch":function(instance){
console.log("[*] Instance found: " + instance.toString());
},
"onComplete":function() {
console.log("[*] Finished heap search")
}
});
});
});
Код:
[*] Starting script
[*] Instance found: android.view.View{7ccea78 G.ED..... ......ID 0,0-0,0 #7f0c01fc app:id/action_bar_black_background}
[*] Instance found: android.view.View{2809551 V.ED..... ........ 0,1731-0,1731 #7f0c01ff app:id/menu_anchor_stub}
[*] Instance found: android.view.View{be471b6 G.ED..... ......I. 0,0-0,0 #7f0c01f5 app:id/location_bar_verbose_status_separator}
[*] Instance found: android.view.View{3ae0eb7 V.ED..... ........ 0,0-1080,63 #102002f android:id/statusBarBackground}
[*] Finished heap search
Предостережения
Когда вы экспериментируете с Frida вы заметите, что есть некоторые нестабильности. Во-первых внедрение стороннего когда в другой процесс может вызвать сбои, потому приложение будет работать не так, как планировалось. Во-вторых, сама Frida является экспериментальной. Она работает, но часто вы должны попробовать несколько способов для получения желаемого результата. Например, Frida всегда крашится, когда я пытаюсь загрузить скрипт и запустить процесс в одну команду. Вместо этого я сначала запускаю процесс, а затем внедряю скрипт. Поэтому я и показывал вам разные способы избежания тайм-аута. Возможно, вам будет нужно какой из них работает в вашем случае.
Python bindings
Если вы хотите автоматизировать вашу работу с Frida еще больше, вы должны посмотреть на биндинги для Python, C и NodeJS, их очень просто использовать как только вы разобрались как работать с Frida. Например, инъекция вашего скрипта chrome.js из Python, вы можете использовать
Ссылка скрыта от гостей
и создать
Код:
chrome.py
#!/usr/bin/python
import frida
# put your javascript-code here
jscode= """
console.log("[*] Starting script");
Java.perform(function() {
var Activity = Java.use("android.app.Activity");
Activity.onResume.implementation = function () {
console.log("[*] onResume() got called!");
this.onResume();
};
});
"""
# startup frida and attach to com.android.chrome process on a usb device
session = frida.get_usb_device().attach("com.android.chrome")
# create a script for frida of jsccode
script = session.create_script(jscode)
# and load the script
script.load()
Для других примеров, как обычно,
Ссылка скрыта от гостей
.Продолжение следует!
Frida Framework vs Android p.2
Frida Framework vs Android p.3