
Ferramenta estática de desofuscação para bytecode V8 JavaScript compilado, com foco em payloads JSCeal. Fornece filtros orientados por padrões, desachatamento de fluxo de controle, reconstrução de strings e renomeação opcional de funções assistida por LLM para análise.
Esta ferramenta é dedicada a desofuscar estaticamente bytecode JavaScript V8 compilado que foi protegido com javascript-obfuscator.
Ela opera sobre pseudocódigo produzido pelo View8, em vez do código-fonte JavaScript original. O projeto foi desenvolvido e testado em payloads JSCeal.
Os filtros são orientados por padrões e destinam-se principalmente a servir como um kit de ferramentas de pesquisa e uma implementação de referência. A ferramenta não é um desofuscador JavaScript de propósito geral, não reconstrói o código-fonte original e não produz JavaScript executável. Sua saída permanece como pseudocódigo View8 destinado à inspeção estática, pesquisa, comparação e exportação de árvores de funções.
pickle do Python. Carregar um arquivo .pkl malicioso ou não confiável pode executar código. Carregue apenas arquivos serializados que você mesmo gerou localmente com o View8.requirements.txt;brotli para o fluxo de trabalho de descompactação em lote no Linux;Crie um ambiente Python isolado:
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
O backend OpenAI em deobf_ai.py requer adicionalmente o pacote Python OpenAI:
python3 -m pip install openai
O backend Anthropic usa a API HTTP por meio de requests. O backend Ollama espera um servidor Ollama acessível.
O payload JSCeal original app.jsc é comprimido com Brotli. No Linux, ele pode ser descomprimido com o utilitário brotli:
brotli -d app.jsc -o app.decompressed.jsc
O fluxo de trabalho em lote sob scripts/ executa esta etapa com scripts/unpack_all.sh.
No Windows, ou quando o utilitário de linha de comando brotli não estiver disponível, o auxiliar Node.js incluído pode ser usado como fallback. Ele apenas descomprime a entrada e não a executa:
node Utils/decompress-jsc.js app.jsc
Ele grava:
app.jsc.decompressed.jsc
O cache de código V8 é específico da versão. Use um desmontador compilado para a mesma versão do V8 que o payload.
As amostras JSCeal usadas durante o desenvolvimento eram baseadas no V8 10.2.154.26. Desmontadores padrão de uma compilação V8 não relacionada não funcionarão corretamente.
A árvore de fontes contém o código-fonte do desmontador e os patches V8 necessários sob:
Utils/disasm/v8dasm.cpp
Utils/disasm/patches/
Um binário Linux pré-compilado é distribuído com o lançamento do projeto, enquanto a árvore de fontes contém o código-fonte e os patches necessários para recompilá-lo. Uma descrição detalhada está disponível na Wiki do projeto. Após obter ou compilar o v8dasm correspondente, execute:
/path/to/v8dasm app.decompressed.jsc > app.jsc.disasm.txt
Alimente o arquivo desmontado para view8.py e produza tanto a saída serializada para processamento posterior quanto o pseudocódigo legível por humanos:
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
Isso produz:
decompiled/app.dec.txt
decompiled/app.dec.pkl
A opção --normalize torna os identificadores de funções gerados reproduzíveis em execuções repetidas de desmontagem e descompilação.
Existem filtros separados para as camadas individuais de ofuscação. Eles podem ser aplicados juntos à saída serializada do View8 com deobf_all.py:
mkdir -p deobfuscated
python3 deobf_all.py \
--inp decompiled/app.dec.pkl \
--out deobfuscated/app.deobf.txt \
--export_format decompiled serialized
O filtro de strings padrão é a variante 2, usada pela maioria dos payloads JSCeal analisados. Para selecionar o esquema de strings mais simples explicitamente, adicione:
--str_deobf 1
As saídas típicas são:
deobfuscated/app.deobf.txt
deobfuscated/app.deobf.pkl
deobfuscated/app.deobf.txt.strings.txt
decompiled/app.dec.resolved_funcs.csv
O CSV de funções resolvidas é um cache específico da amostra. Quando ele está ausente, a passagem de strings recupera a configuração necessária do decodificador, grava o CSV e continua desofuscando strings na mesma execução. Execuções posteriores reutilizam o cache e são normalmente mais rápidas.
Não reutilize um CSV de funções resolvidas com um payload descompilado diferente.
Após todos os filtros estruturais de desofuscação terem sido aplicados, deobf_ai.py pode propor nomes que descrevem o comportamento das funções. Ele suporta backends Anthropic, OpenAI e Ollama.
Passe o modelo explicitamente para que as execuções permaneçam reproduzíveis.
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
No modo padrão, o renomeador constrói uma árvore de chamadas diretas começando pela função de entrada e renomeia apenas funções alcançadas por meio de chamadas. Adicione --greedy para incluir todas as referências de funções visíveis, incluindo callbacks e manipuladores atribuídos.
O CSV de duas colunas gerado atua como um cache e permite que uma execução interrompida continue. Selecione um cache existente explicitamente com --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
No modo normal, o CSV é tratado como um cache potencialmente parcial. Os nomes em cache são aplicados primeiro, funções já cobertas pelo cache são removidas da árvore de chamadas ou referências selecionada, e o LLM é invocado apenas para funções que permanecem não resolvidas. Se o CSV cobrir completamente essa árvore, nenhuma chave de API ou conexão LLM é necessária. Se cobrir apenas parte da árvore, o backend selecionado é inicializado e os mapeamentos recém-gerados são anexados ao mesmo CSV.
Use o mesmo modo de árvore que foi usado quando o CSV foi criado. Um CSV produzido a partir de uma execução --greedy normalmente precisa de --greedy novamente se o objetivo for continuar essa execução em vez de apenas reutilizar o subconjunto de chamadas diretas.
Use --apply-csv-only quando o CSV já contém os rótulos que você deseja aplicar, incluindo mapeamentos revisados, editados, importados ou rebasados:
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
Este modo:
--csv explícito;--func.Linhas cujo identificador de função original não existe na entrada são ignoradas. O comando falha quando o CSV não contém mapeamentos aplicáveis ao arquivo carregado.
Use --func com o identificador completo exato da função para solicitar uma análise semântica focada de uma função desofuscada:
python3 deobf_ai.py \
--inp deobfuscated/app.deobf.pkl \
--func func_example_0x100001234 \
--llm_backend anthropic \
--model '<model-id>'
A análise inclui um nome proposto, resumo do comportamento, entradas e valor de retorno, efeitos colaterais, lógica passo a passo, pseudocódigo limpo, evidências de apoio e incertezas não resolvidas. Fornecer --csv adiciona nomes semânticos em cache como contexto para referências dentro da função selecionada sem modificar o corpus carregado. Use --analysis-out analysis/function.md para salvar o relatório como Markdown. Correspondências difusas são impressas apenas como sugestões; o identificador de função solicitado deve corresponder exatamente.
Use --help para opções que controlam temperatura, processamento em lote, modo de pensamento Anthropic, limites de tokens e caminhos CSV personalizados.
Nomes gerados por LLM são auxílios de navegação, não evidências. Sempre verifique-os contra o corpo desofuscado.
A saída JSCeal desofuscada é geralmente muito grande. Carregue a saída serializada de volta no View8 e divida-a em árvores de funções menores.
Nesta etapa, adicione --scope 0. A propagação de escopo já foi realizada pelo desofuscador, e repeti-la pode propagar valores incorretamente.
Uma árvore baseada em relações de declarador:
python3 View8/view8.py \
--input_format serialized \
--inp deobfuscated/app.deobf.pkl \
--out trees/declarers \
--export_format decompiled \
--tree start \
--scope 0
Uma visão geral compacta de chamadas diretas:
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
Uma árvore de referências mais ampla, incluindo callbacks e manipuladores atribuídos:
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
Diferentes arquivos JSC podem usar diferentes modos de ofuscação de strings.
O modo mais simples observado usa deslocamento de índice e é tratado por deobf_str1.py. O modo JSCeal mais comum usa Base64, RC4, strings fragmentadas e índices transformados; ele é tratado por deobf_str2.py.
O pipeline completo seleciona a variante 2 por padrão. Os filtros também podem ser executados independentemente para testes.
deobf_str2.pyUse --help para exibir todos os modos e opções disponíveis:
python3 deobf_str2.py --help
Uma execução direta de desofuscação de strings pode ser iniciada com:
python3 deobf_str2.py \
--inp decompiled/app.dec.pkl \
--out work/app.strings.txt \
--export_format decompiled serialized
Durante a execução, o script identifica as funções decodificadoras de strings, carrega quaisquer configurações em cache válidas, resolve as ausentes, salva o CSV resultante e decodifica as strings. Uma segunda execução não é necessária.
Quando deobf_str2.py é usado diretamente, seu nome CSV padrão é resolved_funcs.csv. Selecione um caminho específico da amostra com --csv ou -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
Ao encadear filtros individuais, preserve a saída serializada entre os estágios para que passagens posteriores possam continuar operando nos objetos View8.
deobf_all.py aplica os seguintes estágios em ordem:
A renomeação de funções assistida por LLM é opcional e é executada separadamente após a desofuscação estrutural.
O repositório inclui um fluxo de trabalho auxiliar completo sob scripts/. Todos os scripts são mantidos em um único diretório e usam a mesma configuração centralizada.
scripts/config.sh caminhos compartilhados de ferramentas e espaço de trabalho
scripts/copy_payloads.sh coleta e nomeia por MD5 os arquivos JSCeal app.jsc
scripts/unpack_all.sh descompressão Brotli
scripts/disasm_all.sh desmontagem V8 em lote
scripts/decompile_all.sh descompilação View8 em lote
scripts/deobfuscate_all.sh desofuscação em lote com um log combinado
scripts/run_unattended.sh desofuscação e validação destacadas
scripts/collect_output.sh coleta caches de decodificadores e listagens de strings
O scripts/config.sh fornecido contém caminhos de um ambiente de exemplo:
JSC_DEOBF_ROOT="$HOME/jsc_deobfuscator"
V8DASM="$HOME/code/v8/v8dasm"
Edite esse arquivo uma vez para configurar o caminho de instalação, o desmontador V8 correspondente, os diretórios do espaço de trabalho, comandos externos, caminhos de log e layout de coleta. O espaço de trabalho padrão é o diretório a partir do qual o script auxiliar é iniciado.
Cada valor também pode ser substituído por meio de uma variável de ambiente. JSC_HELPER_CONFIG pode selecionar um arquivo de configuração diferente.
Uma execução típica em lote é:
scripts/copy_payloads.sh
scripts/unpack_all.sh
scripts/disasm_all.sh
scripts/decompile_all.sh
scripts/deobfuscate_all.sh
scripts/collect_output.sh
Os scripts preservam as convenções usadas para o corpus JSCeal, incluindo tratar os arquivos app.jsc descobertos como payloads comprimidos com Brotli e nomeá-los por MD5. Revise scripts/README.md antes de aplicar o fluxo de trabalho a amostras não relacionadas.
Para um lote longo, scripts/run_unattended.sh inicia a desofuscação com nohup, grava arquivos de log, PID e status com carimbo de data/hora, e valida cada saída gerada quanto a referências não resolvidas a funções decodificadoras de strings em cache:
scripts/run_unattended.sh
Amostras selecionadas podem ser fornecidas explicitamente:
scripts/run_unattended.sh \
decompiled/sample1.dec.pkl \
decompiled/sample2.dec.pkl
View8/ descompilador View8 e exportador de árvores de funções
Utils/decompress-jsc.js fallback de descompressão Brotli para Windows
Utils/disasm/v8dasm.cpp código-fonte do desmontador V8
Utils/disasm/patches/ patches V8 exigidos pelo desmontador
Utils/check_unresolved_decoder_references.py
auxiliar de validação de saída
deobf_all.py pipeline completo padrão de desofuscação
deobf_str1.py filtro simples de deslocamento de índice de strings
deobf_str2.py filtro de strings RC4/Base64 com recuperação de índice
deobf_scope2.py propagação de escopo e dicionário
deobf_unflattener.py desachatamento de fluxo de controle
deobf_replace_ops.py substituição de proxies e wrappers de operações
deobf_globals.py propagação global
deobf_inline_temporaries.py limpeza final conservadora
deobf_ai.py renomeação opcional de funções assistida por LLM
scripts/ auxiliares configuráveis de lote e validação
Cada passagem principal pode ser executada separadamente para testes. Execute o script selecionado com --help para ver sua interface completa:
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. Novas variantes podem exigir detectores ou transformações adicionais.O pipeline foi testado por regressão contra o corpus JSCeal usado na pesquisa que o acompanha. As verificações básicas de lançamento incluem:
python3 -m compileall -q .
python3 deobf_all.py --help
python3 deobf_str2.py --help
python3 deobf_ai.py --help
python3 View8/view8.py --help
Para cada amostra do corpus, verifique se a execução:
.pkl quanto a .txt;O script auxiliar não supervisionado automatiza a validação final de referências a decodificadores.
javascript-obfuscator.O código-fonte do JSC Deobfuscator criado para este projeto é licenciado sob
a GNU General Public License, versão 2 ou (a seu critério) qualquer versão posterior
(GPL-2.0-or-later). Consulte LICENSE para o texto completo da licença.
Copyright (C) 2026 Aleksandra "Hasherezade" Doniec @ Check Point Research.
O submódulo View8 é um projeto separado. Material de desmontador derivado de terceiros
sob Utils/disasm/ mantém sua proveniência existente e não é
relicenciado pelo aviso de copyright acima.