УДК 004.056.5

Проектирование обфускатора для языка JavaScript

Авторы: Медгаус С.В., Чернышова А.В.

Источник: Сборник статей студенческой научно-технической конференции, г.Севастополь, 04 – 08 апреля 2016 г. / М-во образования и науки РФ, Севастопольский государственный университет; науч. ред. Е.Н. Мащенко – г. Севастополь: СевГУ, 2016. с. 164 – 167.

Аннотация: В тексте данной статьи описан процесс обфускации и существующие обфускаторы для языка JavaScript.Описаны возможные преобразования исходного кода для запутывания кода и для усложнения возможности реверс-инжиниринга. Исходя из анализа существующих обфускаторов, была предложена разработка обфускатора языка JavaScript с открытым кодом, реализующая сложные преобразования исходного кода. Также описаны технологии, которые будут использоваться для разбора программного кода.
Ключевые слова: JavaScript, обфускация, реверс-инжиниринг, синтаксическое дерево, запутывающие преобразования.

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

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

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

Обфускация (от лат. obfuscare – затенять, затемнять; и англ. obfuscate – делать неочевидным, запутанным, сбивать с толку) или запутывание кода – приведение исходного текста или исполняемого кода программы к виду, сохраняющему его функциональность, но затрудняющему анализ и понимание алгоритмов работы.

Для создания запутанного ассемблерного текста могут использоваться специализированные компиляторы, использующие неочевидные или недокументированные возможности среды исполнения программы. Существуют также специальные программы, производящие обфускацию, так называемые обфускаторы [1].

На данный момент существуют 3 уровня обфускации. Первый и самый низкий уровень – обфускация машинных команд. Этот уровень обфускации наименее изучен, и поэтому наименее распространён.

Следующий уровень – это уровень байт-кода, используемый для таких языков как Java или C#, в которых исходный код программы сначала преобразуется в байт-код, а уже потом преобразуется в машинный код. Этот уровень обфускации достаточно распространён.

И последний, 3 уровень обфускации – это запутывание исходного кода на самом верхнем уровне. Этот уровень обфускации применим для скриптовых языков.

Процессы обфускации можно классифицировать по видам, в зависимости от способа модификации кода программы.

Лексическая обфускация заключается в форматировании кода программы, изменении его структуры, таким образом, чтобы он стал нечитабельным, менее информативным и трудным для изучения.

Обфускация такого вида включает в себя:

  • удаление всех комментариев в коде программы, или изменение их на дезинформирующие;
  • удаление различных пробелов, отступов которые обычно используют для лучшего визуального восприятия кода программы;
  • удаление различных пробелов, отступов которые обычно используют для лучшего визуального восприятия кода программы;
  • замену имён идентификаторов на произвольные длинные наборы символов, которые трудно воспринимать человеку;
  • добавление различных лишних операций;
  • изменение расположения блоков (функций, процедур) программы, таким образом, чтобы это никоим образом не повлияло на её работоспособность.

Обфускация данных связана с трансформацией структур данных. Она считается более сложной, является наиболее продвинутой и часто используемой. Её принято делить на три основные группы:

  • обфускация хранения заключается в трансформации хранилищ данных, а также самих типов данных (например, создание и использование необычных типов данных, изменение представления существующих и т.д.);
  • обфускация соединения стремится к усложнению используемых структур данных, что достигается благодаря соединению независимых данных, или разделению зависимых;
  • обфускация переупорядочения заключается в изменении последовательности объявления переменных, внутреннего расположения хранилищ данных, а также переупорядочивании методов, массивов (использование нетривиального представления многомерных массивов), определённых полей в структурах и т.д.

Обфускация управления осуществляет запутывание потока управления, то есть последовательность выполнения программного кода. Методы, позволяющие осуществить обфускацию управления, классифицируются на три основных группы:

  • вычислительная обфускация, которая реализуется расширением условий циклов, добавлением недостижимого исходного кода, устранением библиотечных вызовов (если это возможно) и добавлением мёртвого (недостижимого) кода;
  • обфускация соединения, при этом происходит объединение или разделение определённых фрагментов кода программы для того, чтобы убрать логические связи между ними;
  • обфускация последовательности заключается в переупорядочивании блоков (инструкций переходов), циклов, выражений. [2]

На данный момент существует несколько обфускаторов для JavaScript, но необходимо отметить, что все обфускаторы кроме Google Closure Compiler являются в первую очередь упаковщиками или минификаторами (программы, которые минимизируют размер исходного кода, выполняют оптимизацию для увеличения производительности), а уже как следствие, они являются обфускаторами.

Сравнивая популярные упаковщики (YUIpacker и Packer) были проведены эксперименты по минимизации JavaScript библиотеки JQuery и получили такие результаты: YUIpacker сжал неупакованную версию библиотеки до 0.47 от оригинального размера, Packer сжал до 0.34 от оригинального размера. Можно сделать вывод, что лучшим из них является Packer.

Однако данные программы не являются обфускаторами, которые выполняют сложные преобразования над исходным кодом программы, как упоминалось выше.

Также был рассмотрен коммерческий продукт JavaScriptObfuscator v2.18 [3], который предлагает бесплатную демонстрационную версию, обеспечивающий минимальную обфускацию на уровне упаковщиков. При обфускации JQuery исходный файл был обфусцирован до 0.38 от оригинального размера, но там не обфусцированы типы данных, поток логики приложения и т.д.

Google Closure Compiler разработан таким образом, чтобы на этапе написания кода необходимо было готовить код к обфускации, соблюдая определённые правила и добавляя определённые аннотации. Так как это не представляется возможным сделать для библиотеки JQuery, то степень сжатия и обфускации Google Closure Compiler невозможно сравнить в данном контексте.

Так как в настоящее время нет обфускатора с открытым исходным кодом, который сможет предоставлять продвинутые способы обфускации, то создание такого обфускатора для языка JavaScript является актуальным.

После анализа существующих обфускаторов для языка JavaScript, была разработана диаграмма прецедентов (см. рис. 1).

UML диаграмма прецедентов
Рисунок 1 – UML диаграмма прецедентов

На данном этапе разработки появилась задача распознавания исходного кода программы и построение абстрактного синтаксического дерева. Так как это задача достаточно объёмная, то для ускорения разработки необходимо использовать готовое решение (библиотеку). Сравнивая существующие синтаксические анализаторы, были обнаружены два лидера: библиотека Esprima [4] от JQuery и встроенный интерпретатор JavaScript Nashorn (потомок Rhino) [5] от Oracle.

Esprima – это библиотека на JavaScript для разбора исходного кода того же языка, но так как разработка программного продукта планируется на языке Java, то предпочтение отдано Nashorn, хотя в разработке не будет задействован весь интерпретатор, а только синтаксический анализатор. Nashorn будет принимать на вход исходный код JavaScript и возвращать в виде результата текст в формате JSON (см. рис. 2), с которым уже можно тесно взаимодействовать и использовать для проведения обфускации.

Пример разбора исходного кода JavaScript
Рисунок 2 – Пример разбора исходного кода JavaScript

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

В данной работе были рассмотрены понятия обфускатора и обфускации. Также были представлены основные принципы обфусцирующего преобразования исходного кода, предложена UML диаграмма прецедентов для разрабатываемого обфускатора.

Исходя из результатов, полученных в ходе анализа существующих обфускаторов, можно сказать, что создание обфускатора с открытым исходным кодом для языка JavaScript, обеспечивающего возможность использования продвинутых запутывающих преобразований, актуально и востребовано.

Литература

  1. Википедия. Обфускация [электронный ресурс]. – Режим доступа: https://ru.wikipedia.org/wiki/Обфускация
  2. LynX. Обфускация и защита программных продуктов // CITForum. [электронный ресурс]. – Режим доступа: http://citforum.ru/security/articles/obfus/
  3. JavaScriptObfuscator. Canada [электронный ресурс]. – Режим доступа: https://www.javascriptobfuscator.com/
  4. Esprima [электронный ресурс]. – Режим доступа: http://esprima.org/
  5. Nashorn [электронный ресурс]. – Режим доступа: https://ru.wikipedia.org/wiki/Nashorn_(движок_JavaScript)