Как стать автором
Обновить

Троян в highscreen, или как телефон начал творить чудеса

Время на прочтение6 мин
Количество просмотров132K
Добрый день, Хабр!
Хочу поведать вам историю, которая чуть не спровоцировала поседение моей, еще молодой, головы.
Предыстория
Все началось с того, что я приобрел себе Highscreen Omega Prime S пару месяцев назад, был доволен как слон, никак не мог нарадоваться этому чудесному аппарату, который работал шустро и почти без нареканий. И все бы было отлично, если бы я однажды не увидел кучу нотификаций, которые выглядели как-то так:


И я уж начал думать — что же это такое, откуда оно взялось, может быть, мой телефон сломали, но как?! Но через несколько секунд паника стихла, я зажал одно из уведомлений, выбрал пункт «Информация о приложении», и был очень удивлен, увидев то, что уведомления вывело приложение «Обновление ПО»…

Еще больше меня удивило то, что этому приложению требуются разрешения для отправки SMS, определения местоположения, установка шорткатов и спаривание с Bluetooth устройствами.
Полный список разрешений
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.READ_LOGS"/>
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.GET_TASKS"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="com.android.vending.BILLING"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
    <uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.REBOOT"/>


Пока я думал, как бы мне избавиться от этого приложения, скачивал утилиту для рутования и просто размышлял о том, как такое вообще возможно — у меня появилось штук 5 шотркатов (точнее, я заметил их наличие, вероятно, они появились вместе с нотификациями):


Я сразу же утащил APK файл с телефона, разобрал его на составляющие части с помощью утилит apktool, dex2jar и jd-gui — и приступил к изучению.

Изучение

Изучение началось с анализа AndroidManifest.xml, и второе, что меня смутило в нём — это наличие сервисов и ресиверов, находящихся внутри пакета com.gmobi.trade (при том, что само приложение в com.redbend.dmClient).
Перечень сервисов и ресиверов
<activity android:name="com.gmobi.trade.ActionActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar">
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>
<service android:name="com.gmobi.trade.ActionService"/>
<receiver android:enabled="true" android:name="com.gmobi.trade.ActionMonitor">
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_ADDED"/>
        <action android:name="android.intent.action.PACKAGE_REPLACED"/>
        <action android:name="android.intent.action.PACKAGE_REMOVED"/>
        <data android:scheme="package"/>
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</receiver>


И тут виден очень подозрительный ресивер — зачем приложению, которое обновляет систему, отслеживать добавление/удаление приложений? А также при беглом просмотре кода было обнаружено то, что ActionMonitor запускает ActionService, который в свою очередь запускает TradeService, который же, в свою очередь, запускает что-то неведомое и обфусцированное. К сожалению, большинство кода, который мне выдал jd-gui, не поддается анализу на трезвую голову.

SMS

Да, и код для отправки SMS в этом приложении имеется: откуда-то приходит JSON, из которого создается AlertDialog, и в обработчике нажатия positive button происходит отправка SMS. Радует что хотя бы не в фоне это происходит. Но все равно неясно, зачем утилите для обновления ПО вообще отправлять куда-то SMS-сообщения.
Код отправки SMS
AlertDialog.Builder localBuilder2 = new AlertDialog.Builder(this);
localBuilder2.setTitle(str14);
localBuilder2.setMessage(str15);
localBuilder2.setPositiveButton(str16, new DialogInterface.OnClickListener(locallqe, str1, str19, str18, localNotificationManager, i) {
    public final void onClick(DialogInterface paramDialogInterface, int paramInt) {
        b.b(c, 3);
        SmsManager localSmsManager = SmsManager.getDefault();
        dfe.a("Sending [" + d + "] to [" + e + "]");
        localSmsManager.sendTextMessage(e, null, d, null, null);
        f.cancel(g);
        finish();
        b.b(c, 5);
    }
});
localBuilder2.setNegativeButton(str17, new DialogInterface.OnClickListener(locallqe, str1) {
    public final void onClick(DialogInterface paramDialogInterface, int paramInt) {
        b.b(c, 4);
        finish();
    }
});
localBuilder2.setCancelable(false);
localBuilder2.create().show();



Bluetooth, геокоординаты и прочее

Тут все более-менее безопасно. Ну, как “безопасно”… приложение всего лишь получает MAC-адрес bt-адаптера, получает геокоординаты, проверяет, включен ли Wi-Fi, получает MAC-адрес wifi-адаптера и отправляет эти данные в неизвестность :)
Код сбора информации
public final JSONObject f() {
    JSONObject localJSONObject1 = new JSONObject();
    try {
        localJSONObject1.put("sdk", "go2sync");
        localJSONObject1.put("sdk_v", "1.2");
        localJSONObject1.put("sdk_b", "2014.03.06.1");
        localJSONObject1.put("app", a.getPackageName());
        localJSONObject1.put("ch", t);
        localJSONObject1.put("app_v", opt.e(a));
        localJSONObject1.put("imsi", q.j);
        localJSONObject1.put("imei", q.k);
        localJSONObject1.put("wifi", k);
        localJSONObject1.put("gprs", l);
        localJSONObject1.put("brand", g());
        localJSONObject1.put("sd", opt.c());
        localJSONObject1.put("id", c());
        azw.lqe.azw localazw = opt.c(a);
        StringBuilder localStringBuilder = new StringBuilder("ua:")
                .append(opt.a(false))
                .append("|imei:")
                .append(localazw.a())
                .append("|imsi:")
                .append(localazw.b())
                .append("|wmac:")
                .append(opt.b(a))
                .append("|bmac:");
        localJSONObject1.put("cid", opt.a(opt.a() + "|sn:" + opt.a(a)))
        localJSONObject1.put("ua", opt.a(false));
        localJSONObject1.put("os", "android");
        localJSONObject1.put("os_v", opt.b());
        localJSONObject1.put("lang", Locale.getDefault().getLanguage())
        localJSONObject1.put("country", opt.h(a));
        localJSONObject1.put("gp", q.n);
        localJSONObject1.put("wmac", opt.b(a));
        localJSONObject1.put("bmac", opt.a());
        localJSONObject1.put("sn", opt.a(a));
        localJSONObject1.put("sa", opt.g(a));
        localJSONObject1.put("sw", opt.j(a));
        localJSONObject1.put("sh", opt.k(a));
        Location localLocation = opt.f(a);
        if (localLocation != null) {
            JSONObject localJSONObject2 = new JSONObject();
            localJSONObject2.put("lng", localLocation.getLongitude());
            localJSONObject2.put("lat", localLocation.getLatitude());
            localJSONObject1.put("loc", localJSONObject2);
        }
        localJSONObject1.put("roaming", opt.o(a));
        return localJSONObject1;
    } catch (JSONException localJSONException) {
        dfe.a(localJSONException);
    }
    return localJSONObject1;
}



Итоги

Телефон пришлось рутануть, чтобы удалить это приложение. Как обновлять теперь систему — неизвестно.

P.S.

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

UPD1: Virustotal — www.virustotal.com/ru/file/108299c363e361d85b8e34676806373c7e445ae6731b3f3400d77cf947550b6c/analysis/1412500174

UPD2: Как оказалось, highscreen признал проблему, сославшись на то, что это ошибка GMobi. Ссылка: highscreen.org/babltrabl
Но только есть одно НО: highscreen сослался на FOTA-провайдера, но на мой девайс через OTA не прилетало еще ни одного обновления.
Спасибо Peyt за информацию!
Теги:
Хабы:
Всего голосов 85: ↑81 и ↓4+77
Комментарии56

Публикации

Истории

Работа

Ближайшие события

19 августа – 20 октября
RuCode.Финал. Чемпионат по алгоритмическому программированию и ИИ
МоскваНижний НовгородЕкатеринбургСтавропольНовосибрискКалининградПермьВладивостокЧитаКраснорскТомскИжевскПетрозаводскКазаньКурскТюменьВолгоградУфаМурманскБишкекСочиУльяновскСаратовИркутскДолгопрудныйОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн
24 – 25 октября
One Day Offer для AQA Engineer и Developers
Онлайн
25 октября
Конференция по росту продуктов EGC’24
МоскваОнлайн
26 октября
ProIT Network Fest
Санкт-Петербург
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань