
Descompila bytecode V8 serializado (arquivos JSC) em código legível de alto nível semelhante a JavaScript, com suporte para múltiplas versões do V8, saída em árvore e nomenclatura determinística de funções para análise de malware.
View8 é uma ferramenta de análise estática projetada para descompilar objetos de bytecode V8 serializados (arquivos JSC) em código legível de alto nível. Para analisar e desmontar esses objetos serializados, o View8 utiliza um binário V8 compilado com patch. Como resultado, o View8 produz uma saída textual semelhante a JavaScript.
9.4.146.24 (usada no Node V16.x)10.2.154.26 (usada no Node V18.x)11.3.244.8 (usada no Node V20.x)Para versões compiladas, visite a página de lançamentos.
--inp, : O nome do arquivo de entrada.-i--out, -o: Caminho para a saída. Dependendo das opções selecionadas, a saída pode ser um único arquivo ou uma árvore de diretórios.--input_format, -f: Especifica o formato de entrada. As opções são:
raw: a entrada é um arquivo JSC bruto.disassembled: o arquivo de entrada já está desmontado.serialized: a entrada já está descompilada e armazenada em um formato serializado. O formato serializado atual é o pickle do Python; use apenas entrada confiável.--export_format, -e: Especifica o(s) formato(s) de exportação. As opções são v8_opcode, translated, decompiled e serialized. Várias opções podem ser combinadas. Padrão: decompiled.--path, -p: Caminho para o binário do desmontador. Necessário se a entrada estiver no formato bruto e o View8 não conseguir localizar automaticamente o desmontador correspondente.--scope: Propaga argumentos de escopo. Padrão: 1.--normalize: Substitui identificadores de função derivados de endereços por nomes determinísticos baseados na ordem de análise.--normalize-map [CSV]: Ao usar --normalize, grava um CSV mapeando cada nome de função original para seu nome normalizado. Quando o caminho é omitido, o View8 deriva <output>.name_map.csv de --out, ou de --inp quando nenhum caminho de saída é definido.--tree, -t: Divide a saída em uma estrutura de árvore em vez de armazenar todas as funções em um único arquivo. Especifique a função que será usada como raiz da árvore. Para começar pela função principal padrão, use start.--split_mode: Modo de divisão da árvore. As opções são declarers, calls e references. Padrão: declarers.--inline_depth, -d: Nos modos calls e references, inclui funções alcançáveis a partir da raiz da árvore selecionada até a profundidade N no arquivo principal da árvore. Profundidade 0 significa apenas a raiz selecionada; profundidade 1 inclui chamadas/referências diretas; profundidade 2 inclui seus filhos. Não é usado com declarers.--inline_branch_limit, -l: No modo de árvore, incorpora ramificações filhas completas com no máximo N funções no arquivo principal da árvore quando as ramificações filhas são incluídas por --inline_depth. Ramificações maiores são salvas separadamente.--split_depth: Nos modos calls e references, limita a profundidade em que as ramificações de uso exportadas são percorridas. Padrão: 4.--include, -n: Arquivo contendo funções a serem incluídas na saída.--exclude, -x: Arquivo contendo funções a serem excluídas da saída.--func: Exibe uma função selecionada.--show_all: No modo de exibição de função, também mostra linhas marcadas como ocultas.--verbosity, -v: Nível de verbosidade. Intervalo aceito: 0 a 3.Para descompilar um arquivo de bytecode V8 e exportar o código descompilado:
python view8.py -i input_file -o output_filePor padrão, o View8 detecta a versão do bytecode V8 do arquivo de entrada usando VersionDetector.exe e procura automaticamente um binário de desmontador compatível na pasta Bin. Isso pode ser alterado especificando um binário de desmontador diferente com a opção --path ou -p:
python view8.py -i input_file -o output_file --path /caminho/para/desmontadorPara pular o processo de desmontagem e fornecer um arquivo já desmontado como entrada, use a opção --input_format disassembled ou -f disassembled:
python view8.py -i input_file -o output_file -f disassembledUse --normalize para substituir nomes de função derivados de endereços por identificadores determinísticos. Para preservar a relação entre os nomes originais e normalizados, adicione --normalize-map:
python view8.py \
--input_format disassembled \
--inp sample.jsc.disasm.txt \
--normalize \
--normalize-map \
--out decompiled/sample.dec.txt \
--export_format decompiled serializedIsso grava decompiled/sample.dec.name_map.csv com as seguintes colunas:
original_name,normalized_name
func_start_0x268514e9dcd9,func_start_0x100000000
func_rne_0x268514eb0779,func_rne_0x100000001Um caminho CSV explícito também pode ser fornecido:
python view8.py \
--input_format disassembled \
--inp sample.jsc.disasm.txt \
--normalize \
--normalize-map mappings/sample.names.csv \
--out decompiled/sample.dec.txtÀs vezes é útil descompilar o arquivo em um formato serializado que preserve os objetos e estruturas analisados. Esse tipo de saída pode ser mais fácil de pós-processar do que um formato de texto, por exemplo, durante uma desofuscação adicional. Para criar uma saída serializada, use o formato de exportação serialized:
python view8.py -i input_file -o output_file -e serializedAviso de segurança: o formato serializado atual é um arquivo pickle do Python (.pkl). Deserializar dados de fontes não confiáveis pode executar código arbitrário. Carregue apenas arquivos serializados que você mesmo gerou.
Para carregar uma saída serializada de volta e exportá-la em outro formato, use --input_format serialized ou -f serialized:
python view8.py -i input_file -o output_file -f serializedEspecifique o(s) formato(s) de exportação usando a opção --export_format ou -e. Você pode combinar vários formatos:
v8_opcodetranslateddecompiledserializedPor exemplo, para exportar tanto os opcodes V8 quanto o código descompilado lado a lado:
python view8.py -i input_file -o output_file -e v8_opcode decompiledPor padrão, o formato usado é decompiled.
Para grandes cargas úteis empacotadas, gravar todas as funções descompiladas em um único arquivo pode ser difícil de analisar. A saída em árvore divide a raiz selecionada e as funções relacionadas em uma estrutura de diretórios.
Use --tree para selecionar a raiz da árvore:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_out/ \
--tree startO valor especial start significa a função principal padrão recuperada pelo View8.
A árvore pode ser dividida usando um de três modos:
declarers: segue relações de declaração lexical, ou seja, quais funções são declaradas dentro ou sob outra função. Isso é útil para entender estruturas empacotadas ou semelhantes a módulos, mas não representa o fluxo de execução.calls: segue chamadas de função diretas, como func_x(...). Isso é útil para recuperar o esqueleto de execução a partir de uma raiz selecionada.references: segue todas as referências de função visíveis, não apenas chamadas diretas. Isso inclui callbacks, manipuladores exportados, manipuladores de rotas, propriedades de objetos e outras funções atribuídas. Este modo é útil para descobrir superfícies de capacidade, mas pode produzir árvores muito maiores do que calls.Exemplo:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode callsO arquivo principal da árvore sempre contém a função raiz selecionada.
Nos modos calls e references, --inline_depth controla quantos níveis do grafo são incluídos no arquivo principal:
--inline_depth 0 -> apenas a raiz
--inline_depth 1 -> raiz + chamadas/referências diretas
--inline_depth 2 -> raiz + chamadas/referências diretas + seus filhosPor exemplo, o seguinte comando cria uma visão geral de execução compacta contendo a raiz e suas chamadas diretas:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 1Para incluir uma camada adicional de chamadas:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 2--inline_depth é suportado apenas com os modos calls e references. Não é usado com declarers.
Ramificações filhas grandes são salvas em arquivos separados. Nos modos calls e references, --split_depth controla a profundidade em que as ramificações de uso exportadas são percorridas:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 1 \
--split_depth 5A opção --inline_branch_limit controla se ramificações filhas completas pequenas também são incluídas no arquivo principal:
--inline_branch_limit 3Isso significa que ramificações filhas completas contendo no máximo 3 funções podem ser incorporadas no arquivo principal. Ramificações maiores são salvas separadamente.
Nos modos calls e references, as ramificações filhas são incorporadas apenas quando o --inline_depth selecionado já inclui funções filhas. Por exemplo, --inline_depth 0 significa apenas a raiz, portanto as ramificações filhas não são incorporadas mesmo que sejam pequenas.
Para uma visão geral de execução compacta:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 1 \
--split_depth 5Para uma visão geral arquitetural mais ampla:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 2 \
--split_depth 5Para callbacks exportados, manipuladores, rotas e superfícies de capacidade:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_refs/ \
--tree start \
--split_mode references \
--inline_depth 1 \
--split_depth 3Para estrutura lexical ou semelhante a módulos:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_declarers/ \
--tree start \
--split_mode declarers \
--split_depth 3Para exibir uma função selecionada, use --func:
python view8.py \
--inp input.pkl \
--input_format serialized \
--func func_namePara também mostrar linhas marcadas como ocultas:
python view8.py \
--inp input.pkl \
--input_format serialized \
--func func_name \
--show_allA versão do bytecode V8 é armazenada como um hash no início do arquivo. Abaixo estão as opções disponíveis para VersionDetector.exe:
-h: Obtém uma versão e retorna seu hash.-d: Obtém um hash em formato little-endian e retorna sua versão correspondente usando força bruta.-f: Obtém um arquivo e retorna sua versão.