Как я чуть не подхватил вирус, пытаясь продать сапоги



    Я из тех людей, кто с наступлением осени старается проводить на улице меньше времени. В Москве это не сложно: ограничиваешься маршрутом от дома до офиса и обратно. Однако промозглая погода может причинить дискомфорт и в помещении, особенно если ваше рабочее место, как и моё, находится у окна, а каждый второй коллега, жалуясь на духоту, просит проветрить кабинет. Чтобы не впасть в хандру, этой осенью я обновил гардероб.

    Размышляя о судьбе ненужных вещей, я прикидывал, что с ними делать: выкинуть, порезать на тряпки, отдать донашивать младшему брату? Но для одной вещи ни один из этих способов не годился: то были кожаные сапоги 44 размера приличного вида, но порядком мне надоевшие. Их я решил продать на Avito. Загрузил фотографии, указал ненастоящее имя (информационная безопасность же), выставил сапоги, пару других вещей и пошёл спать. Откуда мне было знать, что это обернётся длительным анализом приложения на предмет скрытых угроз?



    Приятная неожиданность


    На следующий день после пары сомнительных звонков мне пришло интересное смс-сообщение со следующим содержимым:



    Спустя пару дней я получил ещё одно похожее сообщение:



    Удивившись, что кто-то каким-то образом смог перевести мне деньги по интернету (видимо, один я старый — пользуюсь до сих пор бумажными сберегательными книжками), я перешёл по ссылке в СМС.

    После этого мне предложили скачать приложение для Android (apk-файл). Радостно скачав файл, я увидел следующее:



    Вызывает доверие! Я с нетерпением захотел побыстрее всё установить и покончить с этим.
    Но здесь, как обычно бывает, надоедливая операционная система Android почему-то не позволила мне запустить файл. «Да отдайте уже деньги!» — негодовал я. Пришлось перейти в настройки и включить какую-то опцию «Неизвестные источники», неужели телефон настолько глуп в 2018? Кстати, мой телефон — Xiaomi Remdi c Andoid 6.0.1 (примечание для технарей).



    Далее последовала цепочка странных событий. Телефон продолжал сообщать о недостоверных источниках. Но ведь Avito — это достоверный источник! Пришлось погуглить, разобраться, как это обойти, и после отключить в настройках. Вскоре появился и некий антивирус, который я не устанавливал.



    Наконец-то я увидел заветное стандартное окно установки — смотреть на разрешения в наше время нет смысла, сейчас даже блокнот не запустится, пока не дашь ему полный доступ к телефону. Радостный миг окончания установки приложения и ЗАПУСК! Я с нетерпением ждал обещанных денег. Дополнительно приложение запросило администраторские привилегии, с чем я радостно согласился. К сожалению, приложение странно себя вело и не хотело производить оплату, а вскоре и вовсе пропало из списка приложений на общем экране.





    Cпойлер
    Позже я проверил на другом телефоне — Lenovo с Android 4.4.2 на борту. Список разрешений при установке оказался гораздо больше. И никакие Play Защита и Антивирус не мешают, необходимо только разрешить установку из недостоверных источников.





    Альтруизм



    Итак, к чему мы пришли:

    • На установку потрачено 20 минут времени.
    • Деньги я не получил.

    Подумал, что проблема в ошибке кода, как это часто бывает у программистов. Решил выявить, какие ошибки возникают при работе приложения на моём телефоне, и отправить отчёт об этом разработчику.

    Cпойлер
    Сейчас так мало осталось бескорыстных людей, один из них — я.

    Понятно, что приложение такого типа должно работать при подключенном интернете, поэтому для начала я попробовал проанализировать трафик между телефоном и сервером приложения.

    Техническая инструкция по настройке прокси
    Можно прослушать интернет-трафик в любой точке, проходящей по пути от телефона до сервера, будь то домашний роутер, местный интернет-провайдер, магистральный интернет-провайдер или сервер приложения.

    Проблемы:

    • Необходим доступ к данному оборудованию.
    • Требуется отделить трафик нужного приложения от остального.
    • В случае шифрования (а в 2018 шифруется уже всё) — необходимо знание ключа.

    Я задумал пройти более классическим путём и настроить прокси на телефоне с прокси сервером на собственном ноутбуке. Чтобы нивелировать проблему шифрования, решил импортировать свой сертификат, а для отделения трафика приложения не стал запускать другие приложения.
    В качестве программы прокси-сервера выбрал burp suite. Настроил прокси-сервер и экспортировал сертификат на телефон.





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



    Как видно, данные не отправляются (в столбце IP указано значение «unknown host»), более того, их нельзя проанализировать из-за наличия дополнительного шифрования на уровне самого приложения. Судя по ошибке, телефон не мог определить IP-адрес сервера и его поддоменов https://*.sky-sync.pw по его доменному имени.

    Это могло означать только следующие варианты:

    • Доменное имя перестало существовать
      • Его заблокировал сам владелец.
      • Его заблокировал регистратор по жалобе.
    • Проблема с DNS-сервером
      • DNS-сервер не знает адреса, так как разработчик в production выкатил локальный DNS-адрес.
      • DNS-сервер специально блокировал данный запрос, что не удивительно в эпоху интернет-цензуры.

    Чтобы проверить предположение о проблеме с DNS-сервером, я попробовал сделать запросы с разных крупных DNS-серверов: Google, Yandex, OpenDNS (обычно цензуре подвергаются местные DNS):



    Здесь видно, что ни один из них ничего не знает о таком имени. Дальше я посмотрел whois-сведения о регистрации домена:



    Любопытно: домен зарегистрирован, то есть, скорее всего, он не локальный, но поскольку домен не резолвится, возможно, он был заблокирован регистратором по жалобе (abuse). Но за что? Что плохого он сделал?

    Чтобы выяснить, что же это всё-таки за приложение и как мне забрать свои деньги, я решил воспользоваться магией обратной разработкой.

    Погружение в пучину


    Если вы гуманитарий и дочитали до этого места, то это уже хорошо — за освоение последующего вы достойны награды посмертно.

    Инструментарий


    Для выяснения, что же находится «под капотом» у приложения, нам понадобится скачать специализированные инструменты. Можно загрузить их по отдельности:

    • Распаковщик apk-контейнера
      • Классика — ApkTool.
      • Можно распаковать обычным архиватором, но тогда все бинарые ресуры, включая приложения и файл Manifest, будут нечитабельны.
    • Декомпилятор smali-кода
      • Стандартом является Dex2Jar, но учите, что данная программа часто криво отрабатывает.
      • Нужно подойти к делу очень внимательно, потому что декомпилятор декомпилятору рознь, рассмотрим это позднее.
    • Программа для просмотра декомпилированного кода, я бы рекомендовал jd-gui

    Либо можно воспользоваться продуктом, обычно платным, где есть всё сразу. Я предпочитаю JebDecompiler: ему можно просто подать на вход apk-приложение, и он сам аккуратно разложит всё по вкладочкам, плюс в нём удобно переключаться между smali и декомпилированным Java-кодом.

    Отдельно хочется отметить:


    В бой идут одни старики


    Обзор


    При открытии декомпилированного кода сразу становится понятно, что он обфусцирован.



    Как я это понял?

    • Человеко-нечитаемые названия классов
      isqpwcmx.isfdztgb.adscjobz.nxscomkr.jypbdxnt.utagwpym.wprtdznb.swldgrhm.yrbjpktq.wukovicq;
    • Недостижимый код
      if(0 != 0) {</li>
                  String v1 = "flnwznvh";</li>
                  if(v1.length() != 661 && v1.charAt(0) == 104) {</li>
                      v1.length();</li>
                  }
    • Шифрование строк
      vcgrnfjx.execSQL(nvhdzjfo.xipswfqb(new String[]{"f741f04a4991fc2f0a0029f610bbd1c250dfe115fb7770b892f75d8718b822d273251013991b4407e224fa3f9d4e92f6","378f40211b6e32a5406cd97e85bcf9ad","6378a459b1c20edf", "gexnfwok", "meazfhdp", "bsmotaxn"})

    Вряд ли программист настолько рехнулся, чтобы изначально так разрабатывать код. Скорее всего, он использовал один из общедоступных обфускаторов. Этот шаг вполне обычный для усложнения анализа кода с целью защиты интеллектуальной собственности, например, но какой же это «вырвиглаз» для исследователя.

    Обратим внимание на основную функцию шифрования:



    Сама функция шифрования принимает на вход 3 строки (если больше, то остальные не имеют смысла):

    1. шифротекст
    2. ключ
    3. вектор инициализации для CBC — AES

    На эту функцию ссылаются в программе минимум 213 раз:



    Отмечу, что она является важным ключом для нормального анализа кода. Дальше нужно думать у нас есть следующие пути анализа программы:

    1. Восстановить логику работы функции, собрать все вызовы в статическом анализе, дешифровать строки. Может быть, сложно и долго, зато даст 100%-ый результат.
    2. Внести изменения в smali-код приложения, скомпилировать заново, запустить приложение и ловить в логах дешифрованные строки. Делается легко, но как поведёт себя приложение в конкретном запуске — неизвестно, и можно не увидеть всей картины в целом (не получить вызовы всех функций). К тому же, возможны проблемы с самопроверкой приложением сертификата и (или) целостности.
    3. Если восстановить логику работы функции сложно, то можно собрать все вызовы функций и дергать самим эти функции с нужными параметрами прямо в динамике (с помощью, например, ПО Frida.

    Мы выберем способ №1 как самый суровый надежный.

    Деобфускация


    Сразу оговорюсь, деобфускация — это часто долгий и нудный процесс, поэтому нужно правильно оценить свои временные рамки. Для нашего анализа достаточно расшифровать все строки хоть каким-нибудь способом и сделать это за минимальное время, пусть даже костыльным способом, чем месяц возиться ради смутного идеального варианта.

    Качественная деобфускация имеет смысл в случае полной обратной разработки, например, это приходится делать ворам интеллектуальной собственности, когда они пытаются скопировать решение конкурента, либо, если вам часто приходится анализировать программы, обработанные одним обфускатором, но это не наш случай.

    Исходный код после декомпилятора JEB Decompiler v.1.4

    Cпойлер
    public static String podxiwkt(String[] args) {
            int v6;
            int v4;
            byte[] v2;
            Cipher v1;
            String v10 = args[0];
            String v7 = args[1];
            String v0 = args[2];
            if(v10 == null) {
                goto label_9;
            }
    
            if(v10.length() != 0) {
                goto label_11;
            }
    
            goto label_9;
        label_11:
            IvParameterSpec v5 = new IvParameterSpec(v0.getBytes());
            try {
                v1 = Cipher.getInstance("AES/CBC/NoPadding");
                goto label_15;
            }
            catch(NoSuchPaddingException v3) {
            }
            catch(NoSuchAlgorithmException v3_1) {
            }
    
            String v11 = "";
            goto label_10;
        label_15:
            SecretKeySpec v9 = new SecretKeySpec(v7.getBytes(), "AES");
            int v11_1 = 2;
            try {
                v1.init(v11_1, ((Key)v9), ((AlgorithmParameterSpec)v5));
                v2 = Base64.decode(v1.doFinal(bwdoclkr.xkvasepi(v10)), 0);
                if(v2.length <= 0) {
                    goto label_48;
                }
    
                v4 = 0;
                v6 = v2.length - 1;
            label_29:
                if(v6 < 0) {
                    goto label_38;
                }
    
                if(v2[v6] != 0) {
                    goto label_33;
                }
            }
            catch(Exception v3_2) {
                goto label_51;
            }
    
            ++v4;
        label_33:
            --v6;
            goto label_29;
        label_38:
            if(v4 <= 0) {
                goto label_48;
            }
    
            try {
                byte[] v8 = new byte[v2.length - v4];
                System.arraycopy(v2, 0, v8, 0, v2.length - v4);
                v2 = v8;
            }
            catch(Exception v3_2) {
            label_51:
                v11 = "";
                goto label_10;
            }
    
        label_48:
            v11 = new String(v2);
            goto label_10;
        label_9:
            v11 = "";
        label_10:
            return v11;
        }
    }

    Примечание о декомпиляторах
    Кстати, dex2jar часто даёт сбои. Так, на рисунке ниже видно, что dex2jar версии 2.0 не смог справиться и просто выдал smali-код.



    Его свежая версия, собранная из исходников, выдала декомпилированный код данной функции, но не смогла декомпилировать многие другие (вот так фокусы).





    Итог: внимательно отнеситесь к выбору декомпилятора — это сэкономит вам кучу времени и будет проще, чем анализ smali-кода.


    Итак, если мы сейчас просто вставим данный код в IDE, то он не отработает из-за ошибок.

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

    Пример плохой декомпиляции:

    
           if(v10 == null) {
                goto label_9;
            }
    
            if(v10.length() != 0) {
                goto label_11;
            }
    
            goto label_9;
    …
    label_9:
            v11 = "";
            return v11;

    Видим, что получилось плохо и неработоспособно. Перепишем:

    if ((v10 == null) || (v10.length() == 0)) {
        return "";
    }
    

    Теперь стало намного понятнее, здесь обычная проверка входных данных. В данном случае нам нужно:

    • Заменить все «goto» другими конструкциями языка, т.к. «goto» уже давно невалидный оператор.
    • Заменить вызовы библиотек Android на вызовы библиотек Java (если мы пытаемся выполнить код в Java IDE).
    • Вставить зависимые классы, на которые ссылается наш код.
    • Подумать самим, что не так.

    В итоге получаем:

    package com.company;
        //package isqpwcmx.isfdztgb.adscjobz.nxscomkr.jypbdxnt.utagwpym.wprtdznb.swldgrhm.yrbjpktq;
    import java.util.Base64;
        //import android.util.Base64;
    //import bnxvhlyg.nkhoirul.zfxogwqi.mdpqejcw.srnepbly.pcbvwxrs.vixdqclm.wnuqvrhp.bnvceayd.bwdoclkr;
        //вставим свой класс
    import java.security.Key;
    import java.security.NoSuchAlgorithmException;
    import java.security.spec.AlgorithmParameterSpec;
    import javax.crypto.Cipher;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    public abstract class Main {
        public Main() {
            super();
        }
    
        //hex to ascii
        public static byte[] xkvasepi(String str) {
            byte[] v0 = null;
            if(str != null && str.length() >= 2) {
                int v2 = str.length() / 2;
                v0 = new byte[v2];
                int v1;
                for(v1 = 0; v1 < v2; ++v1) {
                    v0[v1] = ((byte)Integer.parseInt(str.substring(v1 * 2, v1 * 2 + 2), 16));
                }
            }
    
            return v0;
        }
    
        public static String podxiwkt(String[] args) {
            int v6;
            int v4;
            byte[] v2;
            Cipher v1;
            String v10 = args[0]; //text
            String v7 = args[1]; //key
            String v0 = args[2]; //IV
            //check
            if ((v10 == null) || (v10.length() == 0)) {
                return "";
            }
    
            IvParameterSpec v5 = new IvParameterSpec(v0.getBytes());
            try {
                v1 = Cipher.getInstance("AES/CBC/NoPadding");
            }
            catch(NoSuchPaddingException v3) {
                return "";
            }
            catch(NoSuchAlgorithmException v3_1) {
                return "";
            }
            SecretKeySpec v9 = new SecretKeySpec(v7.getBytes(), "AES");
            int v11_1 = 2;
            try {
                v1.init(v11_1, ((Key)v9), ((AlgorithmParameterSpec)v5));
                //v2 = Base64.decode(v1.doFinal(bwdoclkr.xkvasepi(v10)), 0);
                v2=v1.doFinal(xkvasepi(v10));
    
                //check
                if(v2.length <= 0) {
                    return new String(v2);
                }
            } catch(Exception v3_2) {
                return "";
            }
    
            v4=0;
            for (v6=v2.length-1;v6>=0;v6--){
                if (v2[v6]==0) ++v4;
            }
    
            if(v4 > 0) {
    
                try {
                    byte[] v8 = new byte[v2.length - v4];
                    System.arraycopy(v2, 0, v8, 0, v2.length - v4);
                    v2 = v8;
                } catch (Exception v3_2) {
                    return "";
                }
            }
            v2 = Base64.getDecoder().decode(v2);
            return new String(v2);
        }
    
    
        public static void main(String[] args) {
            // write your code here
            System.out.println(podxiwkt(new String[] { "b1acd584a6eae4ca6321b1f7cdf9ba9617112b4fb39e76c8def876346e3032fbd32b2d188a09715f27124c1bf9facfdc", "637904cd08aeb2d3f6a21b5c7e84f519", "8f4c796d5a3120eb", "zcmwgvdn", "mkngbsyr", "rwcdaieu" }));
    
        }
    }

    Данный код успешно отрабатывает. После того, как становится понятна его работа, его можно упрощать и упрощать, приводя к предполагаемому изначально лаконичному виду, написанному программистом (если это, конечно, у него руки не были кривыми изначально).

    Примечание
    Кстати, в данном случае дешифрование строк можно продемонстрировать с помощью связки онлайн-ресурсов. Пример вызова шифрованной строки внутри программы:



    Здесь вектор инициализации нужно сначала перевести в Hex-формат:



    Подставляем все значения:



    И в конце декодируем из base64:



    В результате получаем обычную строку, и вызов приобретает осмысленный вид.

    Таким образом, нужно пройтись по всему коду и собрать все шифрованные строки, теперь мы можем самостоятельно их дешифровать. Важный момент здесь в том, что на этапе «модификации и комментирования кода» мы можем работать как на уровне smali, так и на уровне Java (декомпилированный smali).

      Плюсы модификации Минусы модификации
    Smali Можно внести изменения, заново собрать в dex и декомпилировать с новыми строками Не всегда просто работать по smali-коду. При неправильном изменении приложение не соберется
    Java Чаще гораздо проще извлекать данные из высокоуровневых операций Редактировать в большинстве Java-просмотрщиках кода нельзя.

    Ещё один пример строки

    vcgrnfjx.execSQL(nvhdzjfo.xipswfqb(new String[]{"f741f04a4991fc2f0a0029f610bbd1c250dfe115fb7770b892f75d8718b822d273251013991b4407e224fa3f9d4e92f6","378f40211b6e32a5406cd97e85bcf9ad","6378a459b1c20edf", "gexnfwok", "meazfhdp", "bsmotaxn"})

    Отсюда очень легко забрать параметры с помощью регулярного выражения, чем написать регулярку на следующий код:

    Smali-код, пример 1

    00000280  new-instance            v13, Ljava/lang/StringBuilder;
    00000284  invoke-direct           {v13}, Ljava/lang/StringBuilder;-><init>()V
    0000028A  const/4                 v14, 0x6
    0000028C  new-array               v14, v14, [Ljava/lang/String;
    00000290  const/4                 v15, 0x0
    00000292  const-string            v16, "f741f04a4991fc2f0a0029f610bbd1c250dfe115fb7770b892f75d8718b822d273251013991b4407e224fa3f9d4e92f6"
    00000296  aput-object             v16, v14, v15
    0000029A  const/4                 v15, 0x1
    0000029C  const-string            v16, "378f40211b6e32a5406cd97e85bcf9ad"
    000002A0  aput-object             v16, v14, v15
    000002A4  const/4                 v15, 0x2
    000002A6  const-string            v16, "6378a459b1c20edf"
    000002AA  aput-object             v16, v14, v15
    000002AE  const/4                 v15, 0x3
    000002B0  const-string            v16, "gexnfwok"
    000002B4  aput-object             v16, v14, v15
    000002B8  const/4                 v15, 0x4
    000002BA  const-string            v16, "meazfhdp"
    000002BE  aput-object             v16, v14, v15
    000002C2  const/4                 v15, 0x5
    000002C4  const-string            v16, "bsmotaxn"
    000002C8  aput-object             v16, v14, v15


    Smali-код, пример 2

    0000008E  new-array               v0, v0, [Ljava/lang/String;
    00000092  move-object/from16      v89, v0
    00000096  const/16                v90, 0x0
    0000009A  const-string            v91, "4500b5e2e2ad26b7545eb54d70ab360ae28c9d031e2afcc3f6a2b2ac488ea440"
    0000009E  aput-object             v91, v89, v90
    000000A2  const/16                v90, 0x1
    000000A6  const-string            v91, "da96f678922d4b07350b3a184ecc1f5e"
    000000AA  aput-object             v91, v89, v90
    000000AE  const/16                v90, 0x2
    000000B2  const-string            v91, "0cf69e3d2745a1b8"
    000000B6  aput-object             v91, v89, v90
    000000BA  const/16                v90, 0x3
    000000BE  const-string            v91, "jhiqsaoe"
    000000C2  aput-object             v91, v89, v90
    000000C6  const/16                v90, 0x4
    000000CA  const-string            v91, "khbqxurn"
    000000CE aput-object           v91, v89, v90


    Smali-код, пример 3

    00000D3E  new-array               v0, v0, [Ljava/lang/String;
    00000D42  move-object/16          v298, v0
    00000D48  const/4                 v0, 0x0
    00000D4A  move/16                 v299, v0
    00000D50  const-string            v0, "b286945744e085f4d5c19916fd261481"
    00000D54  move-object/16          v300, v0
    00000D5A  move-object/from16      v0, v300
    00000D5E  move-object/from16      v1, v298
    00000D62  move/from16             v2, v299
    00000D66  aput-object             v0, v1, v2
    00000D6A  const/4                 v0, 0x1
    00000D6C  move/16                 v299, v0
    00000D72  const-string            v0, "df6883742b2911ac5ac7b4dee065390f"
    00000D76  move-object/16          v300, v0
    00000D7C  move-object/from16      v0, v300
    00000D80  move-object/from16      v1, v298
    00000D84  move/from16             v2, v299
    00000D88  aput-object             v0, v1, v2
    00000D8C  const/4                 v0, 0x2
    00000D8E  move/16                 v299, v0
    00000D94  const-string            v0, "90a463ce2df17b58"
    00000D98  move-object/16          v300, v0
    00000D9E  move-object/from16      v0, v300
    00000DA2  move-object/from16      v1, v298
    00000DA6  move/from16             v2, v299
    00000DAA  aput-object             v0, v1, v2
    00000DAE  const/4                 v0, 0x3
    00000DB0  move/16                 v299, v0
    00000DB6  const-string            v0, "cupyzsgq"
    00000DBA  move-object/16          v300, v0
    00000DC0  move-object/from16      v0, v300
    00000DC4  move-object/from16      v1, v298
    00000DC8  move/from16             v2, v299
    00000DCC  aput-object             v0, v1, v2


    Как мы видим, внутренние переменные меняются, последовательность команд различается, количество аргументов тоже разнится, вдобавок в программе функция дешифрования вызывается не напрямую, а через функции прослойки. Попробуйте написать правило самостоятельно для поиска данной конструкции, не допустить ошибок по захвату строк из других функций и всё это сделать быстро (удачи).

    План-капкан:

    1. Извлечём все значения из декомпилированного кода.
    2. Дешифруем.
    3. Заменим шифротекст на открытый в smali-коде. Подставим, например, взамен первого оператора. (Профессиональнее будет вырезать весь вызов функции и оставить возвращаемую дешифрованную строку, но тогда опять же есть большой риск сломать программу).
    4. Соберём smali-код в dex-файл.
    5. Дальше будем удобно смотреть в анализаторе кода, с чего и начали.

    Если собрать весь декомпилированный код в один файл, то получится около 20000 строк, что для ручного анализа требует много времени, которое стоит явно больше, чем выставленные мной на продажу сапоги. Для начала соберём регулярным выражением все строки.



    Видим 593 совпадения, плюс с десяток, которые не попали под данное правило, в семье не без урода. Пример:



    Сортируем, отсеиваем, итого 422 уникальные строки:



    Пропускаем через функцию дешифрования, восстановленную нами ранее. Результат:



    Заменим шифротекст на открытый в smali-коде при помощи Python:

    import os
    
    words_replace=dict()
    words_replace["0018aacad3d146266317d8d8c51785fd"]="imei"
    words_replace["016d15e4d0a72667c61428e736a6f3b8"]="WakeLock"
    words_replace["032c534efb6c9990cd845a08c5a08b95"]="inbox"
    #… и т.д.
    
    #Открыть smali-файл
    #Найти все вхождения массива и заменить
    def change(path):
        print("file="+path)
        file_handle = open(path, 'r')
        context_full = file_handle.read()
        file_handle.close()
    
        for i in words_replace:
            context_full=context_full.replace(i, words_replace[i])
            #print (i+""+words_replace[i])
    
        file_handle = open(path, 'w')
        context_full = file_handle.write(context_full)
        file_handle.close()
    
    
    #Пройтись по всем подпапкам и открыть smali-файлы
    for top, dirs, files in os.walk('C:\\work\\test'):
        for nm in files:
            path=os.path.join(top, nm)
            print (path)
            change(path)

    Cобираем smali-файлы в dex:



    Теперь это можно хоть как-то анализировать (читая из всей конструкции первый аргумент):



    Анализ


    Итак, имеем 20 000 более-менее читабельных строк кода, задачи делать полный разбор перед нами не стоит. Необходимо понять функционал в целом. Здесь, по сути, требуется только навык чтения исходного кода на Java. Ходить по коду, смотреть на перекрёстные ссылки, переименовывать переменные и функции.

    Как же лучше анализировать Android-приложение, особенно большое?

    Вариант 1: Можно двигаться от файла Manifest

    Например, последовательно от LAUNCHER попытаться раскрутить всю цепочку вызовов. Кстати, не забывайте, что ещё есть «Receiver» и «Service», которые могут изменить линейное выполнение программы.



    Полный файл Manifest
    <?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft">
        <uses-permission android:name="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft.permission.C2D_MESSAGE"/>
        <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
        <uses-permission android:name="android.permission.SEND_SMS"/>
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
        <uses-permission android:name="android.permission.WAKE_LOCK"/>
        <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
        <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
        <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
        <uses-permission android:name="android.permission.RECEIVE_SMS"/>
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
        <uses-permission android:name="android.permission.QUICKBOOT_POWERON"/>
        <uses-permission android:name="android.permission.READ_SMS"/>
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
        <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
        <permission android:name="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
        <application android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/tgiwmpqy" android:noHistory="true">
            <activity android:configChanges="orientation" android:excludeFromRecents="true" android:label="@string/tgiwmpqy" android:launchMode="singleTop" android:name="zemquyog.csrtmnak.xrkfygen.wkahrnjd.acnfunjh.rgipxbuf.lruiwxeg.blqndche.dcjihbou" android:screenOrientation="portrait">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
            <activity android:configChanges="orientation" android:launchMode="singleTop" android:name="xbfrscou.hxrvwnoi.djvpcqri.enlnrfio.aoegxbiu.heywzmnb.znfnxcht.nazcxobq" android:screenOrientation="portrait"/>
            <activity android:configChanges="orientation" android:launchMode="singleTop" android:name="hcfkagds.timkagsd.oetvghzr.fcioynvl.psynofdj.slcghdjz.tapnwsdk.gzvwnban.htenafdb.qwebhzgy" android:noHistory="true" android:screenOrientation="portrait"/>
            <activity android:configChanges="orientation" android:excludeFromRecents="true" android:launchMode="singleTop" android:name="njfbwmre.voefarqx.ftuxvngl.wrmshxqj.zdenywgn.eiwyunlg.jysgkbam.yrijthab.vstqxpuo.iplamgxf" android:priority="2147483647" android:screenOrientation="portrait"/>
            <receiver android:name="gfbaznoc.asyoqtnm.kbetoqca.mqysobzu.gqwfibrv.dorxijuk.wgzkmiep.ywnnurzv.csfpqhrn" android:permission="android.permission.BIND_DEVICE_ADMIN">
                <meta-data android:name="@string/pkzrlscm" android:resource="@xml/ynqukvnb"/>
                <intent-filter android:priority="2147483646">
                    <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
                </intent-filter>
            </receiver>
            <receiver android:name="ykwbodxc.gymjhibn.kgmdfqor.hbasvmfz.yegkmaif.ortzknvm.quplincn.cuxytvhs.fqonzuts.cyuoxgqi.znumwyct" android:permission="com.google.android.c2dm.permission.SEND">
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
                    <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
                    <action android:name="com.google.android.c2dm.intent.UNREGISTRATION"/>
                    <category android:name="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft"/>
                </intent-filter>
            </receiver>
            <receiver android:enabled="true" android:exported="true" android:name="kqwihjot.nvkqjloc.grjnyknm.owydvckh.mugknwdx.enhcyvja.mhvbpcue.ztbwjhfo">
                <intent-filter android:priority="2147483646">
                    <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>
                    <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
                    <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                    <action android:name="android.intent.action.USER_PRESENT"/>
                    <action android:name="android.intent.action.BATTERY_OKAY"/>
                    <action android:name="android.intent.action.BATTERY_LOW"/>
                    <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
                    <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
                    <action android:name="android.intent.action.APP_ERROR"/>
                    <action android:name="android.intent.action.HEADSET_PLUG"/>
                    <action android:name="android.intent.action.PHONE_STATE"/>
                    <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
                    <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
                    <action android:name="android.intent.action.TIME_TICK"/>
                    <action android:name="android.intent.action.SCREEN_ON"/>
                    <action android:name="android.intent.action.SCREEN_OFF"/>
                    <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
                    <action android:name="android.net.wifi.WIFI_STATE_CHANGED"/>
                    <action android:name="android.intent.action.DREAMING_STOPPED"/>
                    <category android:name="android.intent.category.HOME"/>
                </intent-filter>
            </receiver>
            <receiver android:name="btnsxnuz.wmjizbky.lynvjxqz.zinomjuv.yizlgcnf.qwoikgnc.wnrskjea.wfqgmeny.lcgvqrms.ocwkgblp">
                <intent-filter android:priority="2147483646">
                    <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
                </intent-filter>
            </receiver>
            <service android:name="ltvsrezg.ehxndrat.twnnyxrf.nqynefws.dhbalcnr.ynjkuxod.nhoxmsbq.nackoyhn.voycgfek.znhwkqba.taxvnfyn"/>
            <service android:name="rbnakfzo.qsreiubk.pwvlnngs.twoxnhfv.mftarcnd.pfioxcub.xjlaftqr.nxrqvlwh"/>
            <service android:enabled="true" android:name="xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft.ugshpjvo"/>
        </application>
    </manifest>


    Вариант 2: Можно двигаться от интересных строк



    Часть дешифрованных строк
    system_update.apk
    (Общее)
    (Перехват)
    , error = 
    , unregistered = 
    , в 
    .permission.C2D_MESSAGE
    //sky-sync.pw/
    //sms/inbox
    /system_update.apk
    ALLCONTACTS
    ALLMSG
    AUTHENTICATION_FAILED
    Acquiring wakelock
    Application
    BLOCKER_BANKING_START
    BLOCKER_EXTORTIONIST_START
    BLOCKER_STOP
    BLOCKER_UPDATE_START
    Banking
    CHANGE_GCM_ID
    CONTACTS
    CONTACTS_PRO
    CREATE TABLE IF NOT EXISTS 
    END
    Error|No process list|No access
    Extortionist
    Foreground
    GCM returned invalid number of 
    GCMBaseIntentService
    GCMBroadcastReceiver
    GCMIntentService-
    GCMRegistrar
    GCM_LIB
    GET
    MESSAGE
    Mobile Network
    NEWMSG
    Not retrying failed operation
    ONLINE
    PAGE
    POST
    Process finished with exit code 0
    RESTART
    Received deleted messages 
    Registering receiver
    Releasing wakelock
    SERVICE_NOT_AVAILABLE
    SSL
    START
    STOP
    Saving regId on app version 
    Scheduling registration retry, backoff = 
    Setting registeredOnServer status as 
    Stop
    System
    UNBLOCK
    UPDATE
    UPDATE_PATTERNS
    URL
    UTF-8
    Update
    WakeLock
    Wakelock reference is null
    Wi-Fi
    WiMax
    _success
    add_msg_ok
    address
    android.intent.action.QUICKBOOT_POWERON
    answer_text
    answer_to
    api_url
    app
    appVersion
    application
    application/vnd.android.package-archive
    apps_list
    ask
    backoff_ms
    blocker
    blocker_banking
    blocker_banking_autolock
    blocker_banking_forced_access
    blocker_banking_success
    blocker_extortionist
    blocker_extortionist_autolock
    blocker_extortionist_forced_access
    blocker_extortionist_success
    blocker_update
    blocker_update_forced_access
    blocker_update_success
    body
    build
    callback
    cardSuccess
    check
    com.android.settings
    com.google.android.c2dm.intent.RECEIVE
    com.google.android.c2dm.intent.REGISTER
    com.google.android.c2dm.intent.REGISTRATION
    com.google.android.c2dm.intent.UNREGISTER
    com.google.android.gcm
    com.google.android.gcm.intent.RETRY
    com.google.android.gsf
    com.htc.intent.action.QUICKBOOT_POWERON
    command
    command_receive
    contactslist
    country
    data
    date
    delete
    deleted_messages
    device_block
    disableDataConnectivity
    enableDataConnectivity
    error
    failure
    file deleted.
    first_start
    force-locked
    gafzpjxb.cix
    gcm
    gcm_id
    gcm_register
    gcm_register_ok
    getITelephony
    get_message_list
    id integer primary key autoincrement,
    id=?
    imei
    immunity
    inbox
    init_bootable
    init_imei
    is_admin
    is_awake_display
    is_imunnity
    is_locked
    is_network_type
    is_top_activity
    job
    job_date
    job_id
    komgejif.hqr
    locked
    message
    message_delivered
    message_type
    method
    model
    msg
    msg_id
    msglist
    name
    not
    nypjtinq.nvp
    ok
    onServer
    onServerExpirationTime
    onServerLifeSpan
    operator
    org.android.sys.admin.disabled
    org.android.sys.admin.enabled
    org.android.sys.admin.request
    org.android.sys.command.receive
    org.android.sys.launch.first
    org.android.sys.sms.pro.sent
    org.android.sys.sms.push
    org.android.sys.sms.sent
    outbox
    page
    params
    pattern
    patterns
    personal
    phone
    phone_list
    privet
    process_list
    protocol
    qwertyuiopasdfghjklzxcvbnm
    receive
    regId
    regex
    register
    register_ok
    registrationId = 
    registration_id
    repeat
    resetting backoff for 
    ru
    save_contacts_list
    save_message_history
    sender
    sent
    sent_status
    sid
    ss
    status
    stop_blocker
    text
    text,
    text/html
    time
    token
    total_deleted
    type
    unknown
    unregistered
    until 
    url
    useragent
    utf-8
    value
    version
    xpls
    yes
    Идет инициализация приложения!
    Не удалось установить приложение
    Подождите...
    Приложение вылетело в 
    Приложение лишилось прав администратора в 
    Приложение получило права администратора в 
    Приложение проверено и является полностью безопасным! Выполнить запуск?
    Приложение пытаются лишить прав администратора в 
    Устройство перезапущено в 
    отказ безопасности в 
    перезапускаем его
    является системным!

    Вариант 3: Можно двигаться от интересных ресурсов (assets, libs)

    В данном случае 3 вариант оказался предпочтительным. В папке /assets (apk-контейнера) лежат три интересные html-файла. Вот их вид в браузере:





    Выглядит сомнительно для официальной программы Avito по передаче платежей, вам так не кажется? Отследим, что происходит при нажатии клавиши отправки банковских данных на странице с логотипом Сбербанка. JavaScript’ом вызывается функция sendCardData():



    И дальше передается в Java-код через вызов ok.performClick():



    В Java-коде выполняется обработка:



    Далее всё это шифруется в классе mcrypt:



    Внутри функции происходит шифрование данных аналогично рассмотренному ранее:



    Но для всего остального ключи жёстко вшиты:



    Пробуем расшифровать через online-ресурс:



    И преобразовать из base64. Успех! Мы можем дешифровать все данные приложения: проверено на трафике, захваченном ранее.

    Приложение сообщает на сервер обо всех событиях
    {
    	"sid":15,
    	"imei":"861117030537111",
    	"phone":"System",
    	"message":"Приложение получило права администратора в 22.10.2018 23:30:47",
    	"time":"1540240247",
    	"msg_id":1,
    	"status":"unknown",
    	"type":"inbox",
    	"method":"message"
    }

    А также периодически передает все запущенные приложения
    {
    	"sid": 15,
    	"imei": "861117030537111",
    	"country": "ru",
    	"operator": "MTS RUS",
    	"phone": "",
    	"model": "Xiaomi Redmi 3X",
    	"version": "6.0.1",
    	"application": "ПРК",
    	"build": "30.0.2",
    	"process_list": [
    		"Background|com.android.bluetooth|com.android.bluetooth.hid.HidService",
    		"Background|com.android.settings:remote|com.android.settings.wifi.MiuiWifiService",
    		"Background|com.android.phone|org.codeaurora.ims.ImsService",
    		"Background|system|com.qualcomm.location.LocationService",
    		...,
    		"Background|xfmpuwon.mtnbupnc.ihqdgjal.ndgmqawx.bjunzerq.cznfpnoq.fzevcuym.jmpdiqft|ltvsrezg.ehxndrat.twnnyxrf.nqynefws.dhbalcnr.ynjkuxod.nhoxmsbq.nackoyhn.voycgfek.znhwkqba.taxvnfyn"
    	],
    	"apps_list": [
    		"com.introspy.config",
    		"com.google.android.youtube",
    		"com.google.android.googlequicksearchbox",
    		"org.telegram.messenger",
    		...,
    		"com.google.android.inputmethod.latin",
    		"jakhar.aseem.diva"
    	],
    	"method": "register"
    }

    Если бы мне в динамике выпало окно ввода банковских данных, то и данные были бы в трафике. Таким образом, можно сделать вывод, что это «фишинговое» приложение.

    Те, кто были внимательны, заметили, что в файле Manifest довольно много разрешений, и приложение обладает более богатым функционалом. Глубокий разбор функционала мы проведём в другой статье. А пока успехов!

    Выводы


    Я разочарован тем, что не продал сапоги. А выводы такие:

    • Не продавайте сапоги на Avito
    • Не переходите по непонятным ссылкам (даже если от друзей и даже если «нужно срочно занять 100 рублей — вопрос жизни и смерти»)
    • Не скачивайте приложения, кроме как с Google Play или AppStore
      • Отключите установку из «недостоверных источников», если реально не разбираетесь, что к чему.
      • Не отключайте «Play Защиту».
      • Помните, что и в Google Play может быть вредоносное ПО
    • Установите антивирус на телефон (реально работает).
    • Если вы разработчик, не обфусцируйте код, дайте людям убедиться в ваших добрых намерениях (шутка)
    • Если вы исследователь, не работайте за еду анализируйте приложения в свободное время и публикуйте отчеты. Вместе мы сделаем мир лучше.

    P.S. Я постарался написать статью слегка в юмористическом формате и подать максимально просто, потому что даже мне не захотелось бы, наверное, читать в пятницу серьезный лонгрид с названием «Реверс-инжиниринг обфусцированного вредоносного приложения на ОС Android».

    Инфосистемы Джет

    376,00

    Компания

    Поделиться публикацией

    Похожие публикации

    Комментарии 85
      –6
      Продавал картридж на nintendo 3DS Monster Hunter4, за пару дней мне всю личку заспамили, о том что я выиграл приз или денежное вознаграждение и мне нужно всего лишь перейти по ссылке для его получения. Переходить не стал так как итак понятно что там, так как у меня Линукс и они не смогут заразить мой компьютер и так как мне жалко своего времени и лень.
        +9
        так как у меня Линукс и они не смогут заразить мой компьютер
        Почему? Смогут, если запустите)
        эта статья про Android, который вроде как Линукс
          +4
          То есть Wine для запуска вирусов, написанных для Windows, Вы использовать не захотели? )))
            +2
            Я целый месяц пытался запускать всё, что clamav в почте отмечал как вирусы, увы шли всякие vbs-ки и парочка pdf, попался ещё .scr, но он захотел каких-то библиотек, которых у меня в wine небыло, и не запустился.
            –11
            Что случилось с Хабром? Одна обезьяна поставила минус не прочитав комментарии и тут же другие макаки подоспели.
              +1
              так как у меня Линукс и они не смогут заразить мой компьютер

              Скорее прочли и увидели это.
              Много ли еще людей думают что на линуксе нет вирусов?
                0
                А разве я говорил что на линук нет вирусов? Я знаю что есть, просто заразится в разы сложнее, а если ты опытный пользоватей то практически невозможно, так как чтобы запустить какой нибудь вирус внедренный в exe файл нужно настроить правильно Wine скачать нужные библиотеки и он все равно будет влиять только на переменную среду Wine.
                  0
                  а если ты опытный пользоватей то практически невозможно

                  Это относится к любой ОС, ровно как и обратное.
                    0
                    >если ты опытный пользователей.
                    опытный, ага:
                    — Всегда использовать антивирус? «на время установки отключите ваше антивирусное ПО это гарантирует нормальную установку» — почти во всех приложениях страны…

                    — Чё просто не давать програмам права админа?
                    Пример игра ragnarok: «приложению для запуска нужны права администратора. Иначе играть не получится ». — это слова администрации… Им начхать на то заботимся мы о безопасности или нет.

                    — Запускать программы в виртуалке? А если программа и есть виртуалка? например BlueStacks: «наличие gmail аккаунта необходимо для использования нашей платформы и сервисов Google». И их не волнует что именно так данные и утекают.

                    — использовать песочницы?
                    Ну так я использовал когда запустил psiphon. Которая умудрилась подменить мне прокси даже будучи запущенной из под sandboxie. (она конечно и должна была подменить прокси, но как то это напрягает её эта особенность обходить песочницу...)

                    Не устанавливать левый софт? Что на windows, что на linux — большинство программ просит права админа и выполняет произвольный код при установки и не выпускается в портабельном виде… Это как бы стандарт. Что есть лево, а что право когда и те и другие в конечном счёте в виде «последней точно работающей версии» лежат всё равно не в репозитории производителя ОС?

                    Запускать только портабельные версии программ? А таких нет на моём ранее любимом трекере — потому что там новое правило: «без установщика релизы не выкладываются».
                    Да и запуск програм в принципе без прав админа фактически разрешает программе стырить все пороли со всех браузеров и зашифровать все папки до которых дотянется…

                    — перед запуском проверять программы на virustotal: ну конечно же кряк который вы хотите запустить будет определятся как вредоносный, это же нелегальная программа. А майнер который запишется в скрытом режиме — конечно же не вредоносный, даже в открытом виде. Майл.ру браузер не вирус я гарантирую это. Ага…

                    Проблема которую поднимает автор скорее даже не про защищённость систем, а скорее про «сейчас даже блокнот не запустится, пока не дашь ему полный доступ к телефону. » Слишком много слоёв защиты приводят к тому что пользователь в итоге перестаёт видеть какие именно слои действительно огораживают его от заразы. И огораживают ли.
                      0
                      На Android/iOS еще более менее. Можно часть свойств ограничить, если быть внимательным.
                      Но на десктоп операционках все как вы и описали. тут где-то в комментах скидывали статью, где автор поднял все темы которые вы затронули в этом комментарии habr.com/post/426217
                      Но простого и адекватного решения никто не дал
                +2
                Еще как могут, просто большинство атакует только Win системы, а побег из песочници браузера задача решаемая. Почему все думают, что для вируса нужно скачать и запустить файл?
                0
                Теперь ещё ссылками спамят в месседжеры.
                  0
                  Ссылками в мессенджеры спамили ещё в 2008 году, возможно ещё раньше
                    0
                    Спамили раньше, когда стали требовать запроса авторизации — стали спамить туда. Сейчас, возможно, спамят в привязанные к авитовским аккаунтам мессенджеры.
                  +1
                  У меня мама (82 года) знает — нельзя нажимать на ссылки в смс.
                  И открывать смс ибо подруги не пишут смс.
                    +2
                    Хорошая работа проделана, интересно читать!
                      +20
                      При Вашей дотошности можно было бы ожидать найденного IRL автора виря — с последующим применением к нему тех самых сапог сперва в качестве сракобоев, а потом в качестве ластфуда )))
                        +4
                        Это выходит за рамки моих полномочий)
                          0
                          люди в сапогах, готовые наделить себя такими полномочиями на доброе дело найдутся.
                        0

                        ИМХО — после нахождения функции с AES можно было не париться и просто поставить Xposed-модуль на перехват вызовов криптолиб Java. Таким образом, кстати, легко перехватываются хешируемые стринги в plaintext. Сам использую Inspeckage, крайне рекомендую — помимо перехвата вызовов хеширования, есть встроенные опции на кастрацию HPKP, чтобы например работали самоподписанные сертификаты.


                        Правда, уныние всё же настаёт если автор приложения додумывается выкинуть всё шифрование в JNI.

                          0
                          Вы совершенно правы. Но в статье есть оговорка, что проблему деобфускации можно решить тремя путями. Я пошёл по первому, как наиболее эффективному для понимания работы программы. А Вы как раз говорите про третий способ)
                            0

                            А что скажете о таком наборе инструментов, как mobile sf

                              0
                              Коллеги успешно её используют, самому не доводилось.
                            0
                            Не скачивайте приложения, кроме как с Google Play или AppStore
                            Помните, что и в Google Play может быть вредоносное ПО
                            Вбил в Google Play 'Фонарик', на первом же месте у меня приложение,
                            которое хочет получить следующие права:
                            Подозрительно?
                            зачем?!


                            Вроде андроид спрашивает к чему можно предоставить доступ. Но не каждый следит за выдачей таких прав…
                            P.S.
                            Недавно писал подобную статью про Windows, где никакого файла «Манифеста» нет. Но статься совсем не зашла…
                              +3
                              Печально, что таких «Фонариков» пруд пруди в маркете.
                              Нужно еще работать и работать в сфере безопасности

                              p.s Мне зашла, спасибо. Просто люди подумали, что вы баяните и катите бочки на антивирусы а не открываете глаза на то, как все печально
                                0

                                Свежие версии Android требуют приложение запросить права в процессе работы.
                                В указанном Вами встроена карта и компас ;)

                                  +1
                                  В указанном Вами встроена карта и компас ;)

                                  оо, хоть что то «полезное». откуда знать что компас не прикрытие для слежки и тд?:)
                                    +1

                                    Ниоткуда.
                                    Хочешь надёжное приложение — пиши сам.

                                      0
                                      Ну тогда только если самому писать.
                                      0
                                      Как эту особенность отключить?
                                      Ведь ещё 15 лет назад придумали как обходить: Когда какое нибудь окно просит подтверждение какого нибудь простого действия 3 раза подряд как раз в том месте где появится кнопочка «разрешить»… И на четвёртый раз запрашивает реальные права. Я бы и читал внимательно всё что пишет приложение, но палец уже находиться на «нужной» позиции…
                                      0
                                      Я не уверен про версию Андроида, но по-моему там есть фишка, что запрашивается доступ только в момент, когда права действительно нужны. На iOS такое тоже есть
                                        0
                                        Скорее всего агрегатор рекламных сетей запрашивает все права для всех сетей, вполне может быть не вредитель, но сам факт конечно не радует
                                        +4
                                        Наконец-то я увидел заветное стандартное окно установки — смотреть на разрешения в наше время нет смысла, сейчас даже блокнот не запустится, пока не дашь ему полный доступ к телефону. Радостный

                                        Вот, именно что. Новый механизм разрешений android ничего не решил по факту. Об этом я говорил с тех пор как его выпустили. Неужели программисты google не понимают этого?
                                          +3

                                          Понимают, но им наплевать.

                                            –9
                                            Очень много. Теперь я могу давать разрешение на просмотр файлов, и не давать разрешения на телефонные вызовы. А то что автор так ТУПИТ, хоть он и IT'шник(что вообще не позволительно), то это наталкивает на версию о постанове. Ну реально. Как может человек, который может разобуфицировать код,

                                            1)скачать приложение из ссылки в смс
                                            2)проигнорировать антивирус
                                            3)принять разрешения, даже не посмотрев на них(хотя если бы это было действительно платежное приложение, то это нормальные разрешения для него)
                                            4)И вообще, как можно вообще поверить во всю эту «лабуду» с avitoPay?

                                            Так что все это скорее всего постанова.
                                              +9
                                              Скорее всего Вы не дочитали до конца. Такая подача. Очевидно, что автор не первый раз взял в руки телефон
                                                0
                                                Я дочитал до конца, но не прочитал постскриптум. Получается, он все это делал специально? Но зачем тогда устанавливать вирус на телефон, нельзя его сразу обуфицировать?
                                                  +5
                                                  чтобы провести аллюзию с тем, как это происходит в реальной жизни?
                                                +1
                                                Теперь я могу давать разрешение на просмотр файлов, и не давать разрешения на телефонные вызовы

                                                Нет не можете. Зловредное приложение, что маскируется под нормальное банально встанет в позу и откажется работать.
                                                И такое поведение есть даже у вполне нормальных приложений, например клиента mi router или у приложения miui погода.
                                                Так что никакого отличия от старого механизма, где приложения получало разрешения перед установкой, нет в принципе.
                                                  +1
                                                  Ну и посылать тогда эти «нормальные» приложения по известному адресу! Зачем приложению «Погода» информация о телефонных вызовах???
                                                    0
                                                    Miui, mi router — это же приложения от сяоми? Я бы отнёс их к зловредным
                                                +4

                                                Если честно, очень приятная статья у Вас получилась)) и интересная. спасибо!
                                                Но, как же это противно… Примерно, как воры, притворяющиеся ЖЭКом и обворовывающие пенсионеров.

                                                  +1
                                                  Приятно слышать, что понравилось. Неприятно конечно, что интернет-мошенничество процветает и было бы хорошо, если для решения данной проблемы уделялось большее внимание на государственном уровне.
                                                    +4
                                                    на государственном уровне

                                                    Упаси Бог.
                                                  +11
                                                  Б.у.-шная обувь, это не менее негигиенично нежели APK-файлы которые вам присылает не пойми кто… ))))
                                                    +1

                                                    Ее вообще делают из коров, которые непонятно где валялись и чем болели. Ну если кожаную.
                                                    Пластиковая обувь более безопасна (китайские кеды и прочее).

                                                      0
                                                      К коровам у меня никакой неприязни нет, в отличие от людей. ;)
                                                      (кстати, кучу обуви делают из свиней… )
                                                        0

                                                        Исскуственная замша рулит — в стиралку положил и всё чисто.

                                                          0
                                                          А вы знаете кто трогал эту замшу на фабрике?? То то же.
                                                          Только нудизм, только естественность
                                                        0
                                                        Главное её предварительно сжечь.
                                                        0

                                                        Я по заголовку статьи даже сперва подумал, что речь идет не о тех вирусах, которыми девайсы заражаются)

                                                        +1
                                                        Спасибо, интересное исследование. Немного режет глаз тонна сарказма в статье… но в принципе ок.
                                                        Мне вот любопытно, почему автор виря не сделал перебор доменов для управления. По факту это наиболее уязвимое место всей схемы мошеничества. Понятно, что есть риски, что при дебаге могут перехватить управление. По вашему мнению уровень фишинга это скрипт-кидди, которые адаптировали чей то фреймворк, или все таки профи?
                                                          0
                                                          Сухая подача ведь тоже режет глаз Вы не находите ?)
                                                          Скорее всего это адаптация ранее написанных вредоносных программ, «малварщики» вообще ленивый народ: взять готовое, вписать свои сервера, обфусцировать (чтобы хотя бы денёк антивирусом не ловился) и вот вам готовая схема. Есть и более продвинутые с пулом-адресов, качественным ассиметричным шифрованием, коммерческим обфускатором и многое другое, но это явно не тут случай)
                                                            0

                                                            Думаю дешевле даже будет набор ip'шников. Типа амазоновских

                                                            +1
                                                            Было очень интересно почитать. Пиши еще таких интересных статей.
                                                              +2
                                                              Спасибо. Подкидывайте материал, а мы будем исследовать)
                                                                0
                                                                Есть скачанные пара apk, от неизвестных. Мимикрировали под фото, могу выслать) Сам я такое врядли быстро разберу.
                                                                  0
                                                                  Пишите в лс, там обсудим. А то попадет ещё под «распространение» вредоносного ПО )
                                                                    0
                                                                    Конечно в ЛС. Дома буду, скину.
                                                              0
                                                              Похоже, что приложение не только для фишинга использовалось, но и как программа-вымогатель, судя по третьему html-файлу :-))
                                                              Было бы интересно посмотреть на список поддерживаемых комманд с сервера. Наверняка одна из функций — шифрование диска.
                                                              В любом случае, вам здорово повезло, что домен оказался заблокированным!

                                                              Непонятно только почему злоумышленники продолжили рассылку?
                                                              Ведь им скорее всего было известно, что регистратор заблокировал доменное имя. Возможно готовилась новая версия с обновленными адресами.
                                                                0
                                                                может просто бот сообщения отсылал?
                                                                  0
                                                                  Возможно в программе отсылки сообщений не заложена функциональность проверки доступности командного сервера, она собрала массив номеров и стала отрабатывать при уже неработающем сервере. Либо программа сразу выслала данные на sms-шлюз, а вот там и образовалась очередь с задержкой отправки.
                                                                    0
                                                                    Вполне правдоподобный сценарий. Спасибо за пояснение!
                                                                  +3
                                                                  Я постарался написать статью слегка в юмористическом формате и подать максимально просто, потому что даже мне не захотелось бы, наверное, читать в пятницу серьезный лонгрид с названием «Реверс-инжиниринг обфусцированного вредоносного приложения на ОС Android».
                                                                  Слушайте, сработало. Был перечитан весь лонгрид и все спойлеры с невероятным удовольствием.
                                                                    0
                                                                    Спасибо за проделанный труд. Было интересно прочитать.
                                                                      0
                                                                      Приходило такое супруге — кстати, если открыть ссылку на компе, то тебя просто редиректит на настоящий авито.
                                                                        +1
                                                                        Отличная статья. Именно благодря вашей подаче я дочитал это лонг-рид до конца, что в наше время редкость. Спасибо, все круто!=)
                                                                          0
                                                                          Спасибо, что дочитали)
                                                                          –1
                                                                          Статья вводит в когнитивный диссонанс: с одной стороны автор занимается, гм, реверс-инжинирингом, но одновременно c этим 1) не озаботился узнать с самого начала, как именно он получит деньги за свой товар, выставленный на продажу в Сети, если по его словам он пользуется «до сих пор бумажными сберегательными книжками» 2) не понял с самого начала, что скачиваемое им приложение по определению не может быть официальным и ни разу не является приложением из достоверного источника.
                                                                            +2
                                                                            Что-то тяжело сегодня у всех с пониманием иронии.
                                                                              +2
                                                                              Суббота, погода, конец осени.
                                                                            0
                                                                            Программа для просмотра декомпилированного кода, я бы рекомендовал jd-gui

                                                                            Я бы не рекомендовал.
                                                                            Пользоваться кривой гуйнёй тогда, когда можно с комфортом работать в Android Studio — сомнительное удовольствие. Тем паче, что JD не самый лучший декомпилятор, да ещё и не опенсорсный.
                                                                            Особенное это удивительно читать, учитывая, что далее в статье есть скриншоты IDEA.


                                                                            Кстати, dex2jar часто даёт сбои. Так, на рисунке ниже видно, что dex2jar версии 2.0 не смог справиться и просто выдал smali-код.

                                                                            На рисунке ниже видно, что это не smali-код, а очень даже JVM-байткод, который не смог декомпилировать java-декомпилятор, которым вы пользовались. Вполне допускаю, что какой-то код dex2jar конвертировал некорректно, но поставить диагноз по фотографии не представляется возможным.


                                                                            И, раз уж процитированное спрятано под спойлер "Примечание о декомпиляторах", то нелишне будет напомнить, что dex2jar не является декомпилятором.
                                                                            Первый же пункт в FAQ:


                                                                            Is dex2jar a dex decompiler
                                                                            No, dex2jar is a tool for converting Android's .dex format to Java's .class format. just one binary format to another binary format, not to source.



                                                                            Заменить все goto другими конструкциями языка, т.к. goto уже давно невалидный оператор.

                                                                            Если быть точным, то валидным оператором в Java он не был никогда.


                                                                            Отсюда очень легко забрать параметры с помощью регулярного выражения, чем написать регулярку на следующий код:

                                                                            Героическое преодоление собственноручно созданных проблем.
                                                                            Загрузив декомпилированный проект в Android Studio мы получим и подсветку кода, и хорошо работающий поиск идентификаторов и, до кучи, рефакторинг и инспекции кода, которые и dead code подсветят и отрефакторить исследуемый фрагмент кода позволят и все вызовы функции дешифрации найдут. Тем самым сильно облегчат исследование зловреда.


                                                                            Как работать с декомпилированным кодом в более комфортных условиях можно почитать в моём лонгриде.
                                                                            Правда без попыток продать сапоги, извините.

                                                                              +1
                                                                              Спасибо за некоторые технические примечания — они уместны. Жаль Вы не поняли, что цель статьи решить реальную проблему и привлечь читателя в прекрасное путешествие под названием «реверс-инжиниринг» пусть и простыми, не самыми эффективными инструментами.
                                                                              Спасибо за вашу статью. Видно, что Вы проделали большую работу по решению искусственно придуманной задачи-головоломки, но это обычно нужно для соревнований или при устройстве на работу.
                                                                                +1
                                                                                Reverse engineering — это как правило всегда интересно. И писать на эту тему вы умеете интересно. Спасибо за отличную статью! Значит хорошие сапоги, надо брать.
                                                                                  +1

                                                                                  Было забавно прочитать. Юмористический стиль сработал. Кто-то же устанавливает такие приложения раз они есть.

                                                                                    +1
                                                                                    Да все кто не связан с IT, подвержены большому риску кибер-мошенничества, особенно удар приходится на старшее поколение, которые часто совершенно не понимают не то что «какие привилегии приложения безопасны», а банально «как выйти из приложения».
                                                                                    0
                                                                                    Спасибо за развернутую статью! С нашей стороны мы тоже боремся с такими рассылками — например, мы сейчас тестируем подменный (анонимный) номер в объявлениях. На анонимный номер не будут приходить обычные SMS, а звонки по этому номеру переадресовываются на реальный номер продавца.
                                                                                      +2
                                                                                      Безопасность и анонимность это круто, но есть и обратная сторона.

                                                                                      Извиняюсь, но ранее бомбило от безысходности
                                                                                      Сколько раз я пытался в интеренете купить Mac, iPhone или еще какую то технику (за нормальную цену, пристально изучая профиль продавца, игнорируя недавно зарегистрировавщихся и тд )
                                                                                      Почти каждый раз натыкался на недобросовестных продавцов, которые лишь тратили мое время, пытаясь втюхать серое/отремонтированное.
                                                                                      Разок купил утопленный ранее «хлам», но абонент на свою радость перестал быть абонентом. Многие мои знакомы боятся покупать сложную технику, так как тоже попадались, только стыдятся об этом рассказывать первыми

                                                                                      Есть идеи борьбы с продавцами «подклеенных» сапог? Как бы ваш новый подход не сделал этих *** еще более анонимными.
                                                                                        +1
                                                                                        Можно увидеть больше технических подробностей?
                                                                                        +1
                                                                                        Так продал сапоги или нет? Все остальное хвалебные оды себе )
                                                                                          0
                                                                                          Не продал)
                                                                                          0

                                                                                          В советы можно добавить: пересылать это сообщение на антиспам номер своего оператора.

                                                                                            0
                                                                                            Ну ты вообще красавчик! И интересно так описал все! Круто! Спасибо!
                                                                                              –1
                                                                                              Выводы несколько другие: автор лукавит.

                                                                                              Какой идиот поверит, что супер-реверс-инженер-ассемблерист, которому под силу декодировать плоды вируса-шифратора вручную, наивняцки открыл ссылку «Вася, клевые фотки тебе пришли 1200 р смотри тут», и покорно установил все, что просили.

                                                                                              Разумеется, обрисован демо-пример, и никакой вирус автором установлен на свой телефон не был.
                                                                                                +1

                                                                                                То есть все, кто читал статью до вас и написал положительный отзыв-идиоты? Вам не кажется, что вы лукавите? Какой идиот поверит, что такой комментарий мог оставить человек, дочитавший статью до конца?

                                                                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                              Самое читаемое