
Desofuscador fonte-a-fonte para VBScript e VBA com avaliação parcial
O vbSparkle é um desofuscador de Visual Basic multi-plataforma, de fonte para fonte, baseado em avaliação parcial e dedicado principalmente à análise de código malicioso escrito em VBScript e VBA (Macro do Office).
Ele é escrito em C# nativo e fornece uma biblioteca .Net Standard, funcionando em Windows, Linux, MacOS, etc..
A análise sintática de Visual Basic Script e VBA é processada através do uso de gramática e analisadores léxicos ANTLR.
Install-Package vbSparkle
dotnet add package vbSparkle
Depois de adicionar a biblioteca vbSparkle ao seu projeto, basta chamar a função PrettifyEncoded da classe estática VbPartialEvaluator:
string obfuscatedVB = "msgbox(chr(65)&chr(66)&(chr(67))"
string deobfuscated = VbPartialEvaluator.PrettifyEncoded(obfuscatedVB);
... retornará MsgBox("ABC").
O projeto anexo vbSparkle.CLI é um exemplo de uso do vbSparkle como CLI.
O exemplo atual aceita um caminho como argumento ou um binário completo em StdIn e retorna o resultado desofuscado.

O projeto anexo vbSparkle.Web é um exemplo de uso do vbSparkle dentro de uma interface Web.

A ofuscação de código VBScript e VBA é popular entre atacantes e permite evadir medidas de detecção, antivírus, firewalls, EDRs, além de dificultar a análise de malware.
Dessa forma, é comum ver VBScript ofuscado no primeiro estágio do comprometimento de uma máquina.
Uma técnica típica de ofuscação de código VBScript é encapsular o script em uma string ofuscada e executá-lo por meio da função Execute("...código..." ) depois de decodificado / avaliado.
Vejamos um exemplo:
Execute(chr( 456127/3833 ) & chr( 817650/7110 ) & chr( 759429/7671 ) & chr( 834138/7317 ) & chr( 57960/552 ) & chr( 2549-2437 ) & chr( 1078568/9298 ) & chr( 5143-5097 ) & chr( -8682+8783 ) & chr( 529-430 ) & chr( 673088/6472 ) & chr( 761682/6862 ) & chr( 302336/9448 ) & chr( 9427-9393 ) & chr( 410176/3944 ) & chr( -5271+5372 ) & chr( 796608/7376 ) & chr( 2896-2788 ) & chr( 318792/2872 ) & chr( 1076-1042 ) & vbcrlf )
Aqui, o atacante fez uso de:
chr(CHAR_CODE) para avaliar um caractere de string (ex.: chr(65) = "A")456127/3833) para avaliar o valor do caractere& para montar todos os caracteres decodificadosExecute(..) para executar o script decodificado.Se acompanharmos a execução do script:
456127/3833 => 119chr(119) => "w"817650/7110 => 115chr(115) => "s""w" & "s" => "ws"Execute("ws.....Aqui está o script original:
wscript.echo "hello"
A desofuscação manual torna-se muito difícil e demorada em scripts grandes.
Uma técnica comum de desofuscação com VBScript é simplesmente substituir a função Execute() por um WScript.Echo( e então executar o script para obter a saída.
Essa última técnica é simples, mas tem algumas desvantagens:
E, na época em que este projeto foi iniciado, não havia alternativa a essas duas técnicas.
A avaliação parcial não é um conceito novo; é usada principalmente por compiladores para otimização de código em processos de pré-compilação (ex.: https://en.wikipedia.org/wiki/Partial_evaluation).
Um avaliador parcial lê um programa (chamado de programa sujeito) juntamente com algumas das entradas desse programa e avalia apenas as partes do programa que dependem das entradas fornecidas. Uma vez que todas essas partes foram avaliadas, o programa restante (chamado de programa residual) é emitido como saída.
Por exemplo, um processo de pré-compilação transformaria o seguinte código sujeito:
var1 = 3*3
var2 = sin(arg1)
var3 = var1 + func_xx(2 * var1 + var2)
No seguinte código residual:
var2 = sin(arg1)
var3 = 9 + func_xx(18 + var2)
O código foi parcialmente avaliado antes da compilação, para otimizar o desempenho.
Vemos que esse processo simplifica o código e elimina operações desnecessárias. Isso é interessante porque a ofuscação esconde o código adicionando código e operações desnecessárias para a execução do código.
Se inspecionarmos nossa amostra inicial, passo a passo:
456127/3833 podem ser parcialmente avaliadas: sem efeitos colateraischr(119) pode ser parcialmente avaliado: 119 é uma constante, e esta é uma função nativa, sem efeitos colaterais"Execute(" tem efeitos colaterais conhecidos (execução de script), não será avaliado, exceto se os efeitos colaterais das funções puderem ser gerenciados / emuladosUma avaliação parcial dessa amostra resultaria em:
Execute("wscript.echo ""hello""" & vbCrLf)
E adivinhe? Ah, acabamos de desofuscar nossa amostra.
Bem, na prática, é muito mais complicado:
Felizmente, o ANTLR é um poderoso gerador de parsers para ler, processar, executar ou traduzir texto estruturado ou arquivos binários. Sabe-se que é amplamente usado para construir linguagens, ferramentas e frameworks. A partir de uma gramática, o ANTLR gera um parser que pode construir árvores de análise sintática e também gera uma interface de listener (ou visitor) que facilita responder ao reconhecimento de frases de interesse.
O ANTLR pode gerar lexers, parsers, tree parsers e lexer-parsers combinados. Os parsers podem gerar automaticamente árvores de análise sintática ou árvores sintáticas abstratas que podem ser processadas posteriormente com tree parsers. O ANTLR fornece uma notação única e consistente para especificar lexers, parsers e tree parsers.
Por padrão, o ANTLR lê uma gramática e gera um reconhecedor para a linguagem definida por ela (ou seja, um programa que lê um fluxo de entrada e gera um erro se o fluxo não estiver em conformidade com a sintaxe especificada pela gramática).
Para fazer algo útil com a linguagem, ações podem ser anexadas aos elementos da gramática. Essas ações são escritas na linguagem de programação na qual o reconhecedor está sendo gerado. Quando o reconhecedor é gerado, as ações são incorporadas ao código-fonte do reconhecedor nos pontos apropriados.
Graças ao ANTLR, foi rápido e fácil gerar uma primeira versão da AST, do lexer e do parser graças à gramática existente escrita por Ulrich Wolffgang.