Документация
/
VM-обфускация
/

Поведение прямого eval

Прямой eval() отключает VM-обфускацию

Если функция содержит прямой вызов eval(code) где угодно в своём теле (в том числе во вложенных функциях), VM-обфускация пропускает эту функцию, а обфускатор выдаёт предупреждение VMDynamicCodeSkipped (с именем функции, если оно у неё есть). В режиме root (по умолчанию) пропускаются вся функция и все вложенные в неё функции; в режиме комментариев вложенная функция, помеченная отдельно, всё равно виртуализируется, если только сама не содержит eval. Прямой eval с нестатическим аргументом также выдаёт предупреждение DynamicCodeRenameRisk. Причина в том, что прямой eval имеет доступ к локальным переменным объемлющей функции, а они недоступны, когда функция скомпилирована в байт-код VM.

Важно для кода, обёрнутого в IIFE. Если IIFE верхнего уровня где-то в глубине содержит прямой eval, весь IIFE (включая весь ваш код) не будет VM-обфусцирован.

JavaScript

У разворачивания IIFE есть компромисс: когда ваши функции оказываются на верхнем уровне, пропускается только проблемная функция, но оставшиеся функции теперь находятся на корневом уровне, поэтому VM-обфускация сохраняет их имена. Как не допустить эти имена в результат, описано в разделе Как скрыть имена функций от анализа LLM.

Косвенные формы, такие как (0, eval)(code) и window.eval(code), не блокируют VM-обфускацию. Исключение - eval?.(code): JavaScript выполняет его как косвенный eval, но обфускатор консервативно считает его прямым eval и пропускает функцию.

Конструктор Function (new Function(body) / Function(body)) обрабатывается так же, если аргумент с телом динамический. Функция, содержащая динамический вызов new Function(...), тоже пропускается с предупреждением VMDynamicCodeSkipped. Как и при динамическом прямом eval, обфускатор добавляет предупреждение DynamicCodeRenameRisk, потому что тело, собираемое во время выполнения, может ссылаться на переименованные идентификаторы. Полностью статические вызовы, такие как new Function('a', 'b', 'return a + b'), не пропускаются.

Косвенный eval и конструктор Function выполняются в глобальной области видимости. Они не могут читать локальные переменные вызывающего кода, но всё равно могут упасть, если обращаются к глобальным переменным, которые были переименованы или удалены. Статическое тело, использующее только собственные параметры, например new Function('a', 'b', 'return a + b'), не имеет такой зависимости. Просматривайте предупреждения и тестируйте итоговый бандл: одна лишь смена синтаксиса eval не делает произвольный динамический код безопасным.

Обходной путь (v6.14.0+): задайте vmForceCompileDynamicCode: true (или включите переключатель Force Compile Dynamic Code в группе Переопределения раздела VM), чтобы всё равно преобразовать окружающую функцию в байт-код и подавить VMDynamicCodeSkipped. Это не устраняет зависимости от области видимости: внутри принудительно скомпилированной функции прямой eval не может читать или изменять локальные переменные функции, её параметры или переменные виртуализированной объемлющей функции, даже если код задан строковым литералом. Используйте опцию, только если выполняемый код обращается исключительно к глобальным переменным. DynamicCodeRenameRisk продолжает срабатывать и при включённой опции, потому что описываемый им риск переименования не зависит от пропуска VM.

Полную матрицу случаев, формат предупреждений и обходные пути см. в разделе VM-обфускация с eval и new Function.