Статья 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 и какие возможности открывает динамическая бинарная иструментация.
 

Vander

CodebyTeam
Gold Team
16.01.2016
1 420
4 353
BIT
2
Статья, точнее цикл статей - очень познавательный Оформите пожалуйста код, неудобно читать
 
  • Нравится
Реакции: gushmazuko

gushmazuko

Green Team
24.03.2017
173
451
BIT
1
Статья, точнее цикл статей - очень познавательный Оформите пожалуйста код, неудобно читать
Поддержу, читать жутко не удобно.

Прочитайте Правила оформления статей
Еще могу посоветовать взять пример с: Android + Termux - карманный друг хакера.
 
Последнее редактирование:
  • Нравится
Реакции: Сергей Попов

never

Green Team
24.01.2019
16
5
BIT
0
статьи очень интересные, продолжение будет?( кстати для скрытия рута у фриды в репозитории есть скрипт, как вариант наименьшего сопротивления)
 

di3mus

New member
03.05.2019
1
0
BIT
0
Ещё интересное решение этого крэкми (это же статья-перевод всё-таки) предложил Eduardo Novella -
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!