
Статический набор инструментов для деобфускации скомпилированного байткода V8 JavaScript, ориентированный на полезные нагрузки JSCeal. Предоставляет фильтры на основе шаблонов, восстановление линейного потока управления, реконструкцию строк и опциональное переименование функций с помощью LLM для анализа.
Этот инструмент предназначен для статической деобфускации скомпилированного байт-кода V8 JavaScript, защищённого с помощью javascript-obfuscator.
Он работает с псевдокодом, созданным View8, а не с исходным кодом JavaScript. Проект разрабатывался и тестировался на нагрузках JSCeal.
Фильтры основаны на шаблонах и предназначены в первую очередь как исследовательский инструментарий и эталонная реализация. Инструмент не является универсальным деобфускатором JavaScript, не восстанавливает исходный код и не создаёт исполняемый JavaScript. Его выходные данные остаются псевдокодом View8, предназначенным для статического анализа, поиска, сравнения и экспорта дерева функций.
pickle. Загрузка вредоносного или недоверенного файла .pkl может привести к выполнению кода. Загружайте только те сериализованные файлы, которые вы создали локально с помощью View8.requirements.txt;brotli для пакетного процесса распаковки в Linux;Создайте изолированное окружение Python:
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
Серверная часть OpenAI в deobf_ai.py дополнительно требует пакет OpenAI для Python:
python3 -m pip install openai
Серверная часть Anthropic использует HTTP API через requests. Серверная часть Ollama ожидает доступный сервер Ollama.
Исходная нагрузка JSCeal app.jsc сжата Brotli. В Linux её можно распаковать с помощью утилиты brotli:
brotli -d app.jsc -o app.decompressed.jsc
Пакетный процесс в scripts/ выполняет этот шаг с помощью scripts/unpack_all.sh.
В Windows или когда утилита командной строки brotli недоступна, можно использовать включённый помощник Node.js как запасной вариант. Он только распаковывает входные данные и не выполняет их:
node Utils/decompress-jsc.js app.jsc
Он записывает:
app.jsc.decompressed.jsc
Кэш кода V8 зависит от версии. Используйте дизассемблер, собранный для той же версии V8, что и нагрузка.
Образцы JSCeal, использованные при разработке, были основаны на V8 10.2.154.26. Дизассемблеры по умолчанию из несвязанной сборки V8 работать не будут.
Дерево исходников содержит исходный код дизассемблера и необходимые патчи V8 в:
Utils/disasm/v8dasm.cpp
Utils/disasm/patches/
Предварительно собранный бинарный файл для Linux распространяется с релизом проекта, а дерево исходников содержит исходный код и патчи, необходимые для его пересборки. Подробное описание доступно в Wiki проекта. После получения или сборки соответствующего v8dasm выполните:
/path/to/v8dasm app.decompressed.jsc > app.jsc.disasm.txt
Передайте дизассемблированный файл в view8.py и создайте как сериализованный вывод для дальнейшей обработки, так и читаемый псевдокод:
mkdir -p decompiled
python3 View8/view8.py \
--input_format disassembled \
--inp app.jsc.disasm.txt \
--normalize \
--out decompiled/app.dec.txt \
--export_format decompiled serialized
Это создаёт:
decompiled/app.dec.txt
decompiled/app.dec.pkl
Опция --normalize делает сгенерированные идентификаторы функций воспроизводимыми при повторных запусках дизассемблирования и декомпиляции.
Существуют отдельные фильтры для отдельных слоёв обфускации. Их можно применить вместе к сериализованному выводу View8 с помощью deobf_all.py:
mkdir -p deobfuscated
python3 deobf_all.py \
--inp decompiled/app.dec.pkl \
--out deobfuscated/app.deobf.txt \
--export_format decompiled serialized
Фильтр строк по умолчанию — вариант 2, используемый большинством проанализированных нагрузок JSCeal. Чтобы явно выбрать более простую схему строк, добавьте:
--str_deobf 1
Типичные выходные данные:
deobfuscated/app.deobf.txt
deobfuscated/app.deobf.pkl
deobfuscated/app.deobf.txt.strings.txt
decompiled/app.dec.resolved_funcs.csv
CSV-файл разрешённых функций — это кэш, специфичный для образца. Когда он отсутствует, этап строк восстанавливает необходимую конфигурацию декодера, записывает CSV и продолжает деобфускацию строк в том же запуске. Последующие запуски повторно используют кэш и обычно выполняются быстрее.
Не используйте повторно CSV-файл разрешённых функций с другой декомпилированной нагрузкой.
После применения всех структурных фильтров деобфускации deobf_ai.py может предложить имена, описывающие поведение функций. Он поддерживает серверные части Anthropic, OpenAI и Ollama.
Передавайте модель явно, чтобы запуски оставались воспроизводимыми.
export ANTHROPIC_API_KEY='...'
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend anthropic \
--model '<model-id>' \
--export_format decompiled serialized
export OPENAI_API_KEY='...'
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend openai \
--model '<model-id>' \
--export_format decompiled serialized
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--llm_backend ollama \
--model '<local-model>' \
--ollama_url http://localhost:11434 \
--export_format decompiled serialized
В режиме по умолчанию переименователь строит дерево прямых вызовов, начиная с входной функции, и переименовывает только функции, достигнутые через вызовы. Добавьте --greedy, чтобы включить все видимые ссылки на функции, включая обратные вызовы и назначенные обработчики.
Сгенерированный двухколоночный CSV-файл действует как кэш и позволяет продолжить прерванный запуск. Выберите существующий кэш явно с помощью --csv:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--csv deobfuscated/app.deobf.renamed_funcs.greedy.example-model.csv \
--llm_backend anthropic \
--model '<model-id>' \
--greedy \
--export_format decompiled serialized
В обычном режиме CSV-файл рассматривается как потенциально частичный кэш. Кэшированные имена применяются первыми, функции, уже покрытые кэшем, удаляются из выбранного дерева вызовов или ссылок, и LLM вызывается только для функций, которые остались неразрешёнными. Если CSV-файл полностью покрывает это дерево, ключ API или соединение с LLM не требуются. Если он покрывает только часть дерева, выбранная серверная часть инициализируется, и вновь сгенерированные сопоставления добавляются в тот же CSV-файл.
Используйте тот же режим дерева, который использовался при создании CSV-файла. CSV-файл, созданный из запуска --greedy, обычно снова требует --greedy, если цель — продолжить этот запуск, а не только повторно использовать подмножество прямых вызовов.
Используйте --apply-csv-only, когда CSV-файл уже содержит метки, которые вы хотите применить, включая проверенные, отредактированные, импортированные или перебазированные сопоставления:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--out deobfuscated/app.renamed.txt \
--csv renamed_functions.normalized.csv \
--apply-csv-only \
--export_format decompiled serialized
Этот режим:
--csv;--func.Строки, чей исходный идентификатор функции не существует во входных данных, игнорируются. Команда завершается ошибкой, когда CSV-файл не содержит сопоставлений, применимых к загруженному файлу.
Используйте --func с точным полным идентификатором функции, чтобы запросить целенаправленный семантический анализ одной деобфусцированной функции:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--func func_example_0x100001234 \
--llm_backend anthropic \
--model '<model-id>'
Анализ включает предлагаемое имя, сводку поведения, входные данные и возвращаемое значение, побочные эффекты, пошаговую логику, очищенный псевдокод, подтверждающие доказательства и нерешённые неопределённости. Указание --csv добавляет кэшированные семантические имена как контекст для ссылок внутри выбранной функции без изменения загруженного корпуса. Используйте --analysis-out analysis/function.md, чтобы сохранить отчёт в формате Markdown. Нечёткие совпадения выводятся только как предложения; запрошенный идентификатор функции должен совпадать точно.
Используйте --help для параметров, управляющих температурой, пакетной обработкой, режимом мышления Anthropic, лимитами токенов и пользовательскими путями CSV.
Имена, сгенерированные LLM, — это навигационные подсказки, а не доказательства. Всегда проверяйте их на соответствие деобфусцированному телу.
Деобфусцированные выходные данные JSCeal обычно очень большие. Загрузите сериализованный вывод обратно в View8 и разделите его на более мелкие деревья функций.
На этом этапе добавьте --scope 0. Распространение области уже было выполнено деобфускатором, и его повторение может привести к неправильному распространению значений.
Дерево на основе отношений деклараторов:
python3 View8/view8.py \
--input_format serialized \
--inp deobfuscated/app.deobf.pkl \
--out trees/declarers \
--export_format decompiled \
--tree start \
--scope 0
Компактный обзор прямых вызовов:
python3 View8/view8.py \
--input_format serialized \
--inp deobfuscated/app.deobf.pkl \
--out trees/calls \
--export_format decompiled \
--tree start \
--scope 0 \
--split_mode calls \
--inline_depth 1 \
--split_depth 5
Более широкое дерево ссылок, включая обратные вызовы и назначенные обработчики:
python3 View8/view8.py \
--input_format serialized \
--inp deobfuscated/app.deobf.pkl \
--out trees/references \
--export_format decompiled \
--tree start \
--scope 0 \
--split_mode references \
--inline_depth 1 \
--split_depth 3
Разные JSC-файлы могут использовать разные режимы обфускации строк.
Простейший наблюдаемый режим использует сдвиг индексов и обрабатывается deobf_str1.py. Наиболее распространённый режим JSCeal использует Base64, RC4, фрагментированные строки и преобразованные индексы; он обрабатывается deobf_str2.py.
Полный конвейер по умолчанию выбирает вариант 2. Фильтры также можно запускать независимо для тестирования.
deobf_str2.pyИспользуйте --help, чтобы отобразить все доступные режимы и параметры:
python3 deobf_str2.py --help
Прямой запуск деобфускации строк можно начать с:
python3 deobf_str2.py \
--inp decompiled/app.dec.pkl \
--out work/app.strings.txt \
--export_format decompiled serialized
Во время запуска скрипт идентифицирует функции декодера строк, загружает любые допустимые кэшированные конфигурации, разрешает отсутствующие, сохраняет полученный CSV-файл и декодирует строки. Второй запуск не требуется.
При прямом использовании deobf_str2.py его имя CSV-файла по умолчанию — resolved_funcs.csv. Выберите путь, специфичный для образца, с помощью --csv или -c:
python3 deobf_str2.py \
--inp decompiled/app.dec.pkl \
--out work/app.strings.txt \
--csv decompiled/app.dec.resolved_funcs.csv \
--export_format decompiled serialized \
--verbosity 1
При объединении отдельных фильтров сохраняйте сериализованный вывод между этапами, чтобы последующие проходы могли продолжать работать с объектами View8.
deobf_all.py применяет следующие этапы по порядку:
Переименование функций с помощью LLM является необязательным и выполняется отдельно после структурной деобфускации.
Репозиторий включает полный вспомогательный процесс в scripts/. Все скрипты находятся в одном каталоге и используют одну централизованную конфигурацию.
scripts/config.sh общие пути к инструментам и рабочей области
scripts/copy_payloads.sh сбор и именование MD5 файлов JSCeal app.jsc
scripts/unpack_all.sh декомпрессия Brotli
scripts/disasm_all.sh пакетное дизассемблирование V8
scripts/decompile_all.sh пакетная декомпиляция View8
scripts/deobfuscate_all.sh пакетная деобфускация с объединённым журналом
scripts/run_unattended.sh автономная деобфускация и проверка
scripts/collect_output.sh сбор кэшей декодеров и списков строк
Поставляемый scripts/config.sh содержит пути из примера окружения:
JSC_DEOBF_ROOT="$HOME/jsc_deobfuscator"
V8DASM="$HOME/code/v8/v8dasm"
Отредактируйте этот файл один раз, чтобы настроить путь установки, соответствующий дизассемблер V8, каталоги рабочей области, внешние команды, пути журналов и структуру сбора. Рабочая область по умолчанию — каталог, из которого запускается вспомогательный скрипт.
Каждое значение также можно переопределить через переменную окружения. JSC_HELPER_CONFIG может выбрать другой файл конфигурации.
Типичный пакетный запуск:
scripts/copy_payloads.sh
scripts/unpack_all.sh
scripts/disasm_all.sh
scripts/decompile_all.sh
scripts/deobfuscate_all.sh
scripts/collect_output.sh
Скрипты сохраняют соглашения, используемые для корпуса JSCeal, включая обработку обнаруженных файлов app.jsc как нагрузок, сжатых Brotli, и их именование по MD5. Просмотрите scripts/README.md перед применением процесса к несвязанным образцам.
Для длительного пакетного запуска scripts/run_unattended.sh запускает деобфускацию с nohup, записывает файлы журнала с отметкой времени, PID и статуса, а также проверяет каждый сгенерированный вывод на наличие неразрешённых ссылок на кэшированные функции декодера строк:
scripts/run_unattended.sh
Выбранные образцы можно указать явно:
scripts/run_unattended.sh \
decompiled/sample1.dec.pkl \
decompiled/sample2.dec.pkl
View8/ декомпилятор View8 и экспортёр деревьев функций
Utils/decompress-jsc.js запасной вариант декомпрессии Brotli для Windows
Utils/disasm/v8dasm.cpp исходный код дизассемблера V8
Utils/disasm/patches/ патчи V8, необходимые дизассемблеру
Utils/check_unresolved_decoder_references.py
вспомогательный скрипт проверки вывода
deobf_all.py полный конвейер деобфускации по умолчанию
deobf_str1.py простой фильтр сдвига индексов строк
deobf_str2.py фильтр строк RC4/Base64 с восстановлением индексов
deobf_scope2.py распространение области и словаря
deobf_unflattener.py устранение развёртывания потока управления
deobf_replace_ops.py замена прокси и обёрток операций
deobf_globals.py глобальное распространение
deobf_inline_temporaries.py консервативная финальная очистка
deobf_ai.py необязательное переименование функций с помощью LLM
scripts/ настраиваемые пакетные и проверочные помощники
Каждый основной проход можно выполнять отдельно для тестирования. Запустите выбранный скрипт с --help, чтобы увидеть его полный интерфейс:
python3 deobf_str1.py --help
python3 deobf_str2.py --help
python3 deobf_scope2.py --help
python3 deobf_unflattener.py --help
python3 deobf_replace_ops.py --help
python3 deobf_globals.py --help
python3 deobf_inline_temporaries.py --help
javascript-obfuscator. Новые варианты могут потребовать дополнительных детекторов или преобразований.Конвейер прошёл регрессионное тестирование на корпусе JSCeal, использованном в сопутствующем исследовании. Базовые проверки релиза включают:
python3 -m compileall -q .
python3 deobf_all.py --help
python3 deobf_str2.py --help
python3 deobf_ai.py --help
python3 View8/view8.py --help
Для каждого образца корпуса убедитесь, что запуск:
.pkl, так и .txt;Автономный вспомогательный скрипт автоматизирует финальную проверку ссылок на декодеры.
javascript-obfuscator.Исходный код JSC Deobfuscator, созданный для этого проекта, лицензирован в соответствии с
GNU General Public License, версия 2 или (по вашему выбору) любая более поздняя версия
(GPL-2.0-or-later). См. LICENSE для полного текста лицензии.
Copyright (C) 2026 Александра «Hasherezade» Донец @ Check Point Research.
Подмодуль View8 — это отдельный проект. Материалы дизассемблера, производные от сторонних проектов, в Utils/disasm/ сохраняют своё существующее происхождение и не перелицензируются приведённым выше уведомлением об авторских правах.