habrahabr

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

  • понедельник, 6 октября 2014 г. в 03:10:55
http://habrahabr.ru/post/239213/

Добрый день, Хабр!
Хочу поведать вам историю, которая чуть не спровоцировала поседение моей, еще молодой, головы.
Предыстория
Все началось с того, что я приобрел себе 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 за информацию!