Подключение расширений Chrome в Human Emulator Studio.

Подключение расширений Chrome в Human Emulator Studio.

К сожалению, на данный момент Chromium не позволяет устанавливать расширения Chrome и использовать их. Хотя в планах разработчиков CEF и входит реализация этого функционала. Но есть способ, который всё таки позволяет использовать функционал расширений Хрома в Human Emulator Studio. Давайте сделаем это на примере плагина Font Fingerprint Defender. Этот плагин подменяет отпечатки системных шрифтов — Font Fingerprint. После установки плагина в Chrome при каждом переходе на страницу у вас подменяется значение Font Fingerprint. Это можно увидеть на любом сайте для проверки Font Fingerprint например на browserleaks.com/fonts.

Установка расширения.

Для это находим расширение в интернет-магазин chrome https://chrome.google.com/webstore/detail/font-fingerprint-defender/fhkphphbadjkepgfljndicmgdlndmoke и нажимаем кнопку Установить.

После установки находим id расширения. Если перейти в браузере Chrome по адресу chrome://extensions, то мы перейдём на список всех установленных в Chrome расширений.

Находим интересующий нас нажимаем кнопку Details и переходим на описание расширения при этом в адресной строке можно увидеть id расширения chrome://extensions/?id=fhkphphbadjkepgfljndicmgdlndmoke.

Если внимательно посмотреть на путь к расширению в интернет магазине Chrome, то там также присутствует этот id https://chrome.google.com/webstore/detail/font-fingerprint-defender/fhkphphbadjkepgfljndicmgdlndmoke.

Этот id нам нужен для того что бы найти файлы расширения в папке с расширениями Хрома. В Windows 7 Папка эта находится по адресу C:Usersимя пользователяAppDataLocalGoogleChromeUser DataDefaultExtensions.

Находим папку с именем нашего id. Это и есть интересующий нас шаблон.

В этой папке находим файл inject.js. В этом расширении он лежит в папке fhkphphbadjkepgfljndicmgdlndmoke.1.0_0datacontent_script.

Нас интересует содержимое этого файла.


var background = (function () {
  var tmp = {};
  chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    for (var id in tmp) {
      if (tmp[id] && (typeof tmp[id] === "function")) {
        if (request.path === 'background-to-page') {
          if (request.method === id) tmp[id](request.data);
        }
      }
    }
  });
  /*  */
  return {
    "receive": function (id, callback) {tmp[id] = callback},
    "send": function (id, data) {chrome.runtime.sendMessage({"path": 'page-to-background', "method": id, "data": data})}
  }
})();

var inject = function () {
  var rand = {
    "noise": function () {
      var SIGN = Math.random() < Math.random() ? -1 : 1;
      return Math.floor(Math.random() + SIGN * Math.random());
    },
    "sign": function () {
      const tmp = [-1, -1, -1, -1, -1, -1, +1, -1, -1, -1];
      const index = Math.floor(Math.random() * tmp.length);
      return tmp[index];
    }
  };
  //
  Object.defineProperty(HTMLElement.prototype, "offsetHeight", {
    get () {
      const height = Math.floor(this.getBoundingClientRect().height);
      const valid = height && rand.sign() === 1;
      const result = valid ? height + rand.noise() : height;
      //
      if (valid && result !== height) {
        window.top.postMessage("font-fingerprint-defender-alert", '*');
      }
      //
      return result;
    }
  });
  //
  Object.defineProperty(HTMLElement.prototype, "offsetWidth", {
    get () {
      const width = Math.floor(this.getBoundingClientRect().width);
      const valid = width && rand.sign() === 1;
      const result = valid ? width + rand.noise() : width;
      //
      if (valid && result !== width) {
        window.top.postMessage("font-fingerprint-defender-alert", '*');
      }
      //
      return result;
    }
  });
  //
  document.documentElement.dataset.fbscriptallow = true;
};

var script_1 = document.createElement('script');
script_1.textContent = "(" + inject + ")()";
document.documentElement.appendChild(script_1);

if (document.documentElement.dataset.fbscriptallow !== "true") {
  var script_2 = document.createElement('script');
  script_2.textContent = `{
    const iframes = window.top.document.querySelectorAll("iframe[sandbox]");
    for (var i = 0; i < iframes.length; i++) {
      if (iframes[i].contentWindow) {
        if (iframes[i].contentWindow.HTMLElement) {
          iframes[i].contentWindow.HTMLElement.prototype.offsetWidth = HTMLElement.prototype.offsetWidth;
          iframes[i].contentWindow.HTMLElement.prototype.offsetHeight = HTMLElement.prototype.offsetHeight;
        }
      }
    }
  }`;
  //
  window.top.document.documentElement.appendChild(script_2);
}

window.addEventListener("message", function (e) {
  if (e.data && e.data === "font-fingerprint-defender-alert") {
    background.send("fingerprint", {"host": document.location.host});
  }
}, false);

Это и есть код нашего расширения теперь выполним его в Human Emulator Studio c помощью функцию объекта browser set_init_java_script.

Отладка расширения.

Только перед этим надо удалить всё лишнее из кода. Все обращения к chrome как например chrome.runtime.onMessage.addListener. Проверить код можно с помощью консоли разработчика.

С помощью консоли разработчика (открывается по нажатию на клавишу F12) отладим js код для вызова его в функции.

Открываем в Human Emulator Studio Инструменты разработчика вкладку Console и вставляем туда текст нашего скрипта. Вызываем его на выполнение клавиша Enter.

Получаем список ошибок и убираем строки, которые являются причиной ошибок. Для того что бы посмотреть какая строка источник ошибки нажимаем справа от ошибки на текст WM130:3.

Выполнение расширения.

Убираем лишнее и получаем следующий php код:

// отредактированный код расширения
$js="var inject = function () {
  var rand = {
    'noise': function () {
      var SIGN = Math.random() < Math.random() ? -1 : 1;
      return Math.floor(Math.random() + SIGN * Math.random());
    },
    'sign': function () {
      const tmp = [-1, -1, -1, -1, -1, -1, +1, -1, -1, -1];
      const index = Math.floor(Math.random() * tmp.length);
      return tmp[index];
    }
  };
  //
  Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
    get () {
      const height = Math.floor(this.getBoundingClientRect().height);
      const valid = height && rand.sign() === 1;
      const result = valid ? height + rand.noise() : height;
      return result;
    }
  });
  //
  Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
    get () {
      const width = Math.floor(this.getBoundingClientRect().width);
      const valid = width && rand.sign() === 1;
      const result = valid ? width + rand.noise() : width;
      return result;
    }
  });
  //
  document.documentElement.dataset.fbscriptallow = true;
};

var script_1 = document.createElement('script');
script_1.textContent = '(' + inject + ')()';
document.documentElement.appendChild(script_1);

if (document.documentElement.dataset.fbscriptallow !== 'true') {
  var script_2 = document.createElement('script');
  script_2.textContent = `{
    const iframes = window.top.document.querySelectorAll('iframe[sandbox]');
    for (var i = 0; i < iframes.length; i++) {
      if (iframes[i].contentWindow) {
        if (iframes[i].contentWindow.HTMLElement) {
          iframes[i].contentWindow.HTMLElement.prototype.offsetWidth = HTMLElement.prototype.offsetWidth;
          iframes[i].contentWindow.HTMLElement.prototype.offsetHeight = HTMLElement.prototype.offsetHeight;
        }
      }
    }
  }`;
  //
  window.top.document.documentElement.appendChild(script_2);
}";
// добавим js код расширения
$browser->set_init_java_script($js);
sleep(4);
// перейдём на сайт проверки
$browser->navigate("https://browserleaks.com/fonts");

До вы полнения кода расширения.

После выполнения

При этом при каждом обновлении проверочной страницы мы будем получать новое значение Font Fingerprint.

Задать вопросы или обсудить статью можно на нашем на форуме.

5/5 - (2 голоса)

Актуальные ответы на сайте (не устаревший пост):


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

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.