• 🔥 Бесплатный курс от Академии Кодебай: «Анализ защищенности веб-приложений»

    🛡 Научитесь находить и использовать уязвимости веб-приложений.
    🧠 Изучите SQLi, XSS, CSRF, IDOR и другие типовые атаки на практике.
    🧪 Погрузитесь в реальные лаборатории и взломайте свой первый сайт!
    🚀 Подходит новичкам — никаких сложных предварительных знаний не требуется.

    Доступ открыт прямо сейчас Записаться бесплатно

Статья Frida Framework vs Android p.3


Финальная часть лекций по Frida Framework

Сперва посмотрим как приложение проверяет наличие root. Прямо над сообщением "Root detected" можно увидеть код:
Код:
if (sg.vantagepoint.a.c.a() || sg.vantagepoint.a.c.b() || sg.vantagepoint.a.c.c())
Если вы перейдете в класс sg.vantagepoint.a.c вы увидите различные проверки на root:
Код:
public static boolean a()
    {
        String[] a = System.getenv("PATH").split(":");
        int i = a.length;
        int i0 = 0;
        while(true)
        {
            boolean b = false;
            if (i0 >= i)
            {
                b = false;
            }
            else
            {
                if (!new java.io.File(a[i0], "su").exists())
                {
                    i0 = i0 + 1;
                    continue;
                }
                b = true;
            }
            return b;
        }
    }

    public static boolean b()
    {
        String s = android.os.Build.TAGS;
        if (s != null && s.contains((CharSequence)(Object)"test-keys"))
        {
            return true;
        }
        return false;
    }

    public static boolean c()
    {
        String[] a = new String[7];
        a[0] = "/system/app/Superuser.apk";
        a[1] = "/system/xbin/daemonsu";
        a[2] = "/system/etc/init.d/99SuperSUDaemon";
        a[3] = "/system/bin/.ext/.su";
        a[4] = "/system/etc/.has_su_daemon";
        a[5] = "/system/etc/.installed_su_daemon";
        a[6] = "/dev/com.koushikdutta.superuser.daemon/";
        int i = a.length;
        int i0 = 0;
        while(i0 < i)
        {
            if (new java.io.File(a[i0]).exists())
            {
                return true;
            }
            i0 = i0 + 1;
        }
        return false;
    }
Используя Frida мы можем сделать так, что бы все эти методы возвращали false, перезаписав их как мы делали еще в первой части руководства. Но что происходит, когда функция возвращает true, потому что обнаруживает root. Как мы видели в функции a, находящейся в MainActivity происходит открытие диалога. Так же устанавливается обработчик onClickListener на нажатие кнопки "OK".
Код:
alertDialog.setButton(-3, (CharSequence)"OK", (DialogInterface.OnClickListener)new b(this));
Реализация onClickListener довольно небольшая:
Код:
package sg.vantagepoint.uncrackable1;

class b implements android.content.DialogInterface$OnClickListener {
    final sg.vantagepoint.uncrackable1.MainActivity a;

    b(sg.vantagepoint.uncrackable1.MainActivity a0)
    {
        this.a = a0;
        super();
    }

    public void onClick(android.content.DialogInterface a0, int i)
    {
        System.exit(0);
    }
}
После события нажатия приложение закрывается, вызывая System.exit(0). Таким образов все, что нам нужно сделать это избежать закрытия приложения, переписав метод onClick в Frida. Создайте файл uncrackable1.js и разместите там следующий код:
Код:
setImmediate(function() { //prevent timeout
    console.log("[*] Starting script");

    Java.perform(function() {

      bClass = Java.use("sg.vantagepoint.uncrackable1.b");
      bClass.onClick.implementation = function(v) {
         console.log("[*] onClick called");
      }
      console.log("[*] onClick handler modified")

    })
})
Теперь скрипт должен быть понятен: мы оборачиваем наш код функцией setImmediate для предотвращения тайм-аутов (возможно вам это и не понадобится), а затем вызываем, Java.perform чтобы использовать функции Frida для работы с Java. Затем начинается настоящая магия: мы получаем класс который реализует интерфейс OnClickListener и перезаписываем его метод onClick. В нашей версии эта функция просто пишет какой-то консольный вывод. В отличие от оригинала, выход из приложения не выполняется. Поскольку оригинал функции onClickHandler подменяется на нашу внедренную функцию с помощью Frida, она никогда не выполнится и приложение больше не закроется, когда мы нажмем кнопку "OK" в диалоге. Давайте проверим это.

Откройте приложение (пусть оно снова отобразит диалоговое окно «Root detected»)

0xXPHO3.png


Внедрите скрипт:
Код:
frida -U -l uncrackable1.js sg.vantagepoint.uncrackable1
Дайте Frida несколько секунд для применения изменений кода, пока вы не увидите сообщение “onClick handler modified” (возможно вы получите shell раньше, из-за оборачивания в setImmediate функция выполняется в фоне)

Затем нажмите кнопку "ОК" в приложении. Если все прошло хорошо приложение не закроется.

7NHmXHO.png


Отлично, диалог исчезает, и мы можем ввести пароль. Давайте введем что-нибудь и посмотрим, что происходит:

2N8mHsP.png


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

Снова смотрим в MainActivity и видим функцию:
Код:
public void verify(View object) {
Она вызывает метод a из класса sg.vantagepoint.uncrackable1.a
Код:
if (a.a((String)object)) {
Это декомпилированный код класса sg.vantagepoint.uncrackable1.a:
Код:
package sg.vantagepoint.uncrackable1;

import android.util.Base64;
import android.util.Log;

/*
* Exception performing whole class analysis ignored.
*/
public class a {
    public static boolean a(String string) {
        byte[] arrby = Base64.decode((String)"5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", (int)0);
        byte[] arrby2 = new byte[]{};
        try {
            arrby2 = arrby = sg.vantagepoint.a.a.a((byte[])a.b((String)"8d127684cbc37c17616d806cf50473cc"), (byte[])arrby);
        }
        catch (Exception var2_2) {
            Log.d((String)"CodeCheck", (String)("AES error:" + var2_2.getMessage()));
        }
        if (!string.equals(new String(arrby2))) return false;
        return true;
    }

    public static byte[] b(String string) {
        int n = string.length();
        byte[] arrby = new byte[n / 2];
        int n2 = 0;
        while (n2 < n) {
            arrby[n2 / 2] = (byte)((Character.digit(string.charAt(n2), 16) << 4) + Character.digit(string.charAt(n2 + 1), 16));
            n2 += 2;
        }
        return arrby;
    }
}
Обратите внимание на вызов string.equals для сравнения строк в конце метода a и создание строки arrby2 в блоке try выше. arrby2 это значение возвращаемое из функции sg.vantagepoint.a.a.a. string.equals сравнивает наш ввод с arrby2. Итак, нам нужно получить значение возвращаемое из sg.vantagepoint.a.a.a.

Мы можем начать реверс-инжинерить преобразование строк и функций расшифровки и работать с оригинальным зашифрованными строками, которые содержаться в вышеприведенном коде. Или мы можем оставить все эти действия приложению, не заботясь о них и просто перехватить возвращаемое значение функции sg.vantagepoint.a.a.a. Возвращаемое значение является уже расшифрованной строкой (в виде массива байтов) с которой сравнивается наш ввод. Следующий скрипт нам в этом поможет:
Код:
aaClass = Java.use("sg.vantagepoint.a.a");
        aaClass.a.implementation = function(arg1, arg2) {
            retval = this.a(arg1, arg2);
            password = ''
            for(i = 0; i < retval.length; i++) {
               password += String.fromCharCode(retval);
            }

            console.log("[*] Decrypted: " + password);
            return retval;
        }
        console.log("[*] sg.vantagepoint.a.a.a modified");
Мы перезаписываем функцию sg.vantagepoint.a.a.a, перехватываем ее возвращаемое значение, а после преобразовываем в читаемую строку. Это расшифрованная строка, которую мы ищем, поэтому вы выводим ее в консоли и надеемся, что получили решение.

Соединяем два скрипта в один полный:
Код:
setImmediate(function() {
    console.log("[*] Starting script");

    Java.perform(function() {
       
        bClass = Java.use("sg.vantagepoint.uncrackable1.b");
        bClass.onClick.implementation = function(v) {
         console.log("[*] onClick called.");
        }
        console.log("[*] onClick handler modified")


        aaClass = Java.use("sg.vantagepoint.a.a");
        aaClass.a.implementation = function(arg1, arg2) {
            retval = this.a(arg1, arg2);
            password = ''
            for(i = 0; i < retval.length; i++) {
               password += String.fromCharCode(retval);
            }

            console.log("[*] Decrypted: " + password);
            return retval;
        }
        console.log("[*] sg.vantagepoint.a.a.a modified");


    });

});
Давайте запустим этот скрипт. Как и прежде сохраните его как uncrackable1.js и выполните (если Frida не сделает это автоматически):
Код:
frida -U -l uncrackable1.js sg.vantagepoint.uncrackable1
Дождитесь сообщения о модификации sg.vantagepoint.a.a.a, после чего нажмите "ОК" в диалоге Root detected введите что-нибудь в поле секретного кода и нажмите проверить. Проверку мы не прошли, но посмотрим на вывод во Frida:
Код:
michael@sixtyseven:~/Development/frida$ frida -U -l uncrackable1.js sg.vantagepoint.uncrackable1
     ____
    / _  |   Frida 9.1.16 - A world-class dynamic instrumentation framework
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at Welcome
                                                                                [*] Starting script

[USB::Android Emulator 5554::sg.vantagepoint.uncrackable1]->[*] onClick handler modified
[*] sg.vantagepoint.a.a.a modified
[*] onClick called.
[*] Decrypted: I want to believe
Хорошо. Теперь мы имеем расшифрованную строку I want to believe. Вот и все, она действительно подходит!

Заключение

Я надеюсь, что к этому моменту вы, по крайне мере, немного впечатлены тем, что можете делать с Frida и какие возможности открывает динамическая бинарная иструментация.
 
Статья, точнее цикл статей - очень познавательный Оформите пожалуйста код, неудобно читать
 
  • Нравится
Реакции: gushmazuko
Статья, точнее цикл статей - очень познавательный Оформите пожалуйста код, неудобно читать
Поддержу, читать жутко не удобно.

Прочитайте Правила оформления статей
Еще могу посоветовать взять пример с: Android + Termux - карманный друг хакера.
 
Последнее редактирование:
  • Нравится
Реакции: Сергей Попов
статьи очень интересные, продолжение будет?( кстати для скрытия рута у фриды в репозитории есть скрипт, как вариант наименьшего сопротивления)
 
Ещё интересное решение этого крэкми (это же статья-перевод всё-таки) предложил Eduardo Novella -
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab